summaryrefslogtreecommitdiffstats
path: root/src/libs/kdtools
diff options
context:
space:
mode:
Diffstat (limited to 'src/libs/kdtools')
-rw-r--r--src/libs/kdtools/filedownloader.cpp96
-rw-r--r--src/libs/kdtools/filedownloader.h6
-rw-r--r--src/libs/kdtools/filedownloader_p.h69
-rw-r--r--src/libs/kdtools/genericfactory.cpp26
-rw-r--r--src/libs/kdtools/genericfactory.h21
-rw-r--r--src/libs/kdtools/kdsysinfo_win.cpp14
-rw-r--r--src/libs/kdtools/localpackagehub.cpp36
-rw-r--r--src/libs/kdtools/localpackagehub.h12
-rw-r--r--src/libs/kdtools/lockfile_win.cpp2
-rw-r--r--src/libs/kdtools/sysinfo.cpp2
-rw-r--r--src/libs/kdtools/sysinfo_x11.cpp12
-rw-r--r--src/libs/kdtools/updatefinder.cpp414
-rw-r--r--src/libs/kdtools/updatefinder.h94
-rw-r--r--src/libs/kdtools/updateoperation.cpp179
-rw-r--r--src/libs/kdtools/updateoperation.h19
-rw-r--r--src/libs/kdtools/updateoperations.cpp65
-rw-r--r--src/libs/kdtools/updateoperations.h63
-rw-r--r--src/libs/kdtools/updatesinfo.cpp256
-rw-r--r--src/libs/kdtools/updatesinfo_p.h6
-rw-r--r--src/libs/kdtools/updatesinfodata_p.h14
20 files changed, 860 insertions, 546 deletions
diff --git a/src/libs/kdtools/filedownloader.cpp b/src/libs/kdtools/filedownloader.cpp
index a9f5040f0..4d4002b7a 100644
--- a/src/libs/kdtools/filedownloader.cpp
+++ b/src/libs/kdtools/filedownloader.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -657,14 +658,6 @@ void KDUpdater::FileDownloader::addCheckSumData(const QByteArray &data)
}
/*!
- Adds the \a length of characters of \a data to the cryptographic hash of the downloaded file.
-*/
-void KDUpdater::FileDownloader::addCheckSumData(const char *data, int length)
-{
- d->m_hash.addData(data, length);
-}
-
-/*!
Resets SHA-1 checksum data of the downloaded file.
*/
void KDUpdater::FileDownloader::resetCheckSumData()
@@ -732,6 +725,14 @@ void KDUpdater::FileDownloader::setIgnoreSslErrors(bool ignore)
d->m_ignoreSslErrors = ignore;
}
+/*!
+ Returns the number of received bytes.
+*/
+qint64 FileDownloader::getBytesReceived() const
+{
+ return d->m_bytesReceived;
+}
+
// -- KDUpdater::LocalFileDownloader
/*!
@@ -912,7 +913,7 @@ void KDUpdater::LocalFileDownloader::timerEvent(QTimerEvent *event)
toWrite -= numWritten;
}
addSample(numRead);
- addCheckSumData(buffer.data(), numRead);
+ addCheckSumData(buffer.left(numRead));
if (numRead > 0) {
setProgress(d->source->pos(), d->source->size());
emit downloadProgress(calcProgress(d->source->pos(), d->source->size()));
@@ -1104,7 +1105,7 @@ void KDUpdater::ResourceFileDownloader::timerEvent(QTimerEvent *event)
const qint64 numRead = d->destFile.read(buffer.data(), buffer.size());
addSample(numRead);
- addCheckSumData(buffer.data(), numRead);
+ addCheckSumData(buffer.left(numRead));
if (numRead > 0) {
setProgress(d->destFile.pos(), d->destFile.size());
@@ -1183,9 +1184,8 @@ struct KDUpdater::HttpDownloader::Private
disconnect(http, &QNetworkReply::finished, q, &HttpDownloader::httpReqFinished);
disconnect(http, &QNetworkReply::downloadProgress,
q, &HttpDownloader::httpReadProgress);
- void (QNetworkReply::*errorSignal)(QNetworkReply::NetworkError) = &QNetworkReply::error;
- disconnect(http, errorSignal, q, &HttpDownloader::httpError);
+ disconnect(http, &QNetworkReply::errorOccurred, q, &HttpDownloader::httpError);
http->deleteLater();
}
http = 0;
@@ -1211,8 +1211,14 @@ KDUpdater::HttpDownloader::HttpDownloader(QObject *parent)
#endif
connect(&d->manager, &QNetworkAccessManager::authenticationRequired,
this, &HttpDownloader::onAuthenticationRequired);
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
connect(&d->manager, &QNetworkAccessManager::networkAccessibleChanged,
this, &HttpDownloader::onNetworkAccessibleChanged);
+#else
+ auto netInfo = QNetworkInformation::instance();
+ connect(netInfo, &QNetworkInformation::reachabilityChanged,
+ this, &HttpDownloader::onReachabilityChanged);
+#endif
}
@@ -1305,7 +1311,7 @@ void KDUpdater::HttpDownloader::httpReadyRead()
written += numWritten;
}
addSample(written);
- addCheckSumData(buffer.data(), read);
+ addCheckSumData(buffer.left(read));
updateBytesDownloadedBeforeResume(written);
}
}
@@ -1467,29 +1473,47 @@ void KDUpdater::HttpDownloader::startDownload(const QUrl &url)
d->m_authenticationCount = 0;
d->manager.setProxyFactory(proxyFactory());
clearBytesDownloadedBeforeResume();
- d->http = d->manager.get(QNetworkRequest(url));
+
+ QNetworkRequest request(url);
+ request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::ManualRedirectPolicy);
+ request.setAttribute(QNetworkRequest::Http2AllowedAttribute, false);
+
+ d->http = d->manager.get(request);
connect(d->http, &QIODevice::readyRead, this, &HttpDownloader::httpReadyRead);
connect(d->http, &QNetworkReply::downloadProgress,
this, &HttpDownloader::httpReadProgress);
connect(d->http, &QNetworkReply::finished, this, &HttpDownloader::httpReqFinished);
- void (QNetworkReply::*errorSignal)(QNetworkReply::NetworkError) = &QNetworkReply::error;
- connect(d->http, errorSignal, this, &HttpDownloader::httpError);
+ connect(d->http, &QNetworkReply::errorOccurred, this, &HttpDownloader::httpError);
+ bool fileOpened = false;
if (d->destFileName.isEmpty()) {
QTemporaryFile *file = new QTemporaryFile(this);
- file->open();
+ fileOpened = file->open();
d->destination = file;
} else {
d->destination = new QFile(d->destFileName, this);
- d->destination->open(QIODevice::ReadWrite | QIODevice::Truncate);
+ fileOpened = d->destination->open(QIODevice::ReadWrite | QIODevice::Truncate);
}
-
- if (!d->destination->isOpen()) {
- const QString error = d->destination->errorString();
- const QString fileName = d->destination->fileName();
- d->shutDown();
- setDownloadAborted(tr("Cannot download %1. Cannot create file \"%2\": %3").arg(
- url.toString(), fileName, error));
+ if (!fileOpened) {
+ qCWarning(QInstaller::lcInstallerInstallLog).nospace() << "Failed to open file " << d->destFileName
+ << ": "<<d->destination->errorString() << ". Trying again.";
+ QFileInfo fileInfo;
+ fileInfo.setFile(d->destination->fileName());
+ if (!QDir().mkpath(fileInfo.absolutePath())) {
+ setDownloadAborted(tr("Cannot download %1. Cannot create directory for \"%2\"").arg(
+ url.toString(), fileInfo.filePath()));
+ } else {
+ fileOpened = d->destination->open(QIODevice::ReadWrite | QIODevice::Truncate);
+ if (fileOpened)
+ return;
+ if (d->destination->exists())
+ qCWarning(QInstaller::lcInstallerInstallLog) << "File exists but installer is unable to open it.";
+ else
+ qCWarning(QInstaller::lcInstallerInstallLog) << "File does not exist.";
+ setDownloadAborted(tr("Cannot download %1. Cannot create file \"%2\": %3").arg(
+ url.toString(), d->destination->fileName(), d->destination->errorString()));
+ d->shutDown();
+ }
}
}
@@ -1509,8 +1533,7 @@ void KDUpdater::HttpDownloader::resumeDownload()
connect(d->http, &QNetworkReply::downloadProgress,
this, &HttpDownloader::httpReadProgress);
connect(d->http, &QNetworkReply::finished, this, &HttpDownloader::httpReqFinished);
- void (QNetworkReply::*errorSignal)(QNetworkReply::NetworkError) = &QNetworkReply::error;
- connect(d->http, errorSignal, this, &HttpDownloader::httpError);
+ connect(d->http, &QNetworkReply::errorOccurred, this, &HttpDownloader::httpError);
runDownloadSpeedTimer();
runDownloadDeadlineTimer();
}
@@ -1552,6 +1575,7 @@ void KDUpdater::HttpDownloader::onAuthenticationRequired(QNetworkReply *reply, Q
}
}
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
void KDUpdater::HttpDownloader::onNetworkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible)
{
if (accessible == QNetworkAccessManager::NotAccessible) {
@@ -1566,6 +1590,22 @@ void KDUpdater::HttpDownloader::onNetworkAccessibleChanged(QNetworkAccessManager
}
}
}
+#else
+void KDUpdater::HttpDownloader::onReachabilityChanged(QNetworkInformation::Reachability newReachability)
+{
+ if (newReachability == QNetworkInformation::Reachability::Online) {
+ if (isDownloadPaused()) {
+ setDownloadPaused(false);
+ resumeDownload();
+ }
+ } else {
+ d->shutDown(false);
+ setDownloadPaused(true);
+ setDownloadResumed(false);
+ stopDownloadDeadlineTimer();
+ }
+}
+#endif
#ifndef QT_NO_SSL
@@ -1603,7 +1643,7 @@ void KDUpdater::HttpDownloader::onSslErrors(QNetworkReply* reply, const QList<QS
"the error may be temporary and you can try again.")));
msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
- msgBox.setButtonText(QMessageBox::Yes, tr("Try again"));
+ msgBox.addButton(tr("Try again"), QMessageBox::YesRole);
msgBox.setDefaultButton(QMessageBox::Cancel);
if (msgBox.exec() == QMessageBox::Cancel) {
diff --git a/src/libs/kdtools/filedownloader.h b/src/libs/kdtools/filedownloader.h
index ede20dcfa..e71f7d62f 100644
--- a/src/libs/kdtools/filedownloader.h
+++ b/src/libs/kdtools/filedownloader.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -58,6 +59,8 @@ public:
QByteArray assumedSha1Sum() const;
void setAssumedSha1Sum(const QByteArray &sha1);
+ void setCheckSha1Sum(const bool checkSha1Sum);
+ bool checkSha1Sum() const;
QString scheme() const;
void setScheme(const QString &scheme);
@@ -87,6 +90,8 @@ public:
bool ignoreSslErrors();
void setIgnoreSslErrors(bool ignore);
+ qint64 getBytesReceived() const;
+
public Q_SLOTS:
virtual void cancelDownload();
@@ -138,7 +143,6 @@ protected:
void emitEstimatedDownloadTime();
void addCheckSumData(const QByteArray &data);
- void addCheckSumData(const char *data, int length);
void resetCheckSumData();
private Q_SLOTS:
diff --git a/src/libs/kdtools/filedownloader_p.h b/src/libs/kdtools/filedownloader_p.h
index 41a430554..23eff08d7 100644
--- a/src/libs/kdtools/filedownloader_p.h
+++ b/src/libs/kdtools/filedownloader_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
+** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -34,6 +35,10 @@
#include <QtNetwork/QNetworkReply>
#include <QNetworkAccessManager>
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+#include <QNetworkInformation>
+#endif
+
// these classes are not a part of the public API
namespace KDUpdater {
@@ -46,22 +51,22 @@ public:
explicit LocalFileDownloader(QObject *parent = 0);
~LocalFileDownloader();
- bool canDownload() const;
- bool isDownloaded() const;
- QString downloadedFileName() const;
- void setDownloadedFileName(const QString &name);
- LocalFileDownloader *clone(QObject *parent = 0) const;
+ bool canDownload() const override;
+ bool isDownloaded() const override;
+ QString downloadedFileName() const override;
+ void setDownloadedFileName(const QString &name) override;
+ LocalFileDownloader *clone(QObject *parent = 0) const override;
public Q_SLOTS:
- void cancelDownload();
+ void cancelDownload() override;
protected:
- void timerEvent(QTimerEvent *te);
- void onError();
- void onSuccess();
+ void timerEvent(QTimerEvent *te) override;
+ void onError() override;
+ void onSuccess() override;
private Q_SLOTS:
- void doDownload();
+ void doDownload() override;
private:
struct Private;
@@ -76,22 +81,22 @@ public:
explicit ResourceFileDownloader(QObject *parent = 0);
~ResourceFileDownloader();
- bool canDownload() const;
- bool isDownloaded() const;
- QString downloadedFileName() const;
- void setDownloadedFileName(const QString &name);
- ResourceFileDownloader *clone(QObject *parent = 0) const;
+ bool canDownload() const override;
+ bool isDownloaded() const override;
+ QString downloadedFileName() const override;
+ void setDownloadedFileName(const QString &name) override;
+ ResourceFileDownloader *clone(QObject *parent = 0) const override;
public Q_SLOTS:
- void cancelDownload();
+ void cancelDownload() override;
protected:
- void timerEvent(QTimerEvent *te);
- void onError();
- void onSuccess();
+ void timerEvent(QTimerEvent *te) override;
+ void onError() override;
+ void onSuccess() override;
private Q_SLOTS:
- void doDownload();
+ void doDownload() override;
private:
struct Private;
@@ -106,22 +111,22 @@ public:
explicit HttpDownloader(QObject *parent = 0);
~HttpDownloader();
- bool canDownload() const;
- bool isDownloaded() const;
- QString downloadedFileName() const;
- void setDownloadedFileName(const QString &name);
- HttpDownloader *clone(QObject *parent = 0) const;
+ bool canDownload() const override;
+ bool isDownloaded() const override;
+ QString downloadedFileName() const override;
+ void setDownloadedFileName(const QString &name) override;
+ HttpDownloader *clone(QObject *parent = 0) const override;
public Q_SLOTS:
- void cancelDownload();
+ void cancelDownload() override;
protected:
- void onError();
- void onSuccess();
- void timerEvent(QTimerEvent *event);
+ void onError() override;
+ void onSuccess() override;
+ void timerEvent(QTimerEvent *event) override;
private Q_SLOTS:
- void doDownload();
+ void doDownload() override;
void httpReadyRead();
void httpReadProgress(qint64 done, qint64 total);
@@ -129,7 +134,11 @@ private Q_SLOTS:
void httpDone(bool error);
void httpReqFinished();
void onAuthenticationRequired(QNetworkReply *reply, QAuthenticator *authenticator);
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
void onNetworkAccessibleChanged(QNetworkAccessManager::NetworkAccessibility accessible);
+#else
+ void onReachabilityChanged(QNetworkInformation::Reachability newReachability);
+#endif
#ifndef QT_NO_SSL
void onSslErrors(QNetworkReply* reply, const QList<QSslError> &errors);
#endif
diff --git a/src/libs/kdtools/genericfactory.cpp b/src/libs/kdtools/genericfactory.cpp
index e45fb89ff..4d4fcac98 100644
--- a/src/libs/kdtools/genericfactory.cpp
+++ b/src/libs/kdtools/genericfactory.cpp
@@ -1,11 +1,11 @@
/****************************************************************************
**
** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
**
-** $QT_BEGIN_LICENSE:LGPL$
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -14,24 +14,13 @@
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
@@ -128,6 +117,7 @@
/*!
\fn template <typename BASE, typename IDENTIFIER, typename... ARGUMENTS> BASE *GenericFactory<BASE, IDENTIFIER, ARGUMENTS...>::create(const IDENTIFIER &id, ARGUMENTS... args) const
- Creates and returns the type identified by \a id, but automatically upcasted to BASE. Ownership
- of the type is transferred to the caller.
+ Creates and returns the type identified by \a id with variable number of
+ arguments \a args passed to the object's constructor, but automatically
+ upcasted to BASE. Ownership of the type is transferred to the caller.
*/
diff --git a/src/libs/kdtools/genericfactory.h b/src/libs/kdtools/genericfactory.h
index 467f797d6..885271150 100644
--- a/src/libs/kdtools/genericfactory.h
+++ b/src/libs/kdtools/genericfactory.h
@@ -1,11 +1,11 @@
/****************************************************************************
**
** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
-** Contact: http://www.qt.io/licensing/
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
**
-** $QT_BEGIN_LICENSE:LGPL$
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
@@ -14,24 +14,13 @@
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
diff --git a/src/libs/kdtools/kdsysinfo_win.cpp b/src/libs/kdtools/kdsysinfo_win.cpp
index 0aa7e7aa3..d423ef01e 100644
--- a/src/libs/kdtools/kdsysinfo_win.cpp
+++ b/src/libs/kdtools/kdsysinfo_win.cpp
@@ -66,9 +66,15 @@ QList<ProcessInfo> runningProcesses()
QStringList deviceList;
const DWORD bufferSize = 1024;
char buffer[bufferSize + 1] = { 0 };
- if (QSysInfo::windowsVersion() <= QSysInfo::WV_5_2) {
+
+ // Qt6 does not support Win before 10
+ bool winVerLessEqual5_2 = false;
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ winVerLessEqual5_2 = QSysInfo::windowsVersion() <= QSysInfo::WV_5_2;
+#endif
+ if (winVerLessEqual5_2) {
const DWORD size = GetLogicalDriveStringsA(bufferSize, buffer);
- deviceList = QString::fromLatin1(buffer, size).split(QLatin1Char(char(0)), QString::SkipEmptyParts);
+ deviceList = QString::fromLatin1(buffer, size).split(QLatin1Char(char(0)), Qt::SkipEmptyParts);
}
QLibrary kernel32(QLatin1String("Kernel32.dll"));
@@ -85,7 +91,7 @@ QList<ProcessInfo> runningProcesses()
processStruct.dwSize = sizeof(PROCESSENTRY32);
bool foundProcess = Process32First(snapshot, &processStruct);
while (foundProcess) {
- HANDLE procHandle = OpenProcess(QSysInfo::windowsVersion() > QSysInfo::WV_5_2
+ HANDLE procHandle = OpenProcess(!winVerLessEqual5_2
? KDSYSINFO_PROCESS_QUERY_LIMITED_INFORMATION : PROCESS_QUERY_INFORMATION, false, processStruct
.th32ProcessID);
@@ -93,7 +99,7 @@ QList<ProcessInfo> runningProcesses()
QString executablePath;
DWORD bufferSize = 1024;
- if (QSysInfo::windowsVersion() > QSysInfo::WV_5_2) {
+ if (!winVerLessEqual5_2) {
succ = pQueryFullProcessImageNamePtr(procHandle, 0, buffer, &bufferSize);
executablePath = QString::fromLatin1(buffer);
} else if (pGetProcessImageFileNamePtr) {
diff --git a/src/libs/kdtools/localpackagehub.cpp b/src/libs/kdtools/localpackagehub.cpp
index 2ee880e04..c7b627c51 100644
--- a/src/libs/kdtools/localpackagehub.cpp
+++ b/src/libs/kdtools/localpackagehub.cpp
@@ -1,8 +1,8 @@
/****************************************************************************
**
** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
**
@@ -124,6 +124,13 @@ bool LocalPackageHub::isValid() const
}
/*!
+ Returns a map of all local installed packages. Map key is the package name.
+*/
+QMap<QString, LocalPackage> LocalPackageHub::localPackages() const
+{
+ return d->m_packageInfoMap;
+}
+/*!
Returns a list of all local installed packages.
*/
QStringList LocalPackageHub::packageNames() const
@@ -306,6 +313,7 @@ void LocalPackageHub::refresh()
\a title,
\a treeName,
\a description,
+ \a sortingPriority,
\a dependencies,
\a autoDependencies,
\a forcedInstallation,
@@ -313,13 +321,15 @@ void LocalPackageHub::refresh()
\a uncompressedSize,
\a inheritVersionFrom,
\a checkable,
- and \a expandedByDefault for the package.
+ \a expandedByDefault,
+ and \a contentSha1 for the package.
*/
void LocalPackageHub::addPackage(const QString &name,
const QString &version,
const QString &title,
- const QString &treeName,
+ const QPair<QString, bool> &treeName,
const QString &description,
+ const int sortingPriority,
const QStringList &dependencies,
const QStringList &autoDependencies,
bool forcedInstallation,
@@ -344,6 +354,7 @@ void LocalPackageHub::addPackage(const QString &name,
info.title = title;
info.treeName = treeName;
info.description = description;
+ info.sortingPriority = sortingPriority;
info.dependencies = dependencies;
info.autoDependencies = autoDependencies;
info.forcedInstallation = forcedInstallation;
@@ -403,7 +414,9 @@ void LocalPackageHub::writeToDisk()
addTextChildHelper(&package, QLatin1String("Name"), info.name);
addTextChildHelper(&package, QLatin1String("Title"), info.title);
addTextChildHelper(&package, QLatin1String("Description"), info.description);
- addTextChildHelper(&package, scTreeName, info.treeName);
+ addTextChildHelper(&package, QLatin1String("SortingPriority"), QString::number(info.sortingPriority));
+ addTextChildHelper(&package, scTreeName, info.treeName.first, QLatin1String("moveChildren"),
+ QVariant(info.treeName.second).toString());
if (info.inheritVersionFrom.isEmpty())
addTextChildHelper(&package, QLatin1String("Version"), info.version);
else
@@ -476,9 +489,12 @@ void LocalPackageHub::PackagesInfoData::addPackageFrom(const QDomElement &packag
info.title = childNodeE.text();
else if (childNodeE.tagName() == QLatin1String("Description"))
info.description = childNodeE.text();
- else if (childNodeE.tagName() == scTreeName)
- info.treeName = childNodeE.text();
- else if (childNodeE.tagName() == QLatin1String("Version")) {
+ else if (childNodeE.tagName() == QLatin1String("SortingPriority"))
+ info.sortingPriority = childNodeE.text().toInt();
+ else if (childNodeE.tagName() == scTreeName) {
+ info.treeName.first = childNodeE.text();
+ info.treeName.second = QVariant(childNodeE.attribute(QLatin1String("moveChildren"))).toBool();
+ } else if (childNodeE.tagName() == QLatin1String("Version")) {
info.version = childNodeE.text();
info.inheritVersionFrom = childNodeE.attribute(QLatin1String("inheritVersionFrom"));
}
@@ -488,10 +504,10 @@ void LocalPackageHub::PackagesInfoData::addPackageFrom(const QDomElement &packag
info.uncompressedSize = childNodeE.text().toULongLong();
else if (childNodeE.tagName() == QLatin1String("Dependencies")) {
info.dependencies = childNodeE.text().split(QInstaller::commaRegExp(),
- QString::SkipEmptyParts);
+ Qt::SkipEmptyParts);
} else if (childNodeE.tagName() == QLatin1String("AutoDependOn")) {
info.autoDependencies = childNodeE.text().split(QInstaller::commaRegExp(),
- QString::SkipEmptyParts);
+ Qt::SkipEmptyParts);
} else if (childNodeE.tagName() == QLatin1String("ForcedInstallation"))
info.forcedInstallation = childNodeE.text().toLower() == QLatin1String( "true" ) ? true : false;
else if (childNodeE.tagName() == QLatin1String("LastUpdateDate"))
diff --git a/src/libs/kdtools/localpackagehub.h b/src/libs/kdtools/localpackagehub.h
index 648d6cf6e..5d69faf7d 100644
--- a/src/libs/kdtools/localpackagehub.h
+++ b/src/libs/kdtools/localpackagehub.h
@@ -1,8 +1,8 @@
/****************************************************************************
**
** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
**
@@ -43,7 +43,8 @@ struct KDTOOLS_EXPORT LocalPackage
QString name;
QString title;
QString description;
- QString treeName;
+ int sortingPriority;
+ QPair<QString, bool> treeName;
QString version;
QString inheritVersionFrom;
QStringList dependencies;
@@ -77,6 +78,8 @@ public:
};
bool isValid() const;
+
+ QMap<QString, LocalPackage> localPackages() const;
QStringList packageNames() const;
Error error() const;
@@ -100,8 +103,9 @@ public:
void addPackage(const QString &pkgName,
const QString &version, // mandatory
const QString &title,
- const QString &treeName,
+ const QPair<QString, bool> &treeName,
const QString &description,
+ const int sortingPriority,
const QStringList &dependencies,
const QStringList &autoDependencies,
bool forcedInstallation,
diff --git a/src/libs/kdtools/lockfile_win.cpp b/src/libs/kdtools/lockfile_win.cpp
index 20961cc4e..7fc808d39 100644
--- a/src/libs/kdtools/lockfile_win.cpp
+++ b/src/libs/kdtools/lockfile_win.cpp
@@ -45,7 +45,7 @@ bool LockFile::Private::lock()
errorString.clear();
handle = CreateFile(filename.toStdWString().data(), GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ, NULL, QFileInfo(filename).exists() ? OPEN_EXISTING : CREATE_NEW,
+ FILE_SHARE_READ, NULL, QFileInfo::exists(filename) ? OPEN_EXISTING : CREATE_NEW,
FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE, NULL);
if (handle == INVALID_HANDLE_VALUE) {
diff --git a/src/libs/kdtools/sysinfo.cpp b/src/libs/kdtools/sysinfo.cpp
index df9a374f2..9512e59e3 100644
--- a/src/libs/kdtools/sysinfo.cpp
+++ b/src/libs/kdtools/sysinfo.cpp
@@ -71,7 +71,7 @@ VolumeInfo VolumeInfo::fromPath(const QString &path)
}
// the target directory does not exist yet, we need to cd up till we find the first existing dir
- QStringList parts = targetPath.absolutePath().split(QDir::separator(),QString::SkipEmptyParts);
+ QStringList parts = targetPath.absolutePath().split(QDir::separator(), Qt::SkipEmptyParts);
while (targetPath.absolutePath() != QDir::rootPath()) {
if (targetPath.exists())
break;
diff --git a/src/libs/kdtools/sysinfo_x11.cpp b/src/libs/kdtools/sysinfo_x11.cpp
index bc55939a6..24ef099ca 100644
--- a/src/libs/kdtools/sysinfo_x11.cpp
+++ b/src/libs/kdtools/sysinfo_x11.cpp
@@ -40,7 +40,7 @@
#include <QtCore/QTextStream>
#include <QtCore/QDir>
#include <QtCore/QFileInfo>
-#include <QtCore/QRegExp>
+#include <QtCore/QRegularExpression>
namespace KDUpdater {
@@ -60,7 +60,7 @@ quint64 installedMemory()
else if (s.isEmpty())
return quint64();
- const QStringList parts = s.split(QLatin1Char(' '), QString::SkipEmptyParts);
+ const QStringList parts = s.split(QLatin1Char(' '), Qt::SkipEmptyParts);
return quint64(parts.at(1).toInt() * 1024LL);
}
#else
@@ -99,7 +99,7 @@ QList<VolumeInfo> mountedVolumes()
if (!s.startsWith(QLatin1Char('/')) && !s.startsWith(QLatin1String("tmpfs ") + QDir::tempPath()))
continue;
- const QStringList parts = s.split(QLatin1Char(' '), QString::SkipEmptyParts);
+ const QStringList parts = s.split(QLatin1Char(' '), Qt::SkipEmptyParts);
VolumeInfo v;
v.setMountPath(parts.at(1));
@@ -124,9 +124,9 @@ QList<ProcessInfo> runningProcesses()
QList<ProcessInfo> processes;
QDir procDir(QLatin1String("/proc"));
const QFileInfoList procCont = procDir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::Readable);
- QRegExp validator(QLatin1String("[0-9]+"));
- Q_FOREACH (const QFileInfo &info, procCont) {
- if (validator.exactMatch(info.fileName())) {
+ static const QRegularExpression validator(QLatin1String("^[0-9]+$"));
+ for (const QFileInfo &info : procCont) {
+ if (validator.match(info.fileName()).hasMatch()) {
const QString linkPath = QDir(info.absoluteFilePath()).absoluteFilePath(QLatin1String("exe"));
const QFileInfo linkInfo(linkPath);
if (linkInfo.exists()) {
diff --git a/src/libs/kdtools/updatefinder.cpp b/src/libs/kdtools/updatefinder.cpp
index 034e162d3..dbe7825df 100644
--- a/src/libs/kdtools/updatefinder.cpp
+++ b/src/libs/kdtools/updatefinder.cpp
@@ -1,8 +1,8 @@
/****************************************************************************
**
** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
-** Copyright (C) 2021 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
**
@@ -39,7 +39,8 @@
#include <QCoreApplication>
#include <QFileInfo>
-#include <QRegExp>
+#include <QRegularExpression>
+#include <QFutureWatcher>
using namespace KDUpdater;
using namespace QInstaller;
@@ -55,84 +56,107 @@ using namespace QInstaller;
objects.
*/
+
+static int computeProgressPercentage(int min, int max, int percent)
+{
+ return min + qint64(max-min) * percent / 100;
+}
+
+static int computePercent(int done, int total)
+{
+ return total ? done * Q_INT64_C(100) / total : 0 ;
+}
+
/*!
- \fn void KDUpdater::UpdateFinder::addCompressedPackage(bool add)
- \internal
+ Constructs an update finder.
+*/
+UpdateFinder::UpdateFinder()
+ : Task(QLatin1String("UpdateFinder"), Stoppable)
+ , m_cancel(false)
+ , m_downloadCompleteCount(0)
+ , m_downloadsToComplete(0)
+ , m_updatesXmlTasks(0)
+ , m_updatesXmlTasksToComplete(0)
+{
+}
+/*!
+ Destructor
*/
+UpdateFinder::~UpdateFinder()
+{
+ clear();
+}
/*!
- \fn void KDUpdater::UpdateFinder::isCompressedPackage()
- \internal
+ Returns a list of KDUpdater::Update objects.
+*/
+QList<Update *> UpdateFinder::updates() const
+{
+ return m_updates.values();
+}
+/*!
+ Sets the information about installed local packages \a hub.
*/
+void UpdateFinder::setLocalPackageHub(std::weak_ptr<LocalPackageHub> hub)
+{
+ m_localPackageHub = std::move(hub);
+}
-//
-// Private
-//
-class UpdateFinder::Private
+/*!
+ Sets the package \a sources information when searching for applicable packages.
+*/
+void UpdateFinder::setPackageSources(const QSet<PackageSource> &sources)
{
-public:
- enum struct Resolution {
- AddPackage,
- KeepExisting,
- RemoveExisting
- };
-
- explicit Private(UpdateFinder *qq)
- : q(qq)
- , cancel(false)
- , downloadCompleteCount(0)
- , m_downloadsToComplete(0)
- {}
-
- ~Private()
- {
- clear();
- }
+ m_packageSources = sources;
+}
- struct Data {
- Data()
- : downloader(0) {}
- explicit Data(const PackageSource &i, FileDownloader *d = 0)
- : info(i), downloader(d) {}
+/*!
+ \internal
- PackageSource info;
- FileDownloader *downloader;
- };
- UpdateFinder *q;
- QHash<QString, Update *> updates;
+ Implemented from KDUpdater::Task::doRun().
+*/
+void UpdateFinder::doRun()
+{
+ computeUpdates();
+}
- // Temporary structure that notes down information about updates.
- bool cancel;
- int downloadCompleteCount;
- int m_downloadsToComplete;
- QHash<UpdatesInfo *, Data> m_updatesInfoList;
+/*!
+ \internal
- void clear();
- void computeUpdates();
- void cancelComputeUpdates();
- bool downloadUpdateXMLFiles();
- bool computeApplicableUpdates();
+ Implemented from KDUpdater::Task::doStop().
+*/
+bool UpdateFinder::doStop()
+{
+ cancelComputeUpdates();
- QList<UpdateInfo> applicableUpdates(UpdatesInfo *updatesInfo);
- void createUpdateObjects(const PackageSource &source, const QList<UpdateInfo> &updateInfoList);
- Resolution checkPriorityAndVersion(const PackageSource &source, const QVariantHash &data) const;
- void slotDownloadDone();
+ // Wait until the cancel has actually happened, and then return.
+ // Thinking of using QMutex for this. Frank/Till any suggestions?
- QSet<PackageSource> packageSources;
- std::weak_ptr<LocalPackageHub> m_localPackageHub;
-};
+ return true;
+}
+/*!
+ \internal
-static int computeProgressPercentage(int min, int max, int percent)
+ Implemented from KDUpdater::Task::doStop().
+*/
+bool UpdateFinder::doPause()
{
- return min + qint64(max-min) * percent / 100;
+ // Not a pausable task
+ return false;
}
-static int computePercent(int done, int total)
+/*!
+ \internal
+
+ Implemented from KDUpdater::Task::doStop().
+*/
+bool UpdateFinder::doResume()
{
- return total ? done * Q_INT64_C(100) / total : 0 ;
+ // Not a pausable task, hence it is not resumable as well
+ return false;
}
/*!
@@ -140,20 +164,22 @@ static int computePercent(int done, int total)
Releases all internal resources consumed while downloading and computing updates.
*/
-void UpdateFinder::Private::clear()
+void UpdateFinder::clear()
{
- qDeleteAll(updates);
- updates.clear();
+ qDeleteAll(m_updates);
+ m_updates.clear();
const QList<Data> values = m_updatesInfoList.values();
foreach (const Data &data, values)
delete data.downloader;
- qDeleteAll(m_updatesInfoList.keys());
+ qDeleteAll(m_updatesInfoList.keyBegin(), m_updatesInfoList.keyEnd());
m_updatesInfoList.clear();
- downloadCompleteCount = 0;
+ m_downloadCompleteCount = 0;
m_downloadsToComplete = 0;
+ qDeleteAll(m_xmlFileTasks);
+ m_xmlFileTasks.clear();
}
/*!
@@ -176,51 +202,59 @@ void UpdateFinder::Private::clear()
\note Each time this function is called, all the previously computed updates are discarded
and its resources are freed.
*/
-void UpdateFinder::Private::computeUpdates()
+void UpdateFinder::computeUpdates()
{
// Computing updates is done in two stages
// 1. Downloading Update XML files from all the update sources
- // 2. Matching updates with Package XML and figuring out available updates
+ // 2. Parse attributes from Update XML documents to UpdateInfoList
+ // 3. Remove all updates with invalid content
+ // 4. Matching updates with Package XML and figuring out available updates
- if (!q->isCompressedPackage())
- clear();
- cancel = false;
+ clear();
+ m_cancel = false;
// First do some quick sanity checks on the packages info
std::shared_ptr<LocalPackageHub> packages = m_localPackageHub.lock();
if (!packages) {
- q->reportError(tr("Cannot access the package information of this application."));
+ reportError(tr("Cannot access the package information of this application."));
return;
}
if (!packages->isValid()) {
- q->reportError(packages->errorString());
+ reportError(packages->errorString());
return;
}
// Now do some quick sanity checks on the package sources.
- if (packageSources.count() <= 0) {
- q->reportError(tr("No package sources set for this application."));
+ if (m_packageSources.count() <= 0) {
+ reportError(tr("No package sources set for this application."));
return;
}
// Now we can start...
+ if (!downloadUpdateXMLFiles() || m_cancel) {
+ clear();
+ return;
+ }
+
+ if (!parseUpdateXMLFiles() || m_cancel) {
+ clear();
+ return;
+ }
- // Step 1: 0 - 49 percent
- if (!downloadUpdateXMLFiles() || cancel) {
+ if (!removeInvalidObjects() || m_cancel) {
clear();
return;
}
- // Step 2: 50 - 100 percent
- if (!computeApplicableUpdates() || cancel) {
+ if (!computeApplicableUpdates() || m_cancel) {
clear();
return;
}
// All done
- q->reportProgress(100, tr("%n update(s) found.", "", updates.count()));
- q->reportDone();
+ reportProgress(100, tr("%n update(s) found.", "", m_updates.count()));
+ reportDone();
}
/*!
@@ -230,9 +264,9 @@ void UpdateFinder::Private::computeUpdates()
\sa computeUpdates()
*/
-void UpdateFinder::Private::cancelComputeUpdates()
+void UpdateFinder::cancelComputeUpdates()
{
- cancel = true;
+ m_cancel = true;
}
/*!
@@ -251,32 +285,32 @@ void UpdateFinder::Private::cancelComputeUpdates()
The function gets into an event loop until all the downloads are complete.
*/
-bool UpdateFinder::Private::downloadUpdateXMLFiles()
+bool UpdateFinder::downloadUpdateXMLFiles()
{
// create UpdatesInfo for each update source
- foreach (const PackageSource &info, packageSources) {
+ foreach (const PackageSource &info, m_packageSources) {
const QUrl url = QString::fromLatin1("%1/Updates.xml").arg(info.url.toString());
if (url.scheme() != QLatin1String("resource") && url.scheme() != QLatin1String("file")) {
// create FileDownloader (except for local files and resources)
- FileDownloader *downloader = FileDownloaderFactory::instance().create(url.scheme(), q);
+ FileDownloader *downloader = FileDownloaderFactory::instance().create(url.scheme(), this);
if (!downloader)
break;
downloader->setUrl(url);
downloader->setAutoRemoveDownloadedFile(true);
- connect(downloader, SIGNAL(downloadCanceled()), q, SLOT(slotDownloadDone()));
- connect(downloader, SIGNAL(downloadCompleted()), q, SLOT(slotDownloadDone()));
- connect(downloader, SIGNAL(downloadAborted(QString)), q, SLOT(slotDownloadDone()));
- m_updatesInfoList.insert(new UpdatesInfo, Data(info, downloader));
+ connect(downloader, SIGNAL(downloadCanceled()), this, SLOT(slotDownloadDone()));
+ connect(downloader, SIGNAL(downloadCompleted()), this, SLOT(slotDownloadDone()));
+ connect(downloader, SIGNAL(downloadAborted(QString)), this, SLOT(slotDownloadDone()));
+ m_updatesInfoList.insert(new UpdatesInfo(info.postLoadComponentScript), Data(info, downloader));
} else {
- UpdatesInfo *updatesInfo = new UpdatesInfo;
+ UpdatesInfo *updatesInfo = new UpdatesInfo(info.postLoadComponentScript);
updatesInfo->setFileName(QInstaller::pathFromUrl(url));
m_updatesInfoList.insert(updatesInfo, Data(info));
}
}
// Trigger download of Updates.xml file
- downloadCompleteCount = 0;
+ m_downloadCompleteCount = 0;
m_downloadsToComplete = 0;
foreach (const Data &data, m_updatesInfoList) {
if (data.downloader) {
@@ -286,39 +320,53 @@ bool UpdateFinder::Private::downloadUpdateXMLFiles()
}
// Wait until all downloaders have completed their downloads.
- while (true) {
- QCoreApplication::processEvents();
- if (cancel)
- return false;
-
- if (downloadCompleteCount == m_downloadsToComplete)
- break;
-
- q->reportProgress(computePercent(downloadCompleteCount, m_downloadsToComplete),
- tr("Downloading Updates.xml from update sources."));
- }
+ return waitForJobToFinish(m_downloadCompleteCount, m_downloadsToComplete);
+}
+/*!
+ \internal
+*/
+bool UpdateFinder::parseUpdateXMLFiles()
+{
// Setup the update info objects with the files from download.
- foreach (UpdatesInfo *updatesInfo, m_updatesInfoList.keys()) {
+ m_updatesXmlTasks = 0;
+ m_updatesXmlTasksToComplete = 0;
+ QList<UpdatesInfo *> keys = m_updatesInfoList.keys();
+ for (UpdatesInfo *updatesInfo : qAsConst(keys)) {
const Data data = m_updatesInfoList.value(updatesInfo);
if (data.downloader) {
if (!data.downloader->isDownloaded()) {
- q->reportError(tr("Cannot download package source %1 from \"%2\".").arg(data
- .downloader->url().fileName(), data.info.url.toString()));
+ reportError(tr("Cannot download package source %1 from \"%2\".").arg(data.
+ downloader->url().fileName(), data.info.url.toString()));
} else {
updatesInfo->setFileName(data.downloader->downloadedFileName());
}
}
+ if (!updatesInfo->fileName().isEmpty()) {
+ ParseXmlFilesTask *const task = new ParseXmlFilesTask(updatesInfo);
+ m_xmlFileTasks.append(task);
+ QFutureWatcher<void> *watcher = new QFutureWatcher<void>();
+ m_updatesXmlTasksToComplete++;
+ connect(watcher, &QFutureWatcherBase::finished, this, &UpdateFinder::parseUpdatesXmlTaskFinished);
+ watcher->setFuture(QtConcurrent::run(&ParseXmlFilesTask::doTask, task));
+ }
}
- // Remove all invalid update info objects.
+ // Wait until all updates.xml files are parsed
+ return waitForJobToFinish(m_updatesXmlTasks, m_updatesXmlTasksToComplete);
+}
+/*!
+ \internal
+*/
+bool UpdateFinder::removeInvalidObjects()
+{
QMutableHashIterator<UpdatesInfo *, Data> it(m_updatesInfoList);
while (it.hasNext()) {
UpdatesInfo *info = it.next().key();
if (info->isValid())
continue;
- q->reportError(info->errorString());
+ reportError(info->errorString());
delete info;
it.remove();
}
@@ -326,7 +374,7 @@ bool UpdateFinder::Private::downloadUpdateXMLFiles()
if (m_updatesInfoList.isEmpty())
return false;
- q->reportProgress(49, tr("Updates.xml file(s) downloaded from update sources."));
+ reportProgress(49, tr("Updates.xml file(s) downloaded from update sources."));
return true;
}
@@ -338,36 +386,40 @@ bool UpdateFinder::Private::downloadUpdateXMLFiles()
KDUpdater::PackagesInfo. Thereby figures out whether an update is applicable for
this application or not.
*/
-bool UpdateFinder::Private::computeApplicableUpdates()
+bool UpdateFinder::computeApplicableUpdates()
{
int i = 0;
- foreach (UpdatesInfo *updatesInfo, m_updatesInfoList.keys()) {
+ QList<UpdatesInfo *> keys = m_updatesInfoList.keys();
+ for (UpdatesInfo *updatesInfo : qAsConst(keys)) {
// Fetch updates applicable to this application.
QList<UpdateInfo> updates = applicableUpdates(updatesInfo);
if (!updates.count())
continue;
- if (cancel)
+ if (m_cancel)
return false;
const PackageSource updateSource = m_updatesInfoList.value(updatesInfo).info;
// Create Update objects for updates that have a valid
// UpdateFile
createUpdateObjects(updateSource, updates);
- if (cancel)
+ if (m_cancel)
return false;
// Report progress
- q->reportProgress(computeProgressPercentage(51, 100, computePercent(i,
+ reportProgress(computeProgressPercentage(51, 100, computePercent(i,
m_updatesInfoList.count())), tr("Computing applicable updates."));
++i;
}
- q->reportProgress(99, tr("Application updates computed."));
+ reportProgress(99, tr("Application updates computed."));
return true;
}
-QList<UpdateInfo> UpdateFinder::Private::applicableUpdates(UpdatesInfo *updatesInfo)
+/*!
+ \internal
+*/
+QList<UpdateInfo> UpdateFinder::applicableUpdates(UpdatesInfo *updatesInfo)
{
const QList<UpdateInfo> dummy;
if (!updatesInfo || updatesInfo->updateInfoCount() == 0)
@@ -387,7 +439,7 @@ QList<UpdateInfo> UpdateFinder::Private::applicableUpdates(UpdatesInfo *updatesI
// Catch hold of app names contained updatesInfo->applicationName()
// If the application appName isn't one of the app names, then the updates are not applicable.
- const QStringList apps = appName.split(QInstaller::commaRegExp(), QString::SkipEmptyParts);
+ const QStringList apps = appName.split(QInstaller::commaRegExp(), Qt::SkipEmptyParts);
if (apps.indexOf([&packages] { return packages->isValid() ? packages->applicationName()
: QCoreApplication::applicationName(); } ()) < 0) {
return dummy;
@@ -396,7 +448,10 @@ QList<UpdateInfo> UpdateFinder::Private::applicableUpdates(UpdatesInfo *updatesI
return updatesInfo->updatesInfo();
}
-void UpdateFinder::Private::createUpdateObjects(const PackageSource &source,
+/*!
+ \internal
+*/
+void UpdateFinder::createUpdateObjects(const PackageSource &source,
const QList<UpdateInfo> &updateInfoList)
{
foreach (const UpdateInfo &info, updateInfoList) {
@@ -406,24 +461,24 @@ void UpdateFinder::Private::createUpdateObjects(const PackageSource &source,
const QString name = info.data.value(QLatin1String("Name")).toString();
if (value == Resolution::RemoveExisting)
- delete updates.take(name);
+ delete m_updates.take(name);
// Create and register the update
- if (!q->isCompressedPackage() || value == Resolution::AddPackage)
- updates.insert(name, new Update(source, info));
+ m_updates.insert(name, new Update(source, info));
}
}
-/*
+/*!
+ \internal
If a package of the same name exists, always use the one with the higher
version. If the new package has the same version but a higher
priority, use the new new package, otherwise keep the already existing package.
*/
-UpdateFinder::Private::Resolution UpdateFinder::Private::checkPriorityAndVersion(
+UpdateFinder::Resolution UpdateFinder::checkPriorityAndVersion(
const PackageSource &source, const QVariantHash &newPackage) const
{
const QString name = newPackage.value(QLatin1String("Name")).toString();
- if (Update *existingPackage = updates.value(name)) {
+ if (Update *existingPackage = m_updates.value(name)) {
// Bingo, package was previously found elsewhere.
const int match = compareVersion(newPackage.value(QLatin1String("Version")).toString(),
@@ -450,118 +505,56 @@ UpdateFinder::Private::Resolution UpdateFinder::Private::checkPriorityAndVersion
<< ", Source: " << QFileInfo(source.url.toLocalFile()).fileName() << "'";
return Resolution::RemoveExisting;
}
- if (q->isCompressedPackage() && match == 0 && source.priority == existingPackage->packageSource().priority) {
- //Same package with the same priority and version already exists
- return Resolution::RemoveExisting;
- }
return Resolution::KeepExisting; // otherwise keep existing
}
return Resolution::AddPackage;
}
-//
-// UpdateFinder
-//
-
-/*!
- Constructs an update finder.
-*/
-UpdateFinder::UpdateFinder()
- : Task(QLatin1String("UpdateFinder"), Stoppable),
- m_compressedPackage(false),
- d(new Private(this))
-{
-}
-
-/*!
- Destructor
-*/
-UpdateFinder::~UpdateFinder()
-{
- delete d;
-}
-
-/*!
- Returns a list of KDUpdater::Update objects.
-*/
-QList<Update *> UpdateFinder::updates() const
-{
- return d->updates.values();
-}
-
-/*!
- Sets the information about installed local packages \a hub.
-*/
-void UpdateFinder::setLocalPackageHub(std::weak_ptr<LocalPackageHub> hub)
-{
- d->m_localPackageHub = std::move(hub);
-}
-
-/*!
- Sets the package \a sources information when searching for applicable packages.
-*/
-void UpdateFinder::setPackageSources(const QSet<PackageSource> &sources)
-{
- d->packageSources = sources;
-}
-
/*!
\internal
-
- Implemented from KDUpdater::Task::doRun().
*/
-void UpdateFinder::doRun()
+bool UpdateFinder::waitForJobToFinish(const int &currentCount, const int &totalsCount)
{
- d->computeUpdates();
-}
-
-/*!
- \internal
-
- Implemented from KDUpdater::Task::doStop().
-*/
-bool UpdateFinder::doStop()
-{
- d->cancelComputeUpdates();
+ while (true) {
+ QCoreApplication::processEvents();
+ if (m_cancel)
+ return false;
- // Wait until the cancel has actually happened, and then return.
- // Thinking of using QMutex for this. Frank/Till any suggestions?
+ if (currentCount == totalsCount)
+ break;
+ reportProgress(computePercent(currentCount, totalsCount),
+ tr("Downloading Updates.xml from update sources."));
+ }
return true;
}
-
/*!
\internal
-
- Implemented from KDUpdater::Task::doStop().
*/
-bool UpdateFinder::doPause()
+void UpdateFinder::parseUpdatesXmlTaskFinished()
{
- // Not a pausable task
- return false;
-}
+ ++m_updatesXmlTasks;
-/*!
- \internal
+ int pc = computePercent(m_updatesXmlTasks, m_updatesXmlTasksToComplete);
+ pc = computeProgressPercentage(0, 45, pc);
+ reportProgress( pc, tr("Downloading Updates.xml from update sources.") );
- Implemented from KDUpdater::Task::doStop().
-*/
-bool UpdateFinder::doResume()
-{
- // Not a pausable task, hence it is not resumable as well
- return false;
+ QFutureWatcher<void> *watcher = static_cast<QFutureWatcher<void> *>(sender());
+ watcher->waitForFinished();
+ watcher->deleteLater();
}
+
/*!
\internal
*/
-void UpdateFinder::Private::slotDownloadDone()
+void UpdateFinder::slotDownloadDone()
{
- ++downloadCompleteCount;
+ ++m_downloadCompleteCount;
- int pc = computePercent(downloadCompleteCount, m_downloadsToComplete);
+ int pc = computePercent(m_downloadCompleteCount, m_downloadsToComplete);
pc = computeProgressPercentage(0, 45, pc);
- q->reportProgress( pc, tr("Downloading Updates.xml from update sources.") );
+ reportProgress( pc, tr("Downloading Updates.xml from update sources.") );
}
@@ -607,8 +600,9 @@ int KDUpdater::compareVersion(const QString &v1, const QString &v2)
return 0;
// Split version components across ".", "-" or "_"
- QStringList v1_comps = v1.split(QRegExp(QLatin1String( "\\.|-|_")));
- QStringList v2_comps = v2.split(QRegExp(QLatin1String( "\\.|-|_")));
+ static const QRegularExpression regex(QLatin1String( "\\.|-|_"));
+ QStringList v1_comps = v1.split(regex);
+ QStringList v2_comps = v2.split(regex);
// Check each component of the version
int index = 0;
diff --git a/src/libs/kdtools/updatefinder.h b/src/libs/kdtools/updatefinder.h
index 47fa42c9a..626a700fd 100644
--- a/src/libs/kdtools/updatefinder.h
+++ b/src/libs/kdtools/updatefinder.h
@@ -1,8 +1,8 @@
/****************************************************************************
**
** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
-** Copyright (C) 2017 The Qt Company Ltd.
-** Contact: http://www.qt.io/licensing/
+** Copyright (C) 2023 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
**
@@ -32,19 +32,68 @@
#include "task.h"
#include "packagesource.h"
+#include "filedownloader.h"
+#include "updatesinfo_p.h"
+#include "abstracttask.h"
#include <memory>
+using namespace QInstaller;
namespace KDUpdater {
class LocalPackageHub;
class Update;
+class ParseXmlFilesTask : public AbstractTask<void>
+{
+ Q_OBJECT
+ Q_DISABLE_COPY(ParseXmlFilesTask)
+
+public:
+ ParseXmlFilesTask(UpdatesInfo *info)
+ : m_info(info)
+ {}
+
+ void doTask(QFutureInterface<void> &fi) override
+ {
+ fi.reportStarted();
+ fi.setExpectedResultCount(1);
+
+ if (fi.isCanceled()) {
+ fi.reportFinished();
+ return; // ignore already canceled
+ }
+ m_info->parseFile();
+
+ fi.reportFinished();
+ }
+
+private:
+ UpdatesInfo *const m_info;
+};
+
+
class KDTOOLS_EXPORT UpdateFinder : public Task
{
Q_OBJECT
class Private;
+ struct Data {
+ Data()
+ : downloader(0) {}
+ explicit Data(const QInstaller::PackageSource &i, KDUpdater::FileDownloader *d = 0)
+ : info(i), downloader(d) {}
+
+ QInstaller::PackageSource info;
+ KDUpdater::FileDownloader *downloader;
+ };
+
+ enum struct Resolution {
+ AddPackage,
+ KeepExisting,
+ RemoveExisting
+ };
+
public:
UpdateFinder();
~UpdateFinder();
@@ -53,18 +102,41 @@ public:
void setLocalPackageHub(std::weak_ptr<LocalPackageHub> hub);
void setPackageSources(const QSet<QInstaller::PackageSource> &sources);
- void addCompressedPackage(bool add) { m_compressedPackage = add; }
- bool isCompressedPackage() { return m_compressedPackage; }
+
private:
- void doRun();
- bool doStop();
- bool doPause();
- bool doResume();
+ void doRun() override;
+ bool doStop() override;
+ bool doPause() override;
+ bool doResume() override;
+ void clear();
+ void computeUpdates();
+ void cancelComputeUpdates();
+ bool downloadUpdateXMLFiles();
+ bool parseUpdateXMLFiles();
+ bool removeInvalidObjects();
+ bool computeApplicableUpdates();
+
+ QList<UpdateInfo> applicableUpdates(UpdatesInfo *updatesInfo);
+ void createUpdateObjects(const PackageSource &source, const QList<UpdateInfo> &updateInfoList);
+ Resolution checkPriorityAndVersion(const QInstaller::PackageSource &source, const QVariantHash &data) const;
+ bool waitForJobToFinish(const int &currentCount, const int &totalsCount);
+
+private slots:
+ void parseUpdatesXmlTaskFinished();
+ void slotDownloadDone();
private:
- bool m_compressedPackage;
- Private *d;
- Q_PRIVATE_SLOT(d, void slotDownloadDone())
+ QSet<PackageSource> m_packageSources;
+ std::weak_ptr<LocalPackageHub> m_localPackageHub;
+ QHash<QString, Update *> m_updates;
+
+ bool m_cancel;
+ int m_downloadCompleteCount;
+ int m_downloadsToComplete;
+ QHash<UpdatesInfo *, Data> m_updatesInfoList;
+ int m_updatesXmlTasks;
+ int m_updatesXmlTasksToComplete;
+ QList<ParseXmlFilesTask*> m_xmlFileTasks;
};
} // namespace KDUpdater
diff --git a/src/libs/kdtools/updateoperation.cpp b/src/libs/kdtools/updateoperation.cpp
index 897fecf1b..af89382a8 100644
--- a/src/libs/kdtools/updateoperation.cpp
+++ b/src/libs/kdtools/updateoperation.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -80,6 +81,21 @@ using namespace KDUpdater;
Undo operation.
*/
+/*!
+ \enum UpdateOperation::OperationGroup
+ This enum specifies the execution group of the operation.
+
+ \value Unpack
+ Operation should be run in the unpacking phase. Operations in
+ this group are run concurrently between all selected components.
+ \value Install
+ Operation should be run in the installation phase.
+ \value All
+ All available operation groups.
+ \value Default
+ The default group for operations, synonym for Install.
+*/
+
/*
\internal
Returns a filename for a temporary file based on \a templateName.
@@ -99,10 +115,13 @@ static QString backupFileName(const QString &templateName)
\internal
*/
UpdateOperation::UpdateOperation(QInstaller::PackageManagerCore *core)
- : m_error(0)
+ : m_group(OperationGroup::Default)
+ , m_error(0)
, m_core(core)
, m_requiresUnreplacedVariables(false)
{
+ qRegisterMetaType<UpdateOperation *>();
+
// Store the value for compatibility reasons.
m_values[QLatin1String("installer")] = QVariant::fromValue(core);
}
@@ -139,6 +158,16 @@ QString UpdateOperation::operationCommand() const
}
/*!
+ Returns the execution group this operation belongs to.
+
+ \sa setGroup()
+*/
+UpdateOperation::OperationGroup UpdateOperation::group() const
+{
+ return m_group;
+}
+
+/*!
Returns \c true if a value called \a name exists, otherwise returns \c false.
*/
bool UpdateOperation::hasValue(const QString &name) const
@@ -180,6 +209,17 @@ void UpdateOperation::setName(const QString &name)
}
/*!
+ Sets the execution group of the operation to \a group. Subclasses can change
+ the group to control which installation phase this operation should be run in.
+
+ The default group is \c Install.
+*/
+void UpdateOperation::setGroup(const OperationGroup &group)
+{
+ m_group = group;
+}
+
+/*!
Sets the arguments for the update operation to \a args.
*/
void UpdateOperation::setArguments(const QStringList &args)
@@ -252,23 +292,18 @@ QStringList UpdateOperation::parsePerformOperationArguments()
}
/*!
- Returns undo operation argument list. If the installation is
- cancelled or failed, returns an empty list so that full undo
- operation can be performed.
+ Returns \c true if operation undo should not be performed.
+ Returns \c false if the installation is cancelled or failed, or
+ \c UNDOOPERATION is not set in operation call.
*/
-QStringList UpdateOperation::parseUndoOperationArguments()
+bool UpdateOperation::skipUndoOperation()
{
//Install has failed, allow a normal undo
if (m_core && (m_core->status() == QInstaller::PackageManagerCore::Canceled
|| m_core->status() == QInstaller::PackageManagerCore::Failure)) {
- return QStringList();
- }
- int index = arguments().indexOf(QLatin1String("UNDOOPERATION"));
- QStringList args;
- if ((index != -1) && (arguments().length() > index + 1)) {
- args = arguments().mid(index + 1);
+ return false;
}
- return args;
+ return arguments().contains(QLatin1String("UNDOOPERATION"));
}
/*!
@@ -281,6 +316,41 @@ void UpdateOperation::setRequiresUnreplacedVariables(bool isRequired)
m_requiresUnreplacedVariables = isRequired;
}
+/*!
+ Replaces installer \c value \a variableValue with predefined variable.
+ If \c key is found for the \a variableValue and the \c key ends with string _OLD,
+ the initial \a variableValue is replaced with the \c value having a key
+ without _OLD ending. This way we can replace the hard coded values defined for operations,
+ if the value has for some reason changed. For example if we set following variables
+ in install script:
+ \badcode
+ installer.setValue("MY_OWN_EXECUTABLE", "C:/Qt/NewLocation/Tools.exe")
+ installer.setValue("MY_OWN_EXECUTABLE_OLD", "C:/Qt/OldLocation/Tools.exe")
+ \endcode
+ and we have moved the Tools.exe from OldLocation to NewLocation, the operation
+ continues to work and use the Tools.exe from NewLocation although original
+ installation has been made with Tools.exe in OldLocation.
+ Returns \c true if \a variableValue is replaced.
+*/
+bool UpdateOperation::variableReplacement(QString *variableValue)
+{
+ bool variableValueChanged = false;
+ const QString valueNormalized = QDir::cleanPath(*variableValue);
+ QString key = m_core->key(valueNormalized);
+ if (key.endsWith(QLatin1String("_OLD"))) {
+ key.chop(4);
+ if (m_core->containsValue(key)) {
+ key.prepend(QLatin1String("@"));
+ key.append(QLatin1String("@"));
+ *variableValue = m_core->replaceVariables(key);
+ qCDebug(QInstaller::lcInstallerInstallLog) << "Running above operation with replaced value: " << valueNormalized
+ << "has been replaced with" << *variableValue;
+ variableValueChanged = true;
+ }
+ }
+ return variableValueChanged;
+}
+
struct StartsWith
{
explicit StartsWith(const QString &searchTerm)
@@ -475,8 +545,15 @@ QDomDocument UpdateOperation::toXml() const
const QString target = m_core ? m_core->value(QInstaller::scTargetDir) : QString();
Q_FOREACH (const QString &s, arguments()) {
QDomElement arg = doc.createElement(QLatin1String("argument"));
- arg.appendChild(doc.createTextNode(QInstaller::replacePath(s, target,
- QLatin1String(QInstaller::scRelocatable))));
+ // Do not call cleanPath to Execute operations paths. The operation might require the
+ // exact separators that are set in the operation call.
+ if (name() == QLatin1String("Execute")) {
+ arg.appendChild(doc.createTextNode(QInstaller::replacePath(s, target,
+ QLatin1String(QInstaller::scRelocatable), false)));
+ } else {
+ arg.appendChild(doc.createTextNode(QInstaller::replacePath(s, target,
+ QLatin1String(QInstaller::scRelocatable))));
+ }
args.appendChild(arg);
}
root.appendChild(args);
@@ -495,14 +572,21 @@ QDomDocument UpdateOperation::toXml() const
value.setAttribute(QLatin1String("name"), it.key());
value.setAttribute(QLatin1String("type"), QLatin1String(variant.typeName()));
- if (variant.type() != QVariant::List && variant.type() != QVariant::StringList
- && variant.canConvert(QVariant::String)) {
- // it can convert to string? great!
- value.appendChild(doc.createTextNode(QInstaller::replacePath(variant.toString(),
- target, QLatin1String(QInstaller::scRelocatable))));
+ int variantType;
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ variantType = variant.typeId();
+#else
+ variantType = variant.type();
+#endif
+
+ if (variantType != QMetaType::QStringList
+ && variant.canConvert<QString>()) {
+ // it can convert to string? great!
+ value.appendChild(doc.createTextNode(QInstaller::replacePath(variant.toString(),
+ target, QLatin1String(QInstaller::scRelocatable))));
} else {
// no? then we have to go the hard way...
- if (variant.type() == QVariant::StringList) {
+ if (variantType == QMetaType::QStringList) {
QStringList list = variant.toStringList();
for (int i = 0; i < list.count(); ++i) {
list[i] = QInstaller::replacePath(list.at(i), target,
@@ -528,6 +612,7 @@ QDomDocument UpdateOperation::toXml() const
bool UpdateOperation::fromXml(const QDomDocument &doc)
{
QString target = QCoreApplication::applicationDirPath();
+ static const QLatin1String relocatable = QLatin1String(QInstaller::scRelocatable);
// Does not change target on non macOS platforms.
if (QInstaller::isInBundle(target, &target))
target = QDir::cleanPath(target + QLatin1String("/.."));
@@ -539,8 +624,20 @@ bool UpdateOperation::fromXml(const QDomDocument &doc)
for (QDomNode n = argsElem.firstChild(); ! n.isNull(); n = n.nextSibling()) {
const QDomElement e = n.toElement();
if (!e.isNull() && e.tagName() == QLatin1String("argument")) {
- args << QInstaller::replacePath(e.text(), QLatin1String(QInstaller::scRelocatable),
- target);
+ // Sniff the Execute -operations file path separator. The operation might be
+ // strict with the used path separator
+ bool useCleanPath = true;
+ if (name() == QLatin1String("Execute")) {
+ if (e.text().startsWith(relocatable) && e.text().size() > relocatable.size()) {
+ const QChar separator = e.text().at(relocatable.size());
+ if (separator == QLatin1Char('\\')) {
+ target = QDir::toNativeSeparators(target);
+ useCleanPath = false;
+ }
+ }
+ }
+ args << QInstaller::replacePath(e.text(), relocatable,
+ target, useCleanPath);
}
}
setArguments(args);
@@ -556,25 +653,31 @@ bool UpdateOperation::fromXml(const QDomDocument &doc)
const QString type = v.attribute(QLatin1String("type"));
const QString value = v.text();
+ int variantType;
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ const QMetaType t = QMetaType::fromName(type.toLatin1().data());
+ variantType = t.id();
+#else
const QVariant::Type t = QVariant::nameToType(type.toLatin1().data());
- QVariant var = qVariantFromValue(value);
- if (t == QVariant::List || t == QVariant::StringList || !var.convert(t)) {
- QDataStream stream(QByteArray::fromBase64( value.toLatin1()));
+ variantType = t;
+#endif
+ QVariant var = QVariant::fromValue(value);
+ if (variantType == QMetaType::QStringList || !var.canConvert(t)) {
+ QDataStream stream(QByteArray::fromBase64(value.toLatin1()));
stream >> var;
- if (t == QVariant::StringList) {
+ if (variantType == QMetaType::QStringList) {
QStringList list = var.toStringList();
for (int i = 0; i < list.count(); ++i) {
list[i] = QInstaller::replacePath(list.at(i),
- QLatin1String(QInstaller::scRelocatable), target);
+ relocatable, target);
}
var = QVariant::fromValue(list);
}
- } else if (t == QVariant::String) {
- const QString str = QInstaller::replacePath(value,
- QLatin1String(QInstaller::scRelocatable), target);
- var = QVariant::fromValue(str);
+ } else if (variantType == QMetaType::QString) {
+ const QString str = QInstaller::replacePath(value,
+ relocatable, target);
+ var = QVariant::fromValue(str);
}
-
m_values[name] = var;
}
@@ -582,6 +685,18 @@ bool UpdateOperation::fromXml(const QDomDocument &doc)
}
/*!
+ Returns a numerical representation of how this operation compares to
+ other operations in size, and in time it takes to perform the operation.
+
+ The default returned value is \c 1. Subclasses may override this method to
+ implement custom size hints.
+*/
+quint64 UpdateOperation::sizeHint()
+{
+ return 1;
+}
+
+/*!
\overload
Restores operation arguments and values from the XML file at path \a xml. Returns \c true on
diff --git a/src/libs/kdtools/updateoperation.h b/src/libs/kdtools/updateoperation.h
index a8110791c..e25846cd3 100644
--- a/src/libs/kdtools/updateoperation.h
+++ b/src/libs/kdtools/updateoperation.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
+** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -59,11 +60,20 @@ public:
Undo
};
+ enum OperationGroup {
+ Unpack = 0x1,
+ Install = 0x2,
+ All = (Unpack | Install),
+ Default = Install
+ };
+ Q_DECLARE_FLAGS(OperationGroups, OperationGroup)
+
explicit UpdateOperation(QInstaller::PackageManagerCore *core);
virtual ~UpdateOperation();
QString name() const;
QString operationCommand() const;
+ OperationGroup group() const;
bool hasValue(const QString &name) const;
void clearValue(const QString &name);
@@ -90,8 +100,11 @@ public:
virtual bool fromXml(const QString &xml);
virtual bool fromXml(const QDomDocument &doc);
+ virtual quint64 sizeHint();
+
protected:
void setName(const QString &name);
+ void setGroup(const OperationGroup &group);
void setErrorString(const QString &errorString);
void setError(int error, const QString &errorString = QString());
void registerForDelayedDeletion(const QStringList &files);
@@ -99,11 +112,13 @@ protected:
bool checkArgumentCount(int minArgCount, int maxArgCount, const QString &argDescription = QString());
bool checkArgumentCount(int argCount);
QStringList parsePerformOperationArguments();
- QStringList parseUndoOperationArguments();
+ bool skipUndoOperation();
void setRequiresUnreplacedVariables(bool isRequired);
+ bool variableReplacement(QString *variableValue);
private:
QString m_name;
+ OperationGroup m_group;
QStringList m_arguments;
QString m_errorString;
int m_error;
@@ -115,4 +130,6 @@ private:
} // namespace KDUpdater
+Q_DECLARE_METATYPE(KDUpdater::UpdateOperation *)
+
#endif // UPDATEOPERATION_H
diff --git a/src/libs/kdtools/updateoperations.cpp b/src/libs/kdtools/updateoperations.cpp
index 9301d4f13..5f6135103 100644
--- a/src/libs/kdtools/updateoperations.cpp
+++ b/src/libs/kdtools/updateoperations.cpp
@@ -127,7 +127,7 @@ QString CopyOperation::sourcePath()
QString CopyOperation::destinationPath()
{
- QString destination = arguments().last();
+ QString destination = arguments().at(1);
// if the target is a directory use the source filename to complete the destination path
if (QFileInfo(destination).isDir())
@@ -135,7 +135,6 @@ QString CopyOperation::destinationPath()
return destination;
}
-
void CopyOperation::backup()
{
QString destination = destinationPath();
@@ -156,8 +155,8 @@ void CopyOperation::backup()
bool CopyOperation::performOperation()
{
// We need two args to complete the copy operation. First arg provides the complete file name of source
- // Second arg provides the complete file name of dest
- if (!checkArgumentCount(2))
+ // Second arg provides the complete file name of dest. Optionally UNDOOPERATION can be added as well
+ if (!checkArgumentCount(2, 4, QLatin1String("<source filename> <destination filename> [UNDOOPERATION, \"\"]")))
return false;
QString source = sourcePath();
@@ -193,6 +192,8 @@ bool CopyOperation::performOperation()
bool CopyOperation::undoOperation()
{
+ if (skipUndoOperation())
+ return true;
QString source = sourcePath();
QString destination = destinationPath();
@@ -270,7 +271,7 @@ MoveOperation::~MoveOperation()
void MoveOperation::backup()
{
- const QString dest = arguments().last();
+ const QString dest = arguments().at(1);
if (!QFile::exists(dest)) {
clearValue(QLatin1String("backupOfExistingDestination"));
return;
@@ -286,9 +287,10 @@ void MoveOperation::backup()
bool MoveOperation::performOperation()
{
- // We need two args to complete the copy operation. // First arg provides the complete file name of
- // source, second arg provides the complete file name of dest
- if (!checkArgumentCount(2))
+ // We need two args to complete the copy operation. First arg provides the complete file name of
+ // source, second arg provides the complete file name of dest. Optionally UNDOOPERATION can be added as well
+ if (!checkArgumentCount(2, 4, QLatin1String("<complete source file name> <complete destination "
+ "file name> [UNDOOPERATION, \"\"]")))
return false;
const QStringList args = arguments();
@@ -318,8 +320,10 @@ bool MoveOperation::performOperation()
bool MoveOperation::undoOperation()
{
+ if (skipUndoOperation())
+ return true;
const QStringList args = arguments();
- const QString dest = args.last();
+ const QString dest = args.at(1);
// first: copy back the destination to source
QFile destF(dest);
if (!destF.copy(args.first())) {
@@ -391,7 +395,8 @@ void DeleteOperation::backup()
bool DeleteOperation::performOperation()
{
// Requires only one parameter. That is the name of the file to remove.
- if (!checkArgumentCount(1))
+ // Optionally UNDOOPERATION can be added as well
+ if (!checkArgumentCount(1, 3, QLatin1String("<file to remove> [UNDOOPERATION, \"\"]")))
return false;
return deleteFileNowOrLater(arguments().at(0));
@@ -399,7 +404,7 @@ bool DeleteOperation::performOperation()
bool DeleteOperation::undoOperation()
{
- if (!hasValue(QLatin1String("backupOfExistingFile")))
+ if (skipUndoOperation())
return true;
const QString fileName = arguments().first();
@@ -478,7 +483,8 @@ void MkdirOperation::backup()
bool MkdirOperation::performOperation()
{
// Requires only one parameter. That is the path which should be created
- if (!checkArgumentCount(1))
+ // Optionally UNDOOPERATION can be added as well
+ if (!checkArgumentCount(1, 3, QLatin1String("<file to remove> [UNDOOPERATION, \"\"]")))
return false;
const QString dirName = arguments().at(0);
@@ -493,7 +499,8 @@ bool MkdirOperation::performOperation()
bool MkdirOperation::undoOperation()
{
- Q_ASSERT(arguments().count() == 1);
+ if (skipUndoOperation())
+ return true;
QString createdDirValue = value(QLatin1String("createddir")).toString();
if (packageManager()) {
@@ -572,7 +579,8 @@ void RmdirOperation::backup()
bool RmdirOperation::performOperation()
{
// Requires only one parameter. That is the name of the file to remove.
- if (!checkArgumentCount(1))
+ // Optionally UNDOOPERATION can be added as well
+ if (!checkArgumentCount(1, 3, QLatin1String("<file to remove> [UNDOOPERATION, \"\"]")))
return false;
const QString firstArg = arguments().at(0);
@@ -597,7 +605,7 @@ bool RmdirOperation::performOperation()
bool RmdirOperation::undoOperation()
{
- if (!value(QLatin1String("removed")).toBool())
+ if (!value(QLatin1String("removed")).toBool() || skipUndoOperation())
return true;
errno = 0;
@@ -633,6 +641,12 @@ AppendFileOperation::AppendFileOperation(QInstaller::PackageManagerCore *core)
setName(QLatin1String("AppendFile"));
}
+AppendFileOperation::~AppendFileOperation()
+{
+ if (skipUndoOperation())
+ deleteFileNowOrLater(value(QLatin1String("backupOfFile")).toString());
+}
+
void AppendFileOperation::backup()
{
const QString filename = arguments().first();
@@ -653,10 +667,10 @@ bool AppendFileOperation::performOperation()
{
// This operation takes two arguments. First argument is the name of the file into which a text has to be
// appended. Second argument is the text to append.
- if (!checkArgumentCount(2))
+ if (!checkArgumentCount(2, 4, QLatin1String("<filename> <text to apply> [UNDOOPERATION, \"\"]")))
return false;
- const QStringList args = this->arguments();
+ const QStringList args = arguments();
const QString fName = args.at(0);
QFile file(fName);
if (!file.open(QFile::Append)) {
@@ -695,6 +709,9 @@ bool AppendFileOperation::performOperation()
bool AppendFileOperation::undoOperation()
{
+ if (skipUndoOperation())
+ return true;
+
// backupOfFile being empty -> file didn't exist before -> no error
const QString filename = arguments().first();
const QString backupOfFile = value(QLatin1String("backupOfFile")).toString();
@@ -746,6 +763,12 @@ PrependFileOperation::PrependFileOperation(QInstaller::PackageManagerCore *core)
setName(QLatin1String("PrependFile"));
}
+PrependFileOperation::~PrependFileOperation()
+{
+ if (skipUndoOperation())
+ deleteFileNowOrLater(value(QLatin1String("backupOfFile")).toString());
+}
+
void PrependFileOperation::backup()
{
const QString filename = arguments().first();
@@ -767,10 +790,10 @@ bool PrependFileOperation::performOperation()
// This operation takes two arguments. First argument is the name
// of the file into which a text has to be appended. Second argument
// is the text to append.
- if (!checkArgumentCount(2))
+ if (!checkArgumentCount(2, 4, QLatin1String("<filename> <text to prepend> [UNDOOPERATION, \"\"]")))
return false;
- const QStringList args = this->arguments();
+ const QStringList args = arguments();
const QString fName = args.at(0);
// Load the file first.
QFile file(fName);
@@ -810,7 +833,9 @@ bool PrependFileOperation::performOperation()
bool PrependFileOperation::undoOperation()
{
- // bockupOfFile being empty -> file didn't exist before -> no error
+ if (skipUndoOperation())
+ return true;
+
const QString filename = arguments().first();
const QString backupOfFile = value(QLatin1String("backupOfFile")).toString();
if (!backupOfFile.isEmpty() && !QFile::exists(backupOfFile)) {
diff --git a/src/libs/kdtools/updateoperations.h b/src/libs/kdtools/updateoperations.h
index b13a42559..adbfc7de1 100644
--- a/src/libs/kdtools/updateoperations.h
+++ b/src/libs/kdtools/updateoperations.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
+** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -40,12 +41,12 @@ public:
explicit CopyOperation(QInstaller::PackageManagerCore *core = 0);
~CopyOperation();
- void backup();
- bool performOperation();
- bool undoOperation();
- bool testOperation();
+ void backup() override;
+ bool performOperation() override;
+ bool undoOperation() override;
+ bool testOperation() override;
- QDomDocument toXml() const;
+ QDomDocument toXml() const override;
private:
QString sourcePath();
QString destinationPath();
@@ -58,10 +59,10 @@ public:
explicit MoveOperation(QInstaller::PackageManagerCore *core = 0);
~MoveOperation();
- void backup();
- bool performOperation();
- bool undoOperation();
- bool testOperation();
+ void backup() override;
+ bool performOperation() override;
+ bool undoOperation() override;
+ bool testOperation() override;
};
class KDTOOLS_EXPORT DeleteOperation : public UpdateOperation
@@ -71,12 +72,12 @@ public:
explicit DeleteOperation(QInstaller::PackageManagerCore *core = 0);
~DeleteOperation();
- void backup();
- bool performOperation();
- bool undoOperation();
- bool testOperation();
+ void backup() override;
+ bool performOperation() override;
+ bool undoOperation() override;
+ bool testOperation() override;
- QDomDocument toXml() const;
+ QDomDocument toXml() const override;
};
class KDTOOLS_EXPORT MkdirOperation : public UpdateOperation
@@ -85,10 +86,10 @@ class KDTOOLS_EXPORT MkdirOperation : public UpdateOperation
public:
explicit MkdirOperation(QInstaller::PackageManagerCore *core = 0);
- void backup();
- bool performOperation();
- bool undoOperation();
- bool testOperation();
+ void backup() override;
+ bool performOperation() override;
+ bool undoOperation() override;
+ bool testOperation() override;
};
class KDTOOLS_EXPORT RmdirOperation : public UpdateOperation
@@ -97,10 +98,10 @@ class KDTOOLS_EXPORT RmdirOperation : public UpdateOperation
public:
RmdirOperation(QInstaller::PackageManagerCore *core = 0);
- void backup();
- bool performOperation();
- bool undoOperation();
- bool testOperation();
+ void backup() override;
+ bool performOperation() override;
+ bool undoOperation() override;
+ bool testOperation() override;
};
class KDTOOLS_EXPORT AppendFileOperation : public UpdateOperation
@@ -108,11 +109,12 @@ class KDTOOLS_EXPORT AppendFileOperation : public UpdateOperation
Q_DECLARE_TR_FUNCTIONS(KDUpdater::AppendFileOperation)
public:
explicit AppendFileOperation(QInstaller::PackageManagerCore *core = 0);
+ ~AppendFileOperation();
- void backup();
- bool performOperation();
- bool undoOperation();
- bool testOperation();
+ void backup() override;
+ bool performOperation() override;
+ bool undoOperation() override;
+ bool testOperation() override;
};
class KDTOOLS_EXPORT PrependFileOperation : public UpdateOperation
@@ -120,11 +122,12 @@ class KDTOOLS_EXPORT PrependFileOperation : public UpdateOperation
Q_DECLARE_TR_FUNCTIONS(KDUpdater::PrependFileOperation)
public:
explicit PrependFileOperation(QInstaller::PackageManagerCore *core = 0);
+ ~PrependFileOperation();
- void backup();
- bool performOperation();
- bool undoOperation();
- bool testOperation();
+ void backup() override;
+ bool performOperation() override;
+ bool undoOperation() override;
+ bool testOperation() override;
};
} // namespace KDUpdater
diff --git a/src/libs/kdtools/updatesinfo.cpp b/src/libs/kdtools/updatesinfo.cpp
index eaa9b039e..e82c1c1fb 100644
--- a/src/libs/kdtools/updatesinfo.cpp
+++ b/src/libs/kdtools/updatesinfo.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -28,18 +29,20 @@
#include "updatesinfo_p.h"
#include "utils.h"
+#include "constants.h"
-#include <QDomDocument>
#include <QFile>
#include <QLocale>
#include <QPair>
#include <QVector>
#include <QUrl>
+#include <QXmlStreamReader>
using namespace KDUpdater;
-UpdatesInfoData::UpdatesInfoData()
+UpdatesInfoData::UpdatesInfoData(const bool postLoadComponentScript)
: error(UpdatesInfo::NotYetReadError)
+ , m_postLoadComponentScript(postLoadComponentScript)
{
}
@@ -62,35 +65,26 @@ void UpdatesInfoData::parseFile(const QString &updateXmlFile)
return;
}
- QDomDocument doc;
- QString parseErrorMessage;
- int parseErrorLine, parseErrorColumn;
- if (!doc.setContent(&file, &parseErrorMessage, &parseErrorLine, &parseErrorColumn)) {
- error = UpdatesInfo::InvalidXmlError;
- errorMessage = tr("Parse error in %1 at %2, %3: %4").arg(updateXmlFile,
- QString::number(parseErrorLine), QString::number(parseErrorColumn), parseErrorMessage);
- return;
- }
-
- QDomElement rootE = doc.documentElement();
- if (rootE.tagName() != QLatin1String("Updates")) {
- setInvalidContentError(tr("Root element %1 unexpected, should be \"Updates\".").arg(rootE.tagName()));
- return;
- }
-
- QDomNodeList childNodes = rootE.childNodes();
- for(int i = 0; i < childNodes.count(); i++) {
- const QDomElement childE = childNodes.at(i).toElement();
- if (childE.isNull())
- continue;
-
- if (childE.tagName() == QLatin1String("ApplicationName"))
- applicationName = childE.text();
- else if (childE.tagName() == QLatin1String("ApplicationVersion"))
- applicationVersion = childE.text();
- else if (childE.tagName() == QLatin1String("PackageUpdate")) {
- if (!parsePackageUpdateElement(childE))
- return; //error handled in subroutine
+ QXmlStreamReader reader(&file);
+ if (reader.readNextStartElement()) {
+ if (reader.name() == QLatin1String("Updates")) {
+ while (reader.readNextStartElement()) {
+ if (reader.name() == QLatin1String("ApplicationName")) {
+ applicationName = reader.readElementText();
+ } else if (reader.name() == QLatin1String("ApplicationVersion")) {
+ applicationVersion = reader.readElementText();
+ } else if (reader.name() == QLatin1String("Checksum")) {
+ checkSha1CheckSum = (reader.readElementText());
+ } else if (reader.name() == QLatin1String("PackageUpdate")) {
+ if (!parsePackageUpdateElement(reader, checkSha1CheckSum))
+ return; //error handled in subroutine
+ } else {
+ reader.skipCurrentElement();
+ }
+ }
+ } else {
+ setInvalidContentError(tr("Root element %1 unexpected, should be \"Updates\".").arg(reader.name()));
+ return;
}
}
@@ -108,70 +102,58 @@ void UpdatesInfoData::parseFile(const QString &updateXmlFile)
error = UpdatesInfo::NoError;
}
-bool UpdatesInfoData::parsePackageUpdateElement(const QDomElement &updateE)
+bool UpdatesInfoData::parsePackageUpdateElement(QXmlStreamReader &reader, const QString &checkSha1CheckSum)
{
- if (updateE.isNull())
- return false;
-
UpdateInfo info;
- QMap<QString, QString> localizedDescriptions;
- for (int i = 0; i < updateE.childNodes().count(); i++) {
- QDomElement childE = updateE.childNodes().at(i).toElement();
- if (childE.isNull())
+ QHash<QString, QVariant> scriptHash;
+ while (reader.readNext()) {
+ const QString elementName = reader.name().toString();
+ if ((reader.name() == QLatin1String("PackageUpdate"))
+ && (reader.tokenType() == QXmlStreamReader::EndElement)) {
+ break;
+ }
+ if (elementName.isEmpty() || reader.tokenType() == QXmlStreamReader::EndElement)
continue;
-
- if (childE.tagName() == QLatin1String("ReleaseNotes")) {
- info.data[childE.tagName()] = QUrl(childE.text());
- } else if (childE.tagName() == QLatin1String("Licenses")) {
- QHash<QString, QVariant> licenseHash;
- const QDomNodeList licenseNodes = childE.childNodes();
- for (int index = 0; index < licenseNodes.count(); ++index) {
- const QDomNode licenseNode = licenseNodes.at(index);
- if (licenseNode.nodeName() == QLatin1String("License")) {
- QDomElement element = licenseNode.toElement();
- QVariantMap attributes;
- attributes.insert(QLatin1String("file"), element.attributeNode(QLatin1String("file")).value());
- if (!element.attributeNode(QLatin1String("priority")).isNull())
- attributes.insert(QLatin1String("priority"), element.attributeNode(QLatin1String("priority")).value());
- else
- attributes.insert(QLatin1String("priority"), QLatin1String("0"));
- licenseHash.insert(element.attributeNode(QLatin1String("name")).value(), attributes);
- }
- }
- if (!licenseHash.isEmpty())
- info.data.insert(QLatin1String("Licenses"), licenseHash);
- } else if (childE.tagName() == QLatin1String("Version")) {
+ if (elementName == QLatin1String("Licenses")) {
+ parseLicenses(reader, info.data);
+ } else if (elementName == QLatin1String("TreeName")) {
+ const QXmlStreamAttributes attr = reader.attributes();
+ const bool moveChildren = attr.value(QLatin1String("moveChildren")).toString().toLower() == QInstaller::scTrue ? true : false;
+ const QPair<QString, bool> treeNamePair(reader.readElementText(), moveChildren);
+ info.data.insert(QLatin1String("TreeName"), QVariant::fromValue(treeNamePair));
+ } else if (elementName == QLatin1String("Version")) {
+ const QXmlStreamAttributes attr = reader.attributes();
info.data.insert(QLatin1String("inheritVersionFrom"),
- childE.attribute(QLatin1String("inheritVersionFrom")));
- info.data[childE.tagName()] = childE.text();
- } else if (childE.tagName() == QLatin1String("DisplayName")) {
- processLocalizedTag(childE, info.data);
- } else if (childE.tagName() == QLatin1String("Description")) {
- if (!childE.hasAttribute(QLatin1String("xml:lang")))
- info.data[QLatin1String("Description")] = childE.text();
- QString languageAttribute = childE.attribute(QLatin1String("xml:lang"), QLatin1String("en"));
- localizedDescriptions.insert(languageAttribute.toLower(), childE.text());
- } else if (childE.tagName() == QLatin1String("UpdateFile")) {
- info.data[QLatin1String("CompressedSize")] = childE.attribute(QLatin1String("CompressedSize"));
- info.data[QLatin1String("UncompressedSize")] = childE.attribute(QLatin1String("UncompressedSize"));
- } else if (childE.tagName() == QLatin1String("Operations")) {
- const QDomNodeList operationNodes = childE.childNodes();
- QVariant operationListVariant = parseOperations(childE.childNodes());
- info.data.insert(QLatin1String("Operations"), operationListVariant);
+ attr.value(QLatin1String("inheritVersionFrom")).toString());
+ info.data[elementName] = reader.readElementText();
+ } else if (elementName == QLatin1String("DisplayName")
+ || elementName == QLatin1String("Description")) {
+ processLocalizedTag(reader, info.data);
+ } else if (elementName == QLatin1String("UpdateFile")) {
+ info.data[QLatin1String("CompressedSize")] = reader.attributes().value(QLatin1String("CompressedSize")).toString();
+ info.data[QLatin1String("UncompressedSize")] = reader.attributes().value(QLatin1String("UncompressedSize")).toString();
+ } else if (elementName == QLatin1String("Operations")) {
+ parseOperations(reader, info.data);
+ } else if (elementName == QLatin1String("Script")) {
+ const QXmlStreamAttributes attr = reader.attributes();
+ bool postLoad = false;
+ // postLoad can be set either to individual components or to whole repositories.
+ // If individual components has the postLoad attribute, it overwrites the repository value.
+ if (attr.hasAttribute(QLatin1String("postLoad")))
+ postLoad = attr.value(QLatin1String("postLoad")).toString().toLower() == QInstaller::scTrue ? true : false;
+ else if (m_postLoadComponentScript)
+ postLoad = true;
+
+ if (postLoad)
+ scriptHash.insert(QLatin1String("postLoadScript"), reader.readElementText());
+ else
+ scriptHash.insert(QLatin1String("installScript"), reader.readElementText());
} else {
- info.data[childE.tagName()] = childE.text();
- }
- }
-
- QStringList candidates;
- foreach (const QString &lang, QLocale().uiLanguages())
- candidates << QInstaller::localeCandidates(lang.toLower());
- foreach (const QString &candidate, candidates) {
- if (localizedDescriptions.contains(candidate)) {
- info.data[QLatin1String("Description")] = localizedDescriptions.value(candidate);
- break;
+ info.data[elementName] = reader.readElementText();
}
}
+ if (!scriptHash.isEmpty())
+ info.data.insert(QLatin1String("Script"), scriptHash);
if (!info.data.contains(QLatin1String("Name"))) {
setInvalidContentError(tr("PackageUpdate element without Name"));
@@ -185,54 +167,87 @@ bool UpdatesInfoData::parsePackageUpdateElement(const QDomElement &updateE)
setInvalidContentError(tr("PackageUpdate element without ReleaseDate"));
return false;
}
-
+ info.data[QLatin1String("CheckSha1CheckSum")] = checkSha1CheckSum;
updateInfoList.append(info);
return true;
}
-void UpdatesInfoData::processLocalizedTag(const QDomElement &childE, QHash<QString, QVariant> &info) const
+void UpdatesInfoData::processLocalizedTag(QXmlStreamReader &reader, QHash<QString, QVariant> &info) const
{
- QString languageAttribute = childE.attribute(QLatin1String("xml:lang")).toLower();
- if (!info.contains(childE.tagName()) && (languageAttribute.isEmpty()))
- info[childE.tagName()] = childE.text();
+ const QString languageAttribute = reader.attributes().value(QLatin1String("xml:lang")).toString().toLower();
+ const QString elementName = reader.name().toString();
+ if (!info.contains(elementName) && (languageAttribute.isEmpty()))
+ info[elementName] = reader.readElementText();
+ if (languageAttribute.isEmpty())
+ return;
// overwrite default if we have a language specific description
if (QLocale().name().startsWith(languageAttribute, Qt::CaseInsensitive))
- info[childE.tagName()] = childE.text();
+ info[elementName] = reader.readElementText();
}
-QVariant UpdatesInfoData::parseOperations(const QDomNodeList &operationNodes)
+void UpdatesInfoData::parseOperations(QXmlStreamReader &reader, QHash<QString, QVariant> &info) const
{
- QVariant operationListVariant;
QList<QPair<QString, QVariant>> operationsList;
- for (int i = 0; i < operationNodes.count(); ++i) {
- const QDomNode operationNode = operationNodes.at(i);
- if (operationNode.nodeName() == QLatin1String("Operation")) {
- const QDomNodeList argumentNodes = operationNode.childNodes();
- QStringList attributes;
- for (int index = 0; index < argumentNodes.count(); ++index) {
- const QDomNode argumentNode = argumentNodes.at(index);
- if (argumentNode.nodeName() == QLatin1String("Argument")) {
- QDomElement argumentElement = argumentNode.toElement();
- attributes.append(argumentElement.text());
- }
+ while (reader.readNext()) {
+ const QString subElementName = reader.name().toString();
+ // End of parsing operations
+ if ((subElementName == QLatin1String("Operations"))
+ && (reader.tokenType() == QXmlStreamReader::EndElement)) {
+ break;
+ }
+ if (subElementName != QLatin1String("Operation") || reader.tokenType() == QXmlStreamReader::EndElement)
+ continue;
+ QStringList attributes;
+ const QXmlStreamAttributes attr = reader.attributes();
+ while (reader.readNext()) {
+ const QString subElementName2 = reader.name().toString();
+ // End of parsing single operation
+ if ((subElementName2 == QLatin1String("Operation"))
+ && (reader.tokenType() == QXmlStreamReader::EndElement)) {
+ break;
}
- QPair<QString, QVariant> pair;
- pair.first = operationNode.toElement().attributeNode(QLatin1String("name")).value();
- pair.second = attributes;
- operationsList.append(pair);
+ if (subElementName2 != QLatin1String("Argument") || reader.tokenType() == QXmlStreamReader::EndElement)
+ continue;
+ attributes.append(reader.readElementText());
}
+ QPair<QString, QVariant> pair;
+ pair.first = attr.value(QLatin1String("name")).toString();
+ pair.second = attributes;
+ operationsList.append(pair);
}
- operationListVariant.setValue(operationsList);
- return operationListVariant;
+ info.insert(QLatin1String("Operations"), QVariant::fromValue(operationsList));
}
-
+void UpdatesInfoData::parseLicenses(QXmlStreamReader &reader, QHash<QString, QVariant> &info) const
+{
+ QHash<QString, QVariant> licenseHash;
+ while (reader.readNext()) {
+ const QString subElementName = reader.name().toString();
+ // End of parsing Licenses
+ if ((subElementName == QLatin1String("Licenses"))
+ && (reader.tokenType() == QXmlStreamReader::EndElement)) {
+ break;
+ }
+ if (subElementName != QLatin1String("License") || reader.tokenType() == QXmlStreamReader::EndElement)
+ continue;
+ const QXmlStreamAttributes attr = reader.attributes();
+ QVariantMap attributes;
+ attributes.insert(QLatin1String("file"), attr.value(QLatin1String("file")).toString());
+ if (!attr.value(QLatin1String("priority")).isNull())
+ attributes.insert(QLatin1String("priority"), attr.value(QLatin1String("priority")).toString());
+ else
+ attributes.insert(QLatin1String("priority"), QLatin1String("0"));
+ licenseHash.insert(attr.value(QLatin1String("name")).toString(), attributes);
+ }
+ if (!licenseHash.isEmpty())
+ info.insert(QLatin1String("Licenses"), licenseHash);
+}
//
// UpdatesInfo
//
-UpdatesInfo::UpdatesInfo()
- : d(new UpdatesInfoData)
+UpdatesInfo::UpdatesInfo(const bool postLoadComponentScript)
+ : d(new UpdatesInfoData(postLoadComponentScript))
{
}
@@ -260,6 +275,10 @@ void UpdatesInfo::setFileName(const QString &updateXmlFile)
d->updateInfoList.clear();
d->updateXmlFile = updateXmlFile;
+}
+
+void UpdatesInfo::parseFile()
+{
d->parseFile(d->updateXmlFile);
}
@@ -278,6 +297,11 @@ QString UpdatesInfo::applicationVersion() const
return d->applicationVersion;
}
+QString UpdatesInfo::checkSha1CheckSum() const
+{
+ return d->checkSha1CheckSum;
+}
+
int UpdatesInfo::updateInfoCount() const
{
return d->updateInfoList.count();
diff --git a/src/libs/kdtools/updatesinfo_p.h b/src/libs/kdtools/updatesinfo_p.h
index 93e2fe8c6..a3768232a 100644
--- a/src/libs/kdtools/updatesinfo_p.h
+++ b/src/libs/kdtools/updatesinfo_p.h
@@ -1,6 +1,7 @@
/****************************************************************************
**
** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB)
+** Copyright (C) 2023 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Installer Framework.
@@ -58,7 +59,7 @@ public:
InvalidContentError
};
- UpdatesInfo();
+ UpdatesInfo(const bool postLoadComponentScript = false);
~UpdatesInfo();
bool isValid() const;
@@ -68,10 +69,13 @@ public:
QString fileName() const;
void setFileName(const QString &updateXmlFile);
+ void parseFile();
QString applicationName() const;
QString applicationVersion() const;
+ QString checkSha1CheckSum() const;
+
int updateInfoCount() const;
UpdateInfo updateInfo(int index) const;
QList<UpdateInfo> updatesInfo() const;
diff --git a/src/libs/kdtools/updatesinfodata_p.h b/src/libs/kdtools/updatesinfodata_p.h
index 07da6fcf0..c71a85193 100644
--- a/src/libs/kdtools/updatesinfodata_p.h
+++ b/src/libs/kdtools/updatesinfodata_p.h
@@ -32,8 +32,7 @@
#include <QCoreApplication>
#include <QSharedData>
-QT_FORWARD_DECLARE_CLASS(QDomElement)
-QT_FORWARD_DECLARE_CLASS(QDomNodeList)
+QT_FORWARD_DECLARE_CLASS(QXmlStreamReader)
namespace KDUpdater {
@@ -44,7 +43,7 @@ struct UpdatesInfoData : public QSharedData
Q_DECLARE_TR_FUNCTIONS(KDUpdater::UpdatesInfoData)
public:
- UpdatesInfoData();
+ UpdatesInfoData(const bool postLoadComponentScript);
~UpdatesInfoData();
int error;
@@ -52,16 +51,19 @@ public:
QString updateXmlFile;
QString applicationName;
QString applicationVersion;
+ QString checkSha1CheckSum;
QList<UpdateInfo> updateInfoList;
+ bool m_postLoadComponentScript;
void parseFile(const QString &updateXmlFile);
- bool parsePackageUpdateElement(const QDomElement &updateE);
+ bool parsePackageUpdateElement(QXmlStreamReader &reader, const QString &checkSha1CheckSum);
void setInvalidContentError(const QString &detail);
private:
- void processLocalizedTag(const QDomElement &childE, QHash<QString, QVariant> &info) const;
- QVariant parseOperations(const QDomNodeList &operationNodes);
+ void processLocalizedTag(QXmlStreamReader &reader, QHash<QString, QVariant> &info) const;
+ void parseOperations(QXmlStreamReader &reader, QHash<QString, QVariant> &info) const;
+ void parseLicenses(QXmlStreamReader &reader, QHash<QString, QVariant> &info) const;
};
} // namespace KDUpdater