diff options
Diffstat (limited to 'src/libs')
31 files changed, 395 insertions, 326 deletions
diff --git a/src/libs/ifwtools/binarycreator.cpp b/src/libs/ifwtools/binarycreator.cpp index deea01ed7..a813c7f50 100644 --- a/src/libs/ifwtools/binarycreator.cpp +++ b/src/libs/ifwtools/binarycreator.cpp @@ -410,9 +410,9 @@ static int assemble(Input input, const QInstaller::Settings &settings, const QSt collection.setName(info.name.toUtf8()); qDebug() << "Creating resource archive for" << info.name; - foreach (const QString &file, info.copiedFiles) { - const QSharedPointer<Resource> resource(new Resource(file)); - qDebug().nospace() << "Appending " << file << " (" << humanReadableSize(resource->size()) << ")"; + foreach (const QString &copiedFile, info.copiedFiles) { + const QSharedPointer<Resource> resource(new Resource(copiedFile)); + qDebug().nospace() << "Appending " << copiedFile << " (" << humanReadableSize(resource->size()) << ")"; collection.appendResource(resource); } input.manager.insertCollection(collection); @@ -610,8 +610,8 @@ void QInstallerTools::copyConfigData(const QString &configFile, const QString &t if (tagName == QLatin1String("ProductImages")) { const QDomNodeList childNodes = domElement.childNodes(); - for (int i = 0; i < childNodes.count(); ++i) { - const QDomElement childElement = childNodes.at(i).toElement(); + for (int index = 0; index < childNodes.count(); ++index) { + const QDomElement childElement = childNodes.at(index).toElement(); const QString childName = childElement.tagName(); if (childName != QLatin1String("Image")) continue; diff --git a/src/libs/ifwtools/rcc/rcc.cpp b/src/libs/ifwtools/rcc/rcc.cpp index 10b7cbc4f..12f399937 100644 --- a/src/libs/ifwtools/rcc/rcc.cpp +++ b/src/libs/ifwtools/rcc/rcc.cpp @@ -120,18 +120,18 @@ public: RCCFileInfo::RCCFileInfo(const QString &name, const QFileInfo &fileInfo, QLocale::Language language, QLocale::Country country, uint flags, int compressLevel, int compressThreshold) + : m_flags(flags) + , m_name(name) + , m_language(language) + , m_country(country) + , m_fileInfo(fileInfo) + , m_parent(nullptr) + , m_compressLevel(compressLevel) + , m_compressThreshold(compressThreshold) + , m_nameOffset(0) + , m_dataOffset(0) + , m_childOffset(0) { - m_name = name; - m_fileInfo = fileInfo; - m_language = language; - m_country = country; - m_flags = flags; - m_parent = nullptr; - m_nameOffset = 0; - m_dataOffset = 0; - m_childOffset = 0; - m_compressLevel = compressLevel; - m_compressThreshold = compressThreshold; } RCCFileInfo::~RCCFileInfo() diff --git a/src/libs/ifwtools/repositorygen.cpp b/src/libs/ifwtools/repositorygen.cpp index fbcf7b9f3..d8339b063 100644 --- a/src/libs/ifwtools/repositorygen.cpp +++ b/src/libs/ifwtools/repositorygen.cpp @@ -1,6 +1,6 @@ /************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -52,6 +52,9 @@ #include <iostream> +#define QUOTE_(x) #x +#define QUOTE(x) QUOTE_(x) + using namespace QInstaller; using namespace QInstallerTools; @@ -69,6 +72,8 @@ void QInstallerTools::printRepositoryGenOptions() std::cout << " --ignore-translations Do not use any translation" << std::endl; std::cout << " --ignore-invalid-packages Ignore all invalid packages instead of aborting." << std::endl; std::cout << " --ignore-invalid-repositories Ignore all invalid repositories instead of aborting." << std::endl; + std::cout << " -s|--sha-update p1,...,pn List of packages which are updated using" <<std::endl; + std::cout << " content sha1 instead of version number." << std::endl; } QString QInstallerTools::makePathAbsolute(const QString &path) @@ -289,6 +294,11 @@ void QInstallerTools::copyMetaData(const QString &_targetDir, const QString &met fileElement.setAttribute(QLatin1String("OS"), QLatin1String("Any")); update.appendChild(fileElement); + if (info.createContentSha1Node) { + QDomNode contentSha1Element = update.appendChild(doc.createElement(QLatin1String("ContentSha1"))); + contentSha1Element.appendChild(doc.createTextNode(info.contentSha1)); + } + root.appendChild(update); // copy script file @@ -414,7 +424,7 @@ void QInstallerTools::copyMetaData(const QString &_targetDir, const QString &met } PackageInfoVector QInstallerTools::createListOfPackages(const QStringList &packagesDirectories, - QStringList *packagesToFilter, FilterType filterType) + QStringList *packagesToFilter, FilterType filterType, QStringList packagesUpdatedWithSha) { qDebug() << "Collecting information about available packages..."; @@ -508,6 +518,13 @@ PackageInfoVector QInstallerTools::createListOfPackages(const QStringList &packa info.dependencies = packageElement.firstChildElement(QLatin1String("Dependencies")).text() .split(QInstaller::commaRegExp(), QString::SkipEmptyParts); info.directory = it->filePath(); + if (packagesUpdatedWithSha.contains(info.name)) { + info.createContentSha1Node = true; + packagesUpdatedWithSha.removeOne(info.name); + } else { + info.createContentSha1Node = false; + } + dict.push_back(info); qDebug() << "- it provides the package" << info.name << " - " << info.version; @@ -521,6 +538,11 @@ PackageInfoVector QInstallerTools::createListOfPackages(const QStringList &packa if (dict.isEmpty()) qDebug() << "No available packages found at the specified location."; + if (!packagesUpdatedWithSha.isEmpty()) { + throw QInstaller::Error(QString::fromLatin1("The following packages could not be found in " + "package directory: %1").arg(packagesUpdatedWithSha.join(QLatin1String(", ")))); + } + return dict; } @@ -650,8 +672,33 @@ PackageInfoVector QInstallerTools::createListOfRepositoryPackages(const QStringL el.save(metaStream, 0); } info.metaNode = metaString; - dict.push_back(info); - qDebug() << "- it provides the package" << info.name << " - " << info.version; + + bool pushToDict = true; + bool replacement = false; + // Check whether this package already exists in vector: + for (int i = 0; i < dict.size(); ++i) { + const QInstallerTools::PackageInfo oldInfo = dict.at(i); + if (oldInfo.name != info.name) + continue; + + if (KDUpdater::compareVersion(info.version, oldInfo.version) > 0) { + // A package with newer version, it will replace the existing one. + dict.remove(i); + replacement = true; + } else { + // A package with older or same version, do not add it again. + pushToDict = false; + } + break; + } + + if (pushToDict) { + replacement ? qDebug() << "- it provides a new version of the package" << info.name << " - " << info.version << "- replaced" + : qDebug() << "- it provides the package" << info.name << " - " << info.version; + dict.push_back(info); + } else { + qDebug() << "- it provides an old version of the package" << info.name << " - " << info.version << "- ignored"; + } } } } @@ -755,14 +802,14 @@ QStringList QInstallerTools::unifyMetadata(const QString &repoDir, const QString QFile archiveFile(existingRepoDir); QInstaller::openForRead(&archiveFile); Lib7z::extractArchive(&archiveFile, existingRepoTemp); - QDir dir(existingRepoTemp); - QStringList existingRepoEntries = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); + QDir dir2(existingRepoTemp); + QStringList existingRepoEntries = dir2.entryList(QDir::Dirs | QDir::NoDotAndDotDot); foreach (const QString existingRepoEntry, existingRepoEntries) { if (entryList.contains(existingRepoEntry)) { continue; } else { - dir.cd(existingRepoEntry); - const QString absPath = dir.absolutePath(); + dir2.cd(existingRepoEntry); + const QString absPath = dir2.absolutePath(); absPaths.append(absPath); } } @@ -902,6 +949,8 @@ void QInstallerTools::copyComponentData(const QStringList &packageDirs, const QS archiveHashFile.write(hashOfArchiveData); qDebug() << "Generated sha1 hash:" << hashOfArchiveData; (*infos)[i].copiedFiles.append(archiveHashFile.fileName()); + if ((*infos)[i].createContentSha1Node) + (*infos)[i].contentSha1 = QLatin1String(hashOfArchiveData); archiveHashFile.close(); } catch (const QInstaller::Error &/*e*/) { archiveFile.close(); @@ -987,3 +1036,60 @@ QString QInstallerTools::existingUniteMeta7z(const QString &repositoryDir) } return uniteMeta7z; } + +PackageInfoVector QInstallerTools::collectPackages(RepositoryInfo info, QStringList *filteredPackages, FilterType filterType, bool updateNewComponents, QStringList packagesUpdatedWithSha) +{ + PackageInfoVector packages; + PackageInfoVector precompressedPackages = QInstallerTools::createListOfRepositoryPackages(info.repositoryPackages, + filteredPackages, filterType); + packages.append(precompressedPackages); + + PackageInfoVector preparedPackages = QInstallerTools::createListOfPackages(info.packages, + filteredPackages, filterType, packagesUpdatedWithSha); + packages.append(preparedPackages); + if (updateNewComponents) { + filterNewComponents(info.repositoryDir, packages); + } + foreach (const QInstallerTools::PackageInfo &package, packages) { + const QFileInfo fi(info.repositoryDir, package.name); + if (fi.exists()) + removeDirectory(fi.absoluteFilePath()); + } + return packages; +} + +void QInstallerTools::createRepository(RepositoryInfo info, PackageInfoVector *packages, + const QString &tmpMetaDir, bool createComponentMetadata, bool createUnifiedMetadata) +{ + QHash<QString, QString> pathToVersionMapping = QInstallerTools::buildPathToVersionMapping(*packages); + + QStringList directories; + directories.append(info.packages); + directories.append(info.repositoryPackages); + QStringList unite7zFiles; + foreach (const QString &repositoryDirectory, info.repositoryPackages) { + QDirIterator it(repositoryDirectory, QStringList(QLatin1String("*_meta.7z")) + , QDir::Files | QDir::CaseSensitive); + while (it.hasNext()) { + it.next(); + unite7zFiles.append(it.fileInfo().absoluteFilePath()); + } + } + QInstallerTools::copyComponentData(directories, info.repositoryDir, packages); + QInstallerTools::copyMetaData(tmpMetaDir, info.repositoryDir, *packages, QLatin1String("{AnyApplication}"), + QLatin1String(QUOTE(IFW_REPOSITORY_FORMAT_VERSION)), unite7zFiles); + + QString existing7z = QInstallerTools::existingUniteMeta7z(info.repositoryDir); + if (!existing7z.isEmpty()) + existing7z = info.repositoryDir + QDir::separator() + existing7z; + QInstallerTools::compressMetaDirectories(tmpMetaDir, existing7z, pathToVersionMapping, + createComponentMetadata, createUnifiedMetadata); + + QDirIterator it(info.repositoryDir, QStringList(QLatin1String("Updates*.xml")) + << QLatin1String("*_meta.7z"), QDir::Files | QDir::CaseSensitive); + while (it.hasNext()) { + it.next(); + QFile::remove(it.fileInfo().absoluteFilePath()); + } + QInstaller::moveDirectoryContents(tmpMetaDir, info.repositoryDir); +} diff --git a/src/libs/ifwtools/repositorygen.h b/src/libs/ifwtools/repositorygen.h index 49d0a51dd..0da81db67 100644 --- a/src/libs/ifwtools/repositorygen.h +++ b/src/libs/ifwtools/repositorygen.h @@ -1,6 +1,6 @@ /************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -48,6 +48,8 @@ struct IFWTOOLS_EXPORT PackageInfo QStringList copiedFiles; QString metaFile; QString metaNode; + QString contentSha1; + bool createContentSha1Node; }; typedef QVector<PackageInfo> PackageInfoVector; @@ -56,12 +58,19 @@ enum IFWTOOLS_EXPORT FilterType { Exclude }; +struct IFWTOOLS_EXPORT RepositoryInfo +{ + QStringList packages; + QStringList repositoryPackages; + QString repositoryDir; +}; + void IFWTOOLS_EXPORT printRepositoryGenOptions(); QString IFWTOOLS_EXPORT makePathAbsolute(const QString &path); void IFWTOOLS_EXPORT copyWithException(const QString &source, const QString &target, const QString &kind = QString()); PackageInfoVector IFWTOOLS_EXPORT createListOfPackages(const QStringList &packagesDirectories, QStringList *packagesToFilter, - FilterType ftype); + FilterType ftype, QStringList packagesUpdatedWithSha = QStringList()); PackageInfoVector IFWTOOLS_EXPORT createListOfRepositoryPackages(const QStringList &repositoryDirectories, QStringList *packagesToFilter, FilterType filterType); @@ -82,7 +91,8 @@ void IFWTOOLS_EXPORT copyComponentData(const QStringList &packageDir, const QStr void IFWTOOLS_EXPORT filterNewComponents(const QString &repositoryDir, QInstallerTools::PackageInfoVector &packages); QString IFWTOOLS_EXPORT existingUniteMeta7z(const QString &repositoryDir); - +PackageInfoVector IFWTOOLS_EXPORT collectPackages(RepositoryInfo info, QStringList *filteredPackages, FilterType filterType, bool updateNewComponents, QStringList packagesUpdatedWithSha); +void IFWTOOLS_EXPORT createRepository(RepositoryInfo info, PackageInfoVector *packages, const QString &tmpMetaDir, bool createComponentMetadata, bool createUnifiedMetadata); } // namespace QInstallerTools #endif // REPOSITORYGEN_H diff --git a/src/libs/installer/adminauthorization_x11.cpp b/src/libs/installer/adminauthorization_x11.cpp index 14691c9de..f4951d523 100644 --- a/src/libs/installer/adminauthorization_x11.cpp +++ b/src/libs/installer/adminauthorization_x11.cpp @@ -1,6 +1,6 @@ /************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -28,41 +28,18 @@ #include "adminauthorization.h" -#include <QtCore/QFile> -#include <QtCore/QRegExp> -#include <QDebug> +#include "globals.h" +#include <QDebug> #include <QApplication> -#include <QInputDialog> #include <QMessageBox> +#include <QProcess> -#include <cstdlib> -#include <sys/resource.h> #include <unistd.h> -#include <fcntl.h> - -#ifdef Q_OS_LINUX -#include <linux/limits.h> -#include <pty.h> -#else -#ifdef Q_OS_FREEBSD -#include <libutil.h> -#include <signal.h> -#else -#include <util.h> -#endif -#endif -#include <sys/ioctl.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <errno.h> #include <iostream> -#include "globals.h" - -#define SU_COMMAND "/usr/bin/sudo" -//#define SU_COMMAND "/bin/echo" +#define PKEXEC_COMMAND "/usr/bin/pkexec" namespace QInstaller { @@ -72,24 +49,6 @@ namespace QInstaller { \internal */ -static QString getPassword(QWidget *parent) -{ - if (qobject_cast<QApplication*> (qApp) != 0) { - bool ok = false; - const QString result = QInputDialog::getText(parent, QObject::tr("Authorization required"), - QObject::tr("Enter your password to authorize for sudo:"), - QLineEdit::Password, QString(), &ok); - return ok ? result : QString(); - } else { - std::cout << QObject::tr("Authorization required").toStdString() << std::endl; - std::cout << QObject::tr("Enter your password to authorize for sudo:").toStdString() - << std::endl; - std::string password; - std::cin >> password; - return QString::fromStdString(password); - } -} - static void printError(QWidget *parent, const QString &value) { if (qobject_cast<QApplication*> (qApp) != 0) { @@ -105,184 +64,21 @@ bool AdminAuthorization::execute(QWidget *parent, const QString &program, const const QString fallback = program + QLatin1String(" ") + arguments.join(QLatin1String(" ")); qCDebug(QInstaller::lcServer) << "Fallback:" << fallback; - // as we cannot pipe the password to su in QProcess, we need to setup a pseudo-terminal for it - int masterFD = -1; - int slaveFD = -1; - char ptsn[ PATH_MAX ]; + QProcess process; + process.setProcessChannelMode(QProcess::MergedChannels); + process.start(QLatin1String(PKEXEC_COMMAND), QStringList() << program << arguments, QIODevice::ReadOnly); - if (::openpty(&masterFD, &slaveFD, ptsn, 0, 0)) - return false; - - masterFD = ::posix_openpt(O_RDWR | O_NOCTTY); - if (masterFD < 0) - return false; - - const QByteArray ttyName = ::ptsname(masterFD); - - if (::grantpt(masterFD)) { - ::close(masterFD); - return false; - } - - ::revoke(ttyName); - ::unlockpt(masterFD); - - slaveFD = ::open(ttyName, O_RDWR | O_NOCTTY); - if (slaveFD < 0) { - ::close(masterFD); + if (!process.waitForStarted() || !process.waitForFinished(-1)) { + printError(parent, process.errorString()); + if (process.state() > QProcess::NotRunning) + process.kill(); return false; } - - ::fcntl(masterFD, F_SETFD, FD_CLOEXEC); - ::fcntl(slaveFD, F_SETFD, FD_CLOEXEC); - int pipedData[2]; - if (pipe(pipedData) != 0) - return false; - - int flags = ::fcntl(pipedData[0], F_GETFL); - if (flags != -1) - ::fcntl(pipedData[0], F_SETFL, flags | O_NONBLOCK); - - flags = ::fcntl(masterFD, F_GETFL); - if (flags != -1) - ::fcntl(masterFD, F_SETFL, flags | O_NONBLOCK); - - pid_t child = fork(); - - if (child < -1) { - ::close(masterFD); - ::close(slaveFD); - ::close(pipedData[0]); - ::close(pipedData[1]); - return false; - } - - // parent process - else if (child > 0) { - ::close(slaveFD); - //close writing end of pipe - ::close(pipedData[1]); - - QRegExp re(QLatin1String("[Pp]assword.*:")); - QByteArray data; - QByteArray errData; - int bytes = 0; - int errBytes = 0; - char buf[1024]; - char errBuf[1024]; - int status; - bool statusValid = false; - while (bytes >= 0) { - const pid_t waitResult = ::waitpid(child, &status, WNOHANG); - if (waitResult == -1) { - break; - } - if (waitResult == child) { - statusValid = true; - break; - } - bytes = ::read(masterFD, buf, 1023); - if (bytes == -1 && errno == EAGAIN) - bytes = 0; - else if (bytes > 0) - data.append(buf, bytes); - errBytes = ::read(pipedData[0], errBuf, 1023); - if (errBytes > 0) - { - errData.append(errBuf, errBytes); - errBytes=0; - } - if (bytes > 0) { - const QString line = QString::fromLatin1(data); - if (re.indexIn(line) != -1) { - const QString password = getPassword(parent); - if (password.isEmpty()) { - QByteArray pwd = password.toLatin1(); - for (int i = 0; i < 3; ++i) { - ::write(masterFD, pwd.data(), pwd.length()); - ::write(masterFD, "\n", 1); - } - return false; - } - QByteArray pwd = password.toLatin1(); - ::write(masterFD, pwd.data(), pwd.length()); - ::write(masterFD, "\n", 1); - ::read(masterFD, buf, pwd.length() + 1); - } - } - if (bytes == 0) - ::usleep(100000); - } - - while (true) { - errBytes = ::read(pipedData[0], errBuf, 1023); - if (errBytes == -1 && errno == EAGAIN) { - ::usleep(100000); - continue; - } - - if (errBytes <= 0) - break; - - errData.append(errBuf, errBytes); - } - - const bool success = statusValid && WIFEXITED(status) && WEXITSTATUS(status) == 0; - - if (!success && !errData.isEmpty()) { - printError(parent, QString::fromLocal8Bit(errData.constData())); - } - - ::close(pipedData[0]); - return success; - } - - // child process - else { - ::close(pipedData[0]); - // Reset signal handlers - for (int sig = 1; sig < NSIG; ++sig) - signal(sig, SIG_DFL); - signal(SIGHUP, SIG_IGN); - - ::setsid(); - - ::ioctl(slaveFD, TIOCSCTTY, 1); - int pgrp = ::getpid(); - ::tcsetpgrp(slaveFD, pgrp); - - ::dup2(slaveFD, 0); - ::dup2(slaveFD, 1); - ::dup2(pipedData[1], 2); - - // close all file descriptors - struct rlimit rlp; - getrlimit(RLIMIT_NOFILE, &rlp); - for (int i = 3; i < static_cast<int>(rlp.rlim_cur); ++i) - ::close(i); - - char **argp = (char **) ::malloc((arguments.count() + 4) * sizeof(char *)); - QList<QByteArray> args; - args.push_back(SU_COMMAND); - args.push_back("-b"); - args.push_back(program.toLocal8Bit()); - for (QStringList::const_iterator it = arguments.begin(); it != arguments.end(); ++it) - args.push_back(it->toLocal8Bit()); - - int i = 0; - for (QList<QByteArray>::iterator it = args.begin(); it != args.end(); ++it, ++i) - argp[i] = it->data(); - argp[i] = 0; - - ::unsetenv("LANG"); - ::unsetenv("LC_ALL"); - - int exitStatus = 0; - if (::execv(SU_COMMAND, argp) == -1) - exitStatus = -errno; - _exit(exitStatus); + if (process.exitCode() != EXIT_SUCCESS) { + printError(parent, QLatin1String(process.readAll())); return false; } + return true; } // has no guarantee to work diff --git a/src/libs/installer/binarycontent.h b/src/libs/installer/binarycontent.h index a21cd69e7..7d50c0e28 100644 --- a/src/libs/installer/binarycontent.h +++ b/src/libs/installer/binarycontent.h @@ -1,6 +1,6 @@ /************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -48,6 +48,13 @@ public: static const qint64 MagicUpdaterMarker = 0x12023235UL; static const qint64 MagicPackageManagerMarker = 0x12023236UL; + // additional distinguishers only used at runtime, not written to the binary itself + enum MagicMarkerSupplement { + Default = 0x0, + OfflineGenerator = 0x1, + PackageViewer = 0x2 + }; + // the cookie put at the end of the file static const quint64 MagicCookie = 0xc2630a1c99d668f8LL; // binary static const quint64 MagicCookieDat = 0xc2630a1c99d668f9LL; // data diff --git a/src/libs/installer/commandlineparser.cpp b/src/libs/installer/commandlineparser.cpp index 59d42eefc..4bfc4ad3a 100644 --- a/src/libs/installer/commandlineparser.cpp +++ b/src/libs/installer/commandlineparser.cpp @@ -59,6 +59,9 @@ CommandLineParser::CommandLineParser() .arg(CommandLineOptions::scListShort, CommandLineOptions::scListLong) + indent + QString::fromLatin1("%1, %2 - search available packages - <regexp>\n") .arg(CommandLineOptions::scSearchShort, CommandLineOptions::scSearchLong) + + indent + indent + QString::fromLatin1("Note: The --%1 option can be used to specify\n") + .arg(CommandLineOptions::scFilterPackagesLong) + + indent + indent + QLatin1String("additional filters for the search operation\n") + indent + QString::fromLatin1("%1, %2 - create offline installer from selected packages - <pkg ...>\n") .arg(CommandLineOptions::scCreateOfflineShort, CommandLineOptions::scCreateOfflineLong) + indent + QString::fromLatin1("%1, %2 - uninstall all packages and remove entire program directory") @@ -161,6 +164,12 @@ CommandLineParser::CommandLineParser() << CommandLineOptions::scCreateLocalRepositoryShort << CommandLineOptions::scCreateLocalRepositoryLong, QLatin1String("Create a local repository inside the installation directory. This option " "has no effect on online installers."))); + addOptionWithContext(QCommandLineOption(QStringList() + << CommandLineOptions::scFilterPackagesShort << CommandLineOptions::scFilterPackagesLong, + QLatin1String("[CLI] Comma separated list of additional key-value pair filters used to query packages with the " + "search command. The keys can be any of the possible package information elements, like " + "\"DisplayName\" and \"Description\"."), + QLatin1String("element=regex,...")), CommandLineOnly); // Message query options addOptionWithContext(QCommandLineOption(QStringList() << CommandLineOptions::scAcceptMessageQueryShort diff --git a/src/libs/installer/component.cpp b/src/libs/installer/component.cpp index cb9959ba3..b4b96eb08 100644 --- a/src/libs/installer/component.cpp +++ b/src/libs/installer/component.cpp @@ -300,11 +300,14 @@ void Component::loadDataFromPackage(const KDUpdater::LocalPackage &package) setValue(scCurrentState, scInstalled); setValue(scCheckable, package.checkable ? scTrue : scFalse); setValue(scExpandedByDefault, package.expandedByDefault ? scTrue : scFalse); + setValue(scContentSha1, package.contentSha1); } /*! Sets variables according to the values set in the package.xml file of \a package. Also loads UI files, licenses and translations if they are referenced in the package.xml. + If the \c PackageManagerCore object of this component is run as package viewer, then + only sets the variables without loading referenced files. */ void Component::loadDataFromPackage(const Package &package) { @@ -341,6 +344,10 @@ void Component::loadDataFromPackage(const Package &package) if (PackageManagerCore::noForceInstallation()) forced = scFalse; setValue(scForcedInstallation, forced); + setValue(scContentSha1, package.data(scContentSha1).toString()); + + if (d->m_core->isPackageViewer()) + return; setLocalTempPath(QInstaller::pathFromUrl(package.packageSource().url)); const QStringList uis = package.data(QLatin1String("UserInterfaces")).toString() diff --git a/src/libs/installer/component_p.cpp b/src/libs/installer/component_p.cpp index 8533d8e4c..0f74e423c 100644 --- a/src/libs/installer/component_p.cpp +++ b/src/libs/installer/component_p.cpp @@ -54,6 +54,7 @@ ComponentPrivate::ComponentPrivate(PackageManagerCore *core, Component *qq) , m_autoCreateOperations(true) , m_operationsCreatedSuccessfully(true) , m_updateIsAvailable(false) + , m_unstable(false) { } diff --git a/src/libs/installer/componentmodel.cpp b/src/libs/installer/componentmodel.cpp index aab487b45..642828ad7 100644 --- a/src/libs/installer/componentmodel.cpp +++ b/src/libs/installer/componentmodel.cpp @@ -260,9 +260,9 @@ bool ComponentModel::setData(const QModelIndex &index, const QVariant &value, in newValue = (oldValue == Qt::Checked) ? Qt::Unchecked : Qt::Checked; } QSet<QModelIndex> changed = updateCheckedState(nodes << component, newValue); - foreach (const QModelIndex &index, changed) { - emit dataChanged(index, index); - emit checkStateChanged(index); + foreach (const QModelIndex &changedIndex, changed) { + emit dataChanged(changedIndex, changedIndex); + emit checkStateChanged(changedIndex); } updateAndEmitModelState(); // update the internal state } else { diff --git a/src/libs/installer/componentselectionpage_p.cpp b/src/libs/installer/componentselectionpage_p.cpp index a9f4ba134..974ae1502 100644 --- a/src/libs/installer/componentselectionpage_p.cpp +++ b/src/libs/installer/componentselectionpage_p.cpp @@ -49,6 +49,7 @@ #include <QFileDialog> #include <QStackedLayout> #include <QStackedWidget> +#include <QToolBox> namespace QInstaller { @@ -66,19 +67,29 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP , m_updaterModel(m_core->updaterComponentModel()) , m_currentModel(m_allModel) , m_allowCompressedRepositoryInstall(false) + , m_toolBox(nullptr) + , m_descriptionBaseWidget(nullptr) , m_categoryWidget(Q_NULLPTR) + , m_categoryLayoutVisible(false) { m_treeView->setObjectName(QLatin1String("ComponentsTreeView")); - QVBoxLayout *descriptionVLayout = new QVBoxLayout; + m_descriptionBaseWidget = new QWidget(q); + m_descriptionBaseWidget->setObjectName(QLatin1String("DescriptionBaseWidget")); + + QVBoxLayout *descriptionVLayout = new QVBoxLayout(m_descriptionBaseWidget); descriptionVLayout->setObjectName(QLatin1String("DescriptionLayout")); + descriptionVLayout->setContentsMargins(0, 0, 0, 0); + + m_toolBox = new QToolBox(q); + m_toolBox->setObjectName(QLatin1String("ToolBox")); QScrollArea *descriptionScrollArea = new QScrollArea(q); descriptionScrollArea->setWidgetResizable(true); descriptionScrollArea->setFrameShape(QFrame::NoFrame); descriptionScrollArea->setObjectName(QLatin1String("DescriptionScrollArea")); - m_descriptionLabel = new QLabel(q); + m_descriptionLabel = new QLabel(m_descriptionBaseWidget); m_descriptionLabel->setWordWrap(true); m_descriptionLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); m_descriptionLabel->setOpenExternalLinks(true); @@ -87,8 +98,7 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP descriptionScrollArea->setWidget(m_descriptionLabel); descriptionVLayout->addWidget(descriptionScrollArea); - m_sizeLabel = new QLabel(q); - m_sizeLabel->setMargin(5); + m_sizeLabel = new QLabel(m_descriptionBaseWidget); m_sizeLabel->setWordWrap(true); m_sizeLabel->setObjectName(QLatin1String("ComponentSizeLabel")); descriptionVLayout->addWidget(m_sizeLabel); @@ -151,11 +161,11 @@ ComponentSelectionPagePrivate::ComponentSelectionPagePrivate(ComponentSelectionP QWidget *mainStackedWidget = new QWidget(); m_mainGLayout = new QGridLayout(mainStackedWidget); - m_mainGLayout->addLayout(buttonHLayout, 0, 1); - m_mainGLayout->addLayout(treeViewVLayout, 1, 1); - m_mainGLayout->addLayout(descriptionVLayout, 1, 2); - m_mainGLayout->setColumnStretch(1, 3); - m_mainGLayout->setColumnStretch(2, 2); + m_mainGLayout->addLayout(buttonHLayout, 0, 0); + m_mainGLayout->addLayout(treeViewVLayout, 1, 0); + m_mainGLayout->addWidget(m_descriptionBaseWidget, 1, 1); + m_mainGLayout->setColumnStretch(0, 3); + m_mainGLayout->setColumnStretch(1, 2); m_stackedLayout = new QStackedLayout(q); m_stackedLayout->addWidget(mainStackedWidget); @@ -227,11 +237,11 @@ void ComponentSelectionPagePrivate::setupCategoryLayout() vLayout->setContentsMargins(0, 0, 0, 0); m_categoryWidget->setLayout(vLayout); m_categoryGroupBox = new QGroupBox(q); - m_categoryGroupBox->setTitle(m_core->settings().repositoryCategoryDisplayName()); m_categoryGroupBox->setObjectName(QLatin1String("CategoryGroupBox")); QVBoxLayout *categoryLayout = new QVBoxLayout(m_categoryGroupBox); QPushButton *fetchCategoryButton = new QPushButton(tr("Filter")); fetchCategoryButton->setObjectName(QLatin1String("FetchCategoryButton")); + fetchCategoryButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); fetchCategoryButton->setToolTip( ComponentSelectionPage::tr("Filter the enabled repository categories to selection.")); connect(fetchCategoryButton, &QPushButton::clicked, this, @@ -249,16 +259,29 @@ void ComponentSelectionPagePrivate::setupCategoryLayout() vLayout->addWidget(m_categoryGroupBox); vLayout->addStretch(); - m_mainGLayout->addWidget(m_categoryWidget, 1, 0); + m_toolBox->insertItem(1, m_categoryWidget, m_core->settings().repositoryCategoryDisplayName()); } void ComponentSelectionPagePrivate::showCategoryLayout(bool show) { + if (!show && !m_categoryWidget) + return; + + if (show == m_categoryLayoutVisible) + return; + + setupCategoryLayout(); if (show) { - setupCategoryLayout(); + m_mainGLayout->removeWidget(m_descriptionBaseWidget); + m_toolBox->insertItem(0, m_descriptionBaseWidget, tr("Component Information")); + m_mainGLayout->addWidget(m_toolBox, 1, 1); + } else { + m_toolBox->removeItem(0); + m_mainGLayout->removeWidget(m_toolBox); + m_mainGLayout->addWidget(m_descriptionBaseWidget, 1, 1); } - if (m_categoryWidget) - m_categoryWidget->setVisible(show); + m_toolBox->setVisible(show); + m_categoryLayoutVisible = show; } void ComponentSelectionPagePrivate::updateTreeView() @@ -399,10 +422,9 @@ void ComponentSelectionPagePrivate::fetchRepositoryCategories() { updateWidgetVisibility(true); - QCheckBox *checkbox; QList<QCheckBox*> checkboxes = m_categoryGroupBox->findChildren<QCheckBox *>(); for (int i = 0; i < checkboxes.count(); i++) { - checkbox = checkboxes.at(i); + QCheckBox *checkbox = checkboxes.at(i); enableRepositoryCategory(checkbox->objectName(), checkbox->isChecked()); } diff --git a/src/libs/installer/componentselectionpage_p.h b/src/libs/installer/componentselectionpage_p.h index 37f808286..d2d30e3f0 100644 --- a/src/libs/installer/componentselectionpage_p.h +++ b/src/libs/installer/componentselectionpage_p.h @@ -1,6 +1,6 @@ /************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -46,6 +46,7 @@ class QVBoxLayout; class QHBoxLayout; class QGridLayout; class QStackedLayout; +class QToolBox; namespace QInstaller { @@ -88,6 +89,8 @@ private: ComponentSelectionPage *q; PackageManagerCore *m_core; QTreeView *m_treeView; + QToolBox *m_toolBox; + QWidget *m_descriptionBaseWidget; QLabel *m_sizeLabel; QLabel *m_descriptionLabel; QPushButton *m_checkAll; @@ -99,6 +102,7 @@ private: QProgressBar *m_progressBar; QGridLayout *m_mainGLayout; bool m_allowCompressedRepositoryInstall; + bool m_categoryLayoutVisible; ComponentModel *m_allModel; ComponentModel *m_updaterModel; ComponentModel *m_currentModel; diff --git a/src/libs/installer/constants.h b/src/libs/installer/constants.h index 42b14ce63..0e16d4c4b 100644 --- a/src/libs/installer/constants.h +++ b/src/libs/installer/constants.h @@ -1,6 +1,6 @@ /************************************************************************** ** -** Copyright (C) 2020 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -67,6 +67,7 @@ static const QLatin1String scUncompressedSizeSum("UncompressedSizeSum"); static const QLatin1String scRequiresAdminRights("RequiresAdminRights"); static const QLatin1String scOfflineBinaryName("OfflineBinaryName"); static const QLatin1String scSHA1("SHA1"); +static const QLatin1String scContentSha1("ContentSha1"); // constants used throughout the components class static const QLatin1String scVirtual("Virtual"); @@ -202,6 +203,8 @@ static const QLatin1String scCreateLocalRepositoryShort("cl"); static const QLatin1String scCreateLocalRepositoryLong("create-local-repository"); static const QLatin1String scNoDefaultInstallationShort("nd"); static const QLatin1String scNoDefaultInstallationLong("no-default-installations"); +static const QLatin1String scFilterPackagesShort("fp"); +static const QLatin1String scFilterPackagesLong("filter-packages"); // Developer options static const QLatin1String scScriptShort("s"); diff --git a/src/libs/installer/installiconsoperation.cpp b/src/libs/installer/installiconsoperation.cpp index 9443b7f71..de1ddcc4f 100644 --- a/src/libs/installer/installiconsoperation.cpp +++ b/src/libs/installer/installiconsoperation.cpp @@ -134,8 +134,8 @@ bool InstallIconsOperation::performOperation() if (status == PackageManagerCore::Canceled || status == PackageManagerCore::Failure) return true; - const QString &source = it.next(); - QString target = targetDir.absoluteFilePath(sourceDir.relativeFilePath(source)); + const QString &source2 = it.next(); + QString target = targetDir.absoluteFilePath(sourceDir.relativeFilePath(source2)); emit outputTextChanged(target); @@ -185,7 +185,7 @@ bool InstallIconsOperation::performOperation() } // copy the file to its new location - QFile cf(source); + QFile cf(source2); if (!cf.copy(target)) { setError(UserDefinedError); setErrorString(tr("Failed to copy file \"%1\": %2").arg( @@ -193,8 +193,8 @@ bool InstallIconsOperation::performOperation() undoOperation(); return false; } - deleteFileNowOrLater(source); - files.push_back(source); + deleteFileNowOrLater(source2); + files.push_back(source2); files.push_back(target); setValue(QLatin1String("files"), files); } else if (fi.isDir() && !QDir(target).exists()) { diff --git a/src/libs/installer/keepaliveobject.cpp b/src/libs/installer/keepaliveobject.cpp index 94e91efd8..18ec9743a 100644 --- a/src/libs/installer/keepaliveobject.cpp +++ b/src/libs/installer/keepaliveobject.cpp @@ -1,6 +1,6 @@ /************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -48,7 +48,12 @@ KeepAliveObject::KeepAliveObject() void KeepAliveObject::start() { + if (m_timer) + delete m_timer; m_timer = new QTimer(this); + + if (m_socket) + delete m_socket; m_socket = new QLocalSocket(this); connect(m_timer, &QTimer::timeout, [this]() { diff --git a/src/libs/installer/loggingutils.cpp b/src/libs/installer/loggingutils.cpp index 0ebba10db..45f7aab1b 100644 --- a/src/libs/installer/loggingutils.cpp +++ b/src/libs/installer/loggingutils.cpp @@ -259,7 +259,7 @@ void LoggingHandler::printComponentInfo(const QList<Component *> components) con QDomElement root = doc.createElement(QLatin1String("updates")); doc.appendChild(root); - foreach (Component *component, components) { + foreach (const Component *component, components) { QDomElement update = doc.createElement(QLatin1String("update")); update.setAttribute(QLatin1String("name"), component->value(scDisplayName)); update.setAttribute(QLatin1String("version"), component->value(scVersion)); diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp index 145eb30d7..61b2273af 100644 --- a/src/libs/installer/packagemanagercore.cpp +++ b/src/libs/installer/packagemanagercore.cpp @@ -1556,9 +1556,8 @@ bool PackageManagerCore::fetchPackagesTree(const PackagesList &packages, const L continue; const LocalPackage localPackage = installedPackages.value(name); - const QString updateVersion = update->data(scVersion).toString(); - if (KDUpdater::compareVersion(updateVersion, localPackage.version) <= 0) - continue; // remote version equals or is less than the installed maintenance tool + if (!d->packageNeedsUpdate(localPackage, update)) + continue; const QDate updateDate = update->data(scReleaseDate).toDate(); if (localPackage.lastUpdateDate >= updateDate) @@ -2192,26 +2191,50 @@ ComponentModel *PackageManagerCore::updaterComponentModel() const /*! Lists available packages filtered with \a regexp without GUI. Virtual - components are not listed unless set visible. + components are not listed unless set visible. Optionally, a \a filters + hash containing package information elements and regular expressions + can be used to further filter listed packages. \sa setVirtualComponentsVisible() */ -void PackageManagerCore::listAvailablePackages(const QString ®exp) +void PackageManagerCore::listAvailablePackages(const QString ®exp, const QHash<QString, QString> &filters) { + setPackageViewer(); qCDebug(QInstaller::lcInstallerInstallLog) << "Searching packages with regular expression:" << regexp; + + ComponentModel *model = defaultComponentModel(); d->fetchMetaInformationFromRepositories(DownloadType::UpdatesXML); d->addUpdateResourcesFromRepositories(true); QRegularExpression re(regexp); const PackagesList &packages = d->remotePackages(); + if (!fetchAllPackages(packages, LocalPackagesHash())) { + qCWarning(QInstaller::lcInstallerInstallLog) + << "There was a problem with loading the package data."; + return; + } PackagesList matchedPackages; foreach (Package *package, packages) { const QString name = package->data(scName).toString(); - if (re.match(name).hasMatch() && - (virtualComponentsVisible() ? true : !package->data(scVirtual, false).toBool())) { - matchedPackages.append(package); + Component *component = componentByName(name); + if (!component) + continue; + + const QModelIndex &idx = model->indexFromComponentName(component->treeName()); + if (idx.isValid() && re.match(name).hasMatch()) { + bool ignoreComponent = false; + for (auto &key : filters.keys()) { + const QString elementValue = component->value(key); + QRegularExpression elementRegexp(filters.value(key)); + if (elementValue.isEmpty() || !elementRegexp.match(elementValue).hasMatch()) { + ignoreComponent = true; + break; + } + } + if (!ignoreComponent) + matchedPackages.append(package); } } if (matchedPackages.count() == 0) @@ -2288,10 +2311,26 @@ bool PackageManagerCore::checkComponentsForInstallation(const QStringList &compo model->setData(idx, Qt::Checked, Qt::CheckStateRole); installComponentsFound = true; } - } else { // idx is invalid and component valid when we have invisible virtual component - component->isVirtual() - ? errorMessage.append(tr("Cannot install %1. Component is virtual.\n").arg(name)) - : errorMessage.append(tr("Cannot install %1. Component not found.\n").arg(name)); + } else { + auto isDescendantOfVirtual = [&]() { + Component *trace = component; + forever { + trace = trace->parentComponent(); + if (!trace) { + // We already checked the root component if there is no parent + return false; + } else if (trace->isVirtual()) { + errorMessage.append(tr("Cannot install %1. Component is descendant " + "of a virtual component %2.\n").arg(name, trace->name())); + return true; + } + } + }; + // idx is invalid and component valid when we have invisible virtual component + if (component->isVirtual()) + errorMessage.append(tr("Cannot install %1. Component is virtual.\n").arg(name)); + else if (!isDescendantOfVirtual()) + errorMessage.append(tr("Cannot install %1. Component not found.\n").arg(name)); } } if (!installComponentsFound) @@ -2305,6 +2344,7 @@ bool PackageManagerCore::checkComponentsForInstallation(const QStringList &compo */ void PackageManagerCore::listInstalledPackages(const QString ®exp) { + setPackageViewer(); LocalPackagesHash installedPackages = this->localInstalledPackages(); if (!regexp.isEmpty()) { @@ -2342,6 +2382,7 @@ PackageManagerCore::Status PackageManagerCore::updateComponentsSilently(const QS if (componentList.count() == 0) { qCDebug(QInstaller::lcInstallerInstallLog) << "No updates available."; + setCanceled(); } else { // Check if essential components are available (essential components are disabled). // If essential components are found, update first essential updates, @@ -3402,11 +3443,11 @@ bool PackageManagerCore::isPackageManager() const } /*! - Sets current installer to be offline generator based on \a offlineGenerator. + Sets current installer to be offline generator. */ -void PackageManagerCore::setOfflineGenerator(bool offlineGenerator) +void PackageManagerCore::setOfflineGenerator() { - d->m_offlineGenerator = offlineGenerator; + d->m_magicMarkerSupplement = BinaryContent::OfflineGenerator; } /*! @@ -3420,6 +3461,24 @@ bool PackageManagerCore::isOfflineGenerator() const } /*! + Sets the current installer as the package viewer. +*/ +void PackageManagerCore::setPackageViewer() +{ + d->m_magicMarkerSupplement = BinaryContent::PackageViewer; +} + +/*! + Returns \c true if the current installer is executed as package viewer. + + \sa {installer::isPackageViewer}{installer.isPackageViewer} +*/ +bool PackageManagerCore::isPackageViewer() const +{ + return d->isPackageViewer(); +} + +/*! Sets the installer magic binary marker based on \a magicMarker and userSetBinaryMarker to \c true. */ @@ -3660,7 +3719,7 @@ void PackageManagerCore::storeReplacedComponents(QHash<QString, Component *> &co qCWarning(QInstaller::lcDeveloperBuild) << componentName << "- Does not exist in the repositories anymore."; continue; } - if (!componentToReplace && !d->componentsToReplace().contains(componentName)) { + if (!d->componentsToReplace().contains(componentName)) { componentToReplace = new Component(this); componentToReplace->setValue(scName, componentName); } else { @@ -3799,10 +3858,8 @@ bool PackageManagerCore::fetchUpdaterPackages(const PackagesList &remotes, const continue; // Update for not installed package found, skip it. const LocalPackage &localPackage = locals.value(name); - const QString updateVersion = update->data(scVersion).toString(); - if (KDUpdater::compareVersion(updateVersion, localPackage.version) <= 0) + if (!d->packageNeedsUpdate(localPackage, update)) continue; - // It is quite possible that we may have already installed the update. Lets check the last // update date of the package and the release date of the update. This way we can compare and // figure out if the update has been installed or not. diff --git a/src/libs/installer/packagemanagercore.h b/src/libs/installer/packagemanagercore.h index d4833a979..b5ef6304e 100644 --- a/src/libs/installer/packagemanagercore.h +++ b/src/libs/installer/packagemanagercore.h @@ -33,6 +33,7 @@ #include "repository.h" #include "qinstallerglobal.h" #include "utils.h" +#include "commandlineparser.h" #include <QtCore/QHash> #include <QtCore/QObject> @@ -242,7 +243,8 @@ public: ComponentModel *defaultComponentModel() const; ComponentModel *updaterComponentModel() const; void listInstalledPackages(const QString ®exp = QString()); - void listAvailablePackages(const QString ®exp); + void listAvailablePackages(const QString ®exp = QString(), + const QHash<QString, QString> &filters = QHash<QString, QString>()); PackageManagerCore::Status updateComponentsSilently(const QStringList &componentsToUpdate); PackageManagerCore::Status installSelectedComponentsSilently(const QStringList& components); PackageManagerCore::Status installDefaultComponentsSilently(); @@ -264,9 +266,12 @@ public: Q_INVOKABLE void setPackageManager(); Q_INVOKABLE bool isPackageManager() const; - void setOfflineGenerator(bool offlineGenerator = true); + void setOfflineGenerator(); Q_INVOKABLE bool isOfflineGenerator() const; + void setPackageViewer(); + Q_INVOKABLE bool isPackageViewer() const; + void setUserSetBinaryMarker(qint64 magicMarker); Q_INVOKABLE bool isUserSetBinaryMarker() const; diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp index 24a67d095..0f1bb90be 100644 --- a/src/libs/installer/packagemanagercore_p.cpp +++ b/src/libs/installer/packagemanagercore_p.cpp @@ -225,6 +225,7 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core) , m_repoFetched(false) , m_updateSourcesAdded(false) , m_magicBinaryMarker(0) // initialize with pseudo marker + , m_magicMarkerSupplement(BinaryContent::Default) , m_componentsToInstallCalculated(false) , m_componentScriptEngine(nullptr) , m_controlScriptEngine(nullptr) @@ -243,7 +244,6 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core) , m_autoAcceptLicenses(false) , m_disableWriteMaintenanceTool(false) , m_autoConfirmCommand(false) - , m_offlineGenerator(false) { } @@ -264,6 +264,7 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, q , m_repoFetched(false) , m_updateSourcesAdded(false) , m_magicBinaryMarker(magicInstallerMaker) + , m_magicMarkerSupplement(BinaryContent::Default) , m_componentsToInstallCalculated(false) , m_componentScriptEngine(nullptr) , m_controlScriptEngine(nullptr) @@ -282,7 +283,6 @@ PackageManagerCorePrivate::PackageManagerCorePrivate(PackageManagerCore *core, q , m_autoAcceptLicenses(false) , m_disableWriteMaintenanceTool(false) , m_autoConfirmCommand(false) - , m_offlineGenerator(false) { foreach (const OperationBlob &operation, performedOperations) { QScopedPointer<QInstaller::Operation> op(KDUpdater::UpdateOperationFactory::instance() @@ -717,7 +717,12 @@ bool PackageManagerCorePrivate::isPackageManager() const bool PackageManagerCorePrivate::isOfflineGenerator() const { - return m_offlineGenerator; + return m_magicMarkerSupplement == BinaryContent::OfflineGenerator; +} + +bool PackageManagerCorePrivate::isPackageViewer() const +{ + return m_magicMarkerSupplement == BinaryContent::PackageViewer; } bool PackageManagerCorePrivate::statusCanceledOrFailed() const @@ -2246,7 +2251,8 @@ void PackageManagerCorePrivate::installComponent(Component *component, double pr component->value(scUncompressedSize).toULongLong(), component->value(scInheritVersion), component->isCheckable(), - component->isExpandedByDefault()); + component->isExpandedByDefault(), + component->value(scContentSha1)); m_localPackageHub->writeToDisk(); component->setInstalled(); @@ -2908,4 +2914,19 @@ bool PackageManagerCorePrivate::askUserConfirmCommand() const } } +bool PackageManagerCorePrivate::packageNeedsUpdate(const LocalPackage &localPackage, const Package *update) const +{ + bool updateNeeded = true; + const QString contentSha1 = update->data(scContentSha1).toString(); + if (!contentSha1.isEmpty()) { + if (contentSha1 == localPackage.contentSha1) + updateNeeded = false; + } else { + const QString updateVersion = update->data(scVersion).toString(); + if (KDUpdater::compareVersion(updateVersion, localPackage.version) <= 0) + updateNeeded = false; + } + return updateNeeded; +} + } // namespace QInstaller diff --git a/src/libs/installer/packagemanagercore_p.h b/src/libs/installer/packagemanagercore_p.h index 858baf9eb..b29808228 100644 --- a/src/libs/installer/packagemanagercore_p.h +++ b/src/libs/installer/packagemanagercore_p.h @@ -132,6 +132,8 @@ public: bool runOfflineGenerator(); bool isOfflineGenerator() const; + bool isPackageViewer() const; + QString replaceVariables(const QString &str) const; QByteArray replaceVariables(const QByteArray &str) const; @@ -254,6 +256,7 @@ private: bool acceptLicenseAgreements() const; bool askUserAcceptLicense(const QString &name, const QString &content) const; bool askUserConfirmCommand() const; + bool packageNeedsUpdate(const LocalPackage &localPackage, const Package *update) const; private: PackageManagerCore *m_core; @@ -264,9 +267,10 @@ private: bool m_repoFetched; bool m_updateSourcesAdded; qint64 m_magicBinaryMarker; + int m_magicMarkerSupplement; + bool m_componentsToInstallCalculated; - bool m_foundEssentialUpdate; - bool m_offlineGenerator; + bool m_foundEssentialUpdate;; mutable ScriptEngine *m_componentScriptEngine; mutable ScriptEngine *m_controlScriptEngine; diff --git a/src/libs/installer/packagemanagergui.cpp b/src/libs/installer/packagemanagergui.cpp index 86c3a2d0c..d52034389 100644 --- a/src/libs/installer/packagemanagergui.cpp +++ b/src/libs/installer/packagemanagergui.cpp @@ -321,7 +321,7 @@ PackageManagerGui::PackageManagerGui(PackageManagerCore *core, QWidget *parent) QFile sheet(styleSheetFile); if (sheet.exists()) { if (sheet.open(QIODevice::ReadOnly)) { - setStyleSheet(QString::fromLatin1(sheet.readAll())); + qApp->setStyleSheet(QString::fromLatin1(sheet.readAll())); } else { qCWarning(QInstaller::lcDeveloperBuild) << "The specified style sheet file " "can not be opened."; diff --git a/src/libs/installer/performinstallationform.cpp b/src/libs/installer/performinstallationform.cpp index 2fb6026cc..31b61ceeb 100644 --- a/src/libs/installer/performinstallationform.cpp +++ b/src/libs/installer/performinstallationform.cpp @@ -80,6 +80,7 @@ PerformInstallationForm::PerformInstallationForm(QObject *parent) : QObject(parent) , m_progressBar(nullptr) , m_progressLabel(nullptr) + , m_downloadStatus(nullptr) , m_productImagesScrollArea(nullptr) , m_productImagesLabel(nullptr) , m_detailsButton(nullptr) diff --git a/src/libs/installer/qsettingswrapper.cpp b/src/libs/installer/qsettingswrapper.cpp index 56db28d78..f57750bc1 100644 --- a/src/libs/installer/qsettingswrapper.cpp +++ b/src/libs/installer/qsettingswrapper.cpp @@ -1,6 +1,6 @@ /************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -74,9 +74,9 @@ public: Private(const QString &fileName, QSettings::Format format) : m_filename(fileName) + , m_format(format) , settings(fileName, format) { - m_format = format; m_scope = settings.scope(); m_application = settings.applicationName(); m_organization = settings.organizationName(); diff --git a/src/libs/installer/utils.cpp b/src/libs/installer/utils.cpp index 59be2171b..7506a13fe 100644 --- a/src/libs/installer/utils.cpp +++ b/src/libs/installer/utils.cpp @@ -351,12 +351,12 @@ static QString qt_create_commandline(const QString &program, const QStringList & // as escaping the quote -- rather put the \ behind the quote: e.g. // rather use "foo"\ than "foo\" QString endQuote(QLatin1Char('\"')); - int i = tmp.length(); - while (i > 0 && tmp.at(i - 1) == QLatin1Char('\\')) { - --i; + int j = tmp.length(); + while (j > 0 && tmp.at(j - 1) == QLatin1Char('\\')) { + --j; endQuote += QLatin1Char('\\'); } - args += QLatin1String(" \"") + tmp.left(i) + endQuote; + args += QLatin1String(" \"") + tmp.left(j) + endQuote; } else { args += QLatin1Char(' ') + tmp; } diff --git a/src/libs/kdtools/filedownloader.cpp b/src/libs/kdtools/filedownloader.cpp index 4cccfd9ca..a9f5040f0 100644 --- a/src/libs/kdtools/filedownloader.cpp +++ b/src/libs/kdtools/filedownloader.cpp @@ -192,6 +192,7 @@ struct KDUpdater::FileDownloader::Private : m_hash(QCryptographicHash::Sha1) , m_assumedSha1Sum("") , autoRemove(true) + , followRedirect(false) , m_speedTimerInterval(100) , m_downloadDeadlineTimerInterval(30000) , m_downloadPaused(false) @@ -255,7 +256,6 @@ KDUpdater::FileDownloader::FileDownloader(const QString &scheme, QObject *parent , d(new Private) { d->scheme = scheme; - d->followRedirect = false; } /*! diff --git a/src/libs/kdtools/localpackagehub.cpp b/src/libs/kdtools/localpackagehub.cpp index 1a754d7d5..2ee880e04 100644 --- a/src/libs/kdtools/localpackagehub.cpp +++ b/src/libs/kdtools/localpackagehub.cpp @@ -327,7 +327,8 @@ void LocalPackageHub::addPackage(const QString &name, quint64 uncompressedSize, const QString &inheritVersionFrom, bool checkable, - bool expandedByDefault) + bool expandedByDefault, + const QString &contentSha1) { // TODO: This somewhat unexpected, remove? if (d->m_packageInfoMap.contains(name)) { @@ -350,6 +351,7 @@ void LocalPackageHub::addPackage(const QString &name, info.uncompressedSize = uncompressedSize; info.checkable = checkable; info.expandedByDefault = expandedByDefault; + info.contentSha1 = contentSha1; d->m_packageInfoMap.insert(name, info); } d->modified = true; @@ -426,6 +428,8 @@ void LocalPackageHub::writeToDisk() addTextChildHelper(&package, QLatin1String("Checkable"), QLatin1String("true")); if (info.expandedByDefault) addTextChildHelper(&package, QLatin1String("ExpandedByDefault"), QLatin1String("true")); + if (!info.contentSha1.isEmpty()) + addTextChildHelper(&package, scContentSha1, info.contentSha1); root.appendChild(package); } @@ -498,6 +502,8 @@ void LocalPackageHub::PackagesInfoData::addPackageFrom(const QDomElement &packag info.checkable = childNodeE.text().toLower() == QLatin1String("true") ? true : false; else if (childNodeE.tagName() == QLatin1String("ExpandedByDefault")) info.expandedByDefault = childNodeE.text().toLower() == QLatin1String("true") ? true : false; + else if (childNodeE.tagName() == QLatin1String("ContentSha1")) + info.contentSha1 = childNodeE.text(); } m_packageInfoMap.insert(info.name, info); } diff --git a/src/libs/kdtools/localpackagehub.h b/src/libs/kdtools/localpackagehub.h index d43c4a6a5..648d6cf6e 100644 --- a/src/libs/kdtools/localpackagehub.h +++ b/src/libs/kdtools/localpackagehub.h @@ -55,6 +55,7 @@ struct KDTOOLS_EXPORT LocalPackage quint64 uncompressedSize; bool checkable; bool expandedByDefault; + QString contentSha1; }; class KDTOOLS_EXPORT LocalPackageHub @@ -108,7 +109,8 @@ public: quint64 uncompressedSize, const QString &inheritVersionFrom, bool checkable, - bool expandedByDefault); + bool expandedByDefault, + const QString &contentSha1); bool removePackage(const QString &pkgName); void refresh(); diff --git a/src/libs/kdtools/selfrestarter.cpp b/src/libs/kdtools/selfrestarter.cpp index e94d0fea7..7771fafac 100644 --- a/src/libs/kdtools/selfrestarter.cpp +++ b/src/libs/kdtools/selfrestarter.cpp @@ -36,19 +36,21 @@ class SelfRestarter::Private { public: Private(int argc, char *argv[]) - : restartOnQuit(false) + : executable(QString::fromLocal8Bit(argv[0])) + , restartOnQuit(false) + , workingPath(QDir::currentPath()) { - executable = QString::fromLocal8Bit(argv[0]); - workingPath = QDir::currentPath(); + for (int i = 1; i < argc; ++i) args << QString::fromLocal8Bit(argv[i]); } Private() + : executable(qApp->applicationFilePath()) + , args(qApp->arguments().mid(1)) + , restartOnQuit(false) + , workingPath(QDir::currentPath()) { - executable = qApp->applicationFilePath(); - workingPath = QDir::currentPath(); - args = qApp->arguments().mid(1); } ~Private() diff --git a/src/libs/kdtools/updatefinder.cpp b/src/libs/kdtools/updatefinder.cpp index 535dfde3d..034e162d3 100644 --- a/src/libs/kdtools/updatefinder.cpp +++ b/src/libs/kdtools/updatefinder.cpp @@ -1,7 +1,7 @@ /**************************************************************************** ** ** Copyright (C) 2013 Klaralvdalens Datakonsult AB (KDAB) -** Copyright (C) 2019 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -79,8 +79,9 @@ public: RemoveExisting }; - Private(UpdateFinder *qq) + explicit Private(UpdateFinder *qq) : q(qq) + , cancel(false) , downloadCompleteCount(0) , m_downloadsToComplete(0) {} @@ -93,7 +94,7 @@ public: struct Data { Data() : downloader(0) {} - Data(const PackageSource &i, FileDownloader *d = 0) + explicit Data(const PackageSource &i, FileDownloader *d = 0) : info(i), downloader(d) {} PackageSource info; diff --git a/src/libs/kdtools/updateoperation.cpp b/src/libs/kdtools/updateoperation.cpp index 00b059af1..897fecf1b 100644 --- a/src/libs/kdtools/updateoperation.cpp +++ b/src/libs/kdtools/updateoperation.cpp @@ -283,7 +283,7 @@ void UpdateOperation::setRequiresUnreplacedVariables(bool isRequired) struct StartsWith { - StartsWith(const QString &searchTerm) + explicit StartsWith(const QString &searchTerm) : m_searchTerm(searchTerm) {} bool operator()(const QString &searchString) diff --git a/src/libs/kdtools/updatesinfo.cpp b/src/libs/kdtools/updatesinfo.cpp index 3119b6240..eaa9b039e 100644 --- a/src/libs/kdtools/updatesinfo.cpp +++ b/src/libs/kdtools/updatesinfo.cpp @@ -125,8 +125,8 @@ bool UpdatesInfoData::parsePackageUpdateElement(const QDomElement &updateE) } else if (childE.tagName() == QLatin1String("Licenses")) { QHash<QString, QVariant> licenseHash; const QDomNodeList licenseNodes = childE.childNodes(); - for (int i = 0; i < licenseNodes.count(); ++i) { - const QDomNode licenseNode = licenseNodes.at(i); + 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; @@ -210,8 +210,8 @@ QVariant UpdatesInfoData::parseOperations(const QDomNodeList &operationNodes) if (operationNode.nodeName() == QLatin1String("Operation")) { const QDomNodeList argumentNodes = operationNode.childNodes(); QStringList attributes; - for (int i = 0; i < argumentNodes.count(); ++i) { - const QDomNode argumentNode = argumentNodes.at(i); + 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()); |