diff options
32 files changed, 469 insertions, 180 deletions
diff --git a/doc/installerfw.qdoc b/doc/installerfw.qdoc index e9a6463bc..4ae62eff6 100644 --- a/doc/installerfw.qdoc +++ b/doc/installerfw.qdoc @@ -1215,6 +1215,11 @@ \row \li -v or --verbose \li Display debug output. + \row + \li -s or --sha-update p1,...,pn + \li Comma-separated list of packages to be updated based on the component sha + checksum instead of the version number. This parameter adds a new \c <ContentSha1> + node to the \c Updates.xml. \endtable \note We recommend that you use the \c {--update-new-packages} parameter to update an existing repository, especially if you have a content delivery diff --git a/src/libs/ifwtools/repositorygen.cpp b/src/libs/ifwtools/repositorygen.cpp index fbcf7b9f3..842d4f9cb 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; } @@ -902,6 +924,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 +1011,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/component.cpp b/src/libs/installer/component.cpp index 66f333377..c5d74cdfa 100644 --- a/src/libs/installer/component.cpp +++ b/src/libs/installer/component.cpp @@ -300,6 +300,7 @@ 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); } /*! @@ -341,6 +342,7 @@ void Component::loadDataFromPackage(const Package &package) if (PackageManagerCore::noForceInstallation()) forced = scFalse; setValue(scForcedInstallation, forced); + setValue(scContentSha1, package.data(scContentSha1).toString()); 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/constants.h b/src/libs/installer/constants.h index 42b14ce63..f1105941b 100644 --- a/src/libs/installer/constants.h +++ b/src/libs/installer/constants.h @@ -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"); diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp index ddfc0f832..5f7412c54 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) @@ -2330,6 +2329,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, @@ -3777,10 +3777,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_p.cpp b/src/libs/installer/packagemanagercore_p.cpp index f4670c738..e6220ba35 100644 --- a/src/libs/installer/packagemanagercore_p.cpp +++ b/src/libs/installer/packagemanagercore_p.cpp @@ -2246,7 +2246,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(); @@ -2898,4 +2899,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..4d5021471 100644 --- a/src/libs/installer/packagemanagercore_p.h +++ b/src/libs/installer/packagemanagercore_p.h @@ -254,6 +254,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; 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/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..7326ac070 100644 --- a/src/libs/kdtools/selfrestarter.cpp +++ b/src/libs/kdtools/selfrestarter.cpp @@ -45,6 +45,7 @@ public: } Private() + : restartOnQuit(false) { executable = qApp->applicationFilePath(); workingPath = QDir::currentPath(); diff --git a/src/libs/kdtools/updatefinder.cpp b/src/libs/kdtools/updatefinder.cpp index 535dfde3d..3403430fe 100644 --- a/src/libs/kdtools/updatefinder.cpp +++ b/src/libs/kdtools/updatefinder.cpp @@ -81,6 +81,7 @@ public: Private(UpdateFinder *qq) : q(qq) + , cancel(false) , downloadCompleteCount(0) , m_downloadsToComplete(0) {} diff --git a/tests/auto/installer/contentshaupdate/contentshaupdate.pro b/tests/auto/installer/contentshaupdate/contentshaupdate.pro new file mode 100644 index 000000000..84402794f --- /dev/null +++ b/tests/auto/installer/contentshaupdate/contentshaupdate.pro @@ -0,0 +1,9 @@ +include(../../qttest.pri) + +QT += qml + +SOURCES += tst_contentshaupdate.cpp + +RESOURCES += \ + settings.qrc \ + ..\shared\config.qrc diff --git a/tests/auto/installer/contentshaupdate/data/repository/Updates.xml b/tests/auto/installer/contentshaupdate/data/repository/Updates.xml new file mode 100644 index 000000000..a83d41384 --- /dev/null +++ b/tests/auto/installer/contentshaupdate/data/repository/Updates.xml @@ -0,0 +1,48 @@ +<Updates> + <ApplicationName>{AnyApplication}</ApplicationName> + <ApplicationVersion>1.0.0</ApplicationVersion> + <Checksum>false</Checksum> + <PackageUpdate> + <Name>componentA</Name> + <DisplayName>Component A</DisplayName> + <Description>This component does not depend on any other component.</Description> + <Version>1.0.0</Version> + <ReleaseDate>2014-08-25</ReleaseDate> + <SortingPriority>100</SortingPriority> + <UpdateFile OS="Any" CompressedSize="283" UncompressedSize="101"/> + <DownloadableArchives>content.7z</DownloadableArchives> + <ContentSha1>10</ContentSha1> + </PackageUpdate> + <PackageUpdate> + <Name>componentB</Name> + <DisplayName>Component B</DisplayName> + <Description>This component does not depend on any other component.</Description> + <Version>1.0.0</Version> + <ReleaseDate>2014-08-25</ReleaseDate> + <SortingPriority>90</SortingPriority> + <UpdateFile OS="Any" CompressedSize="283" UncompressedSize="101"/> + <DownloadableArchives>content.7z</DownloadableArchives> + </PackageUpdate> + <PackageUpdate> + <Name>componentC</Name> + <DisplayName>Component C</DisplayName> + <Description>Component C</Description> + <Version>1.0.0</Version> + <ReleaseDate>2014-08-25</ReleaseDate> + <SortingPriority>80</SortingPriority> + <UpdateFile OS="Any" CompressedSize="283" UncompressedSize="101"/> + <DownloadableArchives>content.7z</DownloadableArchives> + <ContentSha1>10</ContentSha1> + </PackageUpdate> + <PackageUpdate> + <Name>componentD</Name> + <DisplayName>Component D</DisplayName> + <Description>Component D</Description> + <Version>1.0.0</Version> + <ReleaseDate>2014-08-25</ReleaseDate> + <SortingPriority>80</SortingPriority> + <UpdateFile CompressedSize="283" UncompressedSize="101" OS="Any"/> + <DownloadableArchives>content.7z</DownloadableArchives> + <ContentSha1>10</ContentSha1> + </PackageUpdate> +</Updates> diff --git a/tests/auto/installer/contentshaupdate/data/repository/componentA/1.0.0content.7z b/tests/auto/installer/contentshaupdate/data/repository/componentA/1.0.0content.7z Binary files differnew file mode 100644 index 000000000..46a9f1d1e --- /dev/null +++ b/tests/auto/installer/contentshaupdate/data/repository/componentA/1.0.0content.7z diff --git a/tests/auto/installer/contentshaupdate/data/repository/componentB/1.0.0content.7z b/tests/auto/installer/contentshaupdate/data/repository/componentB/1.0.0content.7z Binary files differnew file mode 100644 index 000000000..5f1fb2e1b --- /dev/null +++ b/tests/auto/installer/contentshaupdate/data/repository/componentB/1.0.0content.7z diff --git a/tests/auto/installer/contentshaupdate/data/repository/componentC/1.0.0content.7z b/tests/auto/installer/contentshaupdate/data/repository/componentC/1.0.0content.7z Binary files differnew file mode 100644 index 000000000..83e82b5a3 --- /dev/null +++ b/tests/auto/installer/contentshaupdate/data/repository/componentC/1.0.0content.7z diff --git a/tests/auto/installer/contentshaupdate/data/repository/componentD/1.0.0content.7z b/tests/auto/installer/contentshaupdate/data/repository/componentD/1.0.0content.7z Binary files differnew file mode 100644 index 000000000..da50742a4 --- /dev/null +++ b/tests/auto/installer/contentshaupdate/data/repository/componentD/1.0.0content.7z diff --git a/tests/auto/installer/contentshaupdate/data/repositoryUpdate/Updates.xml b/tests/auto/installer/contentshaupdate/data/repositoryUpdate/Updates.xml new file mode 100644 index 000000000..87017cf91 --- /dev/null +++ b/tests/auto/installer/contentshaupdate/data/repositoryUpdate/Updates.xml @@ -0,0 +1,48 @@ +<Updates> + <ApplicationName>{AnyApplication}</ApplicationName> + <ApplicationVersion>1.0.0</ApplicationVersion> + <Checksum>false</Checksum> + <PackageUpdate> + <Name>componentA</Name> + <DisplayName>Component A</DisplayName> + <Description>Component A.</Description> + <Version>0.1.0</Version> + <ReleaseDate>2014-08-25</ReleaseDate> + <SortingPriority>100</SortingPriority> + <UpdateFile CompressedSize="283" UncompressedSize="101" OS="Any"/> + <DownloadableArchives>content.7z</DownloadableArchives> + <ContentSha1>5</ContentSha1> + </PackageUpdate> + <PackageUpdate> + <Name>componentB</Name> + <DisplayName>Component B</DisplayName> + <Description>Component B.</Description> + <Version>0.1.0</Version> + <ReleaseDate>2014-08-25</ReleaseDate> + <SortingPriority>90</SortingPriority> + <UpdateFile CompressedSize="283" UncompressedSize="101" OS="Any"/> + <DownloadableArchives>content.7z</DownloadableArchives> + <ContentSha1>10</ContentSha1> + </PackageUpdate> + <PackageUpdate> + <Name>componentC</Name> + <DisplayName>Component C</DisplayName> + <Description>Component C</Description> + <Version>2.0.0</Version> + <ReleaseDate>2014-08-25</ReleaseDate> + <SortingPriority>80</SortingPriority> + <UpdateFile CompressedSize="283" UncompressedSize="101" OS="Any"/> + <DownloadableArchives>content.7z</DownloadableArchives> + <ContentSha1>10</ContentSha1> + </PackageUpdate> + <PackageUpdate> + <Name>componentD</Name> + <DisplayName>Component D</DisplayName> + <Description>Component D</Description> + <Version>2.0.0</Version> + <ReleaseDate>2014-08-25</ReleaseDate> + <SortingPriority>80</SortingPriority> + <UpdateFile UncompressedSize="101" CompressedSize="283" OS="Any"/> + <DownloadableArchives>content.7z</DownloadableArchives> + </PackageUpdate> +</Updates> diff --git a/tests/auto/installer/contentshaupdate/data/repositoryUpdate/componentA/0.1.0content.7z b/tests/auto/installer/contentshaupdate/data/repositoryUpdate/componentA/0.1.0content.7z Binary files differnew file mode 100644 index 000000000..bdbabc7fd --- /dev/null +++ b/tests/auto/installer/contentshaupdate/data/repositoryUpdate/componentA/0.1.0content.7z diff --git a/tests/auto/installer/contentshaupdate/data/repositoryUpdate/componentB/0.1.0content.7z b/tests/auto/installer/contentshaupdate/data/repositoryUpdate/componentB/0.1.0content.7z Binary files differnew file mode 100644 index 000000000..1c1129b9f --- /dev/null +++ b/tests/auto/installer/contentshaupdate/data/repositoryUpdate/componentB/0.1.0content.7z diff --git a/tests/auto/installer/contentshaupdate/data/repositoryUpdate/componentC/2.0.0content.7z b/tests/auto/installer/contentshaupdate/data/repositoryUpdate/componentC/2.0.0content.7z Binary files differnew file mode 100644 index 000000000..7f75bf503 --- /dev/null +++ b/tests/auto/installer/contentshaupdate/data/repositoryUpdate/componentC/2.0.0content.7z diff --git a/tests/auto/installer/contentshaupdate/data/repositoryUpdate/componentD/2.0.0content.7z b/tests/auto/installer/contentshaupdate/data/repositoryUpdate/componentD/2.0.0content.7z Binary files differnew file mode 100644 index 000000000..4207dfbf2 --- /dev/null +++ b/tests/auto/installer/contentshaupdate/data/repositoryUpdate/componentD/2.0.0content.7z diff --git a/tests/auto/installer/contentshaupdate/settings.qrc b/tests/auto/installer/contentshaupdate/settings.qrc new file mode 100644 index 000000000..a5d045f46 --- /dev/null +++ b/tests/auto/installer/contentshaupdate/settings.qrc @@ -0,0 +1,14 @@ +<RCC> + <qresource prefix="/"> + <file>data/repository/Updates.xml</file> + <file>data/repository/componentA/1.0.0content.7z</file> + <file>data/repository/componentB/1.0.0content.7z</file> + <file>data/repository/componentC/1.0.0content.7z</file> + <file>data/repository/componentD/1.0.0content.7z</file> + <file>data/repositoryUpdate/Updates.xml</file> + <file>data/repositoryUpdate/componentA/0.1.0content.7z</file> + <file>data/repositoryUpdate/componentB/0.1.0content.7z</file> + <file>data/repositoryUpdate/componentC/2.0.0content.7z</file> + <file>data/repositoryUpdate/componentD/2.0.0content.7z</file> + </qresource> +</RCC> diff --git a/tests/auto/installer/contentshaupdate/tst_contentshaupdate.cpp b/tests/auto/installer/contentshaupdate/tst_contentshaupdate.cpp new file mode 100644 index 000000000..d8d2f5377 --- /dev/null +++ b/tests/auto/installer/contentshaupdate/tst_contentshaupdate.cpp @@ -0,0 +1,108 @@ +/************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt Installer Framework. +** +** $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 +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** 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-3.0.html. +** +** $QT_END_LICENSE$ +** +**************************************************************************/ + +#include "../shared/packagemanager.h" +#include "../shared/verifyinstaller.h" + +#include <QTest> + +using namespace QInstaller; + +class tst_ContentSha1Update : public QObject +{ + Q_OBJECT + +private: + void setRepository(const QString &repository) + { + core->reset(); + core->cancelMetaInfoJob(); //Call cancel to reset metadata so that update repositories are fetched + + QSet<Repository> repoList; + Repository repo = Repository::fromUserInput(repository); + repoList.insert(repo); + core->settings().setDefaultRepositories(repoList); + } + +private slots: + void initTestCase() + { + m_installDir = QInstaller::generateTemporaryFileName(); + core = PackageManager::getPackageManagerWithInit(m_installDir); + } + + void updateWithContentSha1_data() + { + QTest::addColumn<QString>("component"); + QTest::addColumn<QString>("content"); + QTest::addColumn<QString>("updatedContent"); + QTest::addColumn<PackageManagerCore::Status>("expectedStatusAfterInstall"); + QTest::addColumn<PackageManagerCore::Status>("expectedStatusAfterUpdate"); + + QTest::newRow("ContentSha1Change") << "componentA" << "1.0.0content.txt" << "0.1.0content.txt" << PackageManagerCore::Success << PackageManagerCore::Success; + QTest::newRow("NewContentSha1") << "componentB" << "1.0.0content.txt" << "0.1.0content.txt" << PackageManagerCore::Success << PackageManagerCore::Success; + QTest::newRow("SameContentSha1") << "componentC" << "1.0.0content.txt" << "1.0.0content.txt" << PackageManagerCore::Success << PackageManagerCore::Canceled; + QTest::newRow("Sha1RemovedFromRepo") << "componentD" << "1.0.0content.txt" << "2.0.0content.txt" << PackageManagerCore::Success << PackageManagerCore::Success; + } + + void updateWithContentSha1() + { + QFETCH(QString, component); + QFETCH(QString, content); + QFETCH(QString, updatedContent); + QFETCH(PackageManagerCore::Status, expectedStatusAfterInstall); + QFETCH(PackageManagerCore::Status, expectedStatusAfterUpdate); + + setRepository(":///data/repository"); + QCOMPARE(expectedStatusAfterInstall, core->installSelectedComponentsSilently(QStringList() << component)); + QCOMPARE(expectedStatusAfterInstall, core->status()); + VerifyInstaller::verifyInstallerResources(m_installDir, component, content); + + core->commitSessionOperations(); + core->setPackageManager(); + setRepository(":///data/repositoryUpdate"); + QCOMPARE(expectedStatusAfterUpdate, core->updateComponentsSilently(QStringList())); + VerifyInstaller::verifyInstallerResources(m_installDir, component, updatedContent); + } + + void cleanupTestCase() + { + QDir dir(m_installDir); + QVERIFY(dir.removeRecursively()); + delete core; + } + +private: + QString m_installDir; + PackageManagerCore *core; +}; + + +QTEST_MAIN(tst_ContentSha1Update) + +#include "tst_contentshaupdate.moc" diff --git a/tests/auto/installer/installer.pro b/tests/auto/installer/installer.pro index 114c43d7a..cb0438ab3 100644 --- a/tests/auto/installer/installer.pro +++ b/tests/auto/installer/installer.pro @@ -39,7 +39,8 @@ SUBDIRS += \ globalsettingsoperation \ elevatedexecuteoperation \ treename \ - createoffline + createoffline \ + contentshaupdate win32 { SUBDIRS += registerfiletypeoperation \ diff --git a/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp b/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp index ae2c3b211..17343e49d 100644 --- a/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp +++ b/tests/auto/installer/packagemanagercore/tst_packagemanagercore.cpp @@ -306,7 +306,7 @@ private slots: QTest::ignoreMessage(QtWarningMsg, re); QTest::ignoreMessage(QtDebugMsg, "No updates available."); - QCOMPARE(PackageManagerCore::Failure, core.updateComponentsSilently(QStringList())); + QCOMPARE(PackageManagerCore::Canceled, core.updateComponentsSilently(QStringList())); QVERIFY(QDir().rmdir(testDirectory)); } diff --git a/tests/auto/tools/repotest/tst_repotest.cpp b/tests/auto/tools/repotest/tst_repotest.cpp index 5aa614454..228c13c80 100644 --- a/tests/auto/tools/repotest/tst_repotest.cpp +++ b/tests/auto/tools/repotest/tst_repotest.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. @@ -39,114 +39,63 @@ class tst_repotest : public QObject { Q_OBJECT private: - // TODO generateRepo() is almost direct copy from repogen.cpp. - // Move the needed parts of repogen.cpp to a usable function for easier maintenance. - void generateRepo(bool createSplitMetadata, bool createUnifiedMetadata, bool updateNewComponents) + void generateRepo(bool createSplitMetadata, bool createUnifiedMetadata, bool updateNewComponents, + QStringList packagesUpdatedWithSha = QStringList()) { QStringList filteredPackages; - QInstallerTools::FilterType filterType = QInstallerTools::Exclude; - QInstallerTools::PackageInfoVector precompressedPackages = QInstallerTools::createListOfRepositoryPackages - (m_repositoryDirectories, &filteredPackages, filterType); - m_packages.append(precompressedPackages); - - QInstallerTools::PackageInfoVector preparedPackages = QInstallerTools::createListOfPackages(m_packagesDirectories, - &filteredPackages, filterType); - m_packages.append(preparedPackages); - - if (updateNewComponents) - QInstallerTools::filterNewComponents(m_repositoryDir, m_packages); - QHash<QString, QString> pathToVersionMapping = QInstallerTools::buildPathToVersionMapping(m_packages); - - foreach (const QInstallerTools::PackageInfo &package, m_packages) { - const QFileInfo fi(m_repositoryDir, package.name); - if (fi.exists()) - removeDirectory(fi.absoluteFilePath()); - } + QInstallerTools::PackageInfoVector m_packages = QInstallerTools::collectPackages(m_repoInfo, + &filteredPackages, QInstallerTools::Exclude, updateNewComponents, packagesUpdatedWithSha); if (updateNewComponents) { //Verify that component B exists as that is not updated if (createSplitMetadata) { - VerifyInstaller::verifyFileExistence(m_repositoryDir + "/B", QStringList() << "1.0.0content.7z" + VerifyInstaller::verifyFileExistence(m_repoInfo.repositoryDir + "/B", QStringList() << "1.0.0content.7z" << "1.0.0content.7z.sha1" << "1.0.0meta.7z"); } else { - VerifyInstaller::verifyFileExistence(m_repositoryDir + "/B", QStringList() << "1.0.0content.7z" + VerifyInstaller::verifyFileExistence(m_repoInfo.repositoryDir + "/B", QStringList() << "1.0.0content.7z" << "1.0.0content.7z.sha1"); } } else { - QDir dir(m_repositoryDir + "/B"); + QDir dir(m_repoInfo.repositoryDir + "/B"); QVERIFY(!dir.exists()); } - QStringList directories; - directories.append(m_packagesDirectories); - directories.append(m_repositoryDirectories); - - QStringList unite7zFiles; - foreach (const QString &repositoryDirectory, m_repositoryDirectories) { - QDirIterator it(repositoryDirectory, QStringList(QLatin1String("*_meta.7z")) - , QDir::Files | QDir::CaseSensitive); - while (it.hasNext()) { - it.next(); - unite7zFiles.append(it.fileInfo().absoluteFilePath()); - } - } - - QInstallerTools::copyComponentData(directories, m_repositoryDir, &m_packages); - QInstallerTools::copyMetaData(m_tmpMetaDir, m_repositoryDir, m_packages, QLatin1String("{AnyApplication}"), - QLatin1String("1.0.0"), unite7zFiles); - QString existing7z = QInstallerTools::existingUniteMeta7z(m_repositoryDir); - if (!existing7z.isEmpty()) - existing7z = m_repositoryDir + QDir::separator() + existing7z; - QInstallerTools::compressMetaDirectories(m_tmpMetaDir, existing7z, pathToVersionMapping, - createSplitMetadata, createUnifiedMetadata); - QDirIterator it(m_repositoryDir, QStringList(QLatin1String("Updates*.xml")) - << QLatin1String("*_meta.7z"), QDir::Files | QDir::CaseSensitive); - while (it.hasNext()) { - it.next(); - QFile::remove(it.fileInfo().absoluteFilePath()); - } - QInstaller::moveDirectoryContents(m_tmpMetaDir, m_repositoryDir); - } - - void generateTempMetaDir() - { - if (!m_tmpMetaDir.isEmpty()) - m_tempDirDeleter.releaseAndDelete(m_tmpMetaDir); QTemporaryDir tmp; tmp.setAutoRemove(false); - m_tmpMetaDir = tmp.path(); - m_tempDirDeleter.add(m_tmpMetaDir); + const QString tmpMetaDir = tmp.path(); + QInstallerTools::createRepository(m_repoInfo, &m_packages, tmpMetaDir, createSplitMetadata, + createUnifiedMetadata); + QInstaller::removeDirectory(tmpMetaDir, true); } void clearData() { - generateTempMetaDir(); - m_packagesDirectories.clear(); - m_repositoryDirectories.clear(); + m_repoInfo.packages.clear(); + m_repoInfo.repositoryPackages.clear(); m_packages.clear(); } void initRepoUpdate() { clearData(); - m_packagesDirectories << ":///packages_update"; + m_repoInfo.packages << ":///packages_update"; } void initRepoUpdateFromRepository(const QString &repository) { clearData(); - m_repositoryDirectories << repository; + m_repoInfo.repositoryPackages << repository; } void verifyUniteMetadata(const QString &scriptVersion) { - QString fileContent = VerifyInstaller::fileContent(m_repositoryDir + QDir::separator() + QString fileContent = VerifyInstaller::fileContent(m_repoInfo.repositoryDir + QDir::separator() + "Updates.xml"); QRegularExpression re("<MetadataName>(.*)<.MetadataName>"); QStringList matches = re.match(fileContent).capturedTexts(); - QString existingUniteMeta7z = QInstallerTools::existingUniteMeta7z(m_repositoryDir); + QString existingUniteMeta7z = QInstallerTools::existingUniteMeta7z(m_repoInfo.repositoryDir); QCOMPARE(2, matches.count()); QCOMPARE(existingUniteMeta7z, matches.at(1)); - QFile file(m_repositoryDir + QDir::separator() + matches.at(1)); + QFile file(m_repoInfo.repositoryDir + QDir::separator() + matches.at(1)); QVERIFY(file.open(QIODevice::ReadOnly)); //We have script<version>.qs for package A in the unite metadata @@ -159,35 +108,35 @@ private: QCOMPARE(qPrintable(fileName.arg(scriptVersion)), fileIt->path); } - VerifyInstaller::verifyFileExistence(m_repositoryDir, QStringList() << "Updates.xml" + VerifyInstaller::verifyFileExistence(m_repoInfo.repositoryDir, QStringList() << "Updates.xml" << matches.at(1)); - VerifyInstaller::verifyFileContent(m_repositoryDir + QDir::separator() + "Updates.xml", + VerifyInstaller::verifyFileContent(m_repoInfo.repositoryDir + QDir::separator() + "Updates.xml", "SHA1"); - VerifyInstaller::verifyFileContent(m_repositoryDir + QDir::separator() + "Updates.xml", + VerifyInstaller::verifyFileContent(m_repoInfo.repositoryDir + QDir::separator() + "Updates.xml", "MetadataName"); } void verifyComponentRepository(const QString &componentAVersion, bool hasComponentMeta) { const QString content = "%1content.7z"; - const QString contentSha = "%1content.7z.sha1"; + const QString contentSha1 = "%1content.7z.sha1"; const QString meta = "%1meta.7z"; QStringList componentA; QStringList componentB; - componentA << qPrintable(content.arg(componentAVersion)) << qPrintable(contentSha.arg(componentAVersion)); + componentA << qPrintable(content.arg(componentAVersion)) << qPrintable(contentSha1.arg(componentAVersion)); componentB << "1.0.0content.7z" << "1.0.0content.7z.sha1"; if (hasComponentMeta) { componentA << qPrintable(meta.arg(componentAVersion)); componentB << "1.0.0meta.7z"; } - VerifyInstaller::verifyFileExistence(m_repositoryDir + "/A", componentA); - VerifyInstaller::verifyFileExistence(m_repositoryDir + "/B", componentB); + VerifyInstaller::verifyFileExistence(m_repoInfo.repositoryDir + "/A", componentA); + VerifyInstaller::verifyFileExistence(m_repoInfo.repositoryDir + "/B", componentB); } void verifyComponentMetaUpdatesXml() { - VerifyInstaller::verifyFileExistence(m_repositoryDir, QStringList() << "Updates.xml"); - VerifyInstaller::verifyFileHasNoContent(m_repositoryDir + QDir::separator() + "Updates.xml", + VerifyInstaller::verifyFileExistence(m_repoInfo.repositoryDir, QStringList() << "Updates.xml"); + VerifyInstaller::verifyFileHasNoContent(m_repoInfo.repositoryDir + QDir::separator() + "Updates.xml", "MetadataName"); } @@ -216,7 +165,7 @@ private: foreach (const QString &fileName, contentFiles) { message = "Copying file from \":///%5/%1/%2%4\" to \"%3/%1/%2%4\""; QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(component).arg(version) - .arg(m_repositoryDir).arg(fileName).arg(repository))); + .arg(m_repoInfo.repositoryDir).arg(fileName).arg(repository))); } } @@ -303,9 +252,23 @@ private: void ignoreMessageForUpdateComponent() { QString message = "Update component \"A\" in \"%1\" ."; - QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(m_repositoryDir))); + QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(m_repoInfo.repositoryDir))); message = "Update component \"C\" in \"%1\" ."; - QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(m_repositoryDir))); + QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(m_repoInfo.repositoryDir))); + } + + void verifyComponentShaUpdate(int shaUpdateComponents) + { + QString updatesXmlFile(m_repoInfo.repositoryDir + QDir::separator() + "Updates.xml"); + QFile file(updatesXmlFile); + QDomDocument dom; + + QVERIFY(file.open(QIODevice::ReadOnly)); + QVERIFY(dom.setContent(&file)); + file.close(); + QCOMPARE(dom.elementsByTagName("ContentSha1").count(), shaUpdateComponents); + VerifyInstaller::verifyFileContent(updatesXmlFile, + "<ContentSha1>059e5ed8cd3a1fbca08cccfa4075265192603e3f</ContentSha1>"); } private slots: @@ -313,11 +276,10 @@ private slots: { ignoreMessageForCollectingPackages("1.0.0", "1.0.0"); - m_repositoryDir = QInstallerTools::makePathAbsolute(QInstaller::generateTemporaryFileName()); - m_tempDirDeleter.add(m_repositoryDir); - generateTempMetaDir(); + m_repoInfo.repositoryDir = QInstallerTools::makePathAbsolute(QInstaller::generateTemporaryFileName()); + m_tempDirDeleter.add(m_repoInfo.repositoryDir); - m_packagesDirectories << ":///packages"; + m_repoInfo.packages << ":///packages"; ignoreMessagesForComponentHash(QStringList() << "A" << "B", false); ignoreMessagesForCopyMetadata("A", true, false); //Only A has metadata @@ -357,6 +319,26 @@ private slots: verifyUniteMetadata("1.0.0"); } + void testWithComponentShaUpdate() + { + ignoreMessagesForComponentSha(QStringList () << "A" << "B", false); + generateRepo(true, false, false, QStringList () << "A"); + + verifyComponentRepository("1.0.0", true); + verifyComponentMetaUpdatesXml(); + verifyComponentShaUpdate(1); + } + + void testWithTwoComponentsShaUpdate() + { + ignoreMessagesForComponentSha(QStringList () << "A" << "B", false); + generateRepo(true, false, false, QStringList () << "A" << "B"); + + verifyComponentRepository("1.0.0", true); + verifyComponentMetaUpdatesXml(); + verifyComponentShaUpdate(2); + } + void testUpdateNewComponents() { // Create 'base' repository which will be updated @@ -371,7 +353,7 @@ private slots: ignoreMessagesForComponentHash(QStringList() << "A", true); ignoreMessagesForCopyMetadata("A", true, true); const QString &message = "Update component \"A\" in \"%1\" ."; - QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(m_repositoryDir))); + QTest::ignoreMessage(QtDebugMsg, qPrintable(message.arg(m_repoInfo.repositoryDir))); generateRepo(true, false, true); verifyComponentRepository("2.0.0", true); verifyComponentMetaUpdatesXml(); @@ -458,7 +440,7 @@ private slots: generateRepo(true, true, true); verifyComponentRepository("2.0.0", true); - VerifyInstaller::verifyFileExistence(m_repositoryDir + "/C", QStringList() << "1.0.0content.7z" << "1.0.0content.7z.sha1" << "1.0.0meta.7z"); + VerifyInstaller::verifyFileExistence(m_repoInfo.repositoryDir + "/C", QStringList() << "1.0.0content.7z" << "1.0.0content.7z.sha1" << "1.0.0meta.7z"); verifyUniteMetadata("2.0.0"); } @@ -478,23 +460,20 @@ private slots: generateRepo(false, true, true); verifyComponentRepository("2.0.0", false); - VerifyInstaller::verifyFileExistence(m_repositoryDir + "/C", QStringList() << "1.0.0content.7z" << "1.0.0content.7z.sha1"); + VerifyInstaller::verifyFileExistence(m_repoInfo.repositoryDir + "/C", QStringList() << "1.0.0content.7z" << "1.0.0content.7z.sha1"); verifyUniteMetadata("2.0.0"); } void cleanup() { m_tempDirDeleter.releaseAndDeleteAll(); - m_packagesDirectories.clear(); + m_repoInfo.packages.clear(); m_packages.clear(); - m_repositoryDirectories.clear(); + m_repoInfo.repositoryPackages.clear(); } private: - QString m_tmpMetaDir; - QString m_repositoryDir; - QStringList m_packagesDirectories; - QStringList m_repositoryDirectories; + QInstallerTools::RepositoryInfo m_repoInfo; QInstallerTools::PackageInfoVector m_packages; TempDirDeleter m_tempDirDeleter; }; diff --git a/tools/repogen/repogen.cpp b/tools/repogen/repogen.cpp index a88867e92..b630f8cd3 100644 --- a/tools/repogen/repogen.cpp +++ b/tools/repogen/repogen.cpp @@ -44,8 +44,6 @@ #include <iostream> -#define QUOTE_(x) #x -#define QUOTE(x) QUOTE_(x) using namespace QInstaller; @@ -100,8 +98,8 @@ int main(int argc, char** argv) QStringList filteredPackages; bool updateExistingRepository = false; - QStringList packagesDirectories; - QStringList repositoryDirectories; + QInstallerTools::RepositoryInfo repoInfo; + QStringList packagesUpdatedWithSha; QInstallerTools::FilterType filterType = QInstallerTools::Exclude; bool remove = false; bool updateExistingRepositoryWithNewComponents = false; @@ -168,7 +166,7 @@ int main(int argc, char** argv) "Error: Package directory is empty")); } - packagesDirectories.append(args.first()); + repoInfo.packages.append(args.first()); args.removeFirst(); } else if (args.first() == QLatin1String("--repository")) { args.removeFirst(); @@ -181,7 +179,7 @@ int main(int argc, char** argv) return printErrorAndUsageAndExit(QCoreApplication::translate("QInstaller", "Error: Only local filesystem repositories now supported")); } - repositoryDirectories.append(args.first()); + repoInfo.repositoryPackages.append(args.first()); args.removeFirst(); } else if (args.first() == QLatin1String("--ignore-translations") || args.first() == QLatin1String("--ignore-invalid-packages")) { @@ -195,14 +193,17 @@ int main(int argc, char** argv) } else if (args.first() == QLatin1String("--component-metadata")) { createUnifiedMetadata = false; args.removeFirst(); - } - else { + } else if (args.first() == QLatin1String("--sha-update") || args.first() == QLatin1String("-s")) { + args.removeFirst(); + packagesUpdatedWithSha = args.first().split(QLatin1Char(',')); + args.removeFirst(); + } else { printUsage(); return 1; } } - if ((packagesDirectories.isEmpty() && repositoryDirectories.isEmpty()) || (args.count() != 1)) { + if ((repoInfo.packages.isEmpty() && repoInfo.repositoryPackages.isEmpty()) || (args.count() != 1)) { printUsage(); return 1; } @@ -213,12 +214,12 @@ int main(int argc, char** argv) "Argument -r|--remove and --update|--update-new-components are mutually exclusive!")); } - const QString repositoryDir = QInstallerTools::makePathAbsolute(args.first()); + repoInfo.repositoryDir = QInstallerTools::makePathAbsolute(args.first()); if (remove) - QInstaller::removeDirectory(repositoryDir); + QInstaller::removeDirectory(repoInfo.repositoryDir); if (updateExistingRepositoryWithNewComponents) { - QStringList meta7z = QDir(repositoryDir).entryList(QStringList() + QStringList meta7z = QDir(repoInfo.repositoryDir).entryList(QStringList() << QLatin1String("*_meta.7z"), QDir::Files); if (!meta7z.isEmpty()) { throw QInstaller::Error(QCoreApplication::translate("QInstaller", @@ -228,72 +229,27 @@ int main(int argc, char** argv) } } - if (!update && QFile::exists(repositoryDir) && !QDir(repositoryDir).entryList( + if (!update && QFile::exists(repoInfo.repositoryDir) && !QDir(repoInfo.repositoryDir).entryList( QDir::AllEntries | QDir::NoDotAndDotDot).isEmpty()) { throw QInstaller::Error(QCoreApplication::translate("QInstaller", - "Repository target directory \"%1\" already exists.").arg(QDir::toNativeSeparators(repositoryDir))); - } - - QInstallerTools::PackageInfoVector packages; - - QInstallerTools::PackageInfoVector precompressedPackages = QInstallerTools::createListOfRepositoryPackages(repositoryDirectories, - &filteredPackages, filterType); - packages.append(precompressedPackages); - - QInstallerTools::PackageInfoVector preparedPackages = QInstallerTools::createListOfPackages(packagesDirectories, - &filteredPackages, filterType); - packages.append(preparedPackages); - - if (updateExistingRepositoryWithNewComponents) { - QInstallerTools::filterNewComponents(repositoryDir, packages); - if (packages.isEmpty()) { - std::cout << QString::fromLatin1("Cannot find new components to update \"%1\".") - .arg(repositoryDir) << std::endl; - return EXIT_SUCCESS; - } + "Repository target directory \"%1\" already exists.").arg(QDir::toNativeSeparators(repoInfo.repositoryDir))); } - QHash<QString, QString> pathToVersionMapping = QInstallerTools::buildPathToVersionMapping(packages); - - foreach (const QInstallerTools::PackageInfo &package, packages) { - const QFileInfo fi(repositoryDir, package.name); - if (fi.exists()) - removeDirectory(fi.absoluteFilePath()); + QInstallerTools::PackageInfoVector packages = QInstallerTools::collectPackages(repoInfo, + &filteredPackages, filterType, updateExistingRepositoryWithNewComponents, packagesUpdatedWithSha); + if (packages.isEmpty()) { + std::cout << QString::fromLatin1("Cannot find components to update \"%1\".") + .arg(repoInfo.repositoryDir) << std::endl; + return EXIT_SUCCESS; } QTemporaryDir tmp; tmp.setAutoRemove(false); tmpMetaDir = tmp.path(); - QStringList directories; - directories.append(packagesDirectories); - directories.append(repositoryDirectories); - QStringList unite7zFiles; - foreach (const QString &repositoryDirectory, repositoryDirectories) { - QDirIterator it(repositoryDirectory, QStringList(QLatin1String("*_meta.7z")) - , QDir::Files | QDir::CaseSensitive); - while (it.hasNext()) { - it.next(); - unite7zFiles.append(it.fileInfo().absoluteFilePath()); - } - } - QInstallerTools::copyComponentData(directories, repositoryDir, &packages); - QInstallerTools::copyMetaData(tmpMetaDir, repositoryDir, packages, QLatin1String("{AnyApplication}"), - QLatin1String(QUOTE(IFW_REPOSITORY_FORMAT_VERSION)), unite7zFiles); - - QString existing7z = QInstallerTools::existingUniteMeta7z(repositoryDir); - if (!existing7z.isEmpty()) - existing7z = repositoryDir + QDir::separator() + existing7z; - QInstallerTools::compressMetaDirectories(tmpMetaDir, existing7z, pathToVersionMapping, - createComponentMetadata, createUnifiedMetadata); - - QDirIterator it(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, repositoryDir); + QInstallerTools::createRepository(repoInfo, &packages, tmpMetaDir, + createComponentMetadata, createUnifiedMetadata); + exitCode = EXIT_SUCCESS; } catch (const Lib7z::SevenZipException &e) { std::cerr << "Caught 7zip exception: " << e.message() << std::endl; |