diff options
author | Katja Marttila <katja.marttila@qt.io> | 2022-10-24 13:24:38 +0300 |
---|---|---|
committer | Katja Marttila <katja.marttila@qt.io> | 2022-10-24 13:24:38 +0300 |
commit | 0f37e52fdb2792507682d767df7405eefb501559 (patch) | |
tree | 48cef12a21a14eb011c192c150054bc8ed16bd18 | |
parent | ea36be89d4f93467eab2f43634632023c734f2e3 (diff) | |
parent | 57c217b5aedbb3f6a84b4b4acc887e0e46263e42 (diff) |
Merge remote-tracking branch 'origin/4.5' into master
Change-Id: Icd08be87fa135868e0ffc8f791afce1617f478e1
-rw-r--r-- | doc/images/ifw-settings-cache.png | bin | 0 -> 14486 bytes | |||
-rw-r--r-- | doc/images/ifw-settings-network.png | bin | 8607 -> 12288 bytes | |||
-rw-r--r-- | doc/images/ifw-settings-repositories.png | bin | 11796 -> 17203 bytes | |||
-rw-r--r-- | doc/installerfw-using.qdoc | 27 | ||||
-rw-r--r-- | doc/installerfw.qdoc | 6 | ||||
-rw-r--r-- | doc/scripting-api/packagemanagercore.qdoc | 6 | ||||
-rw-r--r-- | src/libs/installer/commandlineparser.cpp | 6 | ||||
-rw-r--r-- | src/libs/installer/constants.h | 8 | ||||
-rw-r--r-- | src/libs/installer/genericdatacache.cpp | 22 | ||||
-rw-r--r-- | src/libs/installer/genericdatacache.h | 1 | ||||
-rw-r--r-- | src/libs/installer/metadatajob.cpp | 20 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore.cpp | 43 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore.h | 4 | ||||
-rw-r--r-- | src/libs/installer/packagemanagercore_p.cpp | 1 | ||||
-rw-r--r-- | src/sdk/commandlineinterface.cpp | 12 | ||||
-rw-r--r-- | src/sdk/commandlineinterface.h | 1 | ||||
-rw-r--r-- | src/sdk/main.cpp | 3 | ||||
-rw-r--r-- | src/sdk/sdkapp.h | 10 | ||||
-rw-r--r-- | tests/auto/installer/metadatacache/tst_metadatacache.cpp | 26 |
19 files changed, 161 insertions, 35 deletions
diff --git a/doc/images/ifw-settings-cache.png b/doc/images/ifw-settings-cache.png Binary files differnew file mode 100644 index 000000000..d8678153a --- /dev/null +++ b/doc/images/ifw-settings-cache.png diff --git a/doc/images/ifw-settings-network.png b/doc/images/ifw-settings-network.png Binary files differindex 25e1c9266..11e27ec6a 100644 --- a/doc/images/ifw-settings-network.png +++ b/doc/images/ifw-settings-network.png diff --git a/doc/images/ifw-settings-repositories.png b/doc/images/ifw-settings-repositories.png Binary files differindex df533fd98..46808eb01 100644 --- a/doc/images/ifw-settings-repositories.png +++ b/doc/images/ifw-settings-repositories.png diff --git a/doc/installerfw-using.qdoc b/doc/installerfw-using.qdoc index a2aac9046..5f4674449 100644 --- a/doc/installerfw-using.qdoc +++ b/doc/installerfw-using.qdoc @@ -339,9 +339,9 @@ \title Specifying Settings - Settings pages enable end users to specify proxy settings or install add-on - components. End users select \gui Settings on the introduction page to - specify the settings. + Settings pages enable end users to specify proxy settings, install add-on + components, and modify local cache parameters. End users select \gui Settings + on the introduction page to specify the settings. \section1 Specifying Proxy Settings @@ -366,6 +366,14 @@ After the installation, only default and user-defined repositories will be available. + \section1 Specifying Local Cache Settings + + The installers use a local cache for the meta information fetched from remote + repositories. This improves loading times when the same metadata is accessed + multiple times. End users can configure the location of the metadata cache and + clear the contents of an existing cache. + + \image ifw-settings-cache.png "Local Cache tab on Settings page" */ /*! @@ -479,6 +487,19 @@ installer.exe --root "C:\TargetFolder" --offline-installer-name "MyInstaller" create-offline componentA componentB \endcode + \section1 Clearing the Local Cache + + Online installers and maintenance tools created with the Qt Installer Framework cache the + meta information downloaded from remote repositories to local disk. This improves loading + times for subsequent metadata downloads. + + The cache may grow in size over time. To clear the contents of the entire cache, + use the \c clear-cache command: + + \code + maintenancetool.exe clear-cache + \endcode + \section1 Unattended Usage By default, the generated installers may ask for additional information during installation, diff --git a/doc/installerfw.qdoc b/doc/installerfw.qdoc index e69a545b2..3d251fbc7 100644 --- a/doc/installerfw.qdoc +++ b/doc/installerfw.qdoc @@ -252,6 +252,9 @@ search command. The keys can be any of the possible package information elements, like \c DisplayName and \c Description. \row + \li --cp, --cache-path <path> + \li Sets the path used for local metadata cache. The path must be writable by the current user. + \row \li --am, --accept-messages \li [CLI] Accepts all message queries without user input. \row @@ -334,6 +337,9 @@ \li co, create-offline <pkg ...> \li Create offline installer from selected packages. \row + \li cc, clear-cache + \li Clear contents of the local metadata cache. + \row \li pr, purge \li Uninstall all packages and remove the program directory. \endtable diff --git a/doc/scripting-api/packagemanagercore.qdoc b/doc/scripting-api/packagemanagercore.qdoc index cd2253890..b14fd957f 100644 --- a/doc/scripting-api/packagemanagercore.qdoc +++ b/doc/scripting-api/packagemanagercore.qdoc @@ -325,12 +325,6 @@ */ /*! - \qmlmethod void installer::clearLocalCache() - - Clears the contents of the cache used to store downloaded metadata. -*/ - -/*! \qmlmethod void installer::componentsToInstallNeedsRecalculation() Ensures that component dependencies are re-calculated. diff --git a/src/libs/installer/commandlineparser.cpp b/src/libs/installer/commandlineparser.cpp index 2c09d14b4..3b5b46e0e 100644 --- a/src/libs/installer/commandlineparser.cpp +++ b/src/libs/installer/commandlineparser.cpp @@ -65,6 +65,8 @@ CommandLineParser::CommandLineParser() + 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 - clear contents of the local metadata cache\n") + .arg(CommandLineOptions::scClearCacheShort, CommandLineOptions::scClearCacheLong) + indent + QString::fromLatin1("%1, %2 - uninstall all packages and remove entire program directory") .arg(CommandLineOptions::scPurgeShort, CommandLineOptions::scPurgeLong); @@ -171,6 +173,10 @@ CommandLineParser::CommandLineParser() "search command. The keys can be any of the possible package information elements, like " "\"DisplayName\" and \"Description\"."), QLatin1String("element=regex,...")), CommandLineOnly); + addOption(QCommandLineOption(QStringList() + << CommandLineOptions::scLocalCachePathShort << CommandLineOptions::scLocalCachePathLong, + QLatin1String("Sets the path used for local metadata cache. The path must be writable by the current user."), + QLatin1String("path"))); // Message query options addOptionWithContext(QCommandLineOption(QStringList() << CommandLineOptions::scAcceptMessageQueryShort diff --git a/src/libs/installer/constants.h b/src/libs/installer/constants.h index 38223eaf3..485982672 100644 --- a/src/libs/installer/constants.h +++ b/src/libs/installer/constants.h @@ -150,6 +150,8 @@ static const QLatin1String scSearchShort("se"); static const QLatin1String scSearchLong("search"); static const QLatin1String scCreateOfflineShort("co"); static const QLatin1String scCreateOfflineLong("create-offline"); +static const QLatin1String scClearCacheShort("cc"); +static const QLatin1String scClearCacheLong("clear-cache"); static const QLatin1String scPurgeShort("pr"); static const QLatin1String scPurgeLong("purge"); @@ -211,6 +213,8 @@ static const QLatin1String scNoDefaultInstallationShort("nd"); static const QLatin1String scNoDefaultInstallationLong("no-default-installations"); static const QLatin1String scFilterPackagesShort("fp"); static const QLatin1String scFilterPackagesLong("filter-packages"); +static const QLatin1String scLocalCachePathShort("cp"); +static const QLatin1String scLocalCachePathLong("cache-path"); // Developer options static const QLatin1String scScriptShort("s"); @@ -247,7 +251,9 @@ static const QStringList scCommandLineInterfaceOptions = { scCreateOfflineShort, scCreateOfflineLong, scPurgeShort, - scPurgeLong + scPurgeLong, + scClearCacheShort, + scClearCacheLong }; } // namespace CommandLineOptions diff --git a/src/libs/installer/genericdatacache.cpp b/src/libs/installer/genericdatacache.cpp index 7f21a5365..1b33976c8 100644 --- a/src/libs/installer/genericdatacache.cpp +++ b/src/libs/installer/genericdatacache.cpp @@ -112,6 +112,11 @@ CacheableItem::~CacheableItem() methods declared in the \l{CacheableItem} interface. The GenericDataCache\<T\> class can still be explicitly specialized to use the derived type as a template argument, to allow retrieving items as the derived type without casting. + + Each cache has a manifest file in its root directory, which lists the version + and wrapped type of the cache, and all its items. The file is updated automatically + when the cache object is destructed, or it can be updated periodically by + calling \l{sync()}. */ /*! @@ -273,6 +278,23 @@ bool GenericDataCache<T>::clear() } /*! + \fn template <typename T> QInstaller::GenericDataCache<T>::sync() + + Synchronizes the contents of the cache to its manifest file. Returns \c true + if the manifest file was updates successfully, \c false otherwise. +*/ +template<typename T> +bool GenericDataCache<T>::sync() +{ + if (m_invalidated) { + setErrorString(QCoreApplication::translate("GenericDataCache", + "Cannot synchronize invalidated cache.")); + return false; + } + return toDisk(); +} + +/*! \fn template <typename T> QInstaller::GenericDataCache<T>::isValid() const Returns \c true if the cache is valid, \c false otherwise. A cache is considered diff --git a/src/libs/installer/genericdatacache.h b/src/libs/installer/genericdatacache.h index 7b909cc7a..5042ed9a4 100644 --- a/src/libs/installer/genericdatacache.h +++ b/src/libs/installer/genericdatacache.h @@ -72,6 +72,7 @@ public: bool initialize(); bool clear(); + bool sync(); bool isValid() const; QString errorString() const; diff --git a/src/libs/installer/metadatajob.cpp b/src/libs/installer/metadatajob.cpp index a15209a31..659648e1a 100644 --- a/src/libs/installer/metadatajob.cpp +++ b/src/libs/installer/metadatajob.cpp @@ -346,12 +346,11 @@ bool MetadataJob::updateCache() // Register items from current run to cache QStringList registeredKeys; + bool success = true; for (auto *meta : qAsConst(m_fetchedMetadata)) { if (!m_metaFromCache.registerItem(meta, true)) { - emitFinishedWithError(QInstaller::CacheError, m_metaFromCache.errorString() - + u' ' - + tr("Clearing the cache directory and restarting the application may solve this.")); - return false; + success = false; + break; } meta->setPersistentRepositoryPath(meta->repository().url()); registeredKeys.append(m_fetchedMetadata.key(meta)); @@ -360,11 +359,24 @@ bool MetadataJob::updateCache() for (auto &key : qAsConst(registeredKeys)) m_fetchedMetadata.remove(key); + // Bail out if there was error while registering items + if (!success) { + emitFinishedWithError(QInstaller::CacheError, m_metaFromCache.errorString() + u' ' + + tr("Clearing the cache directory and restarting the application may solve this.")); + m_metaFromCache.sync(); + return false; + } + // ...and clean up obsolete cached items const QList<Metadata *> obsolete = m_metaFromCache.obsoleteItems(); for (auto *meta : obsolete) m_metaFromCache.removeItem(meta->checksum()); + if (!m_metaFromCache.sync()) { + emitFinishedWithError(QInstaller::CacheError, m_metaFromCache.errorString() + u' ' + + tr("Clearing the cache directory and restarting the application may solve this.")); + return false; + } return true; } diff --git a/src/libs/installer/packagemanagercore.cpp b/src/libs/installer/packagemanagercore.cpp index 5285f6958..6ee7ab8d7 100644 --- a/src/libs/installer/packagemanagercore.cpp +++ b/src/libs/installer/packagemanagercore.cpp @@ -573,11 +573,21 @@ void PackageManagerCore::cancelMetaInfoJob() } /*! + Resets the cache used to store downloaded metadata, if one was previously + initialized. If \a init is set to \c true, the cache is reinitialized for + the path configured in installer's settings. + + Returns \c true on success, \c false otherwise. +*/ +bool PackageManagerCore::resetLocalCache(bool init) +{ + return d->m_metadataJob.resetCache(init); +} + +/*! Clears the contents of the cache used to store downloaded metadata. Returns \c true on success, \c false otherwise. An error string can be retrieved with \a error. - - \sa {installer::clearLocalCache}{installer.clearLocalCache} */ bool PackageManagerCore::clearLocalCache(QString *error) { @@ -3013,10 +3023,10 @@ bool PackageManagerCore::checkAvailableSpace(QString &message) const << humanReadableSize(repositorySize); if (d->m_checkAvailableSpace) { - const VolumeInfo tempVolume = VolumeInfo::fromPath(QDir::tempPath()); + const VolumeInfo cacheVolume = VolumeInfo::fromPath(settings().localCachePath()); const VolumeInfo targetVolume = VolumeInfo::fromPath(value(scTargetDir)); - const quint64 tempVolumeAvailableSize = tempVolume.availableSize(); + const quint64 cacheVolumeAvailableSize = cacheVolume.availableSize(); const quint64 installVolumeAvailableSize = targetVolume.availableSize(); // at the moment there is no better way to check this @@ -3027,20 +3037,20 @@ bool PackageManagerCore::checkAvailableSpace(QString &message) const return true; } - const bool tempOnSameVolume = (targetVolume == tempVolume); - if (tempOnSameVolume) { - qDebug() << "Tmp and install directories are on the same volume. Volume mount point:" + const bool cacheOnSameVolume = (targetVolume == cacheVolume); + if (cacheOnSameVolume) { + qDebug() << "Cache and install directories are on the same volume. Volume mount point:" << targetVolume.mountPath() << "Free space available:" << humanReadableSize(installVolumeAvailableSize); } else { - qDebug() << "Tmp is on a different volume than the installation directory. Tmp volume mount point:" - << tempVolume.mountPath() << "Free space available:" - << humanReadableSize(tempVolumeAvailableSize) << "Install volume mount point:" + qDebug() << "Cache is on a different volume than the installation directory. Cache volume mount point:" + << cacheVolume.mountPath() << "Free space available:" + << humanReadableSize(cacheVolumeAvailableSize) << "Install volume mount point:" << targetVolume.mountPath() << "Free space available:" << humanReadableSize(installVolumeAvailableSize); } - if (tempOnSameVolume && (installVolumeAvailableSize <= (required + tempRequired))) { + if (cacheOnSameVolume && (installVolumeAvailableSize <= (required + tempRequired))) { message = tr("Not enough disk space to store temporary files and the " "installation. %1 are available, while the minimum required is %2.").arg( humanReadableSize(installVolumeAvailableSize), humanReadableSize(required + tempRequired)); @@ -3054,16 +3064,11 @@ bool PackageManagerCore::checkAvailableSpace(QString &message) const return false; } - if (tempVolumeAvailableSize < tempRequired) { -#ifdef Q_OS_WIN - static const QLatin1String scTmpVariable("\"TEMP\" or \"TMP\""); -#elif defined(Q_OS_LINUX) || defined(Q_OS_MACOS) - static const QLatin1String scTmpVariable("\"TMPDIR\""); -#endif + if (cacheVolumeAvailableSize < tempRequired) { message = tr("Not enough disk space to store temporary files! %1 are available, " "while the minimum required is %2. You may select another location for the " - "temporary files by modifying the %3 environment variable and restarting the application.") - .arg(humanReadableSize(tempVolumeAvailableSize), humanReadableSize(tempRequired), scTmpVariable); + "temporary files by modifying the local cache path from the installer settings.") + .arg(humanReadableSize(cacheVolumeAvailableSize), humanReadableSize(tempRequired)); return false; } diff --git a/src/libs/installer/packagemanagercore.h b/src/libs/installer/packagemanagercore.h index db1c0765f..2c307971a 100644 --- a/src/libs/installer/packagemanagercore.h +++ b/src/libs/installer/packagemanagercore.h @@ -345,6 +345,9 @@ public: void createLocalDependencyHash(const QString &component, const QString &dependencies) const; void createAutoDependencyHash(const QString &component, const QString &oldDependencies, const QString &newDependencies) const; + bool resetLocalCache(bool init = false); + bool clearLocalCache(QString *error = nullptr); + public Q_SLOTS: bool runInstaller(); bool runUninstaller(); @@ -355,7 +358,6 @@ public Q_SLOTS: void languageChanged(); void setCompleteUninstallation(bool complete); void cancelMetaInfoJob(); - bool clearLocalCache(QString *error = nullptr); void componentsToInstallNeedsRecalculation(); void calculateUserSelectedComponentsToInstall(const QList<QModelIndex> &indexes); void clearComponentsToInstallCalculated(); diff --git a/src/libs/installer/packagemanagercore_p.cpp b/src/libs/installer/packagemanagercore_p.cpp index c61c6bc99..64af77a98 100644 --- a/src/libs/installer/packagemanagercore_p.cpp +++ b/src/libs/installer/packagemanagercore_p.cpp @@ -664,7 +664,6 @@ void PackageManagerCorePrivate::initialize(const QHash<QString, QString> ¶ms m_metadataJob.disconnect(); m_metadataJob.setAutoDelete(false); m_metadataJob.setPackageManagerCore(m_core); - m_metadataJob.resetCache(true); connect(&m_metadataJob, &Job::infoMessage, this, &PackageManagerCorePrivate::infoMessage); connect(&m_metadataJob, &Job::progress, this, &PackageManagerCorePrivate::infoProgress); diff --git a/src/sdk/commandlineinterface.cpp b/src/sdk/commandlineinterface.cpp index 63deaf4d9..a1eea1f8d 100644 --- a/src/sdk/commandlineinterface.cpp +++ b/src/sdk/commandlineinterface.cpp @@ -248,6 +248,18 @@ int CommandLineInterface::createOfflineInstaller() } } +int CommandLineInterface::clearLocalCache() +{ + if (!initialize()) + return EXIT_FAILURE; + + if (!m_core->clearLocalCache()) + return EXIT_FAILURE; + + qCDebug(QInstaller::lcInstallerInstallLog) << "Cache cleared successfully!"; + return EXIT_SUCCESS; +} + bool CommandLineInterface::checkLicense() { const ProductKeyCheck *const productKeyCheck = ProductKeyCheck::instance(); diff --git a/src/sdk/commandlineinterface.h b/src/sdk/commandlineinterface.h index 29bae74a4..aeaca780f 100644 --- a/src/sdk/commandlineinterface.h +++ b/src/sdk/commandlineinterface.h @@ -49,6 +49,7 @@ public: int uninstallPackages(); int removeInstallation(); int createOfflineInstaller(); + int clearLocalCache(); private: bool initialize(); diff --git a/src/sdk/main.cpp b/src/sdk/main.cpp index 4ab9348c8..f7368883b 100644 --- a/src/sdk/main.cpp +++ b/src/sdk/main.cpp @@ -331,6 +331,9 @@ int main(int argc, char *argv[]) } else if (parser.positionalArguments().contains(CommandLineOptions::scCreateOfflineShort) || parser.positionalArguments().contains(CommandLineOptions::scCreateOfflineLong)) { return CommandLineInterface(argc, argv).createOfflineInstaller(); + } else if (parser.positionalArguments().contains(CommandLineOptions::scClearCacheShort) + || parser.positionalArguments().contains(CommandLineOptions::scClearCacheLong)) { + return CommandLineInterface(argc, argv).clearLocalCache(); } if (QInstaller::LoggingHandler::instance().isVerbose()) { std::cout << VERSION << std::endl << BUILDDATE << std::endl << SHA << std::endl; diff --git a/src/sdk/sdkapp.h b/src/sdk/sdkapp.h index d5d126f26..7d39ee3cf 100644 --- a/src/sdk/sdkapp.h +++ b/src/sdk/sdkapp.h @@ -266,6 +266,16 @@ public: KDUpdater::FileDownloaderFactory::instance().setProxyFactory(m_core->proxyFactory()); } + if (m_parser.isSet(CommandLineOptions::scLocalCachePathLong)) { + const QString cachePath = m_parser.value(CommandLineOptions::scLocalCachePathLong); + if (cachePath.isEmpty()) { + errorMessage = QObject::tr("Empty value for option 'cache-path'."); + return false; + } + m_core->settings().setLocalCachePath(cachePath); + } + m_core->resetLocalCache(true); + if (m_parser.isSet(CommandLineOptions::scShowVirtualComponentsLong)) QInstaller::PackageManagerCore::setVirtualComponentsVisible(true); diff --git a/tests/auto/installer/metadatacache/tst_metadatacache.cpp b/tests/auto/installer/metadatacache/tst_metadatacache.cpp index 46e4d1dfe..f3ab1b98e 100644 --- a/tests/auto/installer/metadatacache/tst_metadatacache.cpp +++ b/tests/auto/installer/metadatacache/tst_metadatacache.cpp @@ -86,6 +86,24 @@ private: } } + QStringList itemsFromManifest(const QString &manifestPath) + { + QFile manifestFile(manifestPath); + if (!manifestFile.open(QIODevice::ReadOnly)) + return QStringList(); + + const QByteArray manifestData = manifestFile.readAll(); + const QJsonDocument manifestJsonDoc(QJsonDocument::fromJson(manifestData)); + const QJsonObject docJsonObject = manifestJsonDoc.object(); + const QJsonArray itemsJsonArray = docJsonObject.value(QLatin1String("items")).toArray(); + + QStringList items; + for (const auto &itemJsonValue : itemsJsonArray) + items << itemJsonValue.toString(); + + return items; + } + QByteArray checksumFromUpdateFile(const QString &directory) { QFile updateFile(directory + QDir::separator() + QLatin1String("Updates.xml")); @@ -130,6 +148,9 @@ private slots: metadata = cache.itemByChecksum(m_newMetadataItemChecksum); QVERIFY(metadata); QVERIFY(metadata->isValid()); + QVERIFY(!QFileInfo::exists(m_cachePath + "/manifest.json")); + QVERIFY(cache.sync()); + QVERIFY(itemsFromManifest(m_cachePath + "/manifest.json").contains(QLatin1String(m_newMetadataItemChecksum))); QVERIFY(cache.clear()); QVERIFY(!QFileInfo::exists(m_cachePath)); @@ -141,11 +162,16 @@ private slots: GenericDataCache<Metadata> cache(m_cachePath, "Metadata", "1.0.0"); Metadata *metadata = new Metadata(":/data/local-temp-repository/"); + QVERIFY(itemsFromManifest(m_cachePath + "/manifest.json").contains(QLatin1String(m_oldMetadataItemChecksum))); QVERIFY(cache.registerItem(metadata)); metadata = cache.itemByChecksum(m_newMetadataItemChecksum); QVERIFY(metadata); QVERIFY(metadata->isValid()); + QVERIFY(cache.sync()); + const QStringList manifestItems = itemsFromManifest(m_cachePath + "/manifest.json"); + QVERIFY(manifestItems.contains(QLatin1String(m_oldMetadataItemChecksum))); + QVERIFY(manifestItems.contains(QLatin1String(m_newMetadataItemChecksum))); QVERIFY(cache.clear()); QVERIFY(!QFileInfo::exists(m_cachePath)); |