summaryrefslogtreecommitdiff
path: root/src/application-lib/packagedatabase.cpp
diff options
context:
space:
mode:
authorRobert Griebl <robert.griebl@pelagicore.com>2019-04-03 00:48:22 +0200
committerRobert Griebl <robert.griebl@pelagicore.com>2019-08-01 11:23:31 +0200
commitb4aee167d3bc6b9f64229317fbc428b3f3b83c0d (patch)
tree6b526d57203f34f4b85a82e2e958ace227c83960 /src/application-lib/packagedatabase.cpp
parent3bc3dc4c8e912beb18aec7ab84af40c0129d84c0 (diff)
downloadqtapplicationmanager-b4aee167d3bc6b9f64229317fbc428b3f3b83c0d.tar.gz
Add new package abstraction, which allows multiple executables per package
This is part 1 which is missing doc updates and missing the update-builtin- applications functionality. Both will be added in a follow-up commit. Change-Id: I2b493cfb7585143962067674690b02cc132ef78b Reviewed-by: Dominik Holland <dominik.holland@pelagicore.com>
Diffstat (limited to 'src/application-lib/packagedatabase.cpp')
-rw-r--r--src/application-lib/packagedatabase.cpp215
1 files changed, 215 insertions, 0 deletions
diff --git a/src/application-lib/packagedatabase.cpp b/src/application-lib/packagedatabase.cpp
new file mode 100644
index 00000000..6ca32e1c
--- /dev/null
+++ b/src/application-lib/packagedatabase.cpp
@@ -0,0 +1,215 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 Luxoft Sweden AB
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Luxoft Application Manager.
+**
+** $QT_BEGIN_LICENSE:LGPL-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite 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 Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** 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-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+** SPDX-License-Identifier: LGPL-3.0
+**
+****************************************************************************/
+
+#include <QDir>
+#include <QFile>
+#include <QScopedPointer>
+
+#include "packagedatabase.h"
+#include "packageinfo.h"
+#include "yamlpackagescanner.h"
+#include "applicationinfo.h"
+#include "installationreport.h"
+#include "exception.h"
+#include "logging.h"
+
+QT_BEGIN_NAMESPACE_AM
+
+PackageDatabase::PackageDatabase(const QStringList &builtInAppsDirs,
+ const QString &installedAppsDir)
+ : m_builtInAppsDirs(builtInAppsDirs)
+ , m_installedAppsDir(installedAppsDir)
+{ }
+
+PackageDatabase::PackageDatabase(const QString &singlePackagePath)
+ : m_singlePackagePath(singlePackagePath)
+{
+ Q_ASSERT(!singlePackagePath.isEmpty());
+}
+
+void PackageDatabase::enableLoadFromCache()
+{
+ if (m_parsed)
+ qCWarning(LogSystem) << "PackageDatabase cannot change the caching mode after the initial load";
+ m_loadFromCache = true;
+}
+
+void PackageDatabase::enableSaveToCache()
+{
+ if (m_parsed)
+ qCWarning(LogSystem) << "PackageDatabase cannot change the caching mode after the initial load";
+ m_saveToCache = true;
+}
+
+bool PackageDatabase::loadFromCache()
+{
+ return false;
+ //TODO: read cache file
+}
+
+void PackageDatabase::saveToCache()
+{
+ //TODO: write cache file
+}
+
+bool PackageDatabase::canBeRevertedToBuiltIn(PackageInfo *pi)
+{
+ if (!pi || pi->isBuiltIn() || !m_installedPackages.contains(pi))
+ return false;
+ for (auto it = m_builtInPackages.cbegin(); it != m_builtInPackages.cend(); ++it) {
+ if (it.key()->id() == pi->id())
+ return true;
+ }
+ return false;
+}
+
+
+QMap<PackageInfo *, QString> PackageDatabase::loadManifestsFromDir(YamlPackageScanner *yps, const QString &manifestDir, bool scanningBuiltInApps)
+{
+ QMap<PackageInfo *, QString> result;
+
+ auto flags = scanningBuiltInApps ? QDir::Dirs | QDir::NoDotAndDotDot
+ : QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks;
+ const QDir baseDir(manifestDir);
+ const QStringList pkgDirNames = baseDir.entryList(flags);
+
+ for (const QString &pkgDirName : pkgDirNames) {
+ try {
+ // ignore left-overs from the installer
+ if (pkgDirName.endsWith('+') || pkgDirName.endsWith('-'))
+ continue;
+
+ // ignore filesystem problems
+ QDir pkgDir = baseDir.absoluteFilePath(pkgDirName);
+ if (!pkgDir.exists())
+ continue;
+
+ // ignore directory names with weird/forbidden characters
+ QString pkgIdError;
+ if (!PackageInfo::isValidApplicationId(pkgDirName, &pkgIdError))
+ throw Exception("directory name is not a valid package-id: %1").arg(pkgIdError);
+
+ if (!pkgDir.exists(qSL("info.yaml")))
+ throw Exception("couldn't find an info.yaml manifest");
+ if (!scanningBuiltInApps && !pkgDir.exists(qSL(".installation-report.yaml")))
+ throw Exception("found a non-built-in package without an installation report");
+
+ QString manifestPath = pkgDir.absoluteFilePath(yps->metaDataFileName());
+ QScopedPointer<PackageInfo> pkg(loadManifest(yps, manifestPath));
+
+ if (pkg->id() != pkgDir.dirName()) {
+ throw Exception("an info.yaml must be in a directory that has"
+ " the same name as the package's id: found '%1'").arg(pkg->id());
+ }
+ if (scanningBuiltInApps) {
+ pkg->setBuiltIn(true);
+ } else { // 3rd-party apps
+ QFile f(pkgDir.absoluteFilePath(qSL(".installation-report.yaml")));
+ if (!f.open(QFile::ReadOnly))
+ throw Exception(f, "failed to open the installation report");
+
+ QScopedPointer<InstallationReport> report(new InstallationReport(pkg->id()));
+ if (!report->deserialize(&f))
+ throw Exception(f, "failed to deserialize the installation report");
+
+ pkg->setInstallationReport(report.take());
+ }
+ result.insert(pkg.take(), manifestPath);
+ } catch (const Exception &e) {
+ qCDebug(LogSystem) << "Ignoring package" << pkgDirName << ":" << e.what();
+ }
+ }
+ return result;
+}
+
+PackageInfo *PackageDatabase::loadManifest(YamlPackageScanner *yps, const QString &manifestPath)
+{
+ QScopedPointer<PackageInfo> pkg(yps->scan(manifestPath));
+ Q_ASSERT(pkg);
+
+ if (pkg->applications().isEmpty())
+ throw Exception("package contains no applications");
+
+ return pkg.take();
+}
+
+void PackageDatabase::parse()
+{
+ if (m_parsed)
+ throw Exception("PackageDatabase::parse() has been called multiple times");
+ m_parsed = true;
+
+ if (m_loadFromCache) {
+ if (loadFromCache())
+ return;
+ }
+
+ YamlPackageScanner yps;
+
+ if (!m_singlePackagePath.isEmpty()) {
+ try {
+ m_builtInPackages.insert(loadManifest(&yps, m_singlePackagePath), m_singlePackagePath);
+ } catch (const Exception &e) {
+ throw Exception("Failed to load manifest for package: %1").arg(e.errorString());
+ }
+ } else {
+ for (const QString &dir : m_builtInAppsDirs)
+ m_builtInPackages.unite(loadManifestsFromDir(&yps, dir, true));
+
+ if (!m_installedAppsDir.isEmpty())
+ m_installedPackages = loadManifestsFromDir(&yps, m_installedAppsDir, false);
+ }
+
+ if (m_saveToCache)
+ saveToCache();
+}
+
+QVector<PackageInfo *> PackageDatabase::installedPackages() const
+{
+ return m_installedPackages.keys().toVector();
+}
+
+QVector<PackageInfo *> PackageDatabase::builtInPackages() const
+{
+ return m_builtInPackages.keys().toVector();
+}
+
+QT_END_NAMESPACE_AM