summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDominik Holland <[email protected]>2025-07-07 13:52:39 +0200
committerRobert Griebl <[email protected]>2025-07-11 19:48:37 +0200
commit4b4b79fe02da64c65279ee81f7225b4f509ff4f7 (patch)
treebb5867e6807401e8e134abeee6580c463246ee2b
parent5dd4a58fc05e41a219f840957838092f0fc6005b (diff)
Write the installation-report into its own folderHEADdev
Change-Id: Ie31346041346cae368c9ce29977ed321e64d7cdc Reviewed-by: Robert Griebl <[email protected]>
-rw-r--r--src/application-lib/packagedatabase.cpp14
-rw-r--r--src/manager-lib/installationtask.cpp13
-rw-r--r--src/manager-lib/packagemanager.cpp20
-rw-r--r--tests/auto/main/tst_main.cpp15
-rw-r--r--tests/auto/packagemanager/tst_packagemanager.cpp7
-rw-r--r--tests/auto/packager-tool/tst_packager-tool.cpp7
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);