diff options
author | Dominik Holland <[email protected]> | 2025-07-07 13:52:39 +0200 |
---|---|---|
committer | Robert Griebl <[email protected]> | 2025-07-11 19:48:37 +0200 |
commit | 4b4b79fe02da64c65279ee81f7225b4f509ff4f7 (patch) | |
tree | bb5867e6807401e8e134abeee6580c463246ee2b | |
parent | 5dd4a58fc05e41a219f840957838092f0fc6005b (diff) |
Change-Id: Ie31346041346cae368c9ce29977ed321e64d7cdc
Reviewed-by: Robert Griebl <[email protected]>
-rw-r--r-- | src/application-lib/packagedatabase.cpp | 14 | ||||
-rw-r--r-- | src/manager-lib/installationtask.cpp | 13 | ||||
-rw-r--r-- | src/manager-lib/packagemanager.cpp | 20 | ||||
-rw-r--r-- | tests/auto/main/tst_main.cpp | 15 | ||||
-rw-r--r-- | tests/auto/packagemanager/tst_packagemanager.cpp | 7 | ||||
-rw-r--r-- | tests/auto/packager-tool/tst_packager-tool.cpp | 7 |
6 files changed, 65 insertions, 11 deletions
diff --git a/src/application-lib/packagedatabase.cpp b/src/application-lib/packagedatabase.cpp index 1dbb7623..6a91d92b 100644 --- a/src/application-lib/packagedatabase.cpp +++ b/src/application-lib/packagedatabase.cpp @@ -6,6 +6,7 @@ #include <QDir> #include <QFile> #include <QDataStream> +#include <QStandardPaths> #include "packagedatabase.h" #include "packageinfo.h" @@ -124,8 +125,12 @@ QStringList PackageDatabase::findManifestsInDir(const QDir &manifestDir, bool sc if (!pkgDir.exists(u"info.yaml"_s)) throw Exception("couldn't find an info.yaml manifest"); - if (!scanningBuiltInApps && !pkgDir.exists(u".installation-report.yaml"_s)) - throw Exception("found a non-built-in package without an installation report"); + if (!scanningBuiltInApps) { + QDir dataDir = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); + QString instReport = dataDir.absoluteFilePath(u"installation-reports/"_s + pkgDirName + u".yaml"_s); + if (!QFile::exists(instReport)) + throw Exception("found a non-built-in package without an installation report"); + } QString manifestPath = pkgDir.absoluteFilePath(u"info.yaml"_s); files << manifestPath; @@ -271,7 +276,10 @@ void PackageDatabase::parseInstalled() .arg(pkg->id(), pkgDir.path()); } - QFile f(pkgDir.absoluteFilePath(u".installation-report.yaml"_s)); + QDir dataDir = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); + QString instReport = dataDir.absoluteFilePath(u"installation-reports/"_s + pkg->id() + u".yaml"_s); + + QFile f(instReport); if (!f.open(QFile::ReadOnly)) throw Exception(f, "failed to open the installation report"); diff --git a/src/manager-lib/installationtask.cpp b/src/manager-lib/installationtask.cpp index 0e4c3c69..9a309127 100644 --- a/src/manager-lib/installationtask.cpp +++ b/src/manager-lib/installationtask.cpp @@ -7,6 +7,7 @@ #include <QTemporaryDir> #include <QMessageAuthenticationCode> #include <QPointer> +#include <QStandardPaths> #include "logging.h" #include "packagemanager_p.h" @@ -145,7 +146,7 @@ void InstallationTask::execute() TemporaryDir extractionDir(m_installationPath + u"/.tmp-XXXXXX"_s); if (!extractionDir.isValid()) - throw Exception("could not create a temporary extraction directory"); + throw Exception("could not create a temporary extraction directory at %1").arg(m_installationPath); // protect m_canceled and changes to m_extractor QMutexLocker locker(&m_mutex); @@ -410,7 +411,9 @@ void InstallationTask::finishInstallation() noexcept(false) // create the installation report InstallationReport report = m_extractor->installationReport(); - QFile reportFile(m_extractionDir.absoluteFilePath(u".installation-report.yaml"_s)); + QDir dataDir = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); + QString instReport = dataDir.absoluteFilePath(u"installation-reports/"_s + m_packageId + u".yaml"_s); + QFile reportFile(instReport + u'+'); if (!reportFile.open(QFile::WriteOnly) || !report.serialize(&reportFile)) throw Exception(reportFile, "could not write the installation report"); reportFile.close(); @@ -426,6 +429,10 @@ void InstallationTask::finishInstallation() noexcept(false) // final rename + ScopedRenamer renameReport; + if (!renameReport.rename(instReport, ScopedRenamer::NamePlusToName)) + throw Exception(Error::IO, "could not rename installation-report %1+ to %1 (including a backup to %1-)").arg(m_applicationDir); + // POSIX cannot atomically rename directories, if the destination directory exists // and is non-empty. We need to do a double-rename in this case, which might fail! @@ -439,11 +446,13 @@ void InstallationTask::finishInstallation() noexcept(false) throw Exception(Error::IO, "could not rename application directory %1+ to %1").arg(m_applicationDir); } + // from this point onwards, we are not allowed to throw anymore, since the installation is "done" setState(CleaningUp); renameApplication.take(); + renameReport.take(); documentDirCreator.take(); m_installationDirCreator.take(); diff --git a/src/manager-lib/packagemanager.cpp b/src/manager-lib/packagemanager.cpp index 52a6a362..e8d1bfc5 100644 --- a/src/manager-lib/packagemanager.cpp +++ b/src/manager-lib/packagemanager.cpp @@ -8,6 +8,7 @@ #include <QVersionNumber> #include <QCoreApplication> #include <QScopedValueRollback> +#include <QStandardPaths> #include "packagemanager.h" #include "packagedatabase.h" #include "packagemanager_p.h" @@ -309,6 +310,12 @@ PackageManager *PackageManager::instance() void PackageManager::enableInstaller() { d->enableInstaller = QT_CONFIG(am_installer); + + if (d->enableInstaller) { + QDir dataDir = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); + if (!dataDir.mkpath(u"installation-reports"_s)) + throw Exception("could not create directory for installation-reports: \'%1\'").arg(dataDir.absoluteFilePath(u"installation-reports"_s)); + } } void PackageManager::registerPackages() @@ -859,6 +866,9 @@ void PackageManager::cleanupBrokenInstallations() noexcept(false) validPaths.insert(d->documentPath, QString()); if (!d->installationPath.isEmpty()) validPaths.insert(d->installationPath, QString()); + QString reportPath = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + + u"/installation-reports"_s; + validPaths.insert(reportPath, QString()); auto packages = d->packages; packages.detach(); // we need to detach here, as the loop below might modify the list @@ -870,9 +880,10 @@ void PackageManager::cleanupBrokenInstallations() noexcept(false) QString pkgDir = d->installationPath + QDir::separator() + pkg->id(); QStringList checkDirs; QStringList checkFiles; + QString instReportName = pkg->id() + u".yaml"_s; checkFiles << pkgDir + u"/info.yaml"_s; - checkFiles << pkgDir + u"/.installation-report.yaml"_s; + checkFiles << reportPath + u'/' + instReportName; checkDirs << pkgDir; for (const QString &checkFile : std::as_const(checkFiles)) { @@ -896,6 +907,7 @@ void PackageManager::cleanupBrokenInstallations() noexcept(false) validPaths.insert(d->installationPath, pkg->id() + QDir::separator()); if (!d->documentPath.isEmpty()) validPaths.insert(d->documentPath, pkg->id() + QDir::separator()); + validPaths.insert(reportPath, instReportName); } else { if (startingPackageRemoval(pkg->id())) { if (finishedPackageInstall(pkg->id())) @@ -1429,7 +1441,11 @@ bool PackageManager::finishedPackageInstall(const QString &id) // attach the installation report (unless we're just downgrading a built-in) if (!isDowngrade) { - QFile irfile(newPackageInfo->baseDir().absoluteFilePath(u".installation-report.yaml"_s)); + // the rename from '+' has already happened at this point + QDir dataDir = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); + QString instReport = dataDir.absoluteFilePath(u"installation-reports/"_s + newPackageInfo->id() + u".yaml"_s); + + QFile irfile(instReport); auto ir = std::make_unique<InstallationReport>(package->id()); try { if (Q_UNLIKELY(!irfile.open(QFile::ReadOnly))) diff --git a/tests/auto/main/tst_main.cpp b/tests/auto/main/tst_main.cpp index 49b67e77..0a1812f1 100644 --- a/tests/auto/main/tst_main.cpp +++ b/tests/auto/main/tst_main.cpp @@ -50,6 +50,7 @@ private: void initMain(const QString &mainQml = { }); void destroyMain(); void copyRecursively(const QString &sourceDir, const QString &destDir); + void fixupInstallationReport(const QString &baseDir, const QString &appDir); int argc = 0; char **argv = nullptr; Main *main = nullptr; @@ -96,6 +97,19 @@ void tst_Main::copyRecursively(const QString &sourcePath, const QString &destPat QFile::copy(sourceDir.filePath(fileName), destDir.filePath(fileName)); } +void tst_Main::fixupInstallationReport(const QString &baseDir, const QString &appDir) +{ + QString src = baseDir + u'/' + appDir + u"/.installation-report.yaml"_s; + if (QFile::exists(src)) { + QString dataDir = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); + QString dst = dataDir + u"/installation-reports/"_s + appDir.section(u'/', -1, 1) + u".yaml"_s; + + if (QFile::exists(dst)) + QFile::remove(dst); + QFile::rename(src, dst); + } +} + void tst_Main::cleanUpInstallationDir() { QDir tempDir(m_tempDirPath); @@ -271,6 +285,7 @@ void tst_Main::installAndRemoveUpdateForBuiltIn() void tst_Main::updateForBuiltInAlreadyInstalled() { copyRecursively(QFINDTESTDATA("dir-with-update-already-installed"), m_tempDirPath); + fixupInstallationReport(m_tempDirPath, u"apps/test-pkg"_s); initMain(); diff --git a/tests/auto/packagemanager/tst_packagemanager.cpp b/tests/auto/packagemanager/tst_packagemanager.cpp index b1167928..426ad4c5 100644 --- a/tests/auto/packagemanager/tst_packagemanager.cpp +++ b/tests/auto/packagemanager/tst_packagemanager.cpp @@ -433,6 +433,9 @@ void tst_PackageManager::packageInstallation() : (devSigned ? AllowInstallations::RequireDevSigned : AllowInstallations::AllowUnsigned)); + QDir dataDir = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation); + QString instReport = dataDir.absoluteFilePath(u"installation-reports/test-pkg.yaml"_s); + int lastPass = (updatePackageName.isEmpty() ? 1 : 2); // pass 1 is the installation / pass 2 is the update (if needed) for (int pass = 1; pass <= lastPass; ++pass) { @@ -471,7 +474,7 @@ void tst_PackageManager::packageInstallation() //QDirIterator it(m_workDir.path(), QDirIterator::Subdirectories); //while (it.hasNext()) { qDebug() << it.next(); } - QVERIFY(QFile::exists(installationDir + u"/test-pkg/.installation-report.yaml"_s)); + QVERIFY(QFile::exists(instReport)); QVERIFY(QDir(documentDir + u"/test-pkg"_s).exists()); QString fileCheckPath = installationDir + u"/test-pkg"_s; @@ -556,7 +559,7 @@ void tst_PackageManager::simulateErrorConditions_data() #ifdef Q_OS_LINUX QTest::newRow("applications-dir-read-only") \ - << false << "~could not create installation directory .*" \ + << false << "~could not create a temporary extraction directory .*" \ << FunctionMap { { "before-start", [this]() { return chmod(pathTo(Internal0).toLocal8Bit(), 0000) == 0; } }, { "after-failed", [this]() { return chmod(pathTo(Internal0).toLocal8Bit(), 0777) == 0; } } }; diff --git a/tests/auto/packager-tool/tst_packager-tool.cpp b/tests/auto/packager-tool/tst_packager-tool.cpp index 6cb7d4a9..5d6f7470 100644 --- a/tests/auto/packager-tool/tst_packager-tool.cpp +++ b/tests/auto/packager-tool/tst_packager-tool.cpp @@ -17,6 +17,7 @@ #include "qmlinprocruntime.h" #include "runtimefactory.h" #include "utilities.h" +#include "sudo.h" #include "../error-checking.h" @@ -32,7 +33,7 @@ class tst_PackagerTool : public QObject private Q_SLOTS: void initTestCase(); - void cleanup(); + void cleanupTestCase(); void test(); void brokenMetadata_data(); @@ -68,6 +69,8 @@ void tst_PackagerTool::initTestCase() if (!QDir(QString::fromLatin1(AM_TESTDATA_DIR "/packages")).exists()) QSKIP("No test packages available in the data/ directory"); + Sudo::fallbackServer(); + spyTimeout *= timeoutFactor(); QVERIFY(m_workDir.isValid()); @@ -112,7 +115,7 @@ void tst_PackagerTool::initTestCase() RuntimeFactory::instance()->registerRuntime(new QmlInProcRuntimeManager(u"qml"_s)); } -void tst_PackagerTool::cleanup() +void tst_PackagerTool::cleanupTestCase() { recursiveOperation(pathTo("internal-0"), safeRemove); recursiveOperation(pathTo("documents-0"), safeRemove); |