diff options
422 files changed, 5645 insertions, 5050 deletions
diff --git a/.qmake.conf b/.qmake.conf index 8257f184..4a22cc51 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -1,6 +1,6 @@ load(qt_build_config) -MODULE_VERSION = 5.13.1 +MODULE_VERSION = 5.14.0 SOURCE_DIR=$$PWD BUILD_DIR=$$shadowed($$PWD) diff --git a/application-manager.pro b/application-manager.pro index 62771a35..7fd99d16 100644 --- a/application-manager.pro +++ b/application-manager.pro @@ -116,6 +116,7 @@ OTHER_FILES += \ LICENSE.*[^~] \ config.tests/libarchive/* \ config.tests/libyaml/* \ + config.tests/touchemulation/* \ util/bash/appman-prompt \ util/bash/README \ diff --git a/benchmarks/appman-bench/run.sh b/benchmarks/appman-bench/run.sh index eb5b894c..2cb1ddd9 100755 --- a/benchmarks/appman-bench/run.sh +++ b/benchmarks/appman-bench/run.sh @@ -5,7 +5,7 @@ ## Copyright (C) 2018 Pelagicore AG ## Contact: https://www.qt.io/licensing/ ## -## This file is part of the Luxoft Application Manager. +## This file is part of the Qt Application Manager. ## ## $QT_BEGIN_LICENSE:BSD-QTAS$ ## Commercial License Usage diff --git a/benchmarks/appman-bench/system-ui/main.qml b/benchmarks/appman-bench/system-ui/main.qml index 762303ac..fa7de877 100644 --- a/benchmarks/appman-bench/system-ui/main.qml +++ b/benchmarks/appman-bench/system-ui/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/benchmarks/appman-bench/templates/appman-qml/main.qml b/benchmarks/appman-bench/templates/appman-qml/main.qml index b15ea8aa..87b4597c 100644 --- a/benchmarks/appman-bench/templates/appman-qml/main.qml +++ b/benchmarks/appman-bench/templates/appman-qml/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/benchmarks/appman-bench/templates/qmlscene/main.qml b/benchmarks/appman-bench/templates/qmlscene/main.qml index f31cc6a2..2d1dcf6e 100644 --- a/benchmarks/appman-bench/templates/qmlscene/main.qml +++ b/benchmarks/appman-bench/templates/qmlscene/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/benchmarks/appman-bench/tests/controls2.qml b/benchmarks/appman-bench/tests/controls2.qml index 169d6163..f34db8a2 100644 --- a/benchmarks/appman-bench/tests/controls2.qml +++ b/benchmarks/appman-bench/tests/controls2.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/benchmarks/appman-bench/tests/rect.qml b/benchmarks/appman-bench/tests/rect.qml index c033e910..f5fbec06 100644 --- a/benchmarks/appman-bench/tests/rect.qml +++ b/benchmarks/appman-bench/tests/rect.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/benchmarks/appman-bench/tests/repeater.qml b/benchmarks/appman-bench/tests/repeater.qml index 2866e50d..fb759ceb 100644 --- a/benchmarks/appman-bench/tests/repeater.qml +++ b/benchmarks/appman-bench/tests/repeater.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/benchmarks/appman-bench/tests/shader.qml b/benchmarks/appman-bench/tests/shader.qml index e69d0a55..3aad12a1 100644 --- a/benchmarks/appman-bench/tests/shader.qml +++ b/benchmarks/appman-bench/tests/shader.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/config.tests/libarchive/main.cpp b/config.tests/libarchive/main.cpp index 53515610..58b21a4d 100644 --- a/config.tests/libarchive/main.cpp +++ b/config.tests/libarchive/main.cpp @@ -5,7 +5,7 @@ ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/config.tests/libyaml/main.cpp b/config.tests/libyaml/main.cpp index 546b2634..f6c5442c 100644 --- a/config.tests/libyaml/main.cpp +++ b/config.tests/libyaml/main.cpp @@ -5,7 +5,7 @@ ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/config.tests/touchemulation/main.cpp b/config.tests/touchemulation/main.cpp index 1b012d8f..92ed9484 100644 --- a/config.tests/touchemulation/main.cpp +++ b/config.tests/touchemulation/main.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/doc/QtApplicationManagerDoc b/doc/QtApplicationManagerDoc index 333bf5a6..ccd77195 100644 --- a/doc/QtApplicationManagerDoc +++ b/doc/QtApplicationManagerDoc @@ -4,7 +4,6 @@ #include <QtAppManCommon/QtAppManCommon> #include <QtAppManCrypto/QtAppManCrypto> #include <QtAppManDBus/QtAppManDBus> -#include <QtAppManInstaller/QtAppManInstaller> #include <QtAppManIntentClient/QtAppManIntentClient> #include <QtAppManIntentServer/QtAppManIntentServer> #include <QtAppManLauncher/QtAppManLauncher> diff --git a/doc/apps.qdoc b/doc/apps.qdoc index f73aab20..49d5f708 100644 --- a/doc/apps.qdoc +++ b/doc/apps.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/doc/configuration.qdoc b/doc/configuration.qdoc index 9ef3d870..98bc8c46 100644 --- a/doc/configuration.qdoc +++ b/doc/configuration.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage @@ -160,18 +160,18 @@ or across multiple config files, the final value is resolved based on these rule \li The base directory for built-in application manifests; you can also specify multiple directories as a list. \row - \li \b --installed-apps-manifest-dir - \br [\c applications/installedAppsManifestDir] + \li \b --installation-dir + \br [\c applications/installationDir] \li string - \li The base directory for installed application manifests. This option must be specified - if you want to install new applications; otherwise only the built-in ones are + \li The base directory for package installations. This option must be specified + if you want to install new package; otherwise only the built-in ones are available. (default: empty/disabled) \row - \li \b --app-image-mount-dir - \br [\c applications/appImageMountDir] + \li \b --document-dir + \br [\c applications/documentDir] \li string - \li The base directory where application images are mounted to. - (defaults: \c /opt/am/image-mounts) + \li The base directory for per-package document storage directories. + (default: empty/disabled) \row \li \b --dbus \li string @@ -353,8 +353,9 @@ or across multiple config files, the final value is resolved based on these rule \row \li [\c installationLocations] \li array<object> - \li The definition of installation locations available on the system; an array of - \l {Installation Locations} objects. + \li The definition of installation locations available on the system. This is deprecated, + since only a single installation location is supported now, defined by \c + --installationDir or \c{applications/installationDir}. \row \li [\c runtimes] \li map<object> @@ -495,52 +496,6 @@ of these available interfaces are as follows: \l {freedesktop.org specification} \endtable -\section1 Installation Locations - -The \c installationLocations YAML field is a list of YAML objects, very similar to -ApplicationInstaller::getInstallationLocation. - -\table - \header - \li Config Key - \li Type - \li Description - \row - \li \c id - \li string - \li The installation location ID that is used as the handle for all other - ApplicationInstaller function calls. The \c id consists of a \c type and \c index - field, concatenated with a single dash. For example, \c removable-0. - - Valid values for \c type are \c internal and \c removable. - - In case there is more than one installation location for the same type of device, this - zero-based index is used for disambiguation. For example, two SD card slots will result - in the IDs \c removable-0 and \c removable-1. Otherwise, the index is always \c 0. - \row - \li \c isDefault - \li bool - \li Only one installation location can be the default location, which must be mounted and - accessible at all times. This location can be used by a UI application to get a - sensible default for the installation location that it needs to pass to - \l{ApplicationInstaller::startPackageInstallation()}{startPackageInstallation()}. - \row - \li \c installationPath - \li string - \li The absolute file system path to the base directory where applications are installed. - \row - \li \c documentPath - \li string - \li The absolute file system path to the base directory where per-user document directories - are created. This entry can either be located on this device, or it can be the same as - the \c documentPath of the master installation location. - \row - \li \c mountPoint - \li string - \li Only required for \c removable installation location: The absolute file system path to - the mount-point of the device, where \c installationPath is located. -\endtable - \section1 Runtime Configuration The runtime configuration sub-objects are specific to the actual runtimes, so the table below has diff --git a/doc/container.qdoc b/doc/container.qdoc index 246fc82c..fd7070e4 100644 --- a/doc/container.qdoc +++ b/doc/container.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/doc/controller.qdoc b/doc/controller.qdoc index 6b6511c9..42af67c9 100644 --- a/doc/controller.qdoc +++ b/doc/controller.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage @@ -85,9 +85,6 @@ The following commands are available: \li Installs the package given on the command-line. If the package file is specified as \c{-}, the tool tries to read the package from \c stdin. The following options are supported: - \c{-l, --location}: Install to a specific installation location - (see \c show-installation-location). - \c{-a, --acknowledge}: Automatically acknowledge the installation, instead of relying on the System UI's logic. \row diff --git a/doc/debugging.qdoc b/doc/debugging.qdoc index c1ecfe05..687e1fa7 100644 --- a/doc/debugging.qdoc +++ b/doc/debugging.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/doc/elements-apps.qdoc b/doc/elements-apps.qdoc index fc62c2d3..31658aea 100644 --- a/doc/elements-apps.qdoc +++ b/doc/elements-apps.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/doc/elements-common.qdoc b/doc/elements-common.qdoc index bcd505c4..d1f445a2 100644 --- a/doc/elements-common.qdoc +++ b/doc/elements-common.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/doc/elements-systemui.qdoc b/doc/elements-systemui.qdoc index df5df122..0db9ac7a 100644 --- a/doc/elements-systemui.qdoc +++ b/doc/elements-systemui.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/doc/index.qdoc b/doc/index.qdoc index 64f5a0d1..47e33165 100644 --- a/doc/index.qdoc +++ b/doc/index.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/doc/installation.qdoc b/doc/installation.qdoc index c7b59c14..dbc02466 100644 --- a/doc/installation.qdoc +++ b/doc/installation.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/doc/installer.qdoc b/doc/installer.qdoc index 74016e6a..54989990 100644 --- a/doc/installer.qdoc +++ b/doc/installer.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/doc/introduction.qdoc b/doc/introduction.qdoc index abf4610e..53eefb33 100644 --- a/doc/introduction.qdoc +++ b/doc/introduction.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/doc/manifest.qdoc b/doc/manifest.qdoc index bd7a465a..17f6e2bc 100644 --- a/doc/manifest.qdoc +++ b/doc/manifest.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/doc/migration-guide-5.12.qdoc b/doc/migration-guide-5.12.qdoc index 52ab19ff..f25b4f03 100644 --- a/doc/migration-guide-5.12.qdoc +++ b/doc/migration-guide-5.12.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/doc/package-format.qdoc b/doc/package-format.qdoc index 68d47ccc..8e49492d 100644 --- a/doc/package-format.qdoc +++ b/doc/package-format.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/doc/packager.qdoc b/doc/packager.qdoc index aba3fdd9..87bef980 100644 --- a/doc/packager.qdoc +++ b/doc/packager.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/doc/qmlmodule.qdoc b/doc/qmlmodule.qdoc index a297eb65..16181370 100644 --- a/doc/qmlmodule.qdoc +++ b/doc/qmlmodule.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/doc/singlevsmultiprocess.qdoc b/doc/singlevsmultiprocess.qdoc index 04748c05..f4000092 100644 --- a/doc/singlevsmultiprocess.qdoc +++ b/doc/singlevsmultiprocess.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/doc/systemui.qdoc b/doc/systemui.qdoc index 23732991..334e940c 100644 --- a/doc/systemui.qdoc +++ b/doc/systemui.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/doc/troubleshooting.qdoc b/doc/troubleshooting.qdoc index 48610b96..fd05bfc0 100644 --- a/doc/troubleshooting.qdoc +++ b/doc/troubleshooting.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/doc/yaml.qdoc b/doc/yaml.qdoc index b87c5eaf..8ee10d4b 100644 --- a/doc/yaml.qdoc +++ b/doc/yaml.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/animated-windows/apps/animated-windows.fish/fish.qml b/examples/applicationmanager/animated-windows/apps/animated-windows.fish/fish.qml index 1c6a56e5..60e64926 100644 --- a/examples/applicationmanager/animated-windows/apps/animated-windows.fish/fish.qml +++ b/examples/applicationmanager/animated-windows/apps/animated-windows.fish/fish.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/animated-windows/apps/animated-windows.rabbit/rabbit.qml b/examples/applicationmanager/animated-windows/apps/animated-windows.rabbit/rabbit.qml index 4b5892b0..42a2cfab 100644 --- a/examples/applicationmanager/animated-windows/apps/animated-windows.rabbit/rabbit.qml +++ b/examples/applicationmanager/animated-windows/apps/animated-windows.rabbit/rabbit.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/animated-windows/doc/src/animated-windows.qdoc b/examples/applicationmanager/animated-windows/doc/src/animated-windows.qdoc index d412054c..efdb3157 100644 --- a/examples/applicationmanager/animated-windows/doc/src/animated-windows.qdoc +++ b/examples/applicationmanager/animated-windows/doc/src/animated-windows.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/animated-windows/system-ui/main.qml b/examples/applicationmanager/animated-windows/system-ui/main.qml index cab98951..fd64b494 100644 --- a/examples/applicationmanager/animated-windows/system-ui/main.qml +++ b/examples/applicationmanager/animated-windows/system-ui/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/custom-appman/custom-appman.cpp b/examples/applicationmanager/custom-appman/custom-appman.cpp index 85f5d87a..45591130 100644 --- a/examples/applicationmanager/custom-appman/custom-appman.cpp +++ b/examples/applicationmanager/custom-appman/custom-appman.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage @@ -55,8 +55,8 @@ #include <QtAppManCommon/logging.h> #include <QtAppManMain/main.h> #include <QtAppManMain/defaultconfiguration.h> -#include <QtAppManPackage/package.h> -#include <QtAppManInstaller/sudo.h> +#include <QtAppManPackage/packageutilities.h> +#include <QtAppManManager/sudo.h> QT_USE_NAMESPACE_AM @@ -67,7 +67,7 @@ Q_DECL_EXPORT int main(int argc, char *argv[]) QCoreApplication::setApplicationVersion("0.1"); Logging::initialize(argc, argv); - Package::ensureCorrectLocale(); + PackageUtilities::ensureCorrectLocale(); Sudo::forkServer(Sudo::DropPrivilegesPermanently); try { diff --git a/examples/applicationmanager/custom-appman/doc/src/custom-appman.qdoc b/examples/applicationmanager/custom-appman/doc/src/custom-appman.qdoc index 2f819c32..7aed03bb 100644 --- a/examples/applicationmanager/custom-appman/doc/src/custom-appman.qdoc +++ b/examples/applicationmanager/custom-appman/doc/src/custom-appman.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/frame-timer/apps/frame-timer.fish/fish.qml b/examples/applicationmanager/frame-timer/apps/frame-timer.fish/fish.qml index 823ce505..9d3c6107 100644 --- a/examples/applicationmanager/frame-timer/apps/frame-timer.fish/fish.qml +++ b/examples/applicationmanager/frame-timer/apps/frame-timer.fish/fish.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/frame-timer/apps/frame-timer.rabbit/rabbit.qml b/examples/applicationmanager/frame-timer/apps/frame-timer.rabbit/rabbit.qml index 4b5892b0..42a2cfab 100644 --- a/examples/applicationmanager/frame-timer/apps/frame-timer.rabbit/rabbit.qml +++ b/examples/applicationmanager/frame-timer/apps/frame-timer.rabbit/rabbit.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/frame-timer/doc/src/frame-timer-example.qdoc b/examples/applicationmanager/frame-timer/doc/src/frame-timer-example.qdoc index 2397f508..e0939058 100644 --- a/examples/applicationmanager/frame-timer/doc/src/frame-timer-example.qdoc +++ b/examples/applicationmanager/frame-timer/doc/src/frame-timer-example.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/frame-timer/system-ui/main.qml b/examples/applicationmanager/frame-timer/system-ui/main.qml index 1055843d..b95cec1d 100644 --- a/examples/applicationmanager/frame-timer/system-ui/main.qml +++ b/examples/applicationmanager/frame-timer/system-ui/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/hello-world/apps/hello-world.blue/main.qml b/examples/applicationmanager/hello-world/apps/hello-world.blue/main.qml index 8dd0a2a4..a2ba7929 100644 --- a/examples/applicationmanager/hello-world/apps/hello-world.blue/main.qml +++ b/examples/applicationmanager/hello-world/apps/hello-world.blue/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/hello-world/apps/hello-world.green/main.qml b/examples/applicationmanager/hello-world/apps/hello-world.green/main.qml index e2bbfd41..6fda63f7 100644 --- a/examples/applicationmanager/hello-world/apps/hello-world.green/main.qml +++ b/examples/applicationmanager/hello-world/apps/hello-world.green/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/hello-world/apps/hello-world.red/main.qml b/examples/applicationmanager/hello-world/apps/hello-world.red/main.qml index 944ee7db..fd04b159 100644 --- a/examples/applicationmanager/hello-world/apps/hello-world.red/main.qml +++ b/examples/applicationmanager/hello-world/apps/hello-world.red/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/hello-world/doc/src/hello-world.qdoc b/examples/applicationmanager/hello-world/doc/src/hello-world.qdoc index e3978de5..71d94a65 100644 --- a/examples/applicationmanager/hello-world/doc/src/hello-world.qdoc +++ b/examples/applicationmanager/hello-world/doc/src/hello-world.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/hello-world/system-ui.qml b/examples/applicationmanager/hello-world/system-ui.qml index 2d5aaa11..95f3edb8 100644 --- a/examples/applicationmanager/hello-world/system-ui.qml +++ b/examples/applicationmanager/hello-world/system-ui.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/intents/apps/intents.blue/main.qml b/examples/applicationmanager/intents/apps/intents.blue/main.qml index fe549f88..89321457 100644 --- a/examples/applicationmanager/intents/apps/intents.blue/main.qml +++ b/examples/applicationmanager/intents/apps/intents.blue/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/intents/apps/intents.green/main.qml b/examples/applicationmanager/intents/apps/intents.green/main.qml index fe549f88..89321457 100644 --- a/examples/applicationmanager/intents/apps/intents.green/main.qml +++ b/examples/applicationmanager/intents/apps/intents.green/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/intents/apps/intents.red/main.qml b/examples/applicationmanager/intents/apps/intents.red/main.qml index 3d6b070d..f9c3998a 100644 --- a/examples/applicationmanager/intents/apps/intents.red/main.qml +++ b/examples/applicationmanager/intents/apps/intents.red/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/intents/doc/src/intents.qdoc b/examples/applicationmanager/intents/doc/src/intents.qdoc index 07c062b3..f1da854a 100644 --- a/examples/applicationmanager/intents/doc/src/intents.qdoc +++ b/examples/applicationmanager/intents/doc/src/intents.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/intents/shared/IntentsApplicationWindow.qml b/examples/applicationmanager/intents/shared/IntentsApplicationWindow.qml index 4f56b576..ee58b1c2 100644 --- a/examples/applicationmanager/intents/shared/IntentsApplicationWindow.qml +++ b/examples/applicationmanager/intents/shared/IntentsApplicationWindow.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/intents/shared/IntentsUIPage.qml b/examples/applicationmanager/intents/shared/IntentsUIPage.qml index ccf5534f..0420a089 100644 --- a/examples/applicationmanager/intents/shared/IntentsUIPage.qml +++ b/examples/applicationmanager/intents/shared/IntentsUIPage.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/intents/system-ui.qml b/examples/applicationmanager/intents/system-ui.qml index 07efbcf2..328eb63b 100644 --- a/examples/applicationmanager/intents/system-ui.qml +++ b/examples/applicationmanager/intents/system-ui.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/app1.qml b/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/app1.qml index ae005f47..62aa661a 100644 --- a/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/app1.qml +++ b/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/app1.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage @@ -56,12 +56,12 @@ import QtApplicationManager.Application 2.0 ApplicationManagerWindow { id: root - color: "peachpuff" + color: "lightgrey" Rectangle { anchors.centerIn: parent width: 180; height: 180; radius: width/4 - color: "peru" + color: "lightsteelblue" Image { source: ApplicationInterface.icon @@ -90,7 +90,7 @@ ApplicationManagerWindow { ApplicationManagerWindow { id: popUp visible: false - color: "lightcoral" + color: "orangered" Text { anchors.centerIn: parent diff --git a/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/icon.png b/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/icon.png Binary files differindex adb840ce..35a54600 100644 --- a/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/icon.png +++ b/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/icon.png diff --git a/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/info.yaml b/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/info.yaml index 953e852f..6b2efc9b 100644 --- a/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/info.yaml +++ b/examples/applicationmanager/minidesk/apps/tld.minidesk.app1/info.yaml @@ -1,9 +1,11 @@ formatVersion: 1 -formatType: am-application +formatType: am-package --- -id: 'tld.minidesk.app1' -icon: 'icon.png' -code: 'app1.qml' -runtime: 'qml' +id: 'tld.minidesk.app1' +icon: 'icon.png' name: en: 'App1' +applications: + - id: 'tld.minidesk.app1' + code: 'app1.qml' + runtime: 'qml' diff --git a/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/app2.qml b/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/app2.qml index ae4db3a3..c4bef427 100644 --- a/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/app2.qml +++ b/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/app2.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage @@ -55,7 +55,7 @@ import QtQuick 2.4 import QtApplicationManager.Application 2.0 ApplicationManagerWindow { - color: ApplicationInterface.systemProperties.light ? "peachpuff" : "black" + color: ApplicationInterface.systemProperties.light ? "#B0808080" : "black" Image { anchors.centerIn: parent diff --git a/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/icon.png b/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/icon.png Binary files differindex 3f8caa42..9c1d6cf2 100644 --- a/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/icon.png +++ b/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/icon.png diff --git a/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/info.yaml b/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/info.yaml index 65759aa8..140955eb 100644 --- a/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/info.yaml +++ b/examples/applicationmanager/minidesk/apps/tld.minidesk.app2/info.yaml @@ -1,9 +1,11 @@ formatVersion: 1 -formatType: am-application +formatType: am-package --- -id: 'tld.minidesk.app2' -icon: 'icon.png' -code: 'app2.qml' -runtime: 'qml' +id: 'tld.minidesk.app2' +icon: 'icon.png' name: en: 'App2' +applications: + - id: 'tld.minidesk.app2' + code: 'app2.qml' + runtime: 'qml' diff --git a/examples/applicationmanager/minidesk/doc/images/minidesk.png b/examples/applicationmanager/minidesk/doc/images/minidesk.png Binary files differindex 66a545c9..edbe0783 100644 --- a/examples/applicationmanager/minidesk/doc/images/minidesk.png +++ b/examples/applicationmanager/minidesk/doc/images/minidesk.png diff --git a/examples/applicationmanager/minidesk/doc/src/minidesk.qdoc b/examples/applicationmanager/minidesk/doc/src/minidesk.qdoc index e44e5854..867448e8 100644 --- a/examples/applicationmanager/minidesk/doc/src/minidesk.qdoc +++ b/examples/applicationmanager/minidesk/doc/src/minidesk.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage @@ -81,11 +81,11 @@ The \c appman binary (executable file) is usually located in the Qt installation \dots The \l{QtApplicationManager.SystemUI} module has to be imported to access the application manager -APIs. The System UI window has a fixed size and linen background color. Instead of a \l{Rectangle}, -the root element could also be a \l{Window}. On top of the background, we display a -\c Readme element with information on the -features available. At the bottom left there is a textual indication for whether the -application manager runs in single-process or multi-process mode. +APIs. The System UI window has a fixed size and "whitesmoke" background color. Instead of a +\l{Window}, the root element could also be a regular item, like a \l{Rectangle}. The application +manager would wrap it in a window for you. On top of the background, we display a \c Readme element +with information on the features available. At the bottom left there is a textual indication for +whether the application manager runs in single-process or multi-process mode. \section2 Launcher @@ -114,8 +114,8 @@ WindowManager. The code that populates the window role of this ListModel is show now let's focus on what this Repeater's delegate consists of: \list - \li A fixed size window container \l{Rectangle} in "tan" color. The location depends on the - \c model.index, hence each application window has a different initial location. + \li A mostly transparent background \l{Image}. The location depends on the \c model.index, + hence each application window has a different initial location. \li The name of the application that created that window, prefixed with "Decoration" on top. This name is from the related ApplicationObject, defined in the application's \l{Manifest Definition}{info.yaml} file. @@ -205,7 +205,7 @@ the \l {WindowManager::windowAdded}{onWindowAdded} handler is invoked. Only App1's "pop-up" ApplicationManagerWindow has the user-defined \c type property set. Such a window is placed in the \c popUpContainer WindowItem. All other windows don't have a \c type -property; they are added to the \c topLevelWindowsModel. This model is used in the SystemUI chrome +property; they are added to the \c topLevelWindowsModel. This model is used in the System UI chrome Repeater above. Consequently, the \l {WindowObject}{window} object passed as an argument to \l {WindowManager::windowAdded}{onWindowAdded} is set as the \l{WindowItem::window}{window} property of the WindowItem (within the Repeater's delegate). @@ -215,7 +215,7 @@ will also be displayed since in the configuration file, "\c flags/noSecurity: \c instance in KDE's Calculator: \badcode -$ QT_WAYLAND_DISABLE_WINDOWDECORATION=1 QT_WAYLAND_SHELL_INTEGRATION=xdg-shell-v5 kcalc -platform wayland +$ QT_WAYLAND_DISABLE_WINDOWDECORATION=1 WAYLAND_DISPLAY=qtam-wayland-0 kcalc -platform wayland \endcode \section2 Inter-Process Communication (IPC) Extension diff --git a/examples/applicationmanager/minidesk/system-ui/Readme.qml b/examples/applicationmanager/minidesk/system-ui/Readme.qml index 6565df71..65643913 100644 --- a/examples/applicationmanager/minidesk/system-ui/Readme.qml +++ b/examples/applicationmanager/minidesk/system-ui/Readme.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/minidesk/system-ui/chrome-bg.png b/examples/applicationmanager/minidesk/system-ui/chrome-bg.png Binary files differnew file mode 100644 index 00000000..0a6618c4 --- /dev/null +++ b/examples/applicationmanager/minidesk/system-ui/chrome-bg.png diff --git a/examples/applicationmanager/minidesk/system-ui/main.qml b/examples/applicationmanager/minidesk/system-ui/main.qml index 43265237..577599a2 100644 --- a/examples/applicationmanager/minidesk/system-ui/main.qml +++ b/examples/applicationmanager/minidesk/system-ui/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage @@ -51,13 +51,15 @@ ** ****************************************************************************/ -import QtQuick 2.4 +import QtQuick 2.11 +import QtQuick.Window 2.11 import QtApplicationManager.SystemUI 2.0 -Rectangle { +Window { + title: "Minidesk - QtApplicationManager Example" width: 1024 height: 640 - color: "linen" + color: "whitesmoke" Readme {} @@ -87,10 +89,9 @@ Rectangle { Repeater { model: ListModel { id: topLevelWindowsModel } - delegate: Rectangle { - width: 400; height: 320 + delegate: Image { + source: "chrome-bg.png" z: model.index - color: "tan" Text { anchors.horizontalCenter: parent.horizontalCenter diff --git a/examples/applicationmanager/multi-views/apps/tld.multi-views.app/app1.qml b/examples/applicationmanager/multi-views/apps/tld.multi-views.app/app1.qml index e5e3f6e8..dd8c7bbd 100644 --- a/examples/applicationmanager/multi-views/apps/tld.multi-views.app/app1.qml +++ b/examples/applicationmanager/multi-views/apps/tld.multi-views.app/app1.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/multi-views/doc/src/multi-views.qdoc b/examples/applicationmanager/multi-views/doc/src/multi-views.qdoc index 959b3dd7..7e5c6d9e 100644 --- a/examples/applicationmanager/multi-views/doc/src/multi-views.qdoc +++ b/examples/applicationmanager/multi-views/doc/src/multi-views.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/multi-views/multi-views.pro b/examples/applicationmanager/multi-views/multi-views.pro index 2cff5f66..e7e041b9 100644 --- a/examples/applicationmanager/multi-views/multi-views.pro +++ b/examples/applicationmanager/multi-views/multi-views.pro @@ -4,6 +4,8 @@ CONFIG += am-systemui OTHER_FILES += \ am-config.yaml \ system-ui/*.qml \ + doc/src/*.qdoc \ + doc/images/*.png \ apps/tld.multi-views.app/*.yaml \ apps/tld.multi-views.app/*.qml \ apps/tld.multi-views.app/*.png \ diff --git a/examples/applicationmanager/multi-views/system-ui/Readme.qml b/examples/applicationmanager/multi-views/system-ui/Readme.qml index 23a7fb0b..ab201033 100644 --- a/examples/applicationmanager/multi-views/system-ui/Readme.qml +++ b/examples/applicationmanager/multi-views/system-ui/Readme.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/multi-views/system-ui/main.qml b/examples/applicationmanager/multi-views/system-ui/main.qml index 55f48188..b3ee5309 100644 --- a/examples/applicationmanager/multi-views/system-ui/main.qml +++ b/examples/applicationmanager/multi-views/system-ui/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/process-status/apps/process-status.cpu-hog/main.qml b/examples/applicationmanager/process-status/apps/process-status.cpu-hog/main.qml index baed4f24..4aa746bd 100644 --- a/examples/applicationmanager/process-status/apps/process-status.cpu-hog/main.qml +++ b/examples/applicationmanager/process-status/apps/process-status.cpu-hog/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/process-status/apps/process-status.mem-hog/main.qml b/examples/applicationmanager/process-status/apps/process-status.mem-hog/main.qml index 9a77bcd4..b899ea96 100644 --- a/examples/applicationmanager/process-status/apps/process-status.mem-hog/main.qml +++ b/examples/applicationmanager/process-status/apps/process-status.mem-hog/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/process-status/apps/process-status.slim/main.qml b/examples/applicationmanager/process-status/apps/process-status.slim/main.qml index 82de9abe..89a51cd8 100644 --- a/examples/applicationmanager/process-status/apps/process-status.slim/main.qml +++ b/examples/applicationmanager/process-status/apps/process-status.slim/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/process-status/doc/src/process-status-example.qdoc b/examples/applicationmanager/process-status/doc/src/process-status-example.qdoc index 5d012ac2..1bafdbf5 100644 --- a/examples/applicationmanager/process-status/doc/src/process-status-example.qdoc +++ b/examples/applicationmanager/process-status/doc/src/process-status-example.qdoc @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/process-status/system-ui/ApplicationDisplay.qml b/examples/applicationmanager/process-status/system-ui/ApplicationDisplay.qml index 89fccd9e..3dabe63b 100644 --- a/examples/applicationmanager/process-status/system-ui/ApplicationDisplay.qml +++ b/examples/applicationmanager/process-status/system-ui/ApplicationDisplay.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/process-status/system-ui/CpuGraph.qml b/examples/applicationmanager/process-status/system-ui/CpuGraph.qml index 4ba1edd8..8cd59c72 100644 --- a/examples/applicationmanager/process-status/system-ui/CpuGraph.qml +++ b/examples/applicationmanager/process-status/system-ui/CpuGraph.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/process-status/system-ui/MemoryText.qml b/examples/applicationmanager/process-status/system-ui/MemoryText.qml index 6b999da1..14eaf0b1 100644 --- a/examples/applicationmanager/process-status/system-ui/MemoryText.qml +++ b/examples/applicationmanager/process-status/system-ui/MemoryText.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/process-status/system-ui/Stats.qml b/examples/applicationmanager/process-status/system-ui/Stats.qml index 90983804..a62b6888 100644 --- a/examples/applicationmanager/process-status/system-ui/Stats.qml +++ b/examples/applicationmanager/process-status/system-ui/Stats.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/process-status/system-ui/main.qml b/examples/applicationmanager/process-status/system-ui/main.qml index b342939e..57bfb463 100644 --- a/examples/applicationmanager/process-status/system-ui/main.qml +++ b/examples/applicationmanager/process-status/system-ui/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/softwarecontainer-plugin/README.md b/examples/applicationmanager/softwarecontainer-plugin/README.md index 57d7eb3b..d599c854 100644 --- a/examples/applicationmanager/softwarecontainer-plugin/README.md +++ b/examples/applicationmanager/softwarecontainer-plugin/README.md @@ -35,7 +35,8 @@ that the application-manager is using, if you intend on forwarding this bus. This is a bit tricky if the agent is run as root and the application- manager as non-root user, since the default session-bus policy in most distros disallows root to access user session-busses: the workaround is to -add a `<allow user="root"/>` policy in `/etc/dbus-1/session.conf`. +add a `<allow user="root"/>` policy within the `<policy context="default">` +element in `/etc/dbus-1/session.conf`. Please do also not forget to tell the agent about your environment, when running it via sudo: diff --git a/examples/applicationmanager/softwarecontainer-plugin/softwarecontainer.cpp b/examples/applicationmanager/softwarecontainer-plugin/softwarecontainer.cpp index dd27b4a3..2598f6aa 100644 --- a/examples/applicationmanager/softwarecontainer-plugin/softwarecontainer.cpp +++ b/examples/applicationmanager/softwarecontainer-plugin/softwarecontainer.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/softwarecontainer-plugin/softwarecontainer.h b/examples/applicationmanager/softwarecontainer-plugin/softwarecontainer.h index e951c55d..63ba2614 100644 --- a/examples/applicationmanager/softwarecontainer-plugin/softwarecontainer.h +++ b/examples/applicationmanager/softwarecontainer-plugin/softwarecontainer.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/startup-plugin/startup-plugin.cpp b/examples/applicationmanager/startup-plugin/startup-plugin.cpp index 0a1a9a25..3ec57bf6 100644 --- a/examples/applicationmanager/startup-plugin/startup-plugin.cpp +++ b/examples/applicationmanager/startup-plugin/startup-plugin.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/examples/applicationmanager/startup-plugin/startup-plugin.h b/examples/applicationmanager/startup-plugin/startup-plugin.h index fa62b702..f7540e96 100644 --- a/examples/applicationmanager/startup-plugin/startup-plugin.h +++ b/examples/applicationmanager/startup-plugin/startup-plugin.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/header.BSD-QTAS b/header.BSD-QTAS index b436e34f..00ec0076 100644 --- a/header.BSD-QTAS +++ b/header.BSD-QTAS @@ -1,10 +1,9 @@ /**************************************************************************** ** ** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:BSD-QTAS$ ** Commercial License Usage diff --git a/header.FDL-QTAS b/header.FDL-QTAS index b3064965..40ff9176 100644 --- a/header.FDL-QTAS +++ b/header.FDL-QTAS @@ -1,10 +1,9 @@ /**************************************************************************** ** ** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the documentation of the Luxoft Application Manager. +** This file is part of the documentation of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:FDL-QTAS$ ** Commercial License Usage diff --git a/header.GPL-EXCEPT-QTAS b/header.GPL-EXCEPT-QTAS index 3ead040d..905efde0 100644 --- a/header.GPL-EXCEPT-QTAS +++ b/header.GPL-EXCEPT-QTAS @@ -1,10 +1,9 @@ /**************************************************************************** ** ** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage diff --git a/header.LGPL-QTAS b/header.LGPL-QTAS index 98265f2c..31af987d 100644 --- a/header.LGPL-QTAS +++ b/header.LGPL-QTAS @@ -1,10 +1,9 @@ /**************************************************************************** ** ** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/qmake-features/am-qml-testcase.prf b/qmake-features/am-qml-testcase.prf index c7f2396a..b475deed 100644 --- a/qmake-features/am-qml-testcase.prf +++ b/qmake-features/am-qml-testcase.prf @@ -93,3 +93,6 @@ for (f , FILES) { check.depends = do_copydata QMAKE_EXTRA_TARGETS += do_copydata } + +# Make sure that possible apps are in OTHER_FILES +for (app, TEST_APPS): OTHER_FILES += apps/$${app}/*.yaml apps/$${app}/*.qml apps/$${app}/*.png diff --git a/src/application-lib/application-lib.pro b/src/application-lib/application-lib.pro index 1f75472d..7363acc1 100644 --- a/src/application-lib/application-lib.pro +++ b/src/application-lib/application-lib.pro @@ -13,15 +13,21 @@ CONFIG -= create_cmake HEADERS += \ applicationinfo.h \ - applicationscanner.h \ - yamlapplicationscanner.h \ + packagescanner.h \ + yamlpackagescanner.h \ installationreport.h \ applicationinterface.h \ + intentinfo.h \ + packageinfo.h \ + packagedatabase.h \ SOURCES += \ applicationinfo.cpp \ - yamlapplicationscanner.cpp \ + yamlpackagescanner.cpp \ installationreport.cpp \ applicationinterface.cpp \ + intentinfo.cpp \ + packageinfo.cpp \ + packagedatabase.cpp \ load(qt_module) diff --git a/src/application-lib/applicationinfo.cpp b/src/application-lib/applicationinfo.cpp index f746f849..ca9130be 100644 --- a/src/application-lib/applicationinfo.cpp +++ b/src/application-lib/applicationinfo.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -40,82 +40,16 @@ ** ****************************************************************************/ -#include <QDebug> +#include <QDataStream> #include <QBuffer> #include "applicationinfo.h" #include "exception.h" #include "installationreport.h" +#include "packageinfo.h" QT_BEGIN_NAMESPACE_AM -/////////////////////////////////////////////////////////////////////////////////////////////////// -// AbstractApplicationInfo -/////////////////////////////////////////////////////////////////////////////////////////////////// - -bool AbstractApplicationInfo::isValidApplicationId(const QString &appId, bool isAliasName, QString *errorString) -{ - static const int maxLength = 150; - - try { - if (appId.isEmpty()) - throw Exception(Error::Parse, "must not be empty"); - - // we need to make sure that we can use the name as directory on a FAT formatted SD-card, - // which has a 255 character path length restriction - if (appId.length() > maxLength) - throw Exception(Error::Parse, "the maximum length is %1 characters (found %2 characters)").arg(maxLength, appId.length()); - - int aliasPos = -1; - - // aliases need to have the '@' marker - if (isAliasName) { - aliasPos = appId.indexOf(qL1C('@')); - if (aliasPos < 0 || aliasPos == (appId.size() - 1)) - throw Exception(Error::Parse, "missing alias-id tag '@'"); - } - - // all characters need to be ASCII minus '@' and any filesystem special characters: - bool spaceOnly = true; - static const char forbiddenChars[] = "@<>:\"/\\|?*"; - for (int pos = 0; pos < appId.length(); ++pos) { - if (pos == aliasPos) - continue; - ushort ch = appId.at(pos).unicode(); - if ((ch < 0x20) || (ch > 0x7f) || strchr(forbiddenChars, ch & 0xff)) { - throw Exception(Error::Parse, "must consist of printable ASCII characters only, except any of \'%1'") - .arg(QString::fromLatin1(forbiddenChars)); - } - if (spaceOnly) - spaceOnly = QChar(ch).isSpace(); - } - if (spaceOnly) - throw Exception(Error::Parse, "must not consist of only white-space characters"); - - return true; - } catch (const Exception &e) { - if (errorString) - *errorString = e.errorString(); - return false; - } -} - -bool AbstractApplicationInfo::isValidIcon(const QString &icon, QString &errorString) -{ - if (icon.isEmpty()) { - errorString = qSL("it's empty"); - return false; - } - - QFileInfo fileInfo(icon); - - if (fileInfo.fileName() != icon) { - errorString = QString(qSL("'%1' is not a valid file name")).arg(icon); - return false; - } - - return true; -} //TODO Make this really unique static int uniqueCounter = 0; @@ -127,163 +61,114 @@ static int nextUniqueNumber() { return uniqueCounter; } -AbstractApplicationInfo::AbstractApplicationInfo() - : m_uniqueNumber(nextUniqueNumber()) +ApplicationInfo::ApplicationInfo(PackageInfo *packageInfo) + : m_packageInfo(packageInfo) + , m_uniqueNumber(nextUniqueNumber()) +{ } + +PackageInfo *ApplicationInfo::packageInfo() const { + return m_packageInfo; } -QString AbstractApplicationInfo::id() const +QString ApplicationInfo::id() const { return m_id; } -int AbstractApplicationInfo::uniqueNumber() const +int ApplicationInfo::uniqueNumber() const { return m_uniqueNumber; } -QMap<QString, QString> AbstractApplicationInfo::names() const -{ - return m_name; -} - -QString AbstractApplicationInfo::name(const QString &language) const -{ - return m_name.value(language); -} - -QString AbstractApplicationInfo::icon() const -{ - return m_icon; -} - -QString AbstractApplicationInfo::documentUrl() const -{ - return m_documentUrl; -} - -QVariantMap AbstractApplicationInfo::applicationProperties() const +QVariantMap ApplicationInfo::applicationProperties() const { return m_sysAppProperties; } -QVariantMap AbstractApplicationInfo::allAppProperties() const +QVariantMap ApplicationInfo::allAppProperties() const { return m_allAppProperties; } -void AbstractApplicationInfo::validate() const Q_DECL_NOEXCEPT_EXPR(false) -{ - QString errorMsg; - if (!isValidApplicationId(id(), isAlias(), &errorMsg)) - throw Exception(Error::Parse, "the identifier (%1) is not a valid application-id: %2").arg(id()).arg(errorMsg); - - if (!isValidIcon(icon(), errorMsg)) - throw Exception(Error::Parse, "Invalid 'icon' field: %1").arg(errorMsg); - - if (names().isEmpty()) - throw Exception(Error::Parse, "the 'name' field must not be empty"); - - // This check won't work during installations, since the icon file is extracted after info.json - // if (!QFile::exists(displayIcon())) - // throw Exception("the 'icon' field refers to a non-existent file"); - - //TODO: check for valid capabilities -} - -void AbstractApplicationInfo::read(QDataStream &ds) -{ - ds >> m_id - >> m_uniqueNumber - >> m_name - >> m_icon - >> m_documentUrl - >> m_sysAppProperties - >> m_allAppProperties; - - uniqueCounter = qMax(uniqueCounter, m_uniqueNumber); -} - -void AbstractApplicationInfo::writeToDataStream(QDataStream &ds) const +void ApplicationInfo::writeToDataStream(QDataStream &ds) const { - ds << isAlias() - << m_id + ds << m_id << m_uniqueNumber - << m_name - << m_icon - << m_documentUrl << m_sysAppProperties - << m_allAppProperties; + << m_allAppProperties + << m_codeFilePath + << m_runtimeName + << m_runtimeParameters + << m_supportsApplicationInterface + << m_capabilities + << m_openGLConfiguration; } -AbstractApplicationInfo *AbstractApplicationInfo::readFromDataStream(QDataStream &ds) +ApplicationInfo *ApplicationInfo::readFromDataStream(PackageInfo *pkg, QDataStream &ds) { - bool isAlias; - ds >> isAlias; + QScopedPointer<ApplicationInfo> app(new ApplicationInfo(pkg)); - QScopedPointer<AbstractApplicationInfo> app; + ds >> app->m_id + >> app->m_uniqueNumber + >> app->m_sysAppProperties + >> app->m_allAppProperties + >> app->m_codeFilePath + >> app->m_runtimeName + >> app->m_runtimeParameters + >> app->m_supportsApplicationInterface + >> app->m_capabilities + >> app->m_openGLConfiguration; - if (isAlias) - app.reset(new ApplicationAliasInfo); - else - app.reset(new ApplicationInfo); - - app->read(ds); + uniqueCounter = qMax(uniqueCounter, app->m_uniqueNumber); + app->m_capabilities.sort(); return app.take(); } -void AbstractApplicationInfo::toVariantMapHelper(QVariantMap &map) const + +QVariantMap ApplicationInfo::toVariantMap() const { + QVariantMap map; //TODO: check if we can find a better method to keep this as similar as possible to // ApplicationManager::get(). - // This is used for RuntimeInterface::startApplication(), ContainerInterface and - // ApplicationInstaller::taskRequestingInstallationAcknowledge. + // This is used for RuntimeInterface::startApplication() and the ContainerInterface map[qSL("id")] = m_id; map[qSL("uniqueNumber")] = m_uniqueNumber; { QVariantMap displayName; - auto names = m_name; + auto names = packageInfo()->names(); for (auto it = names.constBegin(); it != names.constEnd(); ++it) displayName.insert(it.key(), it.value()); map[qSL("displayName")] = displayName; } - map[qSL("displayIcon")] = m_icon; + map[qSL("displayIcon")] = packageInfo()->icon(); map[qSL("applicationProperties")] = m_allAppProperties; -} + map[qSL("codeFilePath")] = m_codeFilePath; + map[qSL("runtimeName")] = m_runtimeName; + map[qSL("runtimeParameters")] = m_runtimeParameters; + map[qSL("capabilities")] = m_capabilities; + map[qSL("mimeTypes")] = m_supportedMimeTypes; + + map[qSL("categories")] = packageInfo()->categories(); + map[qSL("version")] = packageInfo()->version(); + map[qSL("baseDir")] = packageInfo()->baseDir().absolutePath(); + map[qSL("codeDir")] = map[qSL("baseDir")]; // 5.12 backward compatibility + map[qSL("manifestDir")] = map[qSL("baseDir")]; // 5.12 backward compatibility + map[qSL("installationLocationId")] = packageInfo()->installationReport() ? qSL("internal-0") : QString(); + map[qSL("supportsApplicationInterface")] = m_supportsApplicationInterface; + map[qSL("dlt")] = packageInfo()->dltConfiguration(); -QVariantMap AbstractApplicationInfo::toVariantMap() const -{ - QVariantMap map; - toVariantMapHelper(map); return map; } -/////////////////////////////////////////////////////////////////////////////////////////////////// -// ApplicationInfo -/////////////////////////////////////////////////////////////////////////////////////////////////// - -ApplicationInfo::ApplicationInfo() -{ } - -void ApplicationInfo::validate() const Q_DECL_NOEXCEPT_EXPR(false) -{ - AbstractApplicationInfo::validate(); - - if (absoluteCodeFilePath().isEmpty()) - throw Exception(Error::Parse, "the 'code' field must not be empty"); - - if (runtimeName().isEmpty()) - throw Exception(Error::Parse, "the 'runtimeName' field must not be empty"); -} - QString ApplicationInfo::absoluteCodeFilePath() const { QString code = m_codeFilePath; - return code.isEmpty() ? QString() : QDir(codeDir()).absoluteFilePath(code); + return code.isEmpty() ? QString() : QDir(packageInfo()->baseDir()).absoluteFilePath(code); } QString ApplicationInfo::codeFilePath() const @@ -301,11 +186,6 @@ QVariantMap ApplicationInfo::runtimeParameters() const return m_runtimeParameters; } -bool ApplicationInfo::isBuiltIn() const -{ - return m_builtIn; -} - QStringList ApplicationInfo::capabilities() const { return m_capabilities; @@ -313,17 +193,7 @@ QStringList ApplicationInfo::capabilities() const QStringList ApplicationInfo::supportedMimeTypes() const { - return m_mimeTypes; -} - -QStringList ApplicationInfo::categories() const -{ - return m_categories; -} - -QString ApplicationInfo::version() const -{ - return m_version; + return m_supportedMimeTypes; } QVariantMap ApplicationInfo::openGLConfiguration() const @@ -331,114 +201,9 @@ QVariantMap ApplicationInfo::openGLConfiguration() const return m_openGLConfiguration; } -QVariantList ApplicationInfo::intents() const -{ - return m_intents; -} - -void ApplicationInfo::setBuiltIn(bool builtIn) -{ - m_builtIn = builtIn; -} - -void ApplicationInfo::setSupportsApplicationInterface(bool supportsAppInterface) -{ - m_supportsApplicationInterface = supportsAppInterface; -} - -void ApplicationInfo::writeToDataStream(QDataStream &ds) const -{ - AbstractApplicationInfo::writeToDataStream(ds); - - QByteArray serializedReport; - - if (auto report = installationReport()) { - QBuffer buffer(&serializedReport); - buffer.open(QBuffer::WriteOnly); - report->serialize(&buffer); - } - - ds << m_codeFilePath - << m_runtimeName - << m_runtimeParameters - << m_supportsApplicationInterface - << m_builtIn - << m_capabilities - << m_categories - << m_mimeTypes - << m_version - << m_openGLConfiguration - << serializedReport - << m_manifestDir.absolutePath() - << m_codeDir.absolutePath() - << m_uid - << m_dlt - << m_intents; -} - bool ApplicationInfo::supportsApplicationInterface() const { return m_supportsApplicationInterface; } -void ApplicationInfo::read(QDataStream &ds) -{ - AbstractApplicationInfo::read(ds); - - QString codeDir; - QString manifestDir; - QByteArray installationReport; - - ds >> m_codeFilePath - >> m_runtimeName - >> m_runtimeParameters - >> m_supportsApplicationInterface - >> m_builtIn - >> m_capabilities - >> m_categories - >> m_mimeTypes - >> m_version - >> m_openGLConfiguration - >> installationReport - >> manifestDir - >> codeDir - >> m_uid - >> m_dlt - >> m_intents; - - m_capabilities.sort(); - m_categories.sort(); - m_mimeTypes.sort(); - - m_codeDir.setPath(codeDir); - m_manifestDir.setPath(manifestDir); - if (!installationReport.isEmpty()) { - QBuffer buffer(&installationReport); - buffer.open(QBuffer::ReadOnly); - m_installationReport.reset(new InstallationReport(m_id)); - if (!m_installationReport->deserialize(&buffer)) - m_installationReport.reset(); - } -} - -void ApplicationInfo::toVariantMapHelper(QVariantMap &map) const -{ - AbstractApplicationInfo::toVariantMapHelper(map); - - map[qSL("codeFilePath")] = m_codeFilePath; - map[qSL("runtimeName")] = m_runtimeName; - map[qSL("runtimeParameters")] = m_runtimeParameters; - map[qSL("capabilities")] = m_capabilities; - map[qSL("mimeTypes")] = m_mimeTypes; - map[qSL("categories")] = m_categories; - map[qSL("version")] = m_version; - map[qSL("codeDir")] = m_codeDir.absolutePath(); - map[qSL("manifestDir")] = m_manifestDir.absolutePath(); - map[qSL("installationLocationId")] = installationReport() ? installationReport()->installationLocationId() - : QString(); - map[qSL("supportsApplicationInterface")] = m_supportsApplicationInterface; - map[qSL("dlt")] = m_dlt; - map[qSL("intents")] = m_intents; -} - QT_END_NAMESPACE_AM diff --git a/src/application-lib/applicationinfo.h b/src/application-lib/applicationinfo.h index aefce00c..6dd9afa5 100644 --- a/src/application-lib/applicationinfo.h +++ b/src/application-lib/applicationinfo.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -42,137 +42,70 @@ #pragma once -#include <QDataStream> #include <QDir> #include <QMap> #include <QString> #include <QStringList> #include <QVariantMap> +#include <QVector> #include <QtAppManCommon/global.h> -#include <QtAppManApplication/installationreport.h> + +QT_FORWARD_DECLARE_CLASS(QDataStream) QT_BEGIN_NAMESPACE_AM -class ApplicationManager; -class InstallationReport; +class PackageInfo; -class AbstractApplicationInfo +class ApplicationInfo { public: - AbstractApplicationInfo(); - virtual ~AbstractApplicationInfo() {} + ApplicationInfo(PackageInfo *packageInfo); + + PackageInfo *packageInfo() const; + QVariantMap toVariantMap() const; QString id() const; int uniqueNumber() const; - QMap<QString, QString> names() const; - QString name(const QString &language) const; - QString icon() const; - QString documentUrl() const; QVariantMap applicationProperties() const; QVariantMap allAppProperties() const; - - QVariantMap toVariantMap() const; - virtual void toVariantMapHelper(QVariantMap &map) const; - - virtual bool isAlias() const = 0; - virtual void writeToDataStream(QDataStream &ds) const; - virtual void validate() const Q_DECL_NOEXCEPT_EXPR(false); - - static bool isValidApplicationId(const QString &appId, bool isAliasName = false, QString *errorString = nullptr); - static bool isValidIcon(const QString &icon, QString &errorString); - static AbstractApplicationInfo *readFromDataStream(QDataStream &ds); - -protected: - virtual void read(QDataStream &ds); - - // static part from info.json - QString m_id; - int m_uniqueNumber; - - QMap<QString, QString> m_name; // language -> name - QString m_icon; // relative to info.json location - QString m_documentUrl; - QVariantMap m_sysAppProperties; - QVariantMap m_allAppProperties; - - friend class YamlApplicationScanner; -}; - -class ApplicationAliasInfo : public AbstractApplicationInfo -{ -public: - bool isAlias() const override { return true; } -}; - -class ApplicationInfo : public AbstractApplicationInfo -{ -public: - ApplicationInfo(); - - bool isAlias() const override { return false; } - void writeToDataStream(QDataStream &ds) const override; - void validate() const Q_DECL_NOEXCEPT_EXPR(false) override; - - const QDir &codeDir() const { return m_codeDir; } QString absoluteCodeFilePath() const; QString codeFilePath() const; QString runtimeName() const; QVariantMap runtimeParameters() const; - QVariantMap environmentVariables() const { return m_environmentVariables; } - bool isBuiltIn() const; QStringList capabilities() const; QStringList supportedMimeTypes() const; - QStringList categories() const; - QString version() const; QVariantMap openGLConfiguration() const; - QVariantList intents() const; bool supportsApplicationInterface() const; - void setSupportsApplicationInterface(bool supportsAppInterface); - void setBuiltIn(bool builtIn); + void writeToDataStream(QDataStream &ds) const; + static ApplicationInfo *readFromDataStream(PackageInfo *pkg, QDataStream &ds); - const InstallationReport *installationReport() const { return m_installationReport.data(); } - void setInstallationReport(InstallationReport *report) { m_installationReport.reset(report); } - QString manifestDir() const { return m_manifestDir.absolutePath(); } - uint uid() const { return m_uid; } - void setManifestDir(const QString &path) { m_manifestDir.setPath(path); } - void setCodeDir(const QString &path) { m_codeDir.setPath(path); } +private: + void read(QDataStream &ds); - void toVariantMapHelper(QVariantMap &map) const override; + // static part from info.json + PackageInfo *m_packageInfo; -private: - void read(QDataStream &ds) override; + QString m_id; + int m_uniqueNumber; + + QVariantMap m_sysAppProperties; + QVariantMap m_allAppProperties; QString m_codeFilePath; // relative to info.json location QString m_runtimeName; QVariantMap m_runtimeParameters; - QVariantMap m_environmentVariables; bool m_supportsApplicationInterface = false; - - bool m_builtIn = false; // system app - not removable - QStringList m_capabilities; - QStringList m_categories; - QStringList m_mimeTypes; - - QString m_version; - QVariantMap m_openGLConfiguration; - QVariantList m_intents; - QVariantMap m_dlt; - - // added by installer - QScopedPointer<InstallationReport> m_installationReport; - QDir m_manifestDir; - QDir m_codeDir; - uint m_uid = uint(-1); // unix user id - move to installationReport + QStringList m_supportedMimeTypes; // deprecated - friend class YamlApplicationScanner; friend class ApplicationManager; // needed to update installation status - friend class ApplicationDatabase; // needed to create ApplicationInfo objects + friend class PackageDatabase; // needed to create ApplicationInfo objects friend class InstallationTask; // needed to set m_uid and m_builtin during the installation + friend class YamlPackageScanner; Q_DISABLE_COPY(ApplicationInfo) }; diff --git a/src/application-lib/applicationinterface.cpp b/src/application-lib/applicationinterface.cpp index ca13eaf3..1ba0ea75 100644 --- a/src/application-lib/applicationinterface.cpp +++ b/src/application-lib/applicationinterface.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/application-lib/applicationinterface.h b/src/application-lib/applicationinterface.h index 5150546e..61e05118 100644 --- a/src/application-lib/applicationinterface.h +++ b/src/application-lib/applicationinterface.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/application-lib/installationreport.cpp b/src/application-lib/installationreport.cpp index 0b4e5c67..b52d772c 100644 --- a/src/application-lib/installationreport.cpp +++ b/src/application-lib/installationreport.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -50,7 +50,7 @@ #include "global.h" #include "qtyaml.h" -#include "applicationinfo.h" +#include "packageinfo.h" #include "utilities.h" #include "exception.h" #include "installationreport.h" @@ -69,28 +69,18 @@ static const unsigned char privateHmacKeyData[64] = { }; -InstallationReport::InstallationReport(const QString &applicationId) - : m_applicationId(applicationId) +InstallationReport::InstallationReport(const QString &packageId) + : m_packageId(packageId) { } -QString InstallationReport::applicationId() const +QString InstallationReport::packageId() const { - return m_applicationId; + return m_packageId; } -void InstallationReport::setApplicationId(const QString &applicationId) +void InstallationReport::setPackageId(const QString &packageId) { - m_applicationId = applicationId; -} - -QString InstallationReport::installationLocationId() const -{ - return m_installationLocationId; -} - -void InstallationReport::setInstallationLocationId(const QString &installationLocationId) -{ - m_installationLocationId = installationLocationId; + m_packageId = packageId; } QVariantMap InstallationReport::extraMetaData() const @@ -170,7 +160,7 @@ void InstallationReport::addFiles(const QStringList &files) bool InstallationReport::isValid() const { - return AbstractApplicationInfo::isValidApplicationId(m_applicationId) && !m_digest.isEmpty() && !m_files.isEmpty(); + return PackageInfo::isValidApplicationId(m_packageId) && !m_digest.isEmpty() && !m_files.isEmpty(); } bool InstallationReport::deserialize(QIODevice *from) @@ -188,7 +178,7 @@ bool InstallationReport::deserialize(QIODevice *from) return false; try { - checkYamlFormat(docs, 3 /*number of expected docs*/, { "am-installation-report" }, 1); + checkYamlFormat(docs, 3 /*number of expected docs*/, { "am-installation-report" }, 3 /*version*/); } catch (const Exception &) { return false; } @@ -196,15 +186,14 @@ bool InstallationReport::deserialize(QIODevice *from) const QVariantMap &root = docs.at(1).toMap(); try { - if (m_applicationId.isEmpty()) { - m_applicationId = root[qSL("applicationId")].toString(); - if (m_applicationId.isEmpty()) + if (m_packageId.isEmpty()) { + m_packageId = root[qSL("packageId")].toString(); + if (m_packageId.isEmpty()) throw false; - } else if (root[qSL("applicationId")].toString() != m_applicationId) { + } else if (root[qSL("packageId")].toString() != m_packageId) { throw false; } - m_installationLocationId = root[qSL("installationLocationId")].toString(); m_diskSpaceUsed = root[qSL("diskSpaceUsed")].toULongLong(); m_digest = QByteArray::fromHex(root[qSL("digest")].toString().toLatin1()); if (m_digest.isEmpty()) @@ -240,7 +229,8 @@ bool InstallationReport::deserialize(QIODevice *from) // see if the file has been tampered with by checking the hmac QByteArray hmacFile = QByteArray::fromHex(docs[2].toMap().value(qSL("hmac")).toString().toLatin1()); - QByteArray hmacKey = QByteArray::fromRawData((const char *) privateHmacKeyData, sizeof(privateHmacKeyData)); + QByteArray hmacKey = QByteArray::fromRawData(reinterpret_cast<const char *>(privateHmacKeyData), + sizeof(privateHmacKeyData)); QByteArray hmacCalc= QMessageAuthenticationCode::hash(QtYaml::yamlFromVariantDocuments({ docs[0], docs[1] }, QtYaml::BlockStyle), hmacKey, QCryptographicHash::Sha256); @@ -264,12 +254,11 @@ bool InstallationReport::serialize(QIODevice *to) const return false; QVariantMap header { - { "formatVersion", 1 }, + { "formatVersion", 3 }, { "formatType", "am-installation-report" } }; QVariantMap root { - { qSL("applicationId"), applicationId() }, - { qSL("installationLocationId"), installationLocationId() }, + { qSL("packageId"), packageId() }, { qSL("diskSpaceUsed"), diskSpaceUsed() }, { qSL("digest"), QLatin1String(digest().toHex()) } }; @@ -289,7 +278,8 @@ bool InstallationReport::serialize(QIODevice *to) const docs << root; // generate hmac to prevent tampering - QByteArray hmacKey = QByteArray::fromRawData((const char *) privateHmacKeyData, sizeof(privateHmacKeyData)); + QByteArray hmacKey = QByteArray::fromRawData(reinterpret_cast<const char *>(privateHmacKeyData), + sizeof(privateHmacKeyData)); QByteArray hmacCalc= QMessageAuthenticationCode::hash(QtYaml::yamlFromVariantDocuments({ docs[0], docs[1] }, QtYaml::BlockStyle), hmacKey, QCryptographicHash::Sha256); diff --git a/src/application-lib/installationreport.h b/src/application-lib/installationreport.h index a619c80a..87fa56c1 100644 --- a/src/application-lib/installationreport.h +++ b/src/application-lib/installationreport.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -55,13 +55,10 @@ QT_BEGIN_NAMESPACE_AM class InstallationReport { public: - InstallationReport(const QString &applicationId = QString()); + InstallationReport(const QString &packageId = QString()); - QString applicationId() const; - void setApplicationId(const QString &applicationId); - - QString installationLocationId() const; - void setInstallationLocationId(const QString &installationLocationId); + QString packageId() const; + void setPackageId(const QString &packageId); QVariantMap extraMetaData() const; void setExtraMetaData(const QVariantMap &extraMetaData); @@ -90,8 +87,7 @@ public: bool serialize(QIODevice *to) const; private: - QString m_applicationId; - QString m_installationLocationId; + QString m_packageId; QByteArray m_digest; quint64 m_diskSpaceUsed = 0; QStringList m_files; diff --git a/src/package-lib/package_p.cpp b/src/application-lib/intentinfo.cpp index 702b94a2..ef53ce7e 100644 --- a/src/package-lib/package_p.cpp +++ b/src/application-lib/intentinfo.cpp @@ -1,10 +1,9 @@ /**************************************************************************** ** ** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -40,51 +39,108 @@ ** ****************************************************************************/ - -#include <QFileInfo> #include <QDataStream> -#include <QCryptographicHash> - -#include <archive.h> -#include "package_p.h" +#include "intentinfo.h" +#include "packageinfo.h" QT_BEGIN_NAMESPACE_AM -ArchiveException::ArchiveException(struct ::archive *ar, const char *errorString) - : Exception(Error::Archive, qSL("[libarchive] ") + qL1S(errorString) + qSL(": ") + QString::fromLocal8Bit(::archive_error_string(ar))) + +IntentInfo::IntentInfo(PackageInfo *packageInfo) + : m_packageInfo(packageInfo) +{ } + +IntentInfo::~IntentInfo() { } +QString IntentInfo::id() const +{ + return m_id; +} + +IntentInfo::Visibility IntentInfo::visibility() const +{ + return m_visibility; +} + +QStringList IntentInfo::requiredCapabilities() const +{ + return m_requiredCapabilities; +} + +QVariantMap IntentInfo::parameterMatch() const +{ + return m_parameterMatch; +} -QVariantMap PackageUtilities::headerDataForDigest = QVariantMap { - { "extraSigned", QVariantMap() } -}; +QString IntentInfo::handlingApplicationId() const +{ + return m_handlingApplicationId; +} -void PackageUtilities::addFileMetadataToDigest(const QString &entryFilePath, const QFileInfo &fi, QCryptographicHash &digest) +QStringList IntentInfo::categories() const { - // (using QDataStream would be more readable, but it would make the algorithm Qt dependent) - QByteArray addToDigest = ((fi.isDir()) ? "D/" : "F/") - + QByteArray::number(fi.isDir() ? 0 : fi.size()) - + '/' + entryFilePath.toUtf8(); - digest.addData(addToDigest); + return m_categories; } -void PackageUtilities::addHeaderDataToDigest(const QVariantMap &header, QCryptographicHash &digest) Q_DECL_NOEXCEPT_EXPR(false) +QMap<QString, QString> IntentInfo::names() const { - for (auto it = headerDataForDigest.constBegin(); it != headerDataForDigest.constEnd(); ++it) { - if (header.contains(it.key())) { - QByteArray ba; - QDataStream ds(&ba, QIODevice::WriteOnly); - - QVariant v = header.value(it.key()); - if (!v.convert(int(it.value().type()))) - throw Exception(Error::Package, "metadata field %1 has invalid type for digest calculation (cannot convert %2 to %3)") - .arg(it.key()).arg(header.value(it.key()).type()).arg(it.value().type()); - ds << v; - - digest.addData(ba); - } - } + return m_name; +} + +QString IntentInfo::name(const QString &language) const +{ + return m_name.value(language); +} + +QMap<QString, QString> IntentInfo::descriptions() const +{ + return m_description; +} + +QString IntentInfo::description(const QString &language) const +{ + return m_description.value(language); +} + +QString IntentInfo::icon() const +{ + return m_icon; +} + +void IntentInfo::writeToDataStream(QDataStream &ds) const +{ + ds << m_id + << (m_visibility == Public ? qSL("public") : qSL("private")) + << m_requiredCapabilities + << m_parameterMatch + << m_handlingApplicationId + << m_categories + << m_name + << m_description + << m_icon; +} + +IntentInfo *IntentInfo::readFromDataStream(PackageInfo *pkg, QDataStream &ds) +{ + QScopedPointer<IntentInfo> intent(new IntentInfo(pkg)); + QString visibilityStr; + + ds >> intent->m_id + >> visibilityStr + >> intent->m_requiredCapabilities + >> intent->m_parameterMatch + >> intent->m_handlingApplicationId + >> intent->m_categories + >> intent->m_name + >> intent->m_description + >> intent->m_icon; + + intent->m_visibility = (visibilityStr == qSL("public")) ? Public : Private; + intent->m_categories.sort(); + + return intent.take(); } QT_END_NAMESPACE_AM diff --git a/src/installer-lib/installationlocation.h b/src/application-lib/intentinfo.h index 43e921ab..aee5b8ab 100644 --- a/src/installer-lib/installationlocation.h +++ b/src/application-lib/intentinfo.h @@ -1,10 +1,9 @@ /**************************************************************************** ** ** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -42,43 +41,64 @@ #pragma once -#include <QtAppManCommon/global.h> +#include <QMap> #include <QString> +#include <QStringList> #include <QVariantMap> +#include <QVector> + +#include <QtAppManCommon/global.h> + +QT_FORWARD_DECLARE_CLASS(QDataStream) QT_BEGIN_NAMESPACE_AM -class InstallationLocation +class YamlPackageScanner; +class PackageInfo; + +class IntentInfo { public: - static const InstallationLocation invalid; + IntentInfo(PackageInfo *packageInfo); + ~IntentInfo(); - bool operator==(const InstallationLocation &other) const; - inline bool operator!=(const InstallationLocation &other) const { return !((*this) == other); } + enum Visibility { + Public, + Private + }; QString id() const; - int index() const; + Visibility visibility() const; + QStringList requiredCapabilities() const; + QVariantMap parameterMatch() const; + QString handlingApplicationId() const; - QString installationPath() const; - QString documentPath() const; + QStringList categories() const; - bool installationDeviceFreeSpace(quint64 *bytesTotal, quint64 *bytesFree) const; - bool documentDeviceFreeSpace(quint64 *bytesTotal, quint64 *bytesFree) const; + QMap<QString, QString> names() const; + QString name(const QString &language) const; + QMap<QString, QString> descriptions() const; + QString description(const QString &language) const; + QString icon() const; - bool isValid() const; - bool isDefault() const; + void writeToDataStream(QDataStream &ds) const; + static IntentInfo *readFromDataStream(PackageInfo *pkg, QDataStream &ds); - QVariantMap toVariantMap() const; +private: + PackageInfo *m_packageInfo; + QString m_id; + Visibility m_visibility = Public; + QStringList m_requiredCapabilities; + QVariantMap m_parameterMatch; - static QVector<InstallationLocation> parseInstallationLocations(const QVariantList &list, - const QString &hardwareId) Q_DECL_NOEXCEPT_EXPR(false); + QString m_handlingApplicationId; + QStringList m_categories; + QMap<QString, QString> m_name; // language -> name + QMap<QString, QString> m_description; // language -> description + QString m_icon; // relative to info.json location -private: - bool m_valid = false; - int m_index = 0; - bool m_isDefault = false; - QString m_installationPath; - QString m_documentPath; + friend class YamlPackageScanner; + Q_DISABLE_COPY(IntentInfo) }; QT_END_NAMESPACE_AM diff --git a/src/application-lib/packagedatabase.cpp b/src/application-lib/packagedatabase.cpp new file mode 100644 index 00000000..3496faa7 --- /dev/null +++ b/src/application-lib/packagedatabase.cpp @@ -0,0 +1,221 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 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 &builtInPackagesDirs, + const QString &installedPackagesDir) + : m_builtInPackagesDirs(builtInPackagesDirs) + , m_installedPackagesDir(installedPackagesDir) +{ } + +PackageDatabase::PackageDatabase(const QString &singlePackagePath) + : m_singlePackagePath(singlePackagePath) +{ + Q_ASSERT(!singlePackagePath.isEmpty()); +} + +QString PackageDatabase::installedPackagesDir() const +{ + return m_installedPackagesDir; +} + +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()); + pkg->setBaseDir(QDir(m_installedPackagesDir).filePath(pkg->id())); + } + 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_builtInPackagesDirs) + m_builtInPackages.unite(loadManifestsFromDir(&yps, dir, true)); + + if (!m_installedPackagesDir.isEmpty()) + m_installedPackages = loadManifestsFromDir(&yps, m_installedPackagesDir, 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 diff --git a/src/manager-lib/applicationdatabase.h b/src/application-lib/packagedatabase.h index 7d11f4a9..ce1610db 100644 --- a/src/manager-lib/applicationdatabase.h +++ b/src/application-lib/packagedatabase.h @@ -1,10 +1,9 @@ /**************************************************************************** ** ** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -43,36 +42,56 @@ #pragma once #include <QtAppManCommon/global.h> -#include <QList> +#include <QVector> #include <QString> +#include <QtAppManApplication/packageinfo.h> + QT_BEGIN_NAMESPACE_AM -class Application; -class AbstractApplication; -class ApplicationDatabasePrivate; +class PackageInfo; +class YamlPackageScanner; + -class ApplicationDatabase +class PackageDatabase { public: - explicit ApplicationDatabase(); - explicit ApplicationDatabase(const QString &fileName); - ~ApplicationDatabase(); + PackageDatabase(const QStringList &builtInPackagesDirs, const QString &installedPackagesDir = QString()); + PackageDatabase(const QString &singlePackagePath); + + QString installedPackagesDir() const; + + void enableLoadFromCache(); + void enableSaveToCache(); - bool isValid() const; - bool isTemporary() const; - QString errorString() const; - QString name() const; + void parse(); - QVector<AbstractApplication *> read() Q_DECL_NOEXCEPT_EXPR(false); - void write(const QVector<AbstractApplication *> &apps) Q_DECL_NOEXCEPT_EXPR(false); - void write(const QVector<AbstractApplicationInfo *> &apps) Q_DECL_NOEXCEPT_EXPR(false); + QVector<PackageInfo *> builtInPackages() const; + QVector<PackageInfo *> installedPackages() const; - void invalidate(); + //TODO: runtime installations + //void addPackage(PackageInfo *package); + //void removePackage(PackageInfo *package); + //void updatePackage(PackageInfo *oldPackage, PackageInfo *newPackage); private: - ApplicationDatabasePrivate *d; - Q_DISABLE_COPY(ApplicationDatabase) + PackageInfo *loadManifest(YamlPackageScanner *yps, const QString &manifestPath); + QMap<PackageInfo *, QString> loadManifestsFromDir(YamlPackageScanner *yps, const QString &manifestDir, bool scanningBuiltInApps); + + bool loadFromCache(); + void saveToCache(); + + bool m_loadFromCache = false; + bool m_saveToCache = false; + bool m_parsed = false; + QStringList m_builtInPackagesDirs; + QString m_installedPackagesDir; + QString m_singlePackagePath; + + QMap<PackageInfo *, QString> m_builtInPackages; + QMap<PackageInfo *, QString> m_installedPackages; + + bool canBeRevertedToBuiltIn(PackageInfo *pi); }; QT_END_NAMESPACE_AM diff --git a/src/application-lib/packageinfo.cpp b/src/application-lib/packageinfo.cpp new file mode 100644 index 00000000..ee306431 --- /dev/null +++ b/src/application-lib/packageinfo.cpp @@ -0,0 +1,283 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 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 <QDataStream> +#include <QBuffer> + +#include "packageinfo.h" +#include "applicationinfo.h" +#include "intentinfo.h" +#include "exception.h" +#include "installationreport.h" + + +QT_BEGIN_NAMESPACE_AM + +PackageInfo::PackageInfo() +{ } + +PackageInfo::~PackageInfo() +{ } + +void PackageInfo::validate() const Q_DECL_NOEXCEPT_EXPR(false) +{ + QString errorMsg; + if (!isValidApplicationId(id(), &errorMsg)) + throw Exception(Error::Parse, "the identifier (%1) is not a valid package-id: %2").arg(id()).arg(errorMsg); + + for (const auto &app : m_applications) { + if (!isValidApplicationId(app->id(), &errorMsg)) + throw Exception(Error::Parse, "the identifier (%1) is not a valid application-id: %2").arg(app->id()).arg(errorMsg); + + if (app->absoluteCodeFilePath().isEmpty()) + throw Exception(Error::Parse, "the 'code' field must not be empty on application %1").arg(app->id()); + + if (app->runtimeName().isEmpty()) + throw Exception(Error::Parse, "the 'runtimeName' field must not be empty on application %1").arg(app->id()); + } +} + +QString PackageInfo::id() const +{ + return m_id; +} + +QMap<QString, QString> PackageInfo::names() const +{ + return m_name; +} + +QString PackageInfo::name(const QString &language) const +{ + return m_name.value(language); +} + +QMap<QString, QString> PackageInfo::descriptions() const +{ + return m_description; +} + +QString PackageInfo::description(const QString &language) const +{ + return m_description.value(language); +} + +QString PackageInfo::icon() const +{ + return m_icon; +} + +QStringList PackageInfo::categories() const +{ + return m_categories; +} + +bool PackageInfo::isBuiltIn() const +{ + return m_builtIn; +} + +void PackageInfo::setBuiltIn(bool builtIn) +{ + m_builtIn = builtIn; +} + +QString PackageInfo::version() const +{ + return m_version; +} + +QVariantMap PackageInfo::dltConfiguration() const +{ + return m_dltConfiguration; +} + +const QDir &PackageInfo::baseDir() const +{ + return m_baseDir; +} + +void PackageInfo::setBaseDir(const QDir &dir) +{ + m_baseDir = dir; +} + +QVector<ApplicationInfo *> PackageInfo::applications() const +{ + return m_applications; +} + +QVector<IntentInfo *> PackageInfo::intents() const +{ + return m_intents; +} + +const InstallationReport *PackageInfo::installationReport() const +{ + return m_installationReport.data(); +} + +void PackageInfo::setInstallationReport(InstallationReport *report) +{ + m_installationReport.reset(report); +} + +void PackageInfo::writeToDataStream(QDataStream &ds) const +{ + QByteArray serializedReport; + + if (auto report = installationReport()) { + QBuffer buffer(&serializedReport); + buffer.open(QBuffer::WriteOnly); + report->serialize(&buffer); + } + + ds << m_id + << m_name + << m_icon + << m_description + << m_categories + << m_version + << m_builtIn + << m_uid + << m_dltConfiguration + << m_baseDir.absolutePath() + << serializedReport; + + ds << m_applications.size(); + for (const auto &app : m_applications) + app->writeToDataStream(ds); + + ds << m_intents.size(); + for (const auto &intent : m_intents) + intent->writeToDataStream(ds); +} + +PackageInfo *PackageInfo::readFromDataStream(QDataStream &ds) +{ + QScopedPointer<PackageInfo> pkg(new PackageInfo); + + QString baseDir; + QByteArray installationReport; + + ds >> pkg->m_id + >> pkg->m_name + >> pkg->m_icon + >> pkg->m_description + >> pkg->m_categories + >> pkg->m_version + >> pkg->m_builtIn + >> pkg->m_uid + >> pkg->m_dltConfiguration + >> baseDir + >> installationReport; + + pkg->m_baseDir.setPath(baseDir); + + if (!installationReport.isEmpty()) { + QBuffer buffer(&installationReport); + buffer.open(QBuffer::ReadOnly); + pkg->m_installationReport.reset(new InstallationReport(pkg->id())); + if (!pkg->m_installationReport->deserialize(&buffer)) + pkg->m_installationReport.reset(); + } + + return pkg.take(); +} + +bool PackageInfo::isValidApplicationId(const QString &appId, QString *errorString) +{ + // we need to make sure that we can use the name as directory in a filesystem and inode names + // are limited to 255 characters in Linux. We need to subtract a safety margin for prefixes + // or suffixes though: + static const int maxLength = 150; + + try { + if (appId.isEmpty()) + throw Exception(Error::Parse, "must not be empty"); + + if (appId.length() > maxLength) + throw Exception(Error::Parse, "the maximum length is %1 characters (found %2 characters)").arg(maxLength, appId.length()); + + // all characters need to be ASCII minus any filesystem special characters: + bool spaceOnly = true; + static const char forbiddenChars[] = "<>:\"/\\|?*"; + for (int pos = 0; pos < appId.length(); ++pos) { + ushort ch = appId.at(pos).unicode(); + if ((ch < 0x20) || (ch > 0x7f) || strchr(forbiddenChars, ch & 0xff)) { + throw Exception(Error::Parse, "must consist of printable ASCII characters only, except any of \'%1'") + .arg(QString::fromLatin1(forbiddenChars)); + } + if (spaceOnly) + spaceOnly = QChar(ch).isSpace(); + } + if (spaceOnly) + throw Exception(Error::Parse, "must not consist of only white-space characters"); + + return true; + } catch (const Exception &e) { + if (errorString) + *errorString = e.errorString(); + return false; + } +} + +bool PackageInfo::isValidIcon(const QString &icon, QString *errorString) +{ + try { + if (icon.isEmpty()) + throw Exception("empty path"); + + QFileInfo fileInfo(icon); + + if (fileInfo.fileName() != icon) + throw Exception("'%1' is not a valid file name").arg(icon); + + return true; + } catch (const Exception &e) { + if (errorString) + *errorString = e.errorString(); + return false; + } +} + + +QT_END_NAMESPACE_AM diff --git a/src/application-lib/packageinfo.h b/src/application-lib/packageinfo.h new file mode 100644 index 00000000..777526f6 --- /dev/null +++ b/src/application-lib/packageinfo.h @@ -0,0 +1,122 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Luxoft Sweden AB +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 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 +** +****************************************************************************/ + +#pragma once + +#include <QDir> +#include <QMap> +#include <QString> +#include <QStringList> +#include <QVariantMap> +#include <QVector> + +#include <QtAppManCommon/global.h> + +QT_FORWARD_DECLARE_CLASS(QDataStream) + +QT_BEGIN_NAMESPACE_AM + +class InstallationReport; +class IntentInfo; +class ApplicationInfo; +class YamlPackageScanner; + +class PackageInfo +{ +public: + PackageInfo(); + ~PackageInfo(); + + void validate() const Q_DECL_NOEXCEPT_EXPR(false); + + QString id() const; + + QMap<QString, QString> names() const; + QString name(const QString &language) const; + QMap<QString, QString> descriptions() const; + QString description(const QString &language) const; + QString icon() const; + QStringList categories() const; + + bool isBuiltIn() const; + void setBuiltIn(bool builtIn); + QString version() const; + QVariantMap dltConfiguration() const; + uint uid() const { return m_uid; } + + const QDir &baseDir() const; + void setBaseDir(const QDir &dir); + + QVector<ApplicationInfo *> applications() const; + QVector<IntentInfo *> intents() const; + + const InstallationReport *installationReport() const; + void setInstallationReport(InstallationReport *report); + + void writeToDataStream(QDataStream &ds) const; + static PackageInfo *readFromDataStream(QDataStream &ds); + + static bool isValidApplicationId(const QString &appId, QString *errorString = nullptr); + static bool isValidIcon(const QString &icon, QString *errorString = nullptr); + +private: + QString m_id; + QMap<QString, QString> m_name; // language -> name + QMap<QString, QString> m_description; // language -> description + QStringList m_categories; + QString m_icon; // relative to info.json location + QString m_version; + bool m_builtIn = false; // system package - not removable + uint m_uid = uint(-1); // unix user id - move to installationReport + QVariantMap m_dltConfiguration; + QVector<ApplicationInfo *> m_applications; + QVector<IntentInfo *> m_intents; + + // added by installer + QScopedPointer<InstallationReport> m_installationReport; + QDir m_baseDir; + + friend class YamlPackageScanner; + friend class InstallationTask; + Q_DISABLE_COPY(PackageInfo) +}; + +QT_END_NAMESPACE_AM diff --git a/src/application-lib/applicationscanner.h b/src/application-lib/packagescanner.h index 5124d5c7..55e9ff3a 100644 --- a/src/application-lib/applicationscanner.h +++ b/src/application-lib/packagescanner.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -46,24 +46,22 @@ QT_BEGIN_NAMESPACE_AM -class ApplicationInfo; -class ApplicationAliasInfo; +class PackageInfo; -class ApplicationScanner +class PackageScanner { public: - virtual ~ApplicationScanner() = default; + virtual ~PackageScanner() = default; - virtual ApplicationInfo *scan(const QString &filePath) Q_DECL_NOEXCEPT_EXPR(false) = 0; - virtual ApplicationAliasInfo *scanAlias(const QString &filePath, const ApplicationInfo *application) Q_DECL_NOEXCEPT_EXPR(false) = 0; + virtual PackageInfo *scan(const QString &filePath) Q_DECL_NOEXCEPT_EXPR(false) = 0; virtual QString metaDataFileName() const = 0; protected: - ApplicationScanner() = default; + PackageScanner() = default; private: - Q_DISABLE_COPY(ApplicationScanner) + Q_DISABLE_COPY(PackageScanner) }; QT_END_NAMESPACE_AM diff --git a/src/application-lib/yamlapplicationscanner.cpp b/src/application-lib/yamlapplicationscanner.cpp deleted file mode 100644 index c3fd8e02..00000000 --- a/src/application-lib/yamlapplicationscanner.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** 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 <QJsonDocument> -#include <QJsonParseError> -#include <QJsonObject> -#include <QJsonArray> -#include <QFile> -#include <QFileInfo> -#include <QScopedPointer> - -#include "global.h" -#include "qtyaml.h" -#include "exception.h" -#include "applicationinfo.h" -#include "yamlapplicationscanner.h" -#include "utilities.h" - -QT_BEGIN_NAMESPACE_AM - -YamlApplicationScanner::YamlApplicationScanner() -{ } - -ApplicationInfo *YamlApplicationScanner::scan(const QString &filePath) Q_DECL_NOEXCEPT_EXPR(false) -{ - return static_cast<ApplicationInfo*>(scanInternal(filePath, false, nullptr)); -} - -ApplicationAliasInfo *YamlApplicationScanner::scanAlias(const QString &filePath, - const ApplicationInfo *application) Q_DECL_NOEXCEPT_EXPR(false) -{ - return static_cast<ApplicationAliasInfo*>(scanInternal(filePath, true, application)); -} - -AbstractApplicationInfo *YamlApplicationScanner::scanInternal(const QString &filePath, bool scanAlias, - const ApplicationInfo *application) Q_DECL_NOEXCEPT_EXPR(false) -{ - try { - if (scanAlias && !application) - throw Exception("cannot scan an alias without a valid base application"); - - QFile f(filePath); - if (!f.open(QIODevice::ReadOnly)) - throw Exception(f, "could not open file for reading"); - - QtYaml::ParseError parseError; - QVector<QVariant> docs = QtYaml::variantDocumentsFromYaml(f.readAll(), &parseError); - - if (parseError.error != QJsonParseError::NoError) { - throw Exception(Error::IO, "YAML parse error at line %1, column %2: %3") - .arg(parseError.line).arg(parseError.column).arg(parseError.errorString()); - } - - try { - checkYamlFormat(docs, 2 /*number of expected docs*/, { "am-application", "am-application-alias" }, 1); - } catch (const Exception &e) { - throw Exception(Error::Parse, "not a valid YAML application meta-data file: %1").arg(e.errorString()); - } - - const auto header = docs.constFirst().toMap(); - bool isApp = (header.value(qSL("formatType")).toString() == qL1S("am-application")); - bool isAlias = (header.value(qSL("formatType")).toString() == qL1S("am-application-alias")); - - if (!isApp && !isAlias) - throw Exception(Error::Parse, "not a valid YAML application manifest"); - if (isAlias && !scanAlias) - throw Exception(Error::Parse, "is an alias, but expected a normal manifest"); - if (!isAlias && scanAlias) - throw Exception(Error::Parse, "is an not alias, although expected such a manifest"); - - QScopedPointer<AbstractApplicationInfo> app; - if (isAlias) - app.reset(new ApplicationAliasInfo); - else { - app.reset(new ApplicationInfo); - auto *appInfo = static_cast<ApplicationInfo*>(app.data()); - appInfo->m_manifestDir = QFileInfo(f).absoluteDir(); - appInfo->m_codeDir.setPath(appInfo->manifestDir()); - } - - QVariantMap yaml = docs.at(1).toMap(); - for (auto it = yaml.constBegin(); it != yaml.constEnd(); ++it) { - QByteArray field = it.key().toLatin1(); - bool unknownField = false; - const QVariant &v = it.value(); - - if ((!isAlias && (field == "id")) - || (isAlias && (field == "aliasId"))) { - app->m_id = v.toString(); - if (isAlias) { - int sepPos = app->m_id.indexOf(qL1C('@')); - if (sepPos < 0 || sepPos == (app->m_id.size() - 1)) - throw Exception(Error::Parse, "malformed aliasId '%1'").arg(app->m_id); - QString realId = app->m_id.left(sepPos); - if (application->id() != realId) { - throw Exception(Error::Parse, "aliasId '%1' does not match base application id '%2'") - .arg(app->m_id, application->id()); - } - } - } else if (field == "icon") { - app->m_icon = v.toString(); - } else if (field == "name") { - auto nameMap = v.toMap(); - for (auto it = nameMap.constBegin(); it != nameMap.constEnd(); ++it) - app->m_name.insert(it.key(), it.value().toString()); - } else if (field == "documentUrl") { - app->m_documentUrl = v.toString(); - } else if (!isAlias) { - auto *appInfo = static_cast<ApplicationInfo*>(app.data()); - if (field == "code") { - appInfo->m_codeFilePath = v.toString(); - } else if (field == "runtime") { - appInfo->m_runtimeName = v.toString(); - } else if (field == "runtimeParameters") { - appInfo->m_runtimeParameters = v.toMap(); - } else if (field == "supportsApplicationInterface") { - appInfo->m_supportsApplicationInterface = v.toBool(); - } else if (field == "capabilities") { - appInfo->m_capabilities = variantToStringList(v); - appInfo->m_capabilities.sort(); - } else if (field == "categories") { - appInfo->m_categories = variantToStringList(v); - appInfo->m_categories.sort(); - } else if (field == "mimeTypes") { - appInfo->m_mimeTypes = variantToStringList(v); - appInfo->m_mimeTypes.sort(); - } else if (field == "applicationProperties") { - const QVariantMap rawMap = v.toMap(); - appInfo->m_sysAppProperties = rawMap.value(qSL("protected")).toMap(); - appInfo->m_allAppProperties = appInfo->m_sysAppProperties; - const QVariantMap pri = rawMap.value(qSL("private")).toMap(); - for (auto it = pri.cbegin(); it != pri.cend(); ++it) - appInfo->m_allAppProperties.insert(it.key(), it.value()); - } else if (field == "version") { - appInfo->m_version = v.toString(); - } else if (field == "opengl") { - appInfo->m_openGLConfiguration = v.toMap(); - - // sanity check - static QStringList validKeys = { - qSL("desktopProfile"), - qSL("esMajorVersion"), - qSL("esMinorVersion") - }; - for (auto it = appInfo->m_openGLConfiguration.cbegin(); - it != appInfo->m_openGLConfiguration.cend(); ++it) { - if (!validKeys.contains(it.key())) { - throw Exception(Error::Parse, "the 'opengl' object contains the unsupported key '%1'") - .arg(it.key()); - } - } - } else if (field == "logging") { - const QVariantMap logging = v.toMap(); - if (!logging.isEmpty()) { - if (logging.size() > 1 || logging.firstKey() != qSL("dlt")) - throw Exception(Error::Parse, "'logging' only supports the 'dlt' key"); - appInfo->m_dlt = logging.value(qSL("dlt")).toMap(); - - // sanity check - for (auto it = appInfo->m_dlt.cbegin(); it != appInfo->m_dlt.cend(); ++it) { - if (it.key() != qSL("id") && it.key() != qSL("description")) - throw Exception(Error::Parse, "unsupported key in 'logging/dlt'"); - } - } - } else if (field == "intents") { - appInfo->m_intents = v.toList(); - } else { - unknownField = true; - } - } else { - unknownField = true; - } - if (unknownField) - throw Exception(Error::Parse, "contains unsupported field: '%1'").arg(field); - } - - app->validate(); - return app.take(); - } catch (const Exception &e) { - throw Exception(e.errorCode(), "Failed to parse manifest file %1: %2").arg(filePath, e.errorString()); - } -} - - -QString YamlApplicationScanner::metaDataFileName() const -{ - return qSL("info.yaml"); -} - -QT_END_NAMESPACE_AM diff --git a/src/application-lib/yamlpackagescanner.cpp b/src/application-lib/yamlpackagescanner.cpp new file mode 100644 index 00000000..9adbd627 --- /dev/null +++ b/src/application-lib/yamlpackagescanner.cpp @@ -0,0 +1,383 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 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 <QJsonDocument> +#include <QJsonParseError> +#include <QJsonObject> +#include <QJsonArray> +#include <QFile> +#include <QFileInfo> +#include <QScopedPointer> + +#include "global.h" +#include "qtyaml.h" +#include "exception.h" +#include "logging.h" +#include "packageinfo.h" +#include "applicationinfo.h" +#include "intentinfo.h" +#include "yamlpackagescanner.h" +#include "utilities.h" + +using Fields = std::vector<std::tuple<QByteArray, bool, const std::function<void(const QVariant &value)>>>; + +QT_BEGIN_NAMESPACE_AM + + +YamlPackageScanner::YamlPackageScanner() +{ } + +PackageInfo *YamlPackageScanner::scan(const QString &filePath) Q_DECL_NOEXCEPT_EXPR(false) +{ + auto parseMap = [](const QVariantMap &map, const Fields &fields) { + QStringList keys = map.keys(); + + for (const auto &field : fields) { + QString fieldName = qL1S(std::get<0>(field)); + + auto it = map.constFind(fieldName); + if (it != map.cend()) { + std::get<2>(field)(it.value()); + } else if (std::get<1>(field)) { // missing, but required + throw Exception("required field missing in YAML: %1").arg(fieldName); + } + keys.removeOne(fieldName); + } + if (!keys.isEmpty()) + throw Exception("unsupported fields found in YAML: %1").arg(keys.join(qSL(", "))); + }; + + + try { + QFile f(filePath); + if (!f.open(QIODevice::ReadOnly)) + throw Exception(f, "could not open file for reading"); + + QtYaml::ParseError parseError; + QVector<QVariant> docs = QtYaml::variantDocumentsFromYaml(f.readAll(), &parseError); + + if (parseError.error != QJsonParseError::NoError) { + throw Exception(Error::IO, "YAML parse error at line %1, column %2: %3") + .arg(parseError.line).arg(parseError.column).arg(parseError.errorString()); + } + + bool legacy = false; + try { + checkYamlFormat(docs, 2 /*number of expected docs*/, { "am-package" }, 1); + } catch (const Exception &e) { + try { + checkYamlFormat(docs, 2 /*number of expected docs*/, { "am-application" }, 1); + qCDebug(LogSystem) << "Manifest file" << f.fileName() << "is still using the legacy 'am-application' format"; + legacy = true; + } catch (const Exception &) { + throw Exception(Error::Parse, "not a valid YAML application meta-data file: %1").arg(e.errorString()); + } + } + + QStringList appIds; // duplicate check + QScopedPointer<PackageInfo> pkgInfo(new PackageInfo); + pkgInfo->setBaseDir(QFileInfo(f).absoluteDir()); + + QScopedPointer<ApplicationInfo> legacyAppInfo(legacy ? new ApplicationInfo(pkgInfo.data()) : nullptr); + + // ----------------- package ----------------- + + Fields fields; + fields.emplace_back("id", true, [&pkgInfo, &legacyAppInfo](const QVariant &v) { + QString id = v.toString(); + if (id.isEmpty()) + throw Exception(Error::Parse, "packages need to have an id"); + pkgInfo->m_id = id; + if (legacyAppInfo) + legacyAppInfo->m_id = pkgInfo->id(); + }); + fields.emplace_back("icon", true, [&pkgInfo](const QVariant &v) { + pkgInfo->m_icon = v.toString(); + }); + fields.emplace_back("name", true, [&pkgInfo](const QVariant &v) { + auto nameMap = v.toMap(); + for (auto it = nameMap.constBegin(); it != nameMap.constEnd(); ++it) + pkgInfo->m_name.insert(it.key(), it.value().toString()); + + if (pkgInfo->m_name.isEmpty()) + throw Exception(Error::Parse, "the 'name' field must not be empty"); + }); + if (!legacy) { + fields.emplace_back("description", false, [&pkgInfo](const QVariant &v) { + auto descriptionMap = v.toMap(); + for (auto it = descriptionMap.constBegin(); it != descriptionMap.constEnd(); ++it) + pkgInfo->m_description.insert(it.key(), it.value().toString()); + }); + } + fields.emplace_back("categories", false, [&pkgInfo](const QVariant &v) { + pkgInfo->m_categories = variantToStringList(v); + pkgInfo->m_categories.sort(); + }); + fields.emplace_back("version", false, [&pkgInfo](const QVariant &v) { + pkgInfo->m_version = v.toString(); + }); + fields.emplace_back("logging", false, [&pkgInfo](const QVariant &v) { + const QVariantMap logging = v.toMap(); + if (!logging.isEmpty()) { + if (logging.size() > 1 || logging.firstKey() != qSL("dlt")) + throw Exception(Error::Parse, "'logging' only supports the 'dlt' key"); + pkgInfo->m_dltConfiguration = logging.value(qSL("dlt")).toMap(); + + // sanity check + for (auto it = pkgInfo->m_dltConfiguration.cbegin(); it != pkgInfo->m_dltConfiguration.cend(); ++it) { + if (it.key() != qSL("id") && it.key() != qSL("description")) + throw Exception(Error::Parse, "unsupported key in 'logging/dlt'"); + } + } + }); + if (legacy) { + fields.emplace_back("code", true, [&legacyAppInfo](const QVariant &v) { + legacyAppInfo->m_codeFilePath = v.toString(); + }); + fields.emplace_back("runtime", true, [&legacyAppInfo](const QVariant &v) { + legacyAppInfo->m_runtimeName = v.toString(); + }); + fields.emplace_back("runtimeParameters", false, [&legacyAppInfo](const QVariant &v) { + legacyAppInfo->m_runtimeParameters = v.toMap(); + }); + fields.emplace_back("supportsApplicationInterface", false, [&legacyAppInfo](const QVariant &v) { + legacyAppInfo->m_supportsApplicationInterface = v.toBool(); + }); + fields.emplace_back("capabilities", false, [&legacyAppInfo](const QVariant &v) { + legacyAppInfo->m_capabilities = variantToStringList(v); + legacyAppInfo->m_capabilities.sort(); + }); + fields.emplace_back("opengl", false, [&legacyAppInfo](const QVariant &v) { + legacyAppInfo->m_openGLConfiguration = v.toMap(); + + // sanity check - could be rewritten using the "fields" mechanism + static QStringList validKeys = { + qSL("desktopProfile"), + qSL("esMajorVersion"), + qSL("esMinorVersion") + }; + for (auto it = legacyAppInfo->m_openGLConfiguration.cbegin(); + it != legacyAppInfo->m_openGLConfiguration.cend(); ++it) { + if (!validKeys.contains(it.key())) { + throw Exception(Error::Parse, "the 'opengl' object contains the unsupported key '%1'") + .arg(it.key()); + } + } + }); + fields.emplace_back("applicationProperties", false, [&legacyAppInfo](const QVariant &v) { + const QVariantMap rawMap = v.toMap(); + legacyAppInfo->m_sysAppProperties = rawMap.value(qSL("protected")).toMap(); + legacyAppInfo->m_allAppProperties = legacyAppInfo->m_sysAppProperties; + const QVariantMap pri = rawMap.value(qSL("private")).toMap(); + for (auto it = pri.cbegin(); it != pri.cend(); ++it) + legacyAppInfo->m_allAppProperties.insert(it.key(), it.value()); + }); + fields.emplace_back("documentUrl", false, [](const QVariant &) { + qCDebug(LogSystem) << " ignoring 'documentUrl'"; + }); + fields.emplace_back("mimeTypes", false, [&legacyAppInfo](const QVariant &v) { + legacyAppInfo->m_supportedMimeTypes = variantToStringList(v); + legacyAppInfo->m_supportedMimeTypes.sort(); + }); + } + + // ----------------- applications ----------------- + + if (!legacy) { + fields.emplace_back("applications", true, [&pkgInfo, &appIds, &parseMap](const QVariant &v) { + QVariantList apps = v.toList(); + + for (auto appsIt = apps.constBegin(); appsIt != apps.constEnd(); ++appsIt) { + QScopedPointer<ApplicationInfo> appInfo(new ApplicationInfo(pkgInfo.data())); + Fields appFields; + + appFields.emplace_back("id", true, [&appInfo, &appIds](const QVariant &v) { + QString id = v.toString(); + if (id.isEmpty()) + throw Exception(Error::Intents, "applications need to have an id"); + if (appIds.contains(id)) + throw Exception(Error::Intents, "found two applications with id %1").arg(id); + appInfo->m_id = id; + }); + appFields.emplace_back("code", true, [&appInfo](const QVariant &v) { + appInfo->m_codeFilePath = v.toString(); + }); + appFields.emplace_back("runtime", true, [&appInfo](const QVariant &v) { + appInfo->m_runtimeName = v.toString(); + }); + appFields.emplace_back("runtimeParameters", false, [&appInfo](const QVariant &v) { + appInfo->m_runtimeParameters = v.toMap(); + }); + appFields.emplace_back("supportsApplicationInterface", false, [&appInfo](const QVariant &v) { + appInfo->m_supportsApplicationInterface = v.toBool(); + }); + appFields.emplace_back("capabilities", false, [&appInfo](const QVariant &v) { + appInfo->m_capabilities = variantToStringList(v); + appInfo->m_capabilities.sort(); + }); + appFields.emplace_back("opengl", false, [&appInfo](const QVariant &v) { + appInfo->m_openGLConfiguration = v.toMap(); + + // sanity check - could be rewritten using the "fields" mechanism + static QStringList validKeys = { + qSL("desktopProfile"), + qSL("esMajorVersion"), + qSL("esMinorVersion") + }; + for (auto it = appInfo->m_openGLConfiguration.cbegin(); + it != appInfo->m_openGLConfiguration.cend(); ++it) { + if (!validKeys.contains(it.key())) { + throw Exception(Error::Parse, "the 'opengl' object contains the unsupported key '%1'") + .arg(it.key()); + } + } + }); + appFields.emplace_back("applicationProperties", false, [&appInfo](const QVariant &v) { + const QVariantMap rawMap = v.toMap(); + appInfo->m_sysAppProperties = rawMap.value(qSL("protected")).toMap(); + appInfo->m_allAppProperties = appInfo->m_sysAppProperties; + const QVariantMap pri = rawMap.value(qSL("private")).toMap(); + for (auto it = pri.cbegin(); it != pri.cend(); ++it) + appInfo->m_allAppProperties.insert(it.key(), it.value()); + }); + + parseMap(appsIt->toMap(), appFields); + pkgInfo->m_applications << appInfo.take(); + } + }); + } + + // ----------------- intents ----------------- + + fields.emplace_back("intents", false, [&pkgInfo, &parseMap, &appIds, legacy](const QVariant &v) { + QVariantList intents = v.toList(); + QStringList intentIds; // duplicate check + + for (auto intentsIt = intents.constBegin(); intentsIt != intents.constEnd(); ++intentsIt) { + QScopedPointer<IntentInfo> intentInfo(new IntentInfo(pkgInfo.data())); + Fields intentFields; + + intentFields.emplace_back("id", true, [&intentInfo, &intentIds, &pkgInfo](const QVariant &v) { + QString id = v.toString(); + if (id.isEmpty()) + throw Exception(Error::Intents, "intents need to have an id (package %1)").arg(pkgInfo->id()); + if (intentIds.contains(id)) + throw Exception(Error::Intents, "found two intent handlers for intent %2 (package %1)").arg(pkgInfo->id()).arg(id); + intentInfo->m_id = id; + }); + intentFields.emplace_back("visibility", false, [&intentInfo](const QVariant &v) { + const QString visibilityStr = v.toString(); + if (visibilityStr == qL1S("private")) { + intentInfo->m_visibility = IntentInfo::Private; + } else if (visibilityStr != qL1S("public")) { + throw Exception(Error::Intents, "intent visibilty '%2' is invalid on intent %1 (valid values are either 'public' or 'private'") + .arg(intentInfo->m_id).arg(visibilityStr); + } + }); + intentFields.emplace_back(legacy ? "handledBy" : "handlingApplicationId", legacy ? false : true, [&pkgInfo, &intentInfo, &appIds](const QVariant &v) { + QString appId = v.toString(); + + if (appId.isEmpty()) { + if (pkgInfo->m_applications.count() == 1) { + intentInfo->m_handlingApplicationId = pkgInfo->m_applications.constFirst()->id(); + } else { + throw Exception(Error::Intents, "a 'handlingApplicationId' field on intent %1 is needed if more than one application is defined") + .arg(intentInfo->m_id); + } + } else { + if (appIds.contains(appId)) { + intentInfo->m_handlingApplicationId = appId; + } else { + throw Exception(Error::Intents, "the 'handlingApplicationId' field on intent %1 points to the unknown application id %2") + .arg(intentInfo->m_id).arg(appId); + } + } + }); + intentFields.emplace_back("requiredCapabilities", false, [&intentInfo](const QVariant &v) { + intentInfo->m_requiredCapabilities = variantToStringList(v); + }); + intentFields.emplace_back("parameterMatch", false, [&intentInfo](const QVariant &v) { + intentInfo->m_parameterMatch = v.toMap(); + }); + intentFields.emplace_back("icon", false, [&intentInfo](const QVariant &v) { + intentInfo->m_icon = v.toString(); + }); + intentFields.emplace_back("name", false, [&intentInfo](const QVariant &v) { + auto nameMap = v.toMap(); + for (auto it = nameMap.constBegin(); it != nameMap.constEnd(); ++it) + intentInfo->m_name.insert(it.key(), it.value().toString()); + }); + intentFields.emplace_back("description", false, [&intentInfo](const QVariant &v) { + auto descriptionMap = v.toMap(); + for (auto it = descriptionMap.constBegin(); it != descriptionMap.constEnd(); ++it) + intentInfo->m_description.insert(it.key(), it.value().toString()); + }); + intentFields.emplace_back("categories", false, [&intentInfo](const QVariant &v) { + intentInfo->m_categories = variantToStringList(v); + intentInfo->m_categories.sort(); + }); + + parseMap(intentsIt->toMap(), intentFields); + pkgInfo->m_intents << intentInfo.take(); + } + }); + + parseMap(docs.at(1).toMap(), fields); + + if (legacy) + pkgInfo->m_applications << legacyAppInfo.take(); + + // validate the ids, runtime names and all referenced files + pkgInfo->validate(); + return pkgInfo.take(); + } catch (const Exception &e) { + throw Exception(e.errorCode(), "Failed to parse manifest file %1: %2").arg(QDir().relativeFilePath(filePath), e.errorString()); + } +} + +QString YamlPackageScanner::metaDataFileName() const +{ + return qSL("info.yaml"); +} + + +QT_END_NAMESPACE_AM diff --git a/src/application-lib/yamlapplicationscanner.h b/src/application-lib/yamlpackagescanner.h index fd667182..d8eb4e22 100644 --- a/src/application-lib/yamlapplicationscanner.h +++ b/src/application-lib/yamlpackagescanner.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -42,26 +42,18 @@ #pragma once -#include <QtAppManApplication/applicationscanner.h> +#include <QtAppManApplication/packagescanner.h> QT_BEGIN_NAMESPACE_AM -class AbstractApplicationInfo; -class YamlApplicationScanner : public ApplicationScanner +class YamlPackageScanner : public PackageScanner { public: - YamlApplicationScanner(); - - ApplicationInfo *scan(const QString &filePath) Q_DECL_NOEXCEPT_EXPR(false) override; - ApplicationAliasInfo *scanAlias(const QString &filePath, - const ApplicationInfo *application) Q_DECL_NOEXCEPT_EXPR(false) override; + YamlPackageScanner(); + PackageInfo *scan(const QString &filePath) Q_DECL_NOEXCEPT_EXPR(false) override; QString metaDataFileName() const override; - -private: - AbstractApplicationInfo *scanInternal(const QString &filePath, bool scanAlias, - const ApplicationInfo *application) Q_DECL_NOEXCEPT_EXPR(false); }; QT_END_NAMESPACE_AM diff --git a/src/common-lib/crashhandler.cpp b/src/common-lib/crashhandler.cpp index 1ec8a83f..95ec9b9f 100644 --- a/src/common-lib/crashhandler.cpp +++ b/src/common-lib/crashhandler.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/common-lib/crashhandler.h b/src/common-lib/crashhandler.h index 79b42730..b09104a8 100644 --- a/src/common-lib/crashhandler.h +++ b/src/common-lib/crashhandler.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/common-lib/dbus-utilities.cpp b/src/common-lib/dbus-utilities.cpp index ff74fb7f..1a8267b6 100644 --- a/src/common-lib/dbus-utilities.cpp +++ b/src/common-lib/dbus-utilities.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/common-lib/dbus-utilities.h b/src/common-lib/dbus-utilities.h index c135d142..fa3de40c 100644 --- a/src/common-lib/dbus-utilities.h +++ b/src/common-lib/dbus-utilities.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/common-lib/error.h b/src/common-lib/error.h index 1e1c16c8..6204783d 100644 --- a/src/common-lib/error.h +++ b/src/common-lib/error.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/common-lib/exception.cpp b/src/common-lib/exception.cpp index 11a54d89..ba3e8020 100644 --- a/src/common-lib/exception.cpp +++ b/src/common-lib/exception.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/common-lib/exception.h b/src/common-lib/exception.h index 3dcdc03a..92e41626 100644 --- a/src/common-lib/exception.h +++ b/src/common-lib/exception.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/common-lib/global.h b/src/common-lib/global.h index c1172b7b..72cec409 100644 --- a/src/common-lib/global.h +++ b/src/common-lib/global.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/common-lib/logging.cpp b/src/common-lib/logging.cpp index 3996d904..09a2b55f 100644 --- a/src/common-lib/logging.cpp +++ b/src/common-lib/logging.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -73,8 +73,8 @@ Q_CORE_EXPORT void qWinMsgHandler(QtMsgType t, const char* str); QT_BEGIN_NAMESPACE_AM #if defined(QT_GENIVIEXTRAS_LIB) -static const char *s_defaultSystemUiDltId = "LXAM"; -static const char *s_defaultSystemUiDltDescription = "Luxoft Application-Manager"; +static const char *s_defaultSystemUiDltId = "QTAM"; +static const char *s_defaultSystemUiDltDescription = "Qt Application Manager"; #endif /* diff --git a/src/common-lib/logging.h b/src/common-lib/logging.h index 7671a6cb..51b64909 100644 --- a/src/common-lib/logging.h +++ b/src/common-lib/logging.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/common-lib/processtitle.cpp b/src/common-lib/processtitle.cpp index c65cdb8f..e2b9401e 100644 --- a/src/common-lib/processtitle.cpp +++ b/src/common-lib/processtitle.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/common-lib/processtitle.h b/src/common-lib/processtitle.h index cecbc150..90c83af5 100644 --- a/src/common-lib/processtitle.h +++ b/src/common-lib/processtitle.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/common-lib/qml-utilities.cpp b/src/common-lib/qml-utilities.cpp index 7cf29393..f3d43965 100644 --- a/src/common-lib/qml-utilities.cpp +++ b/src/common-lib/qml-utilities.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/common-lib/qml-utilities.h b/src/common-lib/qml-utilities.h index 9c9f125d..e13a1f10 100644 --- a/src/common-lib/qml-utilities.h +++ b/src/common-lib/qml-utilities.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/common-lib/qtyaml.cpp b/src/common-lib/qtyaml.cpp index fbb75f50..c840550e 100644 --- a/src/common-lib/qtyaml.cpp +++ b/src/common-lib/qtyaml.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/common-lib/qtyaml.h b/src/common-lib/qtyaml.h index 11edb200..2130fae7 100644 --- a/src/common-lib/qtyaml.h +++ b/src/common-lib/qtyaml.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/common-lib/startuptimer.cpp b/src/common-lib/startuptimer.cpp index 861df663..f007166b 100644 --- a/src/common-lib/startuptimer.cpp +++ b/src/common-lib/startuptimer.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/common-lib/startuptimer.h b/src/common-lib/startuptimer.h index ab2ead55..89f9282e 100644 --- a/src/common-lib/startuptimer.h +++ b/src/common-lib/startuptimer.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/common-lib/unixsignalhandler.cpp b/src/common-lib/unixsignalhandler.cpp index 897a3103..cd51fae3 100644 --- a/src/common-lib/unixsignalhandler.cpp +++ b/src/common-lib/unixsignalhandler.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/common-lib/unixsignalhandler.h b/src/common-lib/unixsignalhandler.h index da2fd0d5..f1de44f1 100644 --- a/src/common-lib/unixsignalhandler.h +++ b/src/common-lib/unixsignalhandler.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/common-lib/utilities.cpp b/src/common-lib/utilities.cpp index b489fe56..392c78dd 100644 --- a/src/common-lib/utilities.cpp +++ b/src/common-lib/utilities.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -120,7 +120,7 @@ void checkYamlFormat(const QVector<QVariant> &docs, int numberOfDocuments, } if (numberOfDocuments < 0) { - if (actualSize < numberOfDocuments) { + if (actualSize < -numberOfDocuments) { throw Exception("wrong number of YAML documents: expected at least %1, got %2") .arg(-numberOfDocuments).arg(actualSize); } @@ -131,7 +131,7 @@ void checkYamlFormat(const QVector<QVariant> &docs, int numberOfDocuments, } } if (!formatTypes.contains(actualFormatType)) { - throw Exception("wrong formatType header: expected %1, got %2") + throw Exception("wrong formatType header: expected '%1', got '%2'") .arg(QString::fromUtf8(formatTypes.toList().join(", or ")), QString::fromUtf8(actualFormatType)); } if (actualFormatVersion != formatVersion) { diff --git a/src/common-lib/utilities.h b/src/common-lib/utilities.h index 9910ce1c..ba8c7006 100644 --- a/src/common-lib/utilities.h +++ b/src/common-lib/utilities.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/crypto-lib/cryptography.cpp b/src/crypto-lib/cryptography.cpp index 17feaaa5..6e3fb327 100644 --- a/src/crypto-lib/cryptography.cpp +++ b/src/crypto-lib/cryptography.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/crypto-lib/cryptography.h b/src/crypto-lib/cryptography.h index e5b609b9..bc3c8a28 100644 --- a/src/crypto-lib/cryptography.h +++ b/src/crypto-lib/cryptography.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/crypto-lib/libcryptofunction.cpp b/src/crypto-lib/libcryptofunction.cpp index 943f9df0..362307cd 100644 --- a/src/crypto-lib/libcryptofunction.cpp +++ b/src/crypto-lib/libcryptofunction.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/crypto-lib/libcryptofunction.h b/src/crypto-lib/libcryptofunction.h index 5e8ff057..d60537d5 100644 --- a/src/crypto-lib/libcryptofunction.h +++ b/src/crypto-lib/libcryptofunction.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/crypto-lib/signature.cpp b/src/crypto-lib/signature.cpp index 34b33e29..320f17b0 100644 --- a/src/crypto-lib/signature.cpp +++ b/src/crypto-lib/signature.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/crypto-lib/signature.h b/src/crypto-lib/signature.h index 3b4dbd87..2e26d81c 100644 --- a/src/crypto-lib/signature.h +++ b/src/crypto-lib/signature.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/crypto-lib/signature_macos.cpp b/src/crypto-lib/signature_macos.cpp index fd565cd2..824474fc 100644 --- a/src/crypto-lib/signature_macos.cpp +++ b/src/crypto-lib/signature_macos.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/crypto-lib/signature_openssl.cpp b/src/crypto-lib/signature_openssl.cpp index 7fa38d54..27b999a9 100644 --- a/src/crypto-lib/signature_openssl.cpp +++ b/src/crypto-lib/signature_openssl.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/crypto-lib/signature_p.h b/src/crypto-lib/signature_p.h index e16896dc..1a8bee96 100644 --- a/src/crypto-lib/signature_p.h +++ b/src/crypto-lib/signature_p.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/crypto-lib/signature_win.cpp b/src/crypto-lib/signature_win.cpp index 1e05c013..31cc5fc3 100644 --- a/src/crypto-lib/signature_win.cpp +++ b/src/crypto-lib/signature_win.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/dbus-lib/abstractdbuscontextadaptor.cpp b/src/dbus-lib/abstractdbuscontextadaptor.cpp index 0716b3e4..aee9a521 100644 --- a/src/dbus-lib/abstractdbuscontextadaptor.cpp +++ b/src/dbus-lib/abstractdbuscontextadaptor.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/dbus-lib/abstractdbuscontextadaptor.h b/src/dbus-lib/abstractdbuscontextadaptor.h index 683dc04f..4753e636 100644 --- a/src/dbus-lib/abstractdbuscontextadaptor.h +++ b/src/dbus-lib/abstractdbuscontextadaptor.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/dbus-lib/applicationinstallerdbuscontextadaptor.cpp b/src/dbus-lib/applicationinstallerdbuscontextadaptor.cpp deleted file mode 100644 index de5097cd..00000000 --- a/src/dbus-lib/applicationinstallerdbuscontextadaptor.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** 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 "applicationinstallerdbuscontextadaptor.h" -#include "applicationinstaller.h" -#include "io.qt.applicationinstaller_adaptor.h" -#include "dbuspolicy.h" -#include "exception.h" -#include "logging.h" - - -QT_BEGIN_NAMESPACE_AM - -static QString taskStateToString(AsynchronousTask::TaskState state) -{ - const char *cstr = QMetaEnum::fromType<AsynchronousTask::TaskState>().valueToKey(state); - return QString::fromUtf8(cstr); -} - -ApplicationInstallerDBusContextAdaptor::ApplicationInstallerDBusContextAdaptor(ApplicationInstaller *ai) - : AbstractDBusContextAdaptor(ai) -{ - m_adaptor = new ApplicationInstallerAdaptor(this); -} - -QT_END_NAMESPACE_AM - -///////////////////////////////////////////////////////////////////////////////////// - -QT_USE_NAMESPACE_AM - -ApplicationInstallerAdaptor::ApplicationInstallerAdaptor(QObject *parent) - : QDBusAbstractAdaptor(parent) -{ - auto ai = ApplicationInstaller::instance(); - - connect(ai, &ApplicationInstaller::taskBlockingUntilInstallationAcknowledge, - this, &ApplicationInstallerAdaptor::taskBlockingUntilInstallationAcknowledge); - connect(ai, &ApplicationInstaller::taskFailed, - this, &ApplicationInstallerAdaptor::taskFailed); - connect(ai, &ApplicationInstaller::taskFinished, - this, &ApplicationInstallerAdaptor::taskFinished); - connect(ai, &ApplicationInstaller::taskProgressChanged, - this, &ApplicationInstallerAdaptor::taskProgressChanged); - connect(ai, &ApplicationInstaller::taskRequestingInstallationAcknowledge, - this, &ApplicationInstallerAdaptor::taskRequestingInstallationAcknowledge); - connect(ai, &ApplicationInstaller::taskStarted, - this, &ApplicationInstallerAdaptor::taskStarted); - connect(ai, &ApplicationInstaller::taskStateChanged, - [this](const QString &taskId, AsynchronousTask::TaskState newState) { - emit taskStateChanged(taskId, taskStateToString(newState)); - }); -} - -ApplicationInstallerAdaptor::~ApplicationInstallerAdaptor() -{ } - -bool ApplicationInstallerAdaptor::allowInstallationOfUnsignedPackages() const -{ - return ApplicationInstaller::instance()->allowInstallationOfUnsignedPackages(); -} - -bool ApplicationInstallerAdaptor::applicationUserIdSeparation() const -{ - return ApplicationInstaller::instance()->isApplicationUserIdSeparationEnabled(); -} - -uint ApplicationInstallerAdaptor::commonApplicationGroupId() const -{ - return ApplicationInstaller::instance()->commonApplicationGroupId(); -} - -bool ApplicationInstallerAdaptor::developmentMode() const -{ - return ApplicationInstaller::instance()->developmentMode(); -} - -void ApplicationInstallerAdaptor::acknowledgePackageInstallation(const QString &taskId) -{ - AM_AUTHENTICATE_DBUS(void) - return ApplicationInstaller::instance()->acknowledgePackageInstallation(taskId); -} - -bool ApplicationInstallerAdaptor::cancelTask(const QString &taskId) -{ - AM_AUTHENTICATE_DBUS(bool) - return ApplicationInstaller::instance()->cancelTask(taskId); -} - -int ApplicationInstallerAdaptor::compareVersions(const QString &version1, const QString &version2) -{ - AM_AUTHENTICATE_DBUS(int) - return ApplicationInstaller::instance()->compareVersions(version1, version2); -} - -QVariantMap ApplicationInstallerAdaptor::getInstallationLocation(const QString &installationLocationId) -{ - AM_AUTHENTICATE_DBUS(QVariantMap) - return ApplicationInstaller::instance()->getInstallationLocation(installationLocationId); -} - -QString ApplicationInstallerAdaptor::installationLocationIdFromApplication(const QString &id) -{ - AM_AUTHENTICATE_DBUS(QString) - return ApplicationInstaller::instance()->installationLocationIdFromApplication(id); -} - -QStringList ApplicationInstallerAdaptor::installationLocationIds() -{ - AM_AUTHENTICATE_DBUS(QStringList) - return ApplicationInstaller::instance()->installationLocationIds(); -} - -qlonglong ApplicationInstallerAdaptor::installedApplicationSize(const QString &id) -{ - AM_AUTHENTICATE_DBUS(qlonglong) - return ApplicationInstaller::instance()->installedApplicationSize(id); -} - -QVariantMap ApplicationInstallerAdaptor::installedApplicationExtraMetaData(const QString &id) -{ - AM_AUTHENTICATE_DBUS(QVariantMap) - return ApplicationInstaller::instance()->installedApplicationExtraMetaData(id); -} - -QVariantMap ApplicationInstallerAdaptor::installedApplicationExtraSignedMetaData(const QString &id) -{ - AM_AUTHENTICATE_DBUS(QVariantMap) - return ApplicationInstaller::instance()->installedApplicationExtraSignedMetaData(id); -} - -QString ApplicationInstallerAdaptor::removePackage(const QString &id, bool keepDocuments) -{ - return removePackage(id, keepDocuments, false); -} - -QString ApplicationInstallerAdaptor::removePackage(const QString &id, bool keepDocuments, bool force) -{ - AM_AUTHENTICATE_DBUS(QString) - return ApplicationInstaller::instance()->removePackage(id, keepDocuments, force); -} - -QString ApplicationInstallerAdaptor::startPackageInstallation(const QString &installationLocationId, const QString &sourceUrl) -{ - AM_AUTHENTICATE_DBUS(QString) - return ApplicationInstaller::instance()->startPackageInstallation(installationLocationId, sourceUrl); -} - -QString ApplicationInstallerAdaptor::taskState(const QString &taskId) -{ - AM_AUTHENTICATE_DBUS(QString) - return taskStateToString(ApplicationInstaller::instance()->taskState(taskId)); -} - -QString ApplicationInstallerAdaptor::taskApplicationId(const QString &taskId) -{ - AM_AUTHENTICATE_DBUS(QString) - return ApplicationInstaller::instance()->taskApplicationId(taskId); -} - -QStringList ApplicationInstallerAdaptor::activeTaskIds() -{ - AM_AUTHENTICATE_DBUS(QStringList) - return ApplicationInstaller::instance()->activeTaskIds(); -} diff --git a/src/dbus-lib/applicationmanagerdbuscontextadaptor.cpp b/src/dbus-lib/applicationmanagerdbuscontextadaptor.cpp index 3ca02d65..5794e79a 100644 --- a/src/dbus-lib/applicationmanagerdbuscontextadaptor.cpp +++ b/src/dbus-lib/applicationmanagerdbuscontextadaptor.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/dbus-lib/applicationmanagerdbuscontextadaptor.h b/src/dbus-lib/applicationmanagerdbuscontextadaptor.h index 073697cd..02a2a805 100644 --- a/src/dbus-lib/applicationmanagerdbuscontextadaptor.h +++ b/src/dbus-lib/applicationmanagerdbuscontextadaptor.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/dbus-lib/dbus-lib.pro b/src/dbus-lib/dbus-lib.pro index 567fb0f3..5635fdf0 100644 --- a/src/dbus-lib/dbus-lib.pro +++ b/src/dbus-lib/dbus-lib.pro @@ -32,10 +32,9 @@ ADAPTORS_XML = \ org.freedesktop.notifications.xml \ !disable-installer { - QT *= appman_installer-private - HEADERS += applicationinstallerdbuscontextadaptor.h - SOURCES += applicationinstallerdbuscontextadaptor.cpp - ADAPTORS_XML += io.qt.applicationinstaller.xml + HEADERS += packagemanagerdbuscontextadaptor.h + SOURCES += packagemanagerdbuscontextadaptor.cpp + ADAPTORS_XML += io.qt.packagemanager.xml } !headless{ @@ -46,7 +45,7 @@ ADAPTORS_XML = \ } OTHER_FILES = \ - io.qt.applicationinstaller.xml \ + io.qt.packagemanager.xml \ io.qt.applicationmanager.applicationinterface.xml \ io.qt.applicationmanager.runtimeinterface.xml \ io.qt.applicationmanager.intentinterface.xml \ @@ -59,8 +58,8 @@ qtPrepareTool(QDBUSCPP2XML, qdbuscpp2xml) recreate-applicationmanager-dbus-xml.CONFIG = phony recreate-applicationmanager-dbus-xml.commands = $$QDBUSCPP2XML -a $$PWD/../manager-lib/applicationmanager.h -o $$PWD/io.qt.applicationmanager.xml -recreate-applicationinstaller-dbus-xml.CONFIG = phony -recreate-applicationinstaller-dbus-xml.commands = $$QDBUSCPP2XML -a $$PWD/../installer-lib/applicationinstaller.h -o $$PWD/io.qt.applicationinstaller.xml +recreate-packagemanager-dbus-xml.CONFIG = phony +recreate-packagemanager-dbus-xml.commands = $$QDBUSCPP2XML -a $$PWD/../installer-lib/packagemanager.h -o $$PWD/io.qt.packagemanager.xml recreate-windowmanager-dbus-xml.CONFIG = phony recreate-windowmanager-dbus-xml.commands = $$QDBUSCPP2XML -a $$PWD/../manager/windowmanager.h -o $$PWD/io.qt.windowmanager.xml @@ -70,7 +69,7 @@ recreate-dbus-xml.depends = recreate-applicationmanager-dbus-xml recreate-applic QMAKE_EXTRA_TARGETS += \ recreate-dbus-xml \ recreate-applicationmanager-dbus-xml \ - recreate-applicationinstaller-dbus-xml \ + recreate-packagemanager-dbus-xml \ recreate-windowmanager-dbus-xml \ load(qt_module) diff --git a/src/dbus-lib/dbusdaemon.cpp b/src/dbus-lib/dbusdaemon.cpp index 94533c3e..0e0117f7 100644 --- a/src/dbus-lib/dbusdaemon.cpp +++ b/src/dbus-lib/dbusdaemon.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/dbus-lib/dbusdaemon.h b/src/dbus-lib/dbusdaemon.h index 34569bc3..ca3fdd4b 100644 --- a/src/dbus-lib/dbusdaemon.h +++ b/src/dbus-lib/dbusdaemon.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/dbus-lib/dbuspolicy.cpp b/src/dbus-lib/dbuspolicy.cpp index bf1a66b5..ef6214f6 100644 --- a/src/dbus-lib/dbuspolicy.cpp +++ b/src/dbus-lib/dbuspolicy.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/dbus-lib/dbuspolicy.h b/src/dbus-lib/dbuspolicy.h index fcdeed9c..e32c03d4 100644 --- a/src/dbus-lib/dbuspolicy.h +++ b/src/dbus-lib/dbuspolicy.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/dbus-lib/io.qt.applicationinstaller.xml b/src/dbus-lib/io.qt.packagemanager.xml index 913ce760..37e41b9d 100644 --- a/src/dbus-lib/io.qt.applicationinstaller.xml +++ b/src/dbus-lib/io.qt.packagemanager.xml @@ -1,10 +1,16 @@ <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> <node> - <interface name="io.qt.ApplicationInstaller"> + <interface name="io.qt.PackageManager"> <property name="allowInstallationOfUnsignedPackages" type="b" access="read"/> <property name="developmentMode" type="b" access="read"/> <property name="applicationUserIdSeparation" type="b" access="read"/> <property name="commonApplicationGroupId" type="u" access="read"/> + <property name="installationLocation" type="v" access="read"> + <annotation name="org.qtproject.QtDBus.QtTypeName" value="QVariantMap"/> + </property> + <property name="documentLocation" type="v" access="read"> + <annotation name="org.qtproject.QtDBus.QtTypeName" value="QVariantMap"/> + </property> <signal name="taskStarted"> <arg name="taskId" type="s" direction="out"/> </signal> @@ -26,7 +32,7 @@ </signal> <signal name="taskRequestingInstallationAcknowledge"> <arg name="taskId" type="s" direction="out"/> - <arg name="applicationAsVariantMap" type="a{sv}" direction="out"/> + <arg name="packageAsVariantMap" type="a{sv}" direction="out"/> <annotation name="org.qtproject.QtDBus.QtTypeName.Out1" value="QVariantMap"/> <arg name="packageExtraMetaData" type="a{sv}" direction="out"/> <annotation name="org.qtproject.QtDBus.QtTypeName.Out2" value="QVariantMap"/> @@ -36,21 +42,16 @@ <signal name="taskBlockingUntilInstallationAcknowledge"> <arg name="taskId" type="s" direction="out"/> </signal> - <method name="installationLocationIds"> + <method name="packageIds"> <arg type="as" direction="out"/> </method> - <method name="installationLocationIdFromApplication"> - <arg type="s" direction="out"/> - <arg name="id" type="s" direction="in"/> - </method> - <method name="getInstallationLocation"> + <method name="get"> <arg type="a{sv}" direction="out"/> <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/> - <arg name="installationLocationId" type="s" direction="in"/> + <arg name="id" type="s" direction="in"/> </method> <method name="startPackageInstallation"> <arg type="s" direction="out"/> - <arg name="installationLocationId" type="s" direction="in"/> <arg name="sourceUrl" type="s" direction="in"/> </method> <method name="acknowledgePackageInstallation"> @@ -71,7 +72,7 @@ <arg type="s" direction="out"/> <arg name="taskId" type="s" direction="in"/> </method> - <method name="taskApplicationId"> + <method name="taskPackageId"> <arg type="s" direction="out"/> <arg name="taskId" type="s" direction="in"/> </method> @@ -87,16 +88,16 @@ <arg name="version1" type="s" direction="in"/> <arg name="version2" type="s" direction="in"/> </method> - <method name="installedApplicationSize"> + <method name="installedPackageSize"> <arg type="x" direction="out"/> <arg name="id" type="s" direction="in"/> </method> - <method name="installedApplicationExtraMetaData"> + <method name="installedPackageExtraMetaData"> <arg type="a{sv}" direction="out"/> <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/> <arg name="id" type="s" direction="in"/> </method> - <method name="installedApplicationExtraSignedMetaData"> + <method name="installedPackageExtraSignedMetaData"> <arg type="a{sv}" direction="out"/> <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QVariantMap"/> <arg name="id" type="s" direction="in"/> diff --git a/src/dbus-lib/notificationmanagerdbuscontextadaptor.cpp b/src/dbus-lib/notificationmanagerdbuscontextadaptor.cpp index eeaefaff..ed80d6a5 100644 --- a/src/dbus-lib/notificationmanagerdbuscontextadaptor.cpp +++ b/src/dbus-lib/notificationmanagerdbuscontextadaptor.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/dbus-lib/notificationmanagerdbuscontextadaptor.h b/src/dbus-lib/notificationmanagerdbuscontextadaptor.h index bcced38f..6f71bdbe 100644 --- a/src/dbus-lib/notificationmanagerdbuscontextadaptor.h +++ b/src/dbus-lib/notificationmanagerdbuscontextadaptor.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/dbus-lib/packagemanagerdbuscontextadaptor.cpp b/src/dbus-lib/packagemanagerdbuscontextadaptor.cpp new file mode 100644 index 00000000..b423389c --- /dev/null +++ b/src/dbus-lib/packagemanagerdbuscontextadaptor.cpp @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 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 "packagemanagerdbuscontextadaptor.h" +#include "packagemanager.h" +#include "io.qt.packagemanager_adaptor.h" +#include "dbuspolicy.h" +#include "exception.h" +#include "logging.h" + + +QT_BEGIN_NAMESPACE_AM + +static QString taskStateToString(AsynchronousTask::TaskState state) +{ + const char *cstr = QMetaEnum::fromType<AsynchronousTask::TaskState>().valueToKey(state); + return QString::fromUtf8(cstr); +} + +PackageManagerDBusContextAdaptor::PackageManagerDBusContextAdaptor(PackageManager *pm) + : AbstractDBusContextAdaptor(pm) +{ + m_adaptor = new PackageManagerAdaptor(this); +} + +QT_END_NAMESPACE_AM + +///////////////////////////////////////////////////////////////////////////////////// + +QT_USE_NAMESPACE_AM + +PackageManagerAdaptor::PackageManagerAdaptor(QObject *parent) + : QDBusAbstractAdaptor(parent) +{ + auto ai = PackageManager::instance(); + + connect(ai, &PackageManager::taskBlockingUntilInstallationAcknowledge, + this, &PackageManagerAdaptor::taskBlockingUntilInstallationAcknowledge); + connect(ai, &PackageManager::taskFailed, + this, &PackageManagerAdaptor::taskFailed); + connect(ai, &PackageManager::taskFinished, + this, &PackageManagerAdaptor::taskFinished); + connect(ai, &PackageManager::taskProgressChanged, + this, &PackageManagerAdaptor::taskProgressChanged); + connect(ai, &PackageManager::taskRequestingInstallationAcknowledge, + this, &PackageManagerAdaptor::taskRequestingInstallationAcknowledge); + connect(ai, &PackageManager::taskStarted, + this, &PackageManagerAdaptor::taskStarted); + connect(ai, &PackageManager::taskStateChanged, + [this](const QString &taskId, AsynchronousTask::TaskState newState) { + emit taskStateChanged(taskId, taskStateToString(newState)); + }); +} + +PackageManagerAdaptor::~PackageManagerAdaptor() +{ } + +bool PackageManagerAdaptor::allowInstallationOfUnsignedPackages() const +{ + return PackageManager::instance()->allowInstallationOfUnsignedPackages(); +} + +bool PackageManagerAdaptor::applicationUserIdSeparation() const +{ + return PackageManager::instance()->isApplicationUserIdSeparationEnabled(); +} + +uint PackageManagerAdaptor::commonApplicationGroupId() const +{ + return PackageManager::instance()->commonApplicationGroupId(); +} + +bool PackageManagerAdaptor::developmentMode() const +{ + return PackageManager::instance()->developmentMode(); +} + +QDBusVariant PackageManagerAdaptor::installationLocation() const +{ + return QDBusVariant(PackageManager::instance()->installationLocation()); +} + +QDBusVariant PackageManagerAdaptor::documentLocation() const +{ + return QDBusVariant(PackageManager::instance()->documentLocation()); +} + +void PackageManagerAdaptor::acknowledgePackageInstallation(const QString &taskId) +{ + AM_AUTHENTICATE_DBUS(void) + return PackageManager::instance()->acknowledgePackageInstallation(taskId); +} + +bool PackageManagerAdaptor::cancelTask(const QString &taskId) +{ + AM_AUTHENTICATE_DBUS(bool) + return PackageManager::instance()->cancelTask(taskId); +} + +int PackageManagerAdaptor::compareVersions(const QString &version1, const QString &version2) +{ + AM_AUTHENTICATE_DBUS(int) + return PackageManager::instance()->compareVersions(version1, version2); +} + +QStringList PackageManagerAdaptor::packageIds() +{ + AM_AUTHENTICATE_DBUS(QStringList) + return PackageManager::instance()->packageIds(); +} + +QVariantMap PackageManagerAdaptor::get(const QString &id) +{ + AM_AUTHENTICATE_DBUS(QVariantMap) + auto map = PackageManager::instance()->get(id); + map.remove(qSL("package")); // cannot marshall QObject * + return map; +} + +qlonglong PackageManagerAdaptor::installedPackageSize(const QString &packageId) +{ + AM_AUTHENTICATE_DBUS(qlonglong) + return PackageManager::instance()->installedPackageSize(packageId); +} + +QVariantMap PackageManagerAdaptor::installedPackageExtraMetaData(const QString &packageId) +{ + AM_AUTHENTICATE_DBUS(QVariantMap) + return PackageManager::instance()->installedPackageExtraMetaData(packageId); +} + +QVariantMap PackageManagerAdaptor::installedPackageExtraSignedMetaData(const QString &packageId) +{ + AM_AUTHENTICATE_DBUS(QVariantMap) + return PackageManager::instance()->installedPackageExtraSignedMetaData(packageId); +} + +QString PackageManagerAdaptor::removePackage(const QString &packageId, bool keepDocuments) +{ + return removePackage(packageId, keepDocuments, false); +} + +QString PackageManagerAdaptor::removePackage(const QString &packageId, bool keepDocuments, bool force) +{ + AM_AUTHENTICATE_DBUS(QString) + return PackageManager::instance()->removePackage(packageId, keepDocuments, force); +} + +QString PackageManagerAdaptor::startPackageInstallation(const QString &sourceUrl) +{ + AM_AUTHENTICATE_DBUS(QString) + return PackageManager::instance()->startPackageInstallation(sourceUrl); +} + +QString PackageManagerAdaptor::taskState(const QString &taskId) +{ + AM_AUTHENTICATE_DBUS(QString) + return taskStateToString(PackageManager::instance()->taskState(taskId)); +} + +QString PackageManagerAdaptor::taskPackageId(const QString &taskId) +{ + AM_AUTHENTICATE_DBUS(QString) + return PackageManager::instance()->taskPackageId(taskId); +} + +QStringList PackageManagerAdaptor::activeTaskIds() +{ + AM_AUTHENTICATE_DBUS(QStringList) + return PackageManager::instance()->activeTaskIds(); +} diff --git a/src/dbus-lib/applicationinstallerdbuscontextadaptor.h b/src/dbus-lib/packagemanagerdbuscontextadaptor.h index 98cac67d..8eb30e88 100644 --- a/src/dbus-lib/applicationinstallerdbuscontextadaptor.h +++ b/src/dbus-lib/packagemanagerdbuscontextadaptor.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -46,12 +46,12 @@ QT_BEGIN_NAMESPACE_AM -class ApplicationInstaller; +class PackageManager; -class ApplicationInstallerDBusContextAdaptor : public AbstractDBusContextAdaptor +class PackageManagerDBusContextAdaptor : public AbstractDBusContextAdaptor { public: - explicit ApplicationInstallerDBusContextAdaptor(ApplicationInstaller *am); + explicit PackageManagerDBusContextAdaptor(PackageManager *pm); }; QT_END_NAMESPACE_AM diff --git a/src/dbus-lib/windowmanagerdbuscontextadaptor.cpp b/src/dbus-lib/windowmanagerdbuscontextadaptor.cpp index cf18f049..b6b1b5a2 100644 --- a/src/dbus-lib/windowmanagerdbuscontextadaptor.cpp +++ b/src/dbus-lib/windowmanagerdbuscontextadaptor.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/dbus-lib/windowmanagerdbuscontextadaptor.h b/src/dbus-lib/windowmanagerdbuscontextadaptor.h index 8d749a3d..a78907bc 100644 --- a/src/dbus-lib/windowmanagerdbuscontextadaptor.h +++ b/src/dbus-lib/windowmanagerdbuscontextadaptor.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/installer-lib/applicationinstaller.cpp b/src/installer-lib/applicationinstaller.cpp deleted file mode 100644 index 10fae7ca..00000000 --- a/src/installer-lib/applicationinstaller.cpp +++ /dev/null @@ -1,1042 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** 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 <QCoreApplication> -#include <QDir> -#include <QUuid> - -#include "logging.h" -#include "application.h" -#include "applicationinstaller.h" -#include "applicationinstaller_p.h" -#include "installationtask.h" -#include "deinstallationtask.h" -#include "sudo.h" -#include "utilities.h" -#include "exception.h" -#include "global.h" -#include "qml-utilities.h" -#include "applicationmanager.h" - - -/*! - \qmltype ApplicationInstaller - \inqmlmodule QtApplicationManager.SystemUI - \ingroup system-ui-singletons - \brief The package installation/removal/update part of the application-manager. - - The ApplicationInstaller singleton type handles the package installation - part of the application manager. It provides both a DBus and QML APIs for - all of its functionality. - - \note The ApplicationInstaller singleton and its corresponding DBus API are only available if you - specify a base directory for installed application manifests. See \l{Configuration} for details. - - \target TaskStates - - The following table describes all possible states that a background task could be in: - - \table - \header - \li Task State - \li Description - \row - \li \c Queued - \li The task was created and is now queued up for execution. - \row - \li \c Executing - \li The task is being executed. - \row - \li \c Finished - \li The task was executed successfully. - \row - \li \c Failed - \li The task failed to execute successfully. - \row - \li \c AwaitingAcknowledge - \li \e{Installation tasks only!} The task is currently halted, waiting for either - acknowledgePackageInstallation() or cancelTask() to continue. See startPackageInstallation() - for more information on the installation workflow. - \row - \li \c Installing - \li \e{Installation tasks only!} The installation was acknowledged via acknowledgePackageInstallation() - and the final installation phase is now running. - \row - \li \c CleaningUp - \li \e{Installation tasks only!} The installation has finished, and previous installations as - well as temporary files are being cleaned up. - \endtable - - The normal workflow for tasks is: \c Queued \unicode{0x2192} \c Executing \unicode{0x2192} \c - Finished. The task can enter the \c Failed state at any point though - either by being canceled via - cancelTask() or simply by failing due to an error. - - Installation tasks are a bit more complex due to the acknowledgment: \c Queued \unicode{0x2192} - \c Executing \unicode{0x2192} \c AwaitingAcknowledge (this state may be skipped if - acknowledgePackageInstallation() was called already) \unicode{0x2192} \c Installing - \unicode{0x2192} \c Cleanup \unicode{0x2192} \c Finished. Again, the task can fail at any point. -*/ - -// THIS IS MISSING AN EXAMPLE! - -/*! - \qmlsignal ApplicationInstaller::taskStateChanged(string taskId, string newState) - - This signal is emitted when the state of the task identified by \a taskId changes. The - new state is supplied in the parameter \a newState. - - \sa taskState() -*/ - -/*! - \qmlsignal ApplicationInstaller::taskStarted(string taskId) - - This signal is emitted when the task identified by \a taskId enters the \c Executing state. - - \sa taskStateChanged() -*/ - -/*! - \qmlsignal ApplicationInstaller::taskFinished(string taskId) - - This signal is emitted when the task identified by \a taskId enters the \c Finished state. - - \sa taskStateChanged() -*/ - -/*! - \qmlsignal ApplicationInstaller::taskFailed(string taskId) - - This signal is emitted when the task identified by \a taskId enters the \c Failed state. - - \sa taskStateChanged() -*/ - -/*! - \qmlsignal ApplicationInstaller::taskRequestingInstallationAcknowledge(string taskId, object application, object packageExtraMetaData, object packageExtraSignedMetaData) - - This signal is emitted when the installation task identified by \a taskId has received enough - meta-data to be able to emit this signal. The task may be in either \c Executing or \c - AwaitingAcknowledge state. - - The contents of the package's manifest file are supplied via \a application as a JavaScript object. - Please see the \l {ApplicationManager Roles}{role names} for the expected object fields. - - In addition, the package's extra meta-data (signed and unsinged) is also supplied via \a - packageExtraMetaData and \a packageExtraSignedMetaData respectively as JavaScript objects. - Both these objects are optional and need to be explicitly either populated during an - application's packaging step or added by an intermediary app-store server. - By default, both will just be empty. - - Following this signal, either cancelTask() or acknowledgePackageInstallation() has to be called - for this \a taskId, to either cancel the installation or try to complete it. - - The ApplicationInstaller has two convenience functions to help the System-UI with verifying the - meta-data: compareVersions() and, in case you are using reverse-DNS notation for application-ids, - validateDnsName(). - - \sa taskStateChanged(), startPackageInstallation() -*/ - -/*! - \qmlsignal ApplicationInstaller::taskBlockingUntilInstallationAcknowledge(string taskId) - - This signal is emitted when the installation task identified by \a taskId cannot continue - due to a missing acknowledgePackageInstallation() call for the task. - - \sa taskStateChanged(), acknowledgePackageInstallation() -*/ - -/*! - \qmlsignal ApplicationInstaller::taskProgressChanged(string taskId, qreal progress) - - This signal is emitted whenever the task identified by \a taskId makes progress towards its - completion. The \a progress is reported as a floating-point number ranging from \c 0.0 to \c 1.0. - - \sa taskStateChanged() -*/ - -QT_BEGIN_NAMESPACE_AM - -ApplicationInstaller *ApplicationInstaller::s_instance = nullptr; - -ApplicationInstaller::ApplicationInstaller(const QVector<InstallationLocation> &installationLocations, - QDir *manifestDir, const QString &hardwareId, - QObject *parent) - : QObject(parent) - , d(new ApplicationInstallerPrivate()) -{ - d->installationLocations = installationLocations; - d->manifestDir.reset(manifestDir); - d->hardwareId = hardwareId; -} - -ApplicationInstaller::~ApplicationInstaller() -{ - delete d; - s_instance = nullptr; -} - -ApplicationInstaller *ApplicationInstaller::createInstance(const QVector<InstallationLocation> &installationLocations, - const QString &manifestDirPath, - const QString &hardwareId, QString *error) -{ - if (Q_UNLIKELY(s_instance)) - qFatal("ApplicationInstaller::createInstance() was called a second time."); - - qRegisterMetaType<AsynchronousTask *>(); - qRegisterMetaType<AsynchronousTask::TaskState>(); - - QScopedPointer<QDir> manifestDir(new QDir(manifestDirPath)); - - if (Q_UNLIKELY(!manifestDir->exists())) { - if (error) - *error = qL1S("ApplicationInstaller::createInstance() could not access the manifest directory ") + manifestDir->absolutePath(); - return nullptr; - } - - qmlRegisterSingletonType<ApplicationInstaller>("QtApplicationManager.SystemUI", 2, 0, "ApplicationInstaller", - &ApplicationInstaller::instanceForQml); - - return s_instance = new ApplicationInstaller(installationLocations, manifestDir.take(), - hardwareId, QCoreApplication::instance()); -} - -ApplicationInstaller *ApplicationInstaller::instance() -{ - if (!s_instance) - qFatal("ApplicationInstaller::instance() was called before createInstance()."); - return s_instance; -} - -QObject *ApplicationInstaller::instanceForQml(QQmlEngine *, QJSEngine *) -{ - QQmlEngine::setObjectOwnership(instance(), QQmlEngine::CppOwnership); - return instance(); -} - -bool ApplicationInstaller::developmentMode() const -{ - return d->developmentMode; -} - -void ApplicationInstaller::setDevelopmentMode(bool b) -{ - d->developmentMode = b; -} - -bool ApplicationInstaller::allowInstallationOfUnsignedPackages() const -{ - return d->allowInstallationOfUnsignedPackages; -} - -void ApplicationInstaller::setAllowInstallationOfUnsignedPackages(bool b) -{ - d->allowInstallationOfUnsignedPackages = b; -} - -QString ApplicationInstaller::hardwareId() const -{ - return d->hardwareId; -} - -bool ApplicationInstaller::isApplicationUserIdSeparationEnabled() const -{ - return d->userIdSeparation; -} - -uint ApplicationInstaller::commonApplicationGroupId() const -{ - return d->commonGroupId; -} - -bool ApplicationInstaller::enableApplicationUserIdSeparation(uint minUserId, uint maxUserId, uint commonGroupId) -{ - if (minUserId >= maxUserId || minUserId == uint(-1) || maxUserId == uint(-1)) - return false; - d->userIdSeparation = true; - d->minUserId = minUserId; - d->maxUserId = maxUserId; - d->commonGroupId = commonGroupId; - return true; -} - -uint ApplicationInstaller::findUnusedUserId() const Q_DECL_NOEXCEPT_EXPR(false) -{ - if (!isApplicationUserIdSeparationEnabled()) - return uint(-1); - - QVector<AbstractApplication *> apps = ApplicationManager::instance()->applications(); - - for (uint uid = d->minUserId; uid <= d->maxUserId; ++uid) { - bool match = false; - for (AbstractApplication *app : qAsConst(apps)) { - if (app->nonAliasedInfo()->uid() == uid) { - match = true; - break; - } - } - if (!match) - return uid; - } - throw Exception("could not find a free user-id for application separation in the range %1 to %2") - .arg(d->minUserId).arg(d->maxUserId); -} - -const QDir *ApplicationInstaller::manifestDirectory() const -{ - return d->manifestDir.get(); -} - -QList<QByteArray> ApplicationInstaller::caCertificates() const -{ - return d->chainOfTrust; -} - -void ApplicationInstaller::setCACertificates(const QList<QByteArray> &chainOfTrust) -{ - d->chainOfTrust = chainOfTrust; -} - -void ApplicationInstaller::cleanupBrokenInstallations() const Q_DECL_NOEXCEPT_EXPR(false) -{ - // Check that everything in the app-db is available - // -> if not, remove from app-db - - ApplicationManager *am = ApplicationManager::instance(); - - // key: baseDirPath, value: subDirName/ or fileName - QMultiMap<QString, QString> validPaths { - { manifestDirectory()->absolutePath(), QString() } - }; - for (const InstallationLocation &il : qAsConst(d->installationLocations)) { - validPaths.insert(il.documentPath(), QString()); - validPaths.insert(il.installationPath(), QString()); - } - - const auto allApps = am->applications(); - for (AbstractApplication *app : allApps) { - const InstallationReport *ir = app->nonAliasedInfo()->installationReport(); - if (ir) { - const InstallationLocation &il = installationLocationFromId(ir->installationLocationId()); - - bool valid = il.isValid(); - - if (!valid) - qCDebug(LogInstaller) << "cleanup: uninstalling" << app->id() << "- installationLocation is invalid"; - - if (valid) { - QStringList checkDirs; - QStringList checkFiles; - - checkDirs << manifestDirectory()->absoluteFilePath(app->id()); - checkFiles << manifestDirectory()->absoluteFilePath(app->id()) + qSL("/info.yaml"); - checkFiles << manifestDirectory()->absoluteFilePath(app->id()) + qSL("/installation-report.yaml"); - checkDirs << il.documentPath() + app->id(); - checkDirs << il.installationPath() + app->id(); - - for (const QString &checkFile : qAsConst(checkFiles)) { - QFileInfo fi(checkFile); - if (!fi.exists() || !fi.isFile() || !fi.isReadable()) { - valid = false; - qCDebug(LogInstaller) << "cleanup: uninstalling" << app->id() << "- file missing:" << checkFile; - break; - } - } - for (const QString &checkDir : checkDirs) { - QFileInfo fi(checkDir); - if (!fi.exists() || !fi.isDir() || !fi.isReadable()) { - valid = false; - qCDebug(LogInstaller) << "cleanup: uninstalling" << app->id() << "- directory missing:" << checkDir; - break; - } - } - - if (valid) { - validPaths.insertMulti(il.installationPath(), app->id() + qL1C('/')); - validPaths.insertMulti(il.documentPath(), app->id() + qL1C('/')); - validPaths.insertMulti(manifestDirectory()->absolutePath(), app->id() + qL1C('/')); - } - } - if (!valid) { - if (am->startingApplicationRemoval(app->id())) { - if (am->finishedApplicationInstall(app->id())) - continue; - } - throw Exception(Error::Package, "could not remove broken installation of app %1 from database").arg(app->id()); - } - } - } - - // Remove everything that is not referenced from the app-db - - for (auto it = validPaths.cbegin(); it != validPaths.cend(); ) { - const QString currentDir = it.key(); - - // collect all values for the unique key currentDir - QVector<QString> validNames; - for ( ; it != validPaths.cend() && it.key() == currentDir; ++it) - validNames << it.value(); - - const QFileInfoList &dirEntries = QDir(currentDir).entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot); - - // check if there is anything in the filesystem that is NOT listed in the validNames - for (const QFileInfo &fi : dirEntries) { - QString name = fi.fileName(); - if (fi.isDir()) - name.append(qL1C('/')); - - if ((!fi.isDir() && !fi.isFile()) || !validNames.contains(name)) { - qCDebug(LogInstaller) << "cleanup: removing unreferenced inode" << name; - - if (SudoClient::instance()) { - if (!SudoClient::instance()->removeRecursive(fi.absoluteFilePath())) - throw Exception(Error::IO, "could not remove broken installation leftover %1 : %2").arg(fi.absoluteFilePath()).arg(SudoClient::instance()->lastError()); - } else { - if (!recursiveOperation(fi.absoluteFilePath(), safeRemove)) - throw Exception(Error::IO, "could not remove broken installation leftover %1 (maybe due to missing root privileges)").arg(fi.absoluteFilePath()); - } - } - } - } -} - -QVector<InstallationLocation> ApplicationInstaller::installationLocations() const -{ - return d->installationLocations; -} - - -const InstallationLocation &ApplicationInstaller::defaultInstallationLocation() const -{ - static bool once = false; - static int defaultIndex = -1; - - if (!once) { - for (int i = 0; i < d->installationLocations.size(); ++i) { - if (d->installationLocations.at(i).isDefault()) { - defaultIndex = i; - break; - } - } - once = true; - } - return (defaultIndex < 0) ? d->invalidInstallationLocation : d->installationLocations.at(defaultIndex); -} - -const InstallationLocation &ApplicationInstaller::installationLocationFromId(const QString &installationLocationId) const -{ - for (const InstallationLocation &il : d->installationLocations) { - if (il.id() == installationLocationId) - return il; - } - return d->invalidInstallationLocation; -} - -const InstallationLocation &ApplicationInstaller::installationLocationFromApplication(const QString &id) const -{ - if (AbstractApplication *a = ApplicationManager::instance()->fromId(id)) { - if (const InstallationReport *report = a->nonAliasedInfo()->installationReport()) - return installationLocationFromId(report->installationLocationId()); - } - return d->invalidInstallationLocation; -} - - -/*! - \qmlmethod list<string> ApplicationInstaller::installationLocationIds() - - Retuns a list of all known installation location ids. Calling getInstallationLocation() on one of - the returned identifiers will yield specific information about the individual installation locations. -*/ -QStringList ApplicationInstaller::installationLocationIds() const -{ - QStringList ids; - ids.reserve(d->installationLocations.size()); - for (const InstallationLocation &il : d->installationLocations) - ids << il.id(); - return ids; -} - -/*! - \qmlmethod string ApplicationInstaller::installationLocationIdFromApplication(string id) - - Returns the installation location id for the application identified by \a id. Returns - an empty string in case the application is not installed. - - \sa installationLocationIds() - */ -QString ApplicationInstaller::installationLocationIdFromApplication(const QString &id) const -{ - const InstallationLocation &il = installationLocationFromApplication(id); - return il.isValid() ? il.id() : QString(); -} - -/*! - \qmlmethod object ApplicationInstaller::getInstallationLocation(string installationLocationId) - - Returns an object describing the installation location identified by \a installationLocationId in detail. - - The returned object has the following members: - - \table - \header - \li \c Name - \li \c Type - \li Description - \row - \li \c id - \li \c string - \li The installation location id that is used as the handle for all other ApplicationInstaller - function calls. The \c id consists of the \c type and \c index field, concatenated by - a single dash (for example, \c internal-0). - \row - \li \c type - \li \c string - \li The type of device this installation location is connected to. Valid values are \c - internal (for any kind of built-in storage, e.g. flash), \c removable (for any kind of - storage that is removable by the user, e.g. an SD card) and \c invalid. - \row - \li \c index - \li \c int - \li In case there is more than one installation location for the same type of device, this - \c zero-based index is used for disambiguation. For example, two SD card slots will - result in the ids \c removable-0 and \c removable-1. Otherwise, the index is always \c 0. - \row - \li \c isDefault - \li \c bool - - \li Exactly one installation location is the default location which must be mounted and - accessible at all times. This can be used by an UI application to get a sensible - default for the installation location that it needs to pass to startPackageInstallation(). - \row - \li \c isRemovable - \li \c bool - \li Indicates whether this installation location is on a removable media (for example, an SD - card). - \row - \li \c isMounted - \li \c bool - \li The current mount status of this installation location: should always be \c true for - non-removable media. - \row - \li \c installationPath - \li \c string - \li The absolute file-system path to the base directory under which applications are installed. - \row - \li \c installationDeviceSize - \li \c int - \li The size of the device holding \c installationPath in bytes. This field is only present if - \c isMounted is \c true. - \row - \li \c installationDeviceFree - \li \c int - \li The amount of bytes available on the device holding \c installationPath. This field is only - present if \c isMounted is \c true. - \row - \li \c documentPath - \li \c string - \li The absolute file-system path to the base directory under which per-user document - directories are created. - \row - \li \c documentDeviceSize - \li \c int - \li The size of the device holding \c documentPath in bytes. This field is only present if - \c isMounted is \c true. - \row - \li \c documentDeviceFree - \li \c int - \li The amount of bytes available on the device holding \c documentPath. This field is only - present if \c isMounted is \c true. - \endtable - - Returns an empty object in case the \a installationLocationId is not valid. -*/ -QVariantMap ApplicationInstaller::getInstallationLocation(const QString &installationLocationId) const -{ - const InstallationLocation &il = installationLocationFromId(installationLocationId); - return il.isValid() ? il.toVariantMap() : QVariantMap(); -} - -/*! - \qmlmethod int ApplicationInstaller::installedApplicationSize(string id) - - Returns the size in bytes that the application identified by \a id is occupying on the storage - device. - - Returns \c -1 in case the application \a id is not valid, or the application is not installed. -*/ -qint64 ApplicationInstaller::installedApplicationSize(const QString &id) const -{ - if (AbstractApplication *a = ApplicationManager::instance()->fromId(id)) { - if (const InstallationReport *report = a->nonAliasedInfo()->installationReport()) - return static_cast<qint64>(report->diskSpaceUsed()); - } - return -1; -} - -/*! - \qmlmethod var ApplicationInstaller::installedApplicationExtraMetaData(string id) - - Returns a map of all extra metadata in the package header of the application identified by \a id. - - Returns an empty map in case the application \a id is not valid, or the application is not installed. -*/ -QVariantMap ApplicationInstaller::installedApplicationExtraMetaData(const QString &id) const -{ - if (AbstractApplication *a = ApplicationManager::instance()->fromId(id)) { - if (const InstallationReport *report = a->nonAliasedInfo()->installationReport()) - return report->extraMetaData(); - } - return QVariantMap(); -} - -/*! - \qmlmethod var ApplicationInstaller::installedApplicationExtraSignedMetaData(string id) - - Returns a map of all signed extra metadata in the package header of the application identified - by \a id. - - Returns an empty map in case the application \a id is not valid, or the application is not installed. -*/ -QVariantMap ApplicationInstaller::installedApplicationExtraSignedMetaData(const QString &id) const -{ - if (AbstractApplication *a = ApplicationManager::instance()->fromId(id)) { - if (const InstallationReport *report = a->nonAliasedInfo()->installationReport()) - return report->extraSignedMetaData(); - } - return QVariantMap(); -} - -/*! \internal - Type safe convenience function, since DBus does not like QUrl -*/ -QString ApplicationInstaller::startPackageInstallation(const QString &installationLocationId, const QUrl &sourceUrl) -{ - AM_TRACE(LogInstaller, installationLocationId, sourceUrl); - - const InstallationLocation &il = installationLocationFromId(installationLocationId); - - return enqueueTask(new InstallationTask(il, sourceUrl)); -} - -/*! - \qmlmethod string ApplicationInstaller::startPackageInstallation(string installationLocationId, string sourceUrl) - - Downloads an application package from \a sourceUrl and installs it to the installation location - described by \a installationLocationId. - - The actual download and installation will happen asynchronously in the background. The - ApplicationInstaller emits the signals \l taskStarted, \l taskProgressChanged, \l - taskRequestingInstallationAcknowledge, \l taskFinished, \l taskFailed, and \l taskStateChanged - for the returned taskId when applicable. - - \note Simply calling this function is not enough to complete a package installation: The - taskRequestingInstallationAcknowledge() signal needs to be connected to a slot where the - supplied application meta-data can be validated (either programmatically or by asking the user). - If the validation is successful, the installation can be completed by calling - acknowledgePackageInstallation() or, if the validation was unsuccessful, the installation should - be canceled by calling cancelTask(). - Failing to do one or the other will leave an unfinished "zombie" installation. - - Returns a unique \c taskId. This can also be an empty string, if the task could not be - created (in this case, no signals will be emitted). -*/ -QString ApplicationInstaller::startPackageInstallation(const QString &installationLocationId, const QString &sourceUrl) -{ - QUrl url(sourceUrl); - if (url.scheme().isEmpty()) - url = QUrl::fromLocalFile(sourceUrl); - return startPackageInstallation(installationLocationId, url); -} - -/*! - \qmlmethod void ApplicationInstaller::acknowledgePackageInstallation(string taskId) - - Calling this function enables the installer to complete the installation task identified by \a - taskId. Normally, this function is called after receiving the taskRequestingInstallationAcknowledge() - signal, and the user and/or the program logic decided to proceed with the installation. - - \sa startPackageInstallation() - */ -void ApplicationInstaller::acknowledgePackageInstallation(const QString &taskId) -{ - AM_TRACE(LogInstaller, taskId) - - const auto allTasks = d->allTasks(); - - for (AsynchronousTask *task : allTasks) { - if (qobject_cast<InstallationTask *>(task) && (task->id() == taskId)) { - static_cast<InstallationTask *>(task)->acknowledge(); - break; - } - } -} - -/*! - \qmlmethod string ApplicationInstaller::removePackage(string id, bool keepDocuments, bool force) - - Uninstalls the application identified by \a id. Normally, the documents directory of the - application is deleted on removal, but this can be prevented by setting \a keepDocuments to \c true. - - The actual removal will happen asynchronously in the background. The ApplicationInstaller will - emit the signals \l taskStarted, \l taskProgressChanged, \l taskFinished, \l taskFailed and \l - taskStateChanged for the returned \c taskId when applicable. - - Normally, \a force should only be set to \c true if a previous call to removePackage() failed. - This may be necessary if the installation process was interrupted, or if an SD card got lost - or has file-system issues. - - Returns a unique \c taskId. This can also be an empty string, if the task could not be created - (in this case, no signals will be emitted). -*/ -QString ApplicationInstaller::removePackage(const QString &id, bool keepDocuments, bool force) -{ - AM_TRACE(LogInstaller, id, keepDocuments) - - if (AbstractApplication *a = ApplicationManager::instance()->fromId(id)) { - if (const InstallationReport *report = a->nonAliasedInfo()->installationReport()) { - const InstallationLocation &il = installationLocationFromId(report->installationLocationId()); - - if (il.isValid() && (il.id() == report->installationLocationId())) - return enqueueTask(new DeinstallationTask(a->nonAliasedInfo(), il, force, keepDocuments)); - } - } - return QString(); -} - - -/*! - \qmlmethod enumeration ApplicationInstaller::taskState(string taskId) - - Returns the current state of the installation task identified by \a taskId. - \l {TaskStates}{See here} for a list of valid task states. - - Returns \c ApplicationInstaller.Invalid if the \a taskId is invalid. -*/ -AsynchronousTask::TaskState ApplicationInstaller::taskState(const QString &taskId) const -{ - const auto allTasks = d->allTasks(); - - for (const AsynchronousTask *task : allTasks) { - if (task && (task->id() == taskId)) - return task->state(); - } - return AsynchronousTask::Invalid; -} - -/*! - \qmlmethod string ApplicationInstaller::taskApplicationId(string taskId) - - Returns the application id associated with the task identified by \a taskId. The task may not - have a valid application id at all times though and in this case the function will return an - empty string (this will be the case for installations before the taskRequestingInstallationAcknowledge - signal has been emitted). - - Returns an empty string if the \a taskId is invalid. -*/ -QString ApplicationInstaller::taskApplicationId(const QString &taskId) const -{ - const auto allTasks = d->allTasks(); - - for (const AsynchronousTask *task : allTasks) { - if (task && (task->id() == taskId)) - return task->applicationId(); - } - return QString(); -} - -/*! - \qmlmethod list<string> ApplicationInstaller::activeTaskIds() - - Retuns a list of all currently active (as in not yet finished or failed) installation task ids. -*/ -QStringList ApplicationInstaller::activeTaskIds() const -{ - const auto allTasks = d->allTasks(); - - QStringList result; - for (const AsynchronousTask *task : allTasks) - result << task->id(); - return result; -} - -/*! - \qmlmethod bool ApplicationInstaller::cancelTask(string taskId) - - Tries to cancel the installation task identified by \a taskId. - - Returns \c true if the task was canceled, \c false otherwise. -*/ -bool ApplicationInstaller::cancelTask(const QString &taskId) -{ - AM_TRACE(LogInstaller, taskId) - - // incoming tasks can be forcefully cancelled right away - for (AsynchronousTask *task : qAsConst(d->incomingTaskList)) { - if (task->id() == taskId) { - task->forceCancel(); - task->deleteLater(); - - handleFailure(task); - - d->incomingTaskList.removeOne(task); - triggerExecuteNextTask(); - return true; - } - } - - // the active task and async tasks might be in a state where cancellation is not possible, - // so we have to ask them nicely - if (d->activeTask && d->activeTask->id() == taskId) - return d->activeTask->cancel(); - - for (AsynchronousTask *task : qAsConst(d->installationTaskList)) { - if (task->id() == taskId) - return task->cancel(); - } - return false; -} - -/*! - \qmlmethod int ApplicationInstaller::compareVersions(string version1, string version2) - - Convenience method for app-store implementations or taskRequestingInstallationAcknowledge() - callbacks for comparing version numbers, as the actual version comparison algorithm is not - trivial. - - Returns \c -1, \c 0 or \c 1 if \a version1 is smaller than, equal to, or greater than \a - version2 (similar to how \c strcmp() works). -*/ -int ApplicationInstaller::compareVersions(const QString &version1, const QString &version2) -{ - int pos1 = 0; - int pos2 = 0; - int len1 = version1.length(); - int len2 = version2.length(); - - forever { - if (pos1 == len1 && pos2 == len2) - return 0; - else if (pos1 >= len1) - return -1; - else if (pos2 >= len2) - return +1; - - QString part1 = version1.mid(pos1++, 1); - QString part2 = version2.mid(pos2++, 1); - - bool isDigit1 = part1.at(0).isDigit(); - bool isDigit2 = part2.at(0).isDigit(); - - if (!isDigit1 || !isDigit2) { - int cmp = part1.compare(part2); - if (cmp) - return (cmp > 0) ? 1 : -1; - } else { - while ((pos1 < len1) && version1.at(pos1).isDigit()) - part1.append(version1.at(pos1++)); - while ((pos2 < len2) && version2.at(pos2).isDigit()) - part2.append(version2.at(pos2++)); - - int num1 = part1.toInt(); - int num2 = part2.toInt(); - - if (num1 != num2) - return (num1 > num2) ? 1 : -1; - } - } -} - -/*! - \qmlmethod int ApplicationInstaller::validateDnsName(string name, int minimalPartCount) - - Convenience method for app-store implementations or taskRequestingInstallationAcknowledge() - callbacks for checking if the given \a name is a valid DNS (or reverse-DNS) name according to - RFC 1035/1123. If the optional parameter \a minimalPartCount is specified, this function will - also check if \a name contains at least this amount of parts/sub-domains. - - Returns \c true if the name is a valid DNS name or \c false otherwise. -*/ -bool ApplicationInstaller::validateDnsName(const QString &name, int minimalPartCount) -{ - try { - // check if we have enough parts: e.g. "tld.company.app" would have 3 parts - QStringList parts = name.split('.'); - if (parts.size() < minimalPartCount) { - throw Exception(Error::Parse, "the minimum amount of parts (subdomains) is %1 (found %2)") - .arg(minimalPartCount).arg(parts.size()); - } - - // standard RFC compliance tests (RFC 1035/1123) - - auto partCheck = [](const QString &part) { - int len = part.length(); - - if (len < 1 || len > 63) - throw Exception(Error::Parse, "domain parts must consist of at least 1 and at most 63 characters (found %2 characters)").arg(len); - - for (int pos = 0; pos < len; ++pos) { - ushort ch = part.at(pos).unicode(); - bool isFirst = (pos == 0); - bool isLast = (pos == (len - 1)); - bool isDash = (ch == '-'); - bool isDigit = (ch >= '0' && ch <= '9'); - bool isLower = (ch >= 'a' && ch <= 'z'); - - if ((isFirst || isLast || !isDash) && !isDigit && !isLower) - throw Exception(Error::Parse, "domain parts must consist of only the characters '0-9', 'a-z', and '-' (which cannot be the first or last character)"); - } - }; - - for (const QString &part : parts) - partCheck(part); - - return true; - } catch (const Exception &e) { - qCDebug(LogInstaller).noquote() << "validateDnsName failed:" << e.errorString(); - return false; - } -} - -QString ApplicationInstaller::enqueueTask(AsynchronousTask *task) -{ - d->incomingTaskList.append(task); - triggerExecuteNextTask(); - return task->id(); -} - -void ApplicationInstaller::triggerExecuteNextTask() -{ - if (!QMetaObject::invokeMethod(this, "executeNextTask", Qt::QueuedConnection)) - qCCritical(LogSystem) << "ERROR: failed to invoke method checkQueue"; -} - -void ApplicationInstaller::executeNextTask() -{ - if (d->activeTask || d->incomingTaskList.isEmpty()) - return; - - AsynchronousTask *task = d->incomingTaskList.takeFirst(); - - if (task->hasFailed()) { - task->setState(AsynchronousTask::Failed); - - handleFailure(task); - - task->deleteLater(); - triggerExecuteNextTask(); - return; - } - - connect(task, &AsynchronousTask::started, this, [this, task]() { - emit taskStarted(task->id()); - }); - - connect(task, &AsynchronousTask::stateChanged, this, [this, task](AsynchronousTask::TaskState newState) { - emit taskStateChanged(task->id(), newState); - }); - - connect(task, &AsynchronousTask::progress, this, [this, task](qreal p) { - emit taskProgressChanged(task->id(), p); - QMetaObject::invokeMethod(ApplicationManager::instance(), - "progressingApplicationInstall", - Qt::DirectConnection, - Q_ARG(QString, task->applicationId()), - Q_ARG(double, p)); - }); - - connect(task, &AsynchronousTask::finished, this, [this, task]() { - task->setState(task->hasFailed() ? AsynchronousTask::Failed : AsynchronousTask::Finished); - - if (task->hasFailed()) { - handleFailure(task); - } else { - qCDebug(LogInstaller) << "emit finished" << task->id(); - emit taskFinished(task->id()); - } - - if (d->activeTask == task) - d->activeTask = nullptr; - d->installationTaskList.removeOne(task); - - delete task; - triggerExecuteNextTask(); - }); - - if (qobject_cast<InstallationTask *>(task)) { - connect(static_cast<InstallationTask *>(task), &InstallationTask::finishedPackageExtraction, this, [this, task]() { - qCDebug(LogInstaller) << "emit blockingUntilInstallationAcknowledge" << task->id(); - emit taskBlockingUntilInstallationAcknowledge(task->id()); - - // we can now start the next download in parallel - the InstallationTask will take care - // of serializing the final installation steps on its own as soon as it gets the - // required acknowledge (or cancel). - if (d->activeTask == task) - d->activeTask = nullptr; - d->installationTaskList.append(task); - triggerExecuteNextTask(); - }); - } - - - d->activeTask = task; - task->setState(AsynchronousTask::Executing); - task->start(); -} - -void ApplicationInstaller::handleFailure(AsynchronousTask *task) -{ - qCDebug(LogInstaller) << "emit failed" << task->id() << task->errorCode() << task->errorString(); - emit taskFailed(task->id(), int(task->errorCode()), task->errorString()); -} - - -bool removeRecursiveHelper(const QString &path) -{ - if (ApplicationInstaller::instance()->isApplicationUserIdSeparationEnabled() && SudoClient::instance()) - return SudoClient::instance()->removeRecursive(path); - else - return recursiveOperation(path, safeRemove); -} - -QT_END_NAMESPACE_AM diff --git a/src/installer-lib/installationlocation.cpp b/src/installer-lib/installationlocation.cpp deleted file mode 100644 index d87383f7..00000000 --- a/src/installer-lib/installationlocation.cpp +++ /dev/null @@ -1,229 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** 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 "installationlocation.h" -#include "global.h" -#include "utilities.h" -#include "exception.h" - -#if defined(Q_OS_WIN) -# include <windows.h> -#else -# include <sys/stat.h> -# include <errno.h> -# if defined(Q_OS_ANDROID) -# include <sys/vfs.h> -# define statvfs statfs -# else -# include <sys/statvfs.h> -# endif -#endif - -QT_BEGIN_NAMESPACE_AM - -static QString fixPath(const QString &path, const QString &hardwareId) -{ - QString realPath = path; - realPath.replace(qL1S("@HARDWARE-ID@"), hardwareId); - QDir dir(realPath); - return (dir.exists() ? dir.canonicalPath() : dir.absolutePath()) + qL1C('/'); -} - -static bool diskUsage(const QString &path, quint64 *bytesTotal, quint64 *bytesFree) -{ - QString cpath = QFileInfo(path).canonicalPath(); - -#if defined(Q_OS_WIN) - return GetDiskFreeSpaceExW((LPCWSTR) cpath.utf16(), (ULARGE_INTEGER *) bytesFree, - (ULARGE_INTEGER *) bytesTotal, nullptr); - -#else // Q_OS_UNIX - int result; - struct ::statvfs svfs; - - do { - result = ::statvfs(cpath.toLocal8Bit(), &svfs); - if (result == -1 && errno == EINTR) - continue; - } while (false); - - if (result == 0) { - if (bytesTotal) - *bytesTotal = quint64(svfs.f_frsize) * svfs.f_blocks; - if (bytesFree) - *bytesFree = quint64(svfs.f_frsize) * svfs.f_bavail; - return true; - } - return false; -#endif // Q_OS_WIN -} - - -bool InstallationLocation::operator==(const InstallationLocation &other) const -{ - return (m_valid == other.m_valid) - && (m_index == other.m_index) - && (m_installationPath == other.m_installationPath) - && (m_documentPath == other.m_documentPath); -} - -QString InstallationLocation::id() const -{ - QString name = m_valid ? qSL("internal") : qSL("invalid"); - if (m_valid) - name = name + QLatin1Char('-') + QString::number(m_index); - return name; -} - -int InstallationLocation::index() const -{ - return m_index; -} - -bool InstallationLocation::isValid() const -{ - return m_valid; -} - -bool InstallationLocation::isDefault() const -{ - return m_isDefault; -} - -QString InstallationLocation::installationPath() const -{ - return m_installationPath; -} - -QString InstallationLocation::documentPath() const -{ - return m_documentPath; -} - -bool InstallationLocation::installationDeviceFreeSpace(quint64 *bytesTotal, quint64 *bytesFree) const -{ - return diskUsage(installationPath(), bytesTotal, bytesFree); -} - -bool InstallationLocation::documentDeviceFreeSpace(quint64 *bytesTotal, quint64 *bytesFree) const -{ - return diskUsage(documentPath(), bytesTotal, bytesFree); -} - -QVariantMap InstallationLocation::toVariantMap() const -{ - QVariantMap map; - map[qSL("id")] = id(); - map[qSL("type")] = m_valid ? qSL("internal") : qSL("invalid"); - map[qSL("index")] = index(); - map[qSL("installationPath")] = installationPath(); - map[qSL("documentPath")] = documentPath(); - map[qSL("isDefault")] = isDefault(); - - quint64 total = 0, free = 0; - installationDeviceFreeSpace(&total, &free); - - map[qSL("installationDeviceSize")] = total; - map[qSL("installationDeviceFree")] = free; - - total = free = 0; - documentDeviceFreeSpace(&total, &free); - - map[qSL("documentDeviceSize")] = total; - map[qSL("documentDeviceFree")] = free; - - return map; -} - -QVector<InstallationLocation> InstallationLocation::parseInstallationLocations(const QVariantList &list, - const QString &hardwareId) Q_DECL_NOEXCEPT_EXPR(false) -{ - QVector<InstallationLocation> locations; - bool gotDefault = false; - - for (const QVariant &v : list) { - QVariantMap map = v.toMap(); - - QString id = map.value(qSL("id")).toString(); - QString instPath = map.value(qSL("installationPath")).toString(); - QString documentPath = map.value(qSL("documentPath")).toString(); - bool isDefault = map.value(qSL("isDefault")).toBool(); - - if (isDefault) { - if (!gotDefault) - gotDefault = true; - else - throw Exception(Error::Parse, "multiple default installation locations defined"); - } - - QString type = id.section('-', 0, 0); - bool ok = false; - int index = id.section('-', 1).toInt(&ok); - - if ((type == qSL("internal")) && (index >= 0) && ok) { - InstallationLocation il; - il.m_valid = true; - il.m_index = index; - il.m_installationPath = fixPath(instPath, hardwareId); - il.m_documentPath = fixPath(documentPath, hardwareId); - il.m_isDefault = isDefault; - - if (!QDir::root().mkpath(instPath)) { - throw Exception(Error::Parse, "the app directory %2 for the installation location %1 does not exist") - .arg(id).arg(instPath); - } - if (!QDir::root().mkpath(documentPath)) { - throw Exception(Error::Parse, "the doc directory %2 for the installation location %1 does not exist") - .arg(id).arg(documentPath); - } - - locations.append(il); - } else { - throw Exception(Error::Parse, "could not parse the installation location with id %1").arg(id); - } - } - return locations; -} - -QT_END_NAMESPACE_AM diff --git a/src/installer-lib/installer-lib.pro b/src/installer-lib/installer-lib.pro deleted file mode 100644 index c61ad7fd..00000000 --- a/src/installer-lib/installer-lib.pro +++ /dev/null @@ -1,40 +0,0 @@ -TEMPLATE = lib -TARGET = QtAppManInstaller -MODULE = appman_installer - -load(am-config) - -QT = core network qml -QT_FOR_PRIVATE *= \ - appman_common-private \ - appman_crypto-private \ - appman_application-private \ - appman_package-private \ - appman_manager-private - -CONFIG *= static internal_module -CONFIG -= create_cmake - -include($$SOURCE_DIR/3rdparty/libarchive.pri) -include($$SOURCE_DIR/3rdparty/libz.pri) - -HEADERS += \ - installationlocation.h \ - asynchronoustask.h \ - deinstallationtask.h \ - installationtask.h \ - scopeutilities.h \ - applicationinstaller.h \ - applicationinstaller_p.h \ - sudo.h \ - -SOURCES += \ - installationlocation.cpp \ - asynchronoustask.cpp \ - installationtask.cpp \ - deinstallationtask.cpp \ - scopeutilities.cpp \ - applicationinstaller.cpp \ - sudo.cpp \ - -load(qt_module) diff --git a/src/intent-client-lib/intentclient.cpp b/src/intent-client-lib/intentclient.cpp index 0c5d5264..e88c7005 100644 --- a/src/intent-client-lib/intentclient.cpp +++ b/src/intent-client-lib/intentclient.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/intent-client-lib/intentclient.h b/src/intent-client-lib/intentclient.h index aa4ed95a..2ecccb31 100644 --- a/src/intent-client-lib/intentclient.h +++ b/src/intent-client-lib/intentclient.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/intent-client-lib/intentclientrequest.cpp b/src/intent-client-lib/intentclientrequest.cpp index bee28543..9c420e8c 100644 --- a/src/intent-client-lib/intentclientrequest.cpp +++ b/src/intent-client-lib/intentclientrequest.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/intent-client-lib/intentclientrequest.h b/src/intent-client-lib/intentclientrequest.h index ce004c97..8d898d32 100644 --- a/src/intent-client-lib/intentclientrequest.h +++ b/src/intent-client-lib/intentclientrequest.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/intent-client-lib/intentclientsysteminterface.cpp b/src/intent-client-lib/intentclientsysteminterface.cpp index 420ee92a..9be9a140 100644 --- a/src/intent-client-lib/intentclientsysteminterface.cpp +++ b/src/intent-client-lib/intentclientsysteminterface.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/intent-client-lib/intentclientsysteminterface.h b/src/intent-client-lib/intentclientsysteminterface.h index 4baa33d4..307aae8f 100644 --- a/src/intent-client-lib/intentclientsysteminterface.h +++ b/src/intent-client-lib/intentclientsysteminterface.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/intent-client-lib/intenthandler.cpp b/src/intent-client-lib/intenthandler.cpp index 24579aef..06b5fd15 100644 --- a/src/intent-client-lib/intenthandler.cpp +++ b/src/intent-client-lib/intenthandler.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/intent-client-lib/intenthandler.h b/src/intent-client-lib/intenthandler.h index 650ea539..95c73e41 100644 --- a/src/intent-client-lib/intenthandler.h +++ b/src/intent-client-lib/intenthandler.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/intent-server-lib/intent.cpp b/src/intent-server-lib/intent.cpp index b1151910..4ee207a8 100644 --- a/src/intent-server-lib/intent.cpp +++ b/src/intent-server-lib/intent.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/intent-server-lib/intent.h b/src/intent-server-lib/intent.h index 0de7f4f1..10f1c8c8 100644 --- a/src/intent-server-lib/intent.h +++ b/src/intent-server-lib/intent.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/intent-server-lib/intentserver.cpp b/src/intent-server-lib/intentserver.cpp index 0ba11e2f..e9afcbcd 100644 --- a/src/intent-server-lib/intentserver.cpp +++ b/src/intent-server-lib/intentserver.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -100,7 +100,8 @@ IntentServer *IntentServer::createInstance(IntentServerSystemInterface *systemIn systemInterface->initialize(is.data()); qRegisterMetaType<Intent>("Intent"); - QMetaType::registerComparators<Intent>(); + if (!QMetaType::hasRegisteredComparators<Intent>()) + QMetaType::registerComparators<Intent>(); // Have a nicer name in the C++ API, since QML cannot cope with QList<Q_GADGET-type> qRegisterMetaType<QVariantList>("IntentList"); diff --git a/src/intent-server-lib/intentserver.h b/src/intent-server-lib/intentserver.h index 1bf62ade..9d658324 100644 --- a/src/intent-server-lib/intentserver.h +++ b/src/intent-server-lib/intentserver.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/intent-server-lib/intentserverrequest.cpp b/src/intent-server-lib/intentserverrequest.cpp index 52fd8280..8985cbe3 100644 --- a/src/intent-server-lib/intentserverrequest.cpp +++ b/src/intent-server-lib/intentserverrequest.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/intent-server-lib/intentserverrequest.h b/src/intent-server-lib/intentserverrequest.h index 1d3b2980..d008ac67 100644 --- a/src/intent-server-lib/intentserverrequest.h +++ b/src/intent-server-lib/intentserverrequest.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/intent-server-lib/intentserversysteminterface.cpp b/src/intent-server-lib/intentserversysteminterface.cpp index 84e54b02..96204582 100644 --- a/src/intent-server-lib/intentserversysteminterface.cpp +++ b/src/intent-server-lib/intentserversysteminterface.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/intent-server-lib/intentserversysteminterface.h b/src/intent-server-lib/intentserversysteminterface.h index 3e03806b..1a2d22e5 100644 --- a/src/intent-server-lib/intentserversysteminterface.h +++ b/src/intent-server-lib/intentserversysteminterface.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/launcher-lib/applicationmanagerwindow.cpp b/src/launcher-lib/applicationmanagerwindow.cpp index 766f4cbe..5bb1e645 100644 --- a/src/launcher-lib/applicationmanagerwindow.cpp +++ b/src/launcher-lib/applicationmanagerwindow.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/launcher-lib/applicationmanagerwindow_p.h b/src/launcher-lib/applicationmanagerwindow_p.h index 6a4ff5f1..825f44cb 100644 --- a/src/launcher-lib/applicationmanagerwindow_p.h +++ b/src/launcher-lib/applicationmanagerwindow_p.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/launcher-lib/intentclientdbusimplementation.cpp b/src/launcher-lib/intentclientdbusimplementation.cpp index 9b5b2a6f..5da608a6 100644 --- a/src/launcher-lib/intentclientdbusimplementation.cpp +++ b/src/launcher-lib/intentclientdbusimplementation.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/launcher-lib/intentclientdbusimplementation.h b/src/launcher-lib/intentclientdbusimplementation.h index 096634d2..06be71f2 100644 --- a/src/launcher-lib/intentclientdbusimplementation.h +++ b/src/launcher-lib/intentclientdbusimplementation.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/launcher-lib/ipcwrapperobject.cpp b/src/launcher-lib/ipcwrapperobject.cpp index 1a9bc0e6..0d3035f2 100644 --- a/src/launcher-lib/ipcwrapperobject.cpp +++ b/src/launcher-lib/ipcwrapperobject.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/launcher-lib/ipcwrapperobject.h b/src/launcher-lib/ipcwrapperobject.h index e7175faf..b36b4ed1 100644 --- a/src/launcher-lib/ipcwrapperobject.h +++ b/src/launcher-lib/ipcwrapperobject.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/launcher-lib/ipcwrapperobject_p.h b/src/launcher-lib/ipcwrapperobject_p.h index 95d3e3b8..9d980d75 100644 --- a/src/launcher-lib/ipcwrapperobject_p.h +++ b/src/launcher-lib/ipcwrapperobject_p.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/launcher-lib/launchermain.cpp b/src/launcher-lib/launchermain.cpp index 5b573c4e..c5147925 100644 --- a/src/launcher-lib/launchermain.cpp +++ b/src/launcher-lib/launchermain.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/launcher-lib/launchermain.h b/src/launcher-lib/launchermain.h index 7ff1dd31..4a9331ed 100644 --- a/src/launcher-lib/launchermain.h +++ b/src/launcher-lib/launchermain.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/launcher-lib/qmlapplicationinterface.cpp b/src/launcher-lib/qmlapplicationinterface.cpp index 07c914f1..4a7b95c8 100644 --- a/src/launcher-lib/qmlapplicationinterface.cpp +++ b/src/launcher-lib/qmlapplicationinterface.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/launcher-lib/qmlapplicationinterface.h b/src/launcher-lib/qmlapplicationinterface.h index 467c3069..296967d0 100644 --- a/src/launcher-lib/qmlapplicationinterface.h +++ b/src/launcher-lib/qmlapplicationinterface.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/launcher-lib/qmlapplicationinterfaceextension.cpp b/src/launcher-lib/qmlapplicationinterfaceextension.cpp index 97ee48d6..3b5067c0 100644 --- a/src/launcher-lib/qmlapplicationinterfaceextension.cpp +++ b/src/launcher-lib/qmlapplicationinterfaceextension.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/launcher-lib/qmlapplicationinterfaceextension.h b/src/launcher-lib/qmlapplicationinterfaceextension.h index 250c7b85..627f6899 100644 --- a/src/launcher-lib/qmlapplicationinterfaceextension.h +++ b/src/launcher-lib/qmlapplicationinterfaceextension.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/launcher-lib/qmlnotification.cpp b/src/launcher-lib/qmlnotification.cpp index a3de76f1..869f7bd2 100644 --- a/src/launcher-lib/qmlnotification.cpp +++ b/src/launcher-lib/qmlnotification.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/launcher-lib/qmlnotification.h b/src/launcher-lib/qmlnotification.h index b0c8826d..a358dd52 100644 --- a/src/launcher-lib/qmlnotification.h +++ b/src/launcher-lib/qmlnotification.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/launcher-lib/waylandqtamclientextension.cpp b/src/launcher-lib/waylandqtamclientextension.cpp index 5cf4e8ad..58c3955a 100644 --- a/src/launcher-lib/waylandqtamclientextension.cpp +++ b/src/launcher-lib/waylandqtamclientextension.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/launcher-lib/waylandqtamclientextension_p.h b/src/launcher-lib/waylandqtamclientextension_p.h index 5dfb7f50..f100fd0c 100644 --- a/src/launcher-lib/waylandqtamclientextension_p.h +++ b/src/launcher-lib/waylandqtamclientextension_p.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/main-lib/applicationinstaller.cpp b/src/main-lib/applicationinstaller.cpp new file mode 100644 index 00000000..7fa31479 --- /dev/null +++ b/src/main-lib/applicationinstaller.cpp @@ -0,0 +1,461 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 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 <QCoreApplication> +#include <qqml.h> +#include <QQmlEngine> + +#include "applicationinstaller.h" + + +/*! + \qmltype ApplicationInstaller + \inqmlmodule QtApplicationManager.SystemUI + \ingroup system-ui-singletons + \brief The package installation/removal/update part of the application-manager. + + The ApplicationInstaller singleton type handles the package installation + part of the application manager. It provides both a DBus and QML APIs for + all of its functionality. + + \note The ApplicationInstaller singleton and its corresponding DBus API are only available if you + specify a base directory for installed application manifests. See \l{Configuration} for details. + + \target TaskStates + + The following table describes all possible states that a background task could be in: + + \table + \header + \li Task State + \li Description + \row + \li \c Queued + \li The task was created and is now queued up for execution. + \row + \li \c Executing + \li The task is being executed. + \row + \li \c Finished + \li The task was executed successfully. + \row + \li \c Failed + \li The task failed to execute successfully. + \row + \li \c AwaitingAcknowledge + \li \e{Installation tasks only!} The task is currently halted, waiting for either + acknowledgePackageInstallation() or cancelTask() to continue. See startPackageInstallation() + for more information on the installation workflow. + \row + \li \c Installing + \li \e{Installation tasks only!} The installation was acknowledged via acknowledgePackageInstallation() + and the final installation phase is now running. + \row + \li \c CleaningUp + \li \e{Installation tasks only!} The installation has finished, and previous installations as + well as temporary files are being cleaned up. + \endtable + + The normal workflow for tasks is: \c Queued \unicode{0x2192} \c Executing \unicode{0x2192} \c + Finished. The task can enter the \c Failed state at any point though - either by being canceled via + cancelTask() or simply by failing due to an error. + + Installation tasks are a bit more complex due to the acknowledgment: \c Queued \unicode{0x2192} + \c Executing \unicode{0x2192} \c AwaitingAcknowledge (this state may be skipped if + acknowledgePackageInstallation() was called already) \unicode{0x2192} \c Installing + \unicode{0x2192} \c Cleanup \unicode{0x2192} \c Finished. Again, the task can fail at any point. +*/ + +// THIS IS MISSING AN EXAMPLE! + +/*! + \qmlsignal ApplicationInstaller::taskStateChanged(string taskId, string newState) + + This signal is emitted when the state of the task identified by \a taskId changes. The + new state is supplied in the parameter \a newState. + + \sa taskState() +*/ + +/*! + \qmlsignal ApplicationInstaller::taskStarted(string taskId) + + This signal is emitted when the task identified by \a taskId enters the \c Executing state. + + \sa taskStateChanged() +*/ + +/*! + \qmlsignal ApplicationInstaller::taskFinished(string taskId) + + This signal is emitted when the task identified by \a taskId enters the \c Finished state. + + \sa taskStateChanged() +*/ + +/*! + \qmlsignal ApplicationInstaller::taskFailed(string taskId) + + This signal is emitted when the task identified by \a taskId enters the \c Failed state. + + \sa taskStateChanged() +*/ + +/*! + \qmlsignal ApplicationInstaller::taskRequestingInstallationAcknowledge(string taskId, object application, object packageExtraMetaData, object packageExtraSignedMetaData) + + This signal is emitted when the installation task identified by \a taskId has received enough + meta-data to be able to emit this signal. The task may be in either \c Executing or \c + AwaitingAcknowledge state. + + The contents of the package's manifest file are supplied via \a application as a JavaScript object. + Please see the \l {ApplicationManager Roles}{role names} for the expected object fields. + + In addition, the package's extra meta-data (signed and unsinged) is also supplied via \a + packageExtraMetaData and \a packageExtraSignedMetaData respectively as JavaScript objects. + Both these objects are optional and need to be explicitly either populated during an + application's packaging step or added by an intermediary app-store server. + By default, both will just be empty. + + Following this signal, either cancelTask() or acknowledgePackageInstallation() has to be called + for this \a taskId, to either cancel the installation or try to complete it. + + The ApplicationInstaller has two convenience functions to help the System-UI with verifying the + meta-data: compareVersions() and, in case you are using reverse-DNS notation for application-ids, + validateDnsName(). + + \sa taskStateChanged(), startPackageInstallation() +*/ + +/*! + \qmlsignal ApplicationInstaller::taskBlockingUntilInstallationAcknowledge(string taskId) + + This signal is emitted when the installation task identified by \a taskId cannot continue + due to a missing acknowledgePackageInstallation() call for the task. + + \sa taskStateChanged(), acknowledgePackageInstallation() +*/ + +/*! + \qmlsignal ApplicationInstaller::taskProgressChanged(string taskId, qreal progress) + + This signal is emitted whenever the task identified by \a taskId makes progress towards its + completion. The \a progress is reported as a floating-point number ranging from \c 0.0 to \c 1.0. + + \sa taskStateChanged() +*/ + +QT_BEGIN_NAMESPACE_AM + +ApplicationInstaller *ApplicationInstaller::s_instance = nullptr; + +ApplicationInstaller::ApplicationInstaller(PackageManager *pm, QObject *parent) + : QObject(parent) + , m_pm(pm) +{ } + +ApplicationInstaller::~ApplicationInstaller() +{ + s_instance = nullptr; +} + +ApplicationInstaller *ApplicationInstaller::createInstance(PackageManager *pm) +{ + if (Q_UNLIKELY(s_instance)) + qFatal("ApplicationInstaller::createInstance() was called a second time."); + + + qmlRegisterSingletonType<ApplicationInstaller>("QtApplicationManager.SystemUI", 2, 0, "ApplicationInstaller", + &ApplicationInstaller::instanceForQml); + + return s_instance = new ApplicationInstaller(pm, QCoreApplication::instance()); +} + +ApplicationInstaller *ApplicationInstaller::instance() +{ + if (!s_instance) + qFatal("ApplicationInstaller::instance() was called before createInstance()."); + return s_instance; +} + +QObject *ApplicationInstaller::instanceForQml(QQmlEngine *, QJSEngine *) +{ + QQmlEngine::setObjectOwnership(instance(), QQmlEngine::CppOwnership); + return instance(); +} + +/*! + \qmlmethod list<string> ApplicationInstaller::installationLocationIds() + + Retuns a list of all known installation location ids. Calling getInstallationLocation() on one of + the returned identifiers will yield specific information about the individual installation locations. +*/ + +/*! + \qmlmethod string ApplicationInstaller::installationLocationIdFromApplication(string id) + + Returns the installation location id for the application identified by \a id. Returns + an empty string in case the application is not installed. + + \sa installationLocationIds() +*/ + +/*! + \qmlmethod object ApplicationInstaller::getInstallationLocation(string installationLocationId) + + Returns an object describing the installation location identified by \a installationLocationId in detail. + + The returned object has the following members: + + \table + \header + \li \c Name + \li \c Type + \li Description + \row + \li \c id + \li \c string + \li The installation location id that is used as the handle for all other ApplicationInstaller + function calls. The \c id consists of the \c type and \c index field, concatenated by + a single dash (for example, \c internal-0). + \row + \li \c type + \li \c string + \li The type of device this installation location is connected to. Valid values are \c + internal (for any kind of built-in storage, e.g. flash), \c removable (for any kind of + storage that is removable by the user, e.g. an SD card) and \c invalid. + \row + \li \c index + \li \c int + \li In case there is more than one installation location for the same type of device, this + \c zero-based index is used for disambiguation. For example, two SD card slots will + result in the ids \c removable-0 and \c removable-1. Otherwise, the index is always \c 0. + \row + \li \c isDefault + \li \c bool + + \li Exactly one installation location is the default location which must be mounted and + accessible at all times. This can be used by an UI application to get a sensible + default for the installation location that it needs to pass to startPackageInstallation(). + \row + \li \c isRemovable + \li \c bool + \li Indicates whether this installation location is on a removable media (for example, an SD + card). + \row + \li \c isMounted + \li \c bool + \li The current mount status of this installation location: should always be \c true for + non-removable media. + \row + \li \c installationPath + \li \c string + \li The absolute file-system path to the base directory under which applications are installed. + \row + \li \c installationDeviceSize + \li \c int + \li The size of the device holding \c installationPath in bytes. This field is only present if + \c isMounted is \c true. + \row + \li \c installationDeviceFree + \li \c int + \li The amount of bytes available on the device holding \c installationPath. This field is only + present if \c isMounted is \c true. + \row + \li \c documentPath + \li \c string + \li The absolute file-system path to the base directory under which per-user document + directories are created. + \row + \li \c documentDeviceSize + \li \c int + \li The size of the device holding \c documentPath in bytes. This field is only present if + \c isMounted is \c true. + \row + \li \c documentDeviceFree + \li \c int + \li The amount of bytes available on the device holding \c documentPath. This field is only + present if \c isMounted is \c true. + \endtable + + Returns an empty object in case the \a installationLocationId is not valid. +*/ + +/*! + \qmlmethod int ApplicationInstaller::installedApplicationSize(string id) + + Returns the size in bytes that the application identified by \a id is occupying on the storage + device. + + Returns \c -1 in case the application \a id is not valid, or the application is not installed. +*/ + +/*! + \qmlmethod var ApplicationInstaller::installedApplicationExtraMetaData(string id) + + Returns a map of all extra metadata in the package header of the application identified by \a id. + + Returns an empty map in case the application \a id is not valid, or the application is not installed. +*/ + +/*! + \qmlmethod var ApplicationInstaller::installedApplicationExtraSignedMetaData(string id) + + Returns a map of all signed extra metadata in the package header of the application identified + by \a id. + + Returns an empty map in case the application \a id is not valid, or the application is not installed. +*/ + +/*! \internal + Type safe convenience function, since DBus does not like QUrl +*/ + +/*! + \qmlmethod string ApplicationInstaller::startPackageInstallation(string installationLocationId, string sourceUrl) + + Downloads an application package from \a sourceUrl and installs it to the installation location + described by \a installationLocationId. + + The actual download and installation will happen asynchronously in the background. The + ApplicationInstaller emits the signals \l taskStarted, \l taskProgressChanged, \l + taskRequestingInstallationAcknowledge, \l taskFinished, \l taskFailed, and \l taskStateChanged + for the returned taskId when applicable. + + \note Simply calling this function is not enough to complete a package installation: The + taskRequestingInstallationAcknowledge() signal needs to be connected to a slot where the + supplied application meta-data can be validated (either programmatically or by asking the user). + If the validation is successful, the installation can be completed by calling + acknowledgePackageInstallation() or, if the validation was unsuccessful, the installation should + be canceled by calling cancelTask(). + Failing to do one or the other will leave an unfinished "zombie" installation. + + Returns a unique \c taskId. This can also be an empty string, if the task could not be + created (in this case, no signals will be emitted). +*/ + +/*! + \qmlmethod void ApplicationInstaller::acknowledgePackageInstallation(string taskId) + + Calling this function enables the installer to complete the installation task identified by \a + taskId. Normally, this function is called after receiving the taskRequestingInstallationAcknowledge() + signal, and the user and/or the program logic decided to proceed with the installation. + + \sa startPackageInstallation() + */ + +/*! + \qmlmethod string ApplicationInstaller::removePackage(string id, bool keepDocuments, bool force) + + Uninstalls the application identified by \a id. Normally, the documents directory of the + application is deleted on removal, but this can be prevented by setting \a keepDocuments to \c true. + + The actual removal will happen asynchronously in the background. The ApplicationInstaller will + emit the signals \l taskStarted, \l taskProgressChanged, \l taskFinished, \l taskFailed and \l + taskStateChanged for the returned \c taskId when applicable. + + Normally, \a force should only be set to \c true if a previous call to removePackage() failed. + This may be necessary if the installation process was interrupted, or if an SD card got lost + or has file-system issues. + + Returns a unique \c taskId. This can also be an empty string, if the task could not be created + (in this case, no signals will be emitted). +*/ + +/*! + \qmlmethod enumeration ApplicationInstaller::taskState(string taskId) + + Returns the current state of the installation task identified by \a taskId. + \l {TaskStates}{See here} for a list of valid task states. + + Returns \c ApplicationInstaller.Invalid if the \a taskId is invalid. +*/ + +/*! + \qmlmethod string ApplicationInstaller::taskApplicationId(string taskId) + + Returns the application id associated with the task identified by \a taskId. The task may not + have a valid application id at all times though and in this case the function will return an + empty string (this will be the case for installations before the taskRequestingInstallationAcknowledge + signal has been emitted). + + Returns an empty string if the \a taskId is invalid. +*/ + + +/*! + \qmlmethod list<string> ApplicationInstaller::activeTaskIds() + + Retuns a list of all currently active (as in not yet finished or failed) installation task ids. +*/ + +/*! + \qmlmethod bool ApplicationInstaller::cancelTask(string taskId) + + Tries to cancel the installation task identified by \a taskId. + + Returns \c true if the task was canceled, \c false otherwise. +*/ + +/*! + \qmlmethod int ApplicationInstaller::compareVersions(string version1, string version2) + + Convenience method for app-store implementations or taskRequestingInstallationAcknowledge() + callbacks for comparing version numbers, as the actual version comparison algorithm is not + trivial. + + Returns \c -1, \c 0 or \c 1 if \a version1 is smaller than, equal to, or greater than \a + version2 (similar to how \c strcmp() works). +*/ + +/*! + \qmlmethod int ApplicationInstaller::validateDnsName(string name, int minimalPartCount) + + Convenience method for app-store implementations or taskRequestingInstallationAcknowledge() + callbacks for checking if the given \a name is a valid DNS (or reverse-DNS) name according to + RFC 1035/1123. If the optional parameter \a minimalPartCount is specified, this function will + also check if \a name contains at least this amount of parts/sub-domains. + + Returns \c true if the name is a valid DNS name or \c false otherwise. +*/ + +QT_END_NAMESPACE_AM diff --git a/src/main-lib/applicationinstaller.h b/src/main-lib/applicationinstaller.h new file mode 100644 index 00000000..978f6ce1 --- /dev/null +++ b/src/main-lib/applicationinstaller.h @@ -0,0 +1,202 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 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 +** +****************************************************************************/ + +#pragma once + +#include <QObject> +#include <QVariant> +#include <QUrl> +#include <QStringList> +#include <QDir> +#include <QDebug> +#include <QtAppManCommon/error.h> +#include <QtAppManCommon/logging.h> +#include <QtAppManManager/applicationmanager.h> +#include <QtAppManManager/packagemanager.h> +#include <QtAppManManager/package.h> +#include <QtAppManManager/asynchronoustask.h> + +QT_FORWARD_DECLARE_CLASS(QQmlEngine) +QT_FORWARD_DECLARE_CLASS(QJSEngine) + +QT_BEGIN_NAMESPACE_AM + + +class ApplicationInstaller : public QObject +{ + Q_OBJECT + Q_CLASSINFO("D-Bus Interface", "io.qt.ApplicationInstaller") + Q_CLASSINFO("AM-QmlType", "QtApplicationManager.SystemUI/ApplicationInstaller 2.0 SINGLETON") + + // both are const on purpose - these should never change in a running system + Q_PROPERTY(bool allowInstallationOfUnsignedPackages READ allowInstallationOfUnsignedPackages CONSTANT) + Q_PROPERTY(bool developmentMode READ developmentMode CONSTANT) + + Q_PROPERTY(bool applicationUserIdSeparation READ isApplicationUserIdSeparationEnabled) + Q_PROPERTY(uint commonApplicationGroupId READ commonApplicationGroupId) + + +public: + Q_ENUMS(QT_PREPEND_NAMESPACE_AM(AsynchronousTask::TaskState)) + + ~ApplicationInstaller(); + static ApplicationInstaller *createInstance(PackageManager *pm); + static ApplicationInstaller *instance(); + static QObject *instanceForQml(QQmlEngine *qmlEngine, QJSEngine *); + + bool developmentMode() const { return m_pm->developmentMode(); } + bool allowInstallationOfUnsignedPackages() const { return m_pm->allowInstallationOfUnsignedPackages(); } + QString hardwareId() const { return m_pm->hardwareId(); } + + bool isApplicationUserIdSeparationEnabled() const { return m_pm->isApplicationUserIdSeparationEnabled(); } + uint commonApplicationGroupId() const { return m_pm->commonApplicationGroupId(); } + + // Q_SCRIPTABLEs are available via both QML and D-Bus + Q_SCRIPTABLE QStringList installationLocationIds() const { return { qL1S("internal-0") }; } + Q_SCRIPTABLE QString installationLocationIdFromApplication(const QString &applicationId) const + { + auto app = ApplicationManager::instance()->fromId(applicationId); + if (app && ((!app->package()->isBuiltIn() || app->package()->canBeRevertedToBuiltIn()))) + return qL1S("internal-0"); + return QString(); + } + Q_SCRIPTABLE QVariantMap getInstallationLocation(const QString &installationLocationId) const + { + if (installationLocationId != qL1S("internal-0")) + return QVariantMap { }; + + auto iloc = m_pm->installationLocation(); + auto dloc = m_pm->documentLocation(); + + return QVariantMap { + { qSL("id"), qSL("internal-0") }, + { qSL("type"), qSL("internal") }, + { qSL("index"), 0 }, + { qSL("isDefault"), true }, + { qSL("installationPath"), iloc.value(qL1S("path")) }, + { qSL("installationDeviceSize"), iloc.value(qL1S("size")) }, + { qSL("installationDeviceFree"), iloc.value(qL1S("free")) }, + { qSL("documentPath"), dloc.value(qL1S("path")) }, + { qSL("documentDeviceSize"), dloc.value(qL1S("size")) }, + { qSL("documentDeviceFree"), dloc.value(qL1S("free")) } + }; + } + + // all QString return values are task-ids + Q_SCRIPTABLE QString startPackageInstallation(const QString &installationLocationId, const QString &sourceUrl) + { + if (installationLocationId == qL1S("internal-0")) { + return m_pm->startPackageInstallation(sourceUrl); + } else { + qCWarning(LogInstaller) << "The only supported legacy installation location is 'internal-0', " + "but an installation was requested to:" << installationLocationId; + return QString(); + } + } + + Q_SCRIPTABLE void acknowledgePackageInstallation(const QString &taskId) + { return m_pm->acknowledgePackageInstallation(taskId); } + Q_SCRIPTABLE QString removePackage(const QString &packageId, bool keepDocuments, bool force = false) + { return m_pm->removePackage(packageId, keepDocuments, force); } + + Q_SCRIPTABLE AsynchronousTask::TaskState taskState(const QString &taskId) const + { return m_pm->taskState(taskId); } + Q_SCRIPTABLE QString taskApplicationId(const QString &taskId) const + { + auto package = m_pm->fromId(m_pm->taskPackageId(taskId)); + if (package && !package->info()->applications().isEmpty()) + return package->info()->applications().constFirst()->id(); + return QString(); + } + Q_SCRIPTABLE QStringList activeTaskIds() const + { return m_pm->activeTaskIds(); } + Q_SCRIPTABLE bool cancelTask(const QString &taskId) + { return m_pm->cancelTask(taskId); } + + // convenience function for app-store implementations + Q_SCRIPTABLE int compareVersions(const QString &version1, const QString &version2) + { return m_pm->compareVersions(version1, version2); } + Q_SCRIPTABLE bool validateDnsName(const QString &name, int minimumParts = 1) + { return m_pm->validateDnsName(name, minimumParts); } + + Q_SCRIPTABLE qint64 installedApplicationSize(const QString &applicationId) const + { + auto app = ApplicationManager::instance()->fromId(applicationId); + return m_pm->installedPackageSize(app ? app->package()->id() : QString()); + } + Q_SCRIPTABLE QVariantMap installedApplicationExtraMetaData(const QString &applicationId) const + { + auto app = ApplicationManager::instance()->fromId(applicationId); + return m_pm->installedPackageExtraMetaData(app ? app->package()->id() : QString()); + } + Q_SCRIPTABLE QVariantMap installedApplicationExtraSignedMetaData(const QString &applicationId) const + { + auto app = ApplicationManager::instance()->fromId(applicationId); + return m_pm->installedPackageExtraSignedMetaData(app ? app->package()->id() : QString()); + } + +signals: + Q_SCRIPTABLE void taskStarted(const QString &taskId); + Q_SCRIPTABLE void taskProgressChanged(const QString &taskId, qreal progress); + Q_SCRIPTABLE void taskFinished(const QString &taskId); + Q_SCRIPTABLE void taskFailed(const QString &taskId, int errorCode, const QString &errorString); + Q_SCRIPTABLE void taskStateChanged(const QString &taskId, + QT_PREPEND_NAMESPACE_AM(AsynchronousTask::TaskState) newState); + + // installation only + Q_SCRIPTABLE void taskRequestingInstallationAcknowledge(const QString &taskId, + const QVariantMap &applicationAsVariantMap, + const QVariantMap &packageExtraMetaData, + const QVariantMap &packageExtraSignedMetaData); + Q_SCRIPTABLE void taskBlockingUntilInstallationAcknowledge(const QString &taskId); + + +private: + PackageManager *m_pm; + ApplicationInstaller(PackageManager *pm, QObject *parent = nullptr); + ApplicationInstaller(const ApplicationInstaller &); + static ApplicationInstaller *s_instance; +}; + +QT_END_NAMESPACE_AM + +Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE_AM(AsynchronousTask::TaskState)) diff --git a/src/main-lib/configuration.cpp b/src/main-lib/configuration.cpp index 313bc861..3dbe8f55 100644 --- a/src/main-lib/configuration.cpp +++ b/src/main-lib/configuration.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/main-lib/configuration.h b/src/main-lib/configuration.h index 85c91008..7d59d288 100644 --- a/src/main-lib/configuration.h +++ b/src/main-lib/configuration.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/main-lib/defaultconfiguration.cpp b/src/main-lib/defaultconfiguration.cpp index 6ba3bada..a0e5f930 100644 --- a/src/main-lib/defaultconfiguration.cpp +++ b/src/main-lib/defaultconfiguration.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -95,7 +95,9 @@ DefaultConfiguration::DefaultConfiguration(const QStringList &defaultConfigFileP m_clp.addOption({ qSL("database"), qSL("filepath of the application database cache."), qSL("file") }); m_clp.addOption({ { qSL("r"), qSL("recreate-database") }, qSL("recreate the application database cache.") }); m_clp.addOption({ qSL("builtin-apps-manifest-dir"), qSL("base directory for built-in application manifests."), qSL("dir") }); - m_clp.addOption({ qSL("installed-apps-manifest-dir"), qSL("base directory for installed application manifests."), qSL("dir") }); + m_clp.addOption({ qSL("installation-dir"), qSL("base directory for package installations."), qSL("dir") }); + m_clp.addOption({ qSL("document-dir"), qSL("base directory for per-package document directories."), qSL("dir") }); + m_clp.addOption({ qSL("installed-apps-manifest-dir"), qSL("deprecated (ignored)."), qSL("dir") }); m_clp.addOption({ qSL("app-image-mount-dir"), qSL("deprecated, not needed anymore."), qSL("dir") }); m_clp.addOption({ qSL("disable-installer"), qSL("disable the application installer sub-system.") }); m_clp.addOption({ qSL("disable-intents"), qSL("disable the intents sub-system.") }); @@ -143,10 +145,30 @@ void DefaultConfiguration::parseWithArguments(const QStringList &arguments, QStr *deploymentWarnings << qL1S("No --database command line parameter or applications/database configuration" " key specified. Database won't be cached to speed up subsequent System-UI startups."); - if (installedAppsManifestDir().isEmpty()) - *deploymentWarnings << qL1S("No --installed-apps-manifest-dir command line parameter or" - " applications/installedAppsManifestDir configuration key specified. It won't be possible to install," - " remove or access installable applications."); + if (installationDir().isEmpty()) { + const auto ilocs = value<QVariant>(nullptr, { "installationLocations" }).toList(); + if (!ilocs.isEmpty()) { + *deploymentWarnings << qL1S("Support for \"installationLocations\" in the main config file has been removed:"); + + for (const auto iloc : ilocs) { + QVariantMap map = iloc.toMap(); + QString id = map.value(qSL("id")).toString(); + if (id == qSL("internal-0")) { + m_installationDir = map.value(qSL("installationPath")).toString(); + m_documentDir = map.value(qSL("documentPath")).toString(); + *deploymentWarnings << qL1S(" * still using installation location \"internal-0\" for backward compatibility"); + } else { + *deploymentWarnings << qL1S(" * ignoring installation location ") + id; + } + } + } + } + + if (installationDir().isEmpty()) { + *deploymentWarnings << qL1S("No --installation-dir command line parameter or" + " applications/installationDir configuration key specified. It won't be possible to install," + " remove or access installable packages."); + } if (value<bool>("start-session-dbus")) *deploymentWarnings << qL1S("Option \"--start-session-dbus\" has been deprecated and will be ignored."); @@ -154,7 +176,7 @@ void DefaultConfiguration::parseWithArguments(const QStringList &arguments, QStr QString DefaultConfiguration::mainQmlFile() const { - if (!m_clp.positionalArguments().isEmpty() && m_clp.positionalArguments().at(0).endsWith(qL1S(".qml"))) + if (!m_clp.positionalArguments().isEmpty()) return m_clp.positionalArguments().at(0); else return value<QString>(nullptr, { "ui", "mainQml" }); @@ -176,9 +198,18 @@ QStringList DefaultConfiguration::builtinAppsManifestDirs() const return value<QStringList>("builtin-apps-manifest-dir", { "applications", "builtinAppsManifestDir" }); } -QString DefaultConfiguration::installedAppsManifestDir() const +QString DefaultConfiguration::installationDir() const { - return value<QString>("installed-apps-manifest-dir", { "applications", "installedAppsManifestDir" }); + if (m_installationDir.isEmpty()) + m_installationDir = value<QString>("installation-dir", { "applications", "installationDir" }); + return m_installationDir; +} + +QString DefaultConfiguration::documentDir() const +{ + if (m_documentDir.isEmpty()) + m_documentDir = value<QString>("document-dir", { "applications", "documentDir" }); + return m_documentDir; } bool DefaultConfiguration::disableInstaller() const @@ -347,11 +378,6 @@ QVariantMap DefaultConfiguration::openGLConfiguration() const return value<QVariant>(nullptr, { "ui", "opengl" }).toMap(); } -QVariantList DefaultConfiguration::installationLocations() const -{ - return value<QVariant>(nullptr, { "installationLocations" }).toList(); -} - QList<QPair<QString, QString>> DefaultConfiguration::containerSelectionConfiguration() const { QList<QPair<QString, QString>> config; diff --git a/src/main-lib/defaultconfiguration.h b/src/main-lib/defaultconfiguration.h index d253d420..b6317ba3 100644 --- a/src/main-lib/defaultconfiguration.h +++ b/src/main-lib/defaultconfiguration.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -65,7 +65,10 @@ public: bool recreateDatabase() const; QStringList builtinAppsManifestDirs() const; - QString installedAppsManifestDir() const; + + QString installationDir() const; + QString documentDir() const; + bool disableInstaller() const; bool disableIntents() const; QMap<QString, int> intentTimeouts() const; @@ -98,8 +101,6 @@ public: QVariantMap openGLConfiguration() const; - QVariantList installationLocations() const; - QList<QPair<QString, QString>> containerSelectionConfiguration() const; QVariantMap containerConfigurations() const; QVariantMap runtimeConfigurations() const; @@ -131,6 +132,8 @@ private: QString m_mainQmlFile; bool m_onlyOnePositionalArgument = false; bool m_forceVerbose = false; + mutable QString m_installationDir; // cached value + mutable QString m_documentDir; // cached value }; QT_END_NAMESPACE_AM diff --git a/src/main-lib/main-lib.pro b/src/main-lib/main-lib.pro index 73a972c3..721a54ce 100644 --- a/src/main-lib/main-lib.pro +++ b/src/main-lib/main-lib.pro @@ -14,7 +14,6 @@ QT *= \ appman_application-private \ appman_manager-private \ appman_package-private \ - appman_installer-private \ appman_notification-private \ appman_monitor-private \ appman_shared_main-private \ @@ -37,6 +36,7 @@ HEADERS += \ !headless:HEADERS += \ windowframetimer.h \ + applicationinstaller.h \ SOURCES += \ main.cpp \ @@ -45,5 +45,6 @@ SOURCES += \ !headless:SOURCES += \ windowframetimer.cpp \ + applicationinstaller.cpp \ load(qt_module) diff --git a/src/main-lib/main.cpp b/src/main-lib/main.cpp index 0ebc6211..5f7d6d67 100644 --- a/src/main-lib/main.cpp +++ b/src/main-lib/main.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -49,7 +49,7 @@ # include "dbusdaemon.h" # include "dbuspolicy.h" # include "applicationmanagerdbuscontextadaptor.h" -# include "applicationinstallerdbuscontextadaptor.h" +# include "packagemanagerdbuscontextadaptor.h" # include "notificationmanagerdbuscontextadaptor.h" #endif @@ -95,13 +95,18 @@ #include "main.h" #include "defaultconfiguration.h" #include "applicationinfo.h" +#include "intentinfo.h" +#include "packageinfo.h" #include "applicationmanager.h" -#include "applicationdatabase.h" +#include "packagemanager.h" +#include "package.h" +#include "packagedatabase.h" #include "installationreport.h" -#include "yamlapplicationscanner.h" +#include "yamlpackagescanner.h" #if !defined(AM_DISABLE_INSTALLER) # include "applicationinstaller.h" # include "sudo.h" +# include "packageutilities.h" #endif #include "runtimefactory.h" #include "containerfactory.h" @@ -116,7 +121,6 @@ #include "qmlinprocessapplicationinterface.h" #include "qml-utilities.h" #include "dbus-utilities.h" -#include "package.h" #include "intentserver.h" #include "intentaminterface.h" @@ -186,6 +190,10 @@ Main::~Main() delete m_view; # endif delete m_applicationManager; +#if !defined(AM_DISABLE_INSTALLER) + delete m_applicationInstaller; +#endif + delete m_packageManager; delete m_quickLauncher; delete m_applicationIPCManager; @@ -204,7 +212,8 @@ void Main::setup(const DefaultConfiguration *cfg, const QStringList &deploymentW m_noSecurity = cfg->noSecurity(); m_developmentMode = cfg->developmentMode(); m_builtinAppsManifestDirs = cfg->builtinAppsManifestDirs(); - m_installedAppsManifestDir = cfg->installedAppsManifestDir(); + m_installationDir = cfg->installationDir(); + m_documentDir = cfg->documentDir(); CrashHandler::setCrashActionConfiguration(cfg->managerCrashAction()); setupLogging(cfg->verbose(), cfg->loggingRules(), cfg->messagePattern(), cfg->useAMConsoleLogger()); @@ -228,16 +237,13 @@ void Main::setup(const DefaultConfiguration *cfg, const QStringList &deploymentW setupRuntimesAndContainers(cfg->runtimeConfigurations(), cfg->openGLConfiguration(), cfg->containerConfigurations(), cfg->pluginFilePaths("container"), cfg->iconThemeSearchPaths(), cfg->iconThemeName()); - if (!cfg->disableInstaller()) - setupInstallationLocations(cfg->installationLocations()); - if (!cfg->database().isEmpty()) - loadApplicationDatabase(cfg->database(), cfg->recreateDatabase(), cfg->singleApp()); + loadPackageDatabase(cfg->recreateDatabase(), cfg->singleApp()); setupSingletons(cfg->containerSelectionConfiguration(), cfg->quickLaunchRuntimesPerContainer(), - cfg->quickLaunchIdleLoad(), cfg->singleApp()); + cfg->quickLaunchIdleLoad()); - if (m_installedAppsManifestDir.isEmpty() || cfg->disableInstaller()) { + if (m_installationDir.isEmpty() || cfg->disableInstaller()) { StartupTimer::instance()->checkpoint("skipping installer"); } else { setupInstaller(cfg->caCertificates(), @@ -349,11 +355,11 @@ void Main::parseSystemProperties(const QVariantMap &rawSystemProperties) void Main::setMainQmlFile(const QString &mainQml) Q_DECL_NOEXCEPT_EXPR(false) { - // For some weird reason, QFile cannot cope with "qrc:/" and QUrl cannot cope with ":/" , so - // we have to translate ourselves between those two "worlds". + // For some weird reason, QFile cannot cope with "qrc:/" and QUrl cannot cope with ":/", + // so we have to translate ourselves between those two "worlds". if (mainQml.startsWith(qSL(":/"))) - m_mainQml = QUrl(qSL("qrc:") + mainQml.mid(1)); + m_mainQml = QUrl(qSL("qrc") + mainQml); else m_mainQml = QUrl::fromUserInput(mainQml, QDir::currentPath(), QUrl::AssumeLocalFile); @@ -362,8 +368,14 @@ void Main::setMainQmlFile(const QString &mainQml) Q_DECL_NOEXCEPT_EXPR(false) else if (m_mainQml.scheme() == qSL("qrc")) m_mainQmlLocalFile = qL1C(':') + m_mainQml.path(); - if (!m_mainQmlLocalFile.isEmpty() && !QFile::exists(m_mainQmlLocalFile)) - throw Exception("no/invalid main QML file specified: %1").arg(m_mainQmlLocalFile); + if (!QFileInfo(m_mainQmlLocalFile).isFile()) { + if (mainQml.isEmpty()) + throw Exception("No main QML file specified"); + + // basically accept schemes other than file and qrc: + if (!m_mainQmlLocalFile.isEmpty()) + throw Exception("Invalid main QML file specified: %1").arg(mainQml); + } } void Main::setupSingleOrMultiProcess(bool forceSingleProcess, bool forceMultiProcess) Q_DECL_NOEXCEPT_EXPR(false) @@ -412,66 +424,33 @@ void Main::setupRuntimesAndContainers(const QVariantMap &runtimeConfigurations, StartupTimer::instance()->checkpoint("after runtime registration"); } -void Main::setupInstallationLocations(const QVariantList &installationLocations) +void Main::loadPackageDatabase(bool recreateDatabase, const QString &singlePackage) Q_DECL_NOEXCEPT_EXPR(false) { - m_installationLocations = InstallationLocation::parseInstallationLocations(installationLocations, - hardwareId()); - if (m_installationLocations.isEmpty()) - qCWarning(LogDeployment) << "No installation locations defined in config file"; -} - -void Main::loadApplicationDatabase(const QString &databasePath, bool recreateDatabase, - const QString &singleApp) Q_DECL_NOEXCEPT_EXPR(false) -{ - if (singleApp.isEmpty()) { - if (!QFile::exists(databasePath)) // make sure to create a database on the first run - recreateDatabase = true; - if (QFileInfo(databasePath).size() == 0) // cope with Windows' 0-byte left-overs - recreateDatabase = true; - - if (recreateDatabase) { - const QString dbDir = QFileInfo(databasePath).absolutePath(); - if (Q_UNLIKELY(!QDir(dbDir).exists()) && Q_UNLIKELY(!QDir::root().mkpath(dbDir))) - throw Exception("could not create application database directory %1").arg(dbDir); - } - m_applicationDatabase.reset(new ApplicationDatabase(databasePath)); + if (!singlePackage.isEmpty()) { + m_packageDatabase = new PackageDatabase(singlePackage); } else { - m_applicationDatabase.reset(new ApplicationDatabase()); - recreateDatabase = true; + m_packageDatabase = new PackageDatabase(m_builtinAppsManifestDirs, m_installationDir); + if (!recreateDatabase) + m_packageDatabase->enableLoadFromCache(); + m_packageDatabase->enableSaveToCache(); } + m_packageDatabase->parse(); - if (Q_UNLIKELY(!m_applicationDatabase->isValid() && !recreateDatabase)) { - throw Exception("database file %1 is not a valid application database: %2") - .arg(m_applicationDatabase->name(), m_applicationDatabase->errorString()); - } + const QVector<PackageInfo *> allPackages = + m_packageDatabase->builtInPackages() + + m_packageDatabase->installedPackages(); - if (!m_applicationDatabase->isValid() || recreateDatabase) { - QVector<AbstractApplicationInfo *> apps; + for (auto package : allPackages) { + // check that the runtimes are supported in this instance of the AM + auto apps = package->applications(); - if (!singleApp.isEmpty()) { - apps = scanForApplication(singleApp, m_builtinAppsManifestDirs); - } else { - apps = scanForApplications(m_builtinAppsManifestDirs, - m_installedAppsManifestDir, - m_installationLocations); + for (const auto app : apps) { + if (!RuntimeFactory::instance()->manager(app->runtimeName())) + qCWarning(LogSystem) << "Application" << app->id() << "uses an unknown runtime:" << app->runtimeName(); } - - if (LogSystem().isDebugEnabled()) { - qCDebug(LogSystem) << "Registering applications:"; - for (auto *app : qAsConst(apps)) { - if (app->isAlias()) - qCDebug(LogSystem).nospace().noquote() << " * " << app->id(); - else - qCDebug(LogSystem).nospace().noquote() << " * " << app->id() << " [at: " - << static_cast<const ApplicationInfo*>(app)->codeDir().path() << "]"; - } - } - - m_applicationDatabase->write(apps); - qDeleteAll(apps); } - StartupTimer::instance()->checkpoint("after application database loading"); + StartupTimer::instance()->checkpoint("after package database loading"); } void Main::setupIntents(const QMap<QString, int> &timeouts) Q_DECL_NOEXCEPT_EXPR(false) @@ -480,38 +459,56 @@ void Main::setupIntents(const QMap<QString, int> &timeouts) Q_DECL_NOEXCEPT_EXPR qCDebug(LogSystem) << "Registering intents:"; - const auto apps = m_applicationManager->applications(); - for (AbstractApplication *app : apps) - IntentAMImplementation::addApplicationIntents(app, m_intentServer); + const auto packages = m_packageManager->packages(); + for (const Package *package : packages) { + const auto intents = package->info()->intents(); + if (!intents.isEmpty()) + m_intentServer->addApplication(package->id()); + + for (const IntentInfo *intent : intents) { + if (!m_intentServer->addIntent(intent->id(), package->id(), intent->handlingApplicationId(), + intent->requiredCapabilities(), + intent->visibility() == IntentInfo::Public ? Intent::Public + : Intent::Private, + intent->parameterMatch())) { + throw Exception(Error::Intents, "could not add intent %1 for package %2") + .arg(intent->id()).arg(package->id()); + } + qCDebug(LogSystem).nospace().noquote() << " * " << intent->id() << " [package: " << package->id() << "]"; + } + } StartupTimer::instance()->checkpoint("after Intents setup"); } void Main::setupSingletons(const QList<QPair<QString, QString>> &containerSelectionConfiguration, - int quickLaunchRuntimesPerContainer, qreal quickLaunchIdleLoad, - const QString &singleApp) Q_DECL_NOEXCEPT_EXPR(false) + int quickLaunchRuntimesPerContainer, + qreal quickLaunchIdleLoad) Q_DECL_NOEXCEPT_EXPR(false) { - m_applicationManager = ApplicationManager::createInstance(m_isSingleProcessMode); - - if (m_applicationDatabase) { - setupApplicationManagerWithDatabase(); - } else { - QVector<AbstractApplicationInfo *> appInfoVector; - - if (!singleApp.isEmpty()) { - appInfoVector = scanForApplication(singleApp, m_builtinAppsManifestDirs); - } else { - appInfoVector = scanForApplications(m_builtinAppsManifestDirs, - m_installedAppsManifestDir, - m_installationLocations); + m_packageManager = PackageManager::createInstance(m_packageDatabase, m_documentDir); + + qCDebug(LogSystem) << "Registering packages:"; + + QVector<Application *> applications; + const auto allPackages = m_packageManager->packages(); + for (auto package : allPackages) { + qCDebug(LogSystem).nospace().noquote() << " * " << package->id() << " [at: " + << QDir().relativeFilePath(package->info()->baseDir().path()) << "]"; + const auto appInfos = package->info()->applications(); + for (auto appInfo : appInfos) { + applications << new Application(appInfo, package); + qCDebug(LogSystem).nospace().noquote() << " * application:" << appInfo->id(); } - - QVector<AbstractApplication *> apps = AbstractApplication::fromApplicationInfoVector(appInfoVector); - m_applicationManager->setApplications(apps); } - if (!singleApp.isEmpty()) - m_applicationManager->enableSingleAppMode(); + m_applicationManager = ApplicationManager::createInstance(m_isSingleProcessMode); + m_applicationManager->setApplications(applications); + + connect(&m_applicationManager->internalSignals, &ApplicationManagerInternalSignals::applicationsChanged, + this, [this]() { + //m_packageDatabase->saveToCache(); + //TODO: this is wrong - we haven't update the info cache! + }); if (m_noSecurity) m_applicationManager->setSecurityChecksEnabled(false); @@ -534,27 +531,11 @@ void Main::setupSingletons(const QList<QPair<QString, QString>> &containerSelect StartupTimer::instance()->checkpoint("after quick-launcher setup"); } -void Main::setupApplicationManagerWithDatabase() -{ - m_applicationManager->setApplications(m_applicationDatabase->read()); - - connect(&m_applicationManager->internalSignals, &ApplicationManagerInternalSignals::applicationsChanged, - this, [this]() { - try { - if (m_applicationDatabase) - m_applicationDatabase->write(m_applicationManager->applications()); - } catch (const Exception &e) { - qCCritical(LogInstaller) << "Failed to write the application database to disk:" << e.errorString(); - m_applicationDatabase->invalidate(); // make sure that the next AM start will rebuild the DB - } - }); -} - void Main::setupInstaller(const QStringList &caCertificatePaths, const std::function<bool(uint *, uint *, uint *)> &userIdSeparation) Q_DECL_NOEXCEPT_EXPR(false) { #if !defined(AM_DISABLE_INSTALLER) - if (!Package::checkCorrectLocale()) { + if (!PackageUtilities::checkCorrectLocale()) { // we should really throw here, but so many embedded systems are badly set up qCWarning(LogDeployment) << "The appman installer needs a UTF-8 locale to work correctly: " "even automatically switching to C.UTF-8 or en_US.UTF-8 failed."; @@ -563,24 +544,20 @@ void Main::setupInstaller(const QStringList &caCertificatePaths, if (Q_UNLIKELY(hardwareId().isEmpty())) throw Exception("the installer is enabled, but the device-id is empty"); - if (Q_UNLIKELY(!QDir::root().mkpath(m_installedAppsManifestDir))) - throw Exception("could not create manifest directory for installed applications: \'%1\'").arg(m_installedAppsManifestDir); + if (!m_installationDir.isEmpty() && !QDir::root().mkpath(m_installationDir)) + throw Exception("could not create package installation directory: \'%1\'").arg(m_installationDir); + if (!m_documentDir.isEmpty() && !QDir::root().mkpath(m_documentDir)) + throw Exception("could not create document directory for packages: \'%1\'").arg(m_documentDir); StartupTimer::instance()->checkpoint("after installer setup checks"); - QString error; - m_applicationInstaller = ApplicationInstaller::createInstance(m_installationLocations, - m_installedAppsManifestDir, - hardwareId(), - &error); - if (Q_UNLIKELY(!m_applicationInstaller)) - throw Exception(Error::System, error); + m_applicationInstaller = ApplicationInstaller::createInstance(m_packageManager); if (m_developmentMode) - m_applicationInstaller->setDevelopmentMode(true); + m_packageManager->setDevelopmentMode(true); if (m_noSecurity) { - m_applicationInstaller->setAllowInstallationOfUnsignedPackages(true); + m_packageManager->setAllowInstallationOfUnsignedPackages(true); } else { QList<QByteArray> caCertificateList; @@ -593,13 +570,13 @@ void Main::setupInstaller(const QStringList &caCertificatePaths, throw Exception(f, "CA-certificate file is empty"); caCertificateList << cert; } - m_applicationInstaller->setCACertificates(caCertificateList); + m_packageManager->setCACertificates(caCertificateList); } uint minUserId, maxUserId, commonGroupId; if (userIdSeparation && userIdSeparation(&minUserId, &maxUserId, &commonGroupId)) { # if defined(Q_OS_LINUX) - if (!m_applicationInstaller->enableApplicationUserIdSeparation(minUserId, maxUserId, commonGroupId)) + if (!m_packageManager->enableApplicationUserIdSeparation(minUserId, maxUserId, commonGroupId)) throw Exception("could not enable application user-id separation in the installer."); # else qCCritical(LogSystem) << "WARNING: application user-id separation requested, but not possible on this platform."; @@ -607,9 +584,12 @@ void Main::setupInstaller(const QStringList &caCertificatePaths, } //TODO: this could be delayed, but needs to have a lock on the app-db in this case - m_applicationInstaller->cleanupBrokenInstallations(); + m_packageManager->cleanupBrokenInstallations(); - StartupTimer::instance()->checkpoint("after ApplicationInstaller instantiation"); + StartupTimer::instance()->checkpoint("after PackageManager instantiation"); +#else + Q_UNUSED(caCertificatePaths) + Q_UNUSED(userIdSeparation) #endif // AM_DISABLE_INSTALLER } @@ -1002,9 +982,9 @@ void Main::setupDBus(const std::function<QString(const char *)> &busForInterface }; # if !defined(AM_DISABLE_INSTALLER) - if (m_applicationInstaller) { - addInterface(new ApplicationInstallerDBusContextAdaptor(m_applicationInstaller), - "io.qt.ApplicationManager", "/ApplicationInstaller"); + if (m_packageManager) { + addInterface(new PackageManagerDBusContextAdaptor(m_packageManager), + "io.qt.ApplicationManager", "/PackageManager"); } # endif # if !defined(AM_HEADLESS) @@ -1071,149 +1051,6 @@ void Main::setupDBus(const std::function<QString(const char *)> &busForInterface #endif // defined(QT_DBUS_LIB) && !defined(AM_DISABLE_EXTERNAL_DBUS_INTERFACES) } - -QVector<AbstractApplicationInfo *> Main::scanForApplication(const QString &singleAppInfoYaml, - const QStringList &builtinAppsDirs) Q_DECL_NOEXCEPT_EXPR(false) -{ - QVector<AbstractApplicationInfo *> result; - YamlApplicationScanner yas; - - QDir appDir = QFileInfo(singleAppInfoYaml).dir(); - - QScopedPointer<ApplicationInfo> a(yas.scan(singleAppInfoYaml)); - Q_ASSERT(a); - - if (!RuntimeFactory::instance()->manager(a->runtimeName())) { - qCDebug(LogSystem) << "Ignoring application" << a->id() << ", because it uses an unknown runtime:" << a->runtimeName(); - return result; - } - - QStringList aliasPaths = appDir.entryList(QStringList(qSL("info-*.yaml"))); - std::vector<std::unique_ptr<AbstractApplicationInfo>> aliases; - - for (int i = 0; i < aliasPaths.size(); ++i) { - std::unique_ptr<AbstractApplicationInfo> alias(yas.scanAlias(appDir.absoluteFilePath(aliasPaths.at(i)), a.data())); - - Q_ASSERT(alias); - Q_ASSERT(alias->isAlias()); - - aliases.push_back(std::move(alias)); - } - - if (appDir.cdUp()) { - for (const QString &dir : builtinAppsDirs) { - if (appDir == QDir(dir)) { - a->setBuiltIn(true); - break; - } - } - } - - result << a.take(); - for (auto &&alias : aliases) - result << alias.release(); - - return result; -} - -QVector<AbstractApplicationInfo *> Main::scanForApplications(const QStringList &builtinAppsDirs, const QString &installedAppsDir, - const QVector<InstallationLocation> &installationLocations) Q_DECL_NOEXCEPT_EXPR(false) -{ - QVector<AbstractApplicationInfo *> result; - YamlApplicationScanner yas; - - auto scan = [&result, &yas, &installationLocations](const QDir &baseDir, bool scanningBuiltinApps) { - auto flags = scanningBuiltinApps ? QDir::Dirs | QDir::NoDotAndDotDot - : QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks; - const QStringList appDirNames = baseDir.entryList(flags); - - for (const QString &appDirName : appDirNames) { - if (appDirName.endsWith('+') || appDirName.endsWith('-')) - continue; - QString appIdError; - if (!AbstractApplicationInfo::isValidApplicationId(appDirName, false, &appIdError)) { - qCDebug(LogSystem) << "Ignoring application directory" << appDirName - << ": not a valid application-id:" << qPrintable(appIdError); - continue; - } - QDir appDir = baseDir.absoluteFilePath(appDirName); - if (!appDir.exists()) - continue; - if (!appDir.exists(qSL("info.yaml"))) { - qCDebug(LogSystem) << "Couldn't find a info.yaml in:" << appDir; - continue; - } - if (!scanningBuiltinApps && !appDir.exists(qSL("installation-report.yaml"))) - continue; - - QScopedPointer<ApplicationInfo> a(yas.scan(appDir.absoluteFilePath(qSL("info.yaml")))); - Q_ASSERT(a); - - AbstractRuntimeManager *runtimeManager = RuntimeFactory::instance()->manager(a->runtimeName()); - if (!runtimeManager) { - qCDebug(LogSystem) << "Ignoring application" << a->id() << ", because it uses an unknown runtime:" << a->runtimeName(); - continue; - } - if (runtimeManager->supportsQuickLaunch()) { - if (a->supportsApplicationInterface()) - qCDebug(LogSystem) << "Ignoring supportsApplicationInterface for application" << a->id() << - "as the runtime launcher supports it by default"; - a->setSupportsApplicationInterface(true); - } - if (a->id() != appDirName) { - throw Exception(Error::Parse, "an info.yaml for built-in applications must be in a directory " - "that has the same name as the application's id: found %1 in %2") - .arg(a->id(), appDirName); - } - if (scanningBuiltinApps) { - a->setBuiltIn(true); - QStringList aliasPaths = appDir.entryList(QStringList(qSL("info-*.yaml"))); - std::vector<std::unique_ptr<AbstractApplicationInfo>> aliases; - - for (int i = 0; i < aliasPaths.size(); ++i) { - std::unique_ptr<AbstractApplicationInfo> alias(yas.scanAlias(appDir.absoluteFilePath(aliasPaths.at(i)), a.data())); - - Q_ASSERT(alias); - Q_ASSERT(alias->isAlias()); - - aliases.push_back(std::move(alias)); - } - result << a.take(); - for (auto &&alias : aliases) - result << alias.release(); - } else { // 3rd-party apps - QFile f(appDir.absoluteFilePath(qSL("installation-report.yaml"))); - if (!f.open(QFile::ReadOnly)) - continue; - - QScopedPointer<InstallationReport> report(new InstallationReport(a->id())); - if (!report->deserialize(&f)) - continue; - -#if !defined(AM_DISABLE_INSTALLER) - // fix the basedir of the application - for (const InstallationLocation &il : installationLocations) { - if (il.id() == report->installationLocationId()) { - a->setCodeDir(il.installationPath() + a->id()); - break; - } - } -#endif - a->setInstallationReport(report.take()); - result << a.take(); - } - } - }; - - for (const QString &dir : builtinAppsDirs) - scan(dir, true); -#if !defined(AM_DISABLE_INSTALLER) - if (!installedAppsDir.isEmpty()) - scan(installedAppsDir, false); -#endif - return result; -} - QString Main::hardwareId() const { static QString hardwareId; diff --git a/src/main-lib/main.h b/src/main-lib/main.h index 28838e6e..b7a38cee 100644 --- a/src/main-lib/main.h +++ b/src/main-lib/main.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -59,7 +59,6 @@ typedef QApplication MainBase; typedef QGuiApplication MainBase; #endif -#include <QtAppManInstaller/installationlocation.h> #include <QtAppManSharedMain/sharedmain.h> #include <QVector> @@ -71,10 +70,11 @@ class StartupInterface; QT_BEGIN_NAMESPACE_AM -class AbstractApplicationInfo; +class ApplicationInfo; class StartupTimer; class ApplicationIPCManager; -class ApplicationDatabase; +class PackageDatabase; +class PackageManager; class ApplicationManager; class ApplicationInstaller; class NotificationManager; @@ -114,13 +114,10 @@ protected: void setupRuntimesAndContainers(const QVariantMap &runtimeConfigurations, const QVariantMap &openGLConfiguration, const QVariantMap &containerConfigurations, const QStringList &containerPluginPaths, const QStringList &iconThemeSearchPaths, const QString &iconThemeName); - void setupInstallationLocations(const QVariantList &installationLocations); - void loadApplicationDatabase(const QString &databasePath, bool recreateDatabase, - const QString &singleApp) Q_DECL_NOEXCEPT_EXPR(false); + void loadPackageDatabase(bool recreateDatabase, const QString &singlePackage) Q_DECL_NOEXCEPT_EXPR(false); void setupIntents(const QMap<QString, int> &timeouts) Q_DECL_NOEXCEPT_EXPR(false); void setupSingletons(const QList<QPair<QString, QString>> &containerSelectionConfiguration, - int quickLaunchRuntimesPerContainer, qreal quickLaunchIdleLoad, - const QString &singleApp) Q_DECL_NOEXCEPT_EXPR(false); + int quickLaunchRuntimesPerContainer, qreal quickLaunchIdleLoad) Q_DECL_NOEXCEPT_EXPR(false); void setupInstaller(const QStringList &caCertificatePaths, const std::function<bool(uint *, uint *, uint *)> &userIdSeparation) Q_DECL_NOEXCEPT_EXPR(false); @@ -145,16 +142,8 @@ private: void registerDBusObject(QDBusAbstractAdaptor *adaptor, QString dbusName, const char *serviceName, const char *interfaceName, const char *path) Q_DECL_NOEXCEPT_EXPR(false); #endif - static QVector<AbstractApplicationInfo *> scanForApplication(const QString &singleAppInfoYaml, - const QStringList &builtinAppsDirs) Q_DECL_NOEXCEPT_EXPR(false); - static QVector<AbstractApplicationInfo *> scanForApplications(const QStringList &builtinAppsDirs, - const QString &installedAppsDir, - const QVector<InstallationLocation> &installationLocations) Q_DECL_NOEXCEPT_EXPR(false); - - void setupApplicationManagerWithDatabase(); private: - QVector<InstallationLocation> m_installationLocations; bool m_isSingleProcessMode = false; QUrl m_mainQml; QString m_mainQmlLocalFile; @@ -162,10 +151,13 @@ private: QQmlApplicationEngine *m_engine = nullptr; QQuickView *m_view = nullptr; // only set if we allocate the window ourselves - QScopedPointer<ApplicationDatabase> m_applicationDatabase; + PackageDatabase *m_packageDatabase = nullptr; + PackageManager *m_packageManager = nullptr; ApplicationManager *m_applicationManager = nullptr; ApplicationIPCManager *m_applicationIPCManager = nullptr; +#if !defined(AM_DISABLE_INSTALLER) ApplicationInstaller *m_applicationInstaller = nullptr; +#endif NotificationManager *m_notificationManager = nullptr; IntentServer *m_intentServer = nullptr; WindowManager *m_windowManager = nullptr; @@ -176,7 +168,8 @@ private: bool m_noSecurity = false; bool m_developmentMode = false; QStringList m_builtinAppsManifestDirs; - QString m_installedAppsManifestDir; + QString m_installationDir; + QString m_documentDir; }; QT_END_NAMESPACE_AM diff --git a/src/main-lib/windowframetimer.cpp b/src/main-lib/windowframetimer.cpp index 11cc342e..c240023e 100644 --- a/src/main-lib/windowframetimer.cpp +++ b/src/main-lib/windowframetimer.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/main-lib/windowframetimer.h b/src/main-lib/windowframetimer.h index 098cacff..de9aefcf 100644 --- a/src/main-lib/windowframetimer.h +++ b/src/main-lib/windowframetimer.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/manager-lib/abstractcontainer.cpp b/src/manager-lib/abstractcontainer.cpp index 8827c788..aa444268 100644 --- a/src/manager-lib/abstractcontainer.cpp +++ b/src/manager-lib/abstractcontainer.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -118,7 +118,7 @@ AbstractContainerProcess *AbstractContainer::process() const return m_process; } -void AbstractContainer::setApplication(AbstractApplication *app) +void AbstractContainer::setApplication(Application *app) { if (app != m_app) { m_app = app; @@ -126,12 +126,12 @@ void AbstractContainer::setApplication(AbstractApplication *app) } } -AbstractApplication *AbstractContainer::application() const +Application *AbstractContainer::application() const { return m_app; } -AbstractContainer::AbstractContainer(AbstractContainerManager *manager, AbstractApplication *app) +AbstractContainer::AbstractContainer(AbstractContainerManager *manager, Application *app) : QObject(manager) , m_manager(manager) , m_app(app) diff --git a/src/manager-lib/abstractcontainer.h b/src/manager-lib/abstractcontainer.h index 15e7d1f1..435c9eba 100644 --- a/src/manager-lib/abstractcontainer.h +++ b/src/manager-lib/abstractcontainer.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE_AM -class AbstractApplication; +class Application; class AbstractContainer; class AbstractContainerManager : public QObject @@ -66,7 +66,7 @@ public: QString identifier() const; virtual bool supportsQuickLaunch() const; - virtual AbstractContainer *create(AbstractApplication *app, const QVector<int> &stdioRedirections, + virtual AbstractContainer *create(Application *app, const QVector<int> &stdioRedirections, const QMap<QString, QString> &debugWrapperEnvironment, const QStringList &debugWrapperCommand) = 0; @@ -124,17 +124,17 @@ public: AbstractContainerProcess *process() const; - void setApplication(AbstractApplication *app); - AbstractApplication *application() const; + void setApplication(Application *app); + Application *application() const; signals: void ready(); void memoryLowWarning(); void memoryCriticalWarning(); - void applicationChanged(AbstractApplication *newApplication); + void applicationChanged(Application *newApplication); protected: - explicit AbstractContainer(AbstractContainerManager *manager, AbstractApplication *app); + explicit AbstractContainer(AbstractContainerManager *manager, Application *app); QVariantMap configuration() const; @@ -142,7 +142,7 @@ protected: QString m_baseDirectory; AbstractContainerManager *m_manager; AbstractContainerProcess *m_process = nullptr; - AbstractApplication *m_app; + Application *m_app; }; QT_END_NAMESPACE_AM diff --git a/src/manager-lib/abstractruntime.cpp b/src/manager-lib/abstractruntime.cpp index 1c4ba03f..ec34aabd 100644 --- a/src/manager-lib/abstractruntime.cpp +++ b/src/manager-lib/abstractruntime.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/manager-lib/abstractruntime.h b/src/manager-lib/abstractruntime.h index 8276be47..ef70120b 100644 --- a/src/manager-lib/abstractruntime.h +++ b/src/manager-lib/abstractruntime.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/manager-lib/amnamespace.h b/src/manager-lib/amnamespace.h index f407da90..c144f96b 100644 --- a/src/manager-lib/amnamespace.h +++ b/src/manager-lib/amnamespace.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/manager-lib/application.cpp b/src/manager-lib/application.cpp index bc2c7e4f..432cc86e 100644 --- a/src/manager-lib/application.cpp +++ b/src/manager-lib/application.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -43,14 +43,12 @@ #include "application.h" #include "abstractruntime.h" #include "applicationinfo.h" +#include "package.h" #include "exception.h" #include "logging.h" #include <QDebug> -#if defined(Q_OS_UNIX) -# include <signal.h> -#endif /*! \qmltype ApplicationObject @@ -90,9 +88,12 @@ /*! \qmlproperty string ApplicationObject::documentUrl \readonly + \obsolete - This property always returns the default \c documentUrl specified in the manifest file, even if - a different URL was used to start the application. + This was used to distinguish between application aliases, which have been replaced by the + intents mechanism. + + Always returns an empty string. */ /*! \qmlproperty bool ApplicationObject::builtIn @@ -104,22 +105,22 @@ /*! \qmlproperty bool ApplicationObject::alias \readonly + \obsolete - Will return \c true if this ApplicationObject object is an alias to another one. + This was used to distinguish between application aliases, which have been replaced by the + intents mechanism. - \sa nonAliased + Always returns \c false. */ /*! \qmlproperty ApplicationObject ApplicationObject::nonAliased \readonly + \obsolete - If this ApplicationObject is an alias, then you can access the non-alias, base ApplicationObject - via this property, otherwise it contains a reference to itself. This means that if you're interested - in accessing the base application regardless of whether the object at hand is just an alias, you - can always safely refer to this property. + This was used to distinguish between application aliases, which have been replaced by the + intents mechanism. - If you want to know whether this object is an alias or a base ApplicationObject, use - ApplicationObject::alias instead. + Always returns the object itself. */ /*! \qmlproperty list<string> ApplicationObject::capabilities @@ -190,10 +191,7 @@ \qmlproperty string ApplicationObject::codeDir \readonly - The absolute path to the application's installation directory. Please note this directory might - not always be available for applications that were installed onto removable media. - - \sa {Installation Locations} + The absolute path to the application's installation directory. */ /*! \qmlproperty enumeration ApplicationObject::state @@ -272,237 +270,162 @@ QT_BEGIN_NAMESPACE_AM + /////////////////////////////////////////////////////////////////////////////////////////////////// -// AbstractApplication +// Application /////////////////////////////////////////////////////////////////////////////////////////////////// -AbstractApplication::AbstractApplication(AbstractApplicationInfo *info) +Application::Application(ApplicationInfo *info, Package *package) : m_info(info) + , m_package(package) { + Q_ASSERT(info); + Q_ASSERT(package); + + // handle package blocking: all apps have to be stopped and the stop state has to be reported + // back to the package + connect(package, &Package::blockedChanged, this, [this](bool blocked) { + emit blockedChanged(blocked); + if (blocked && (runState() == Am::NotRunning)) + this->package()->applicationStoppedDueToBlock(id()); + else if (blocked) + stop(true); + }); + connect(this, &Application::runStateChanged, this, [this](Am::RunState runState) { + if (isBlocked() && (runState == Am::NotRunning)) + this->package()->applicationStoppedDueToBlock(id()); + }); } -QString AbstractApplication::id() const +bool Application::start(const QString &documentUrl) { - return m_info->id(); + if (requests.startRequested) + return requests.startRequested(documentUrl); + else + return false; } -QUrl AbstractApplication::icon() const +bool Application::debug(const QString &debugWrapper, const QString &documentUrl) { - if (info()->icon().isEmpty()) - return QUrl(); - - auto appInfo = this->nonAliasedInfo(); - QDir dir; - switch (state()) { - default: - case Installed: - dir.setPath(appInfo->manifestDir()); - break; - case BeingInstalled: - case BeingUpdated: - dir.setPath(appInfo->codeDir().absolutePath() + QLatin1Char('+')); - break; - case BeingRemoved: - dir.setPath(appInfo->codeDir().absolutePath() + QLatin1Char('-')); - break; - } - return QUrl::fromLocalFile(dir.absoluteFilePath(info()->icon())); + if (requests.debugRequested) + return requests.debugRequested(debugWrapper, documentUrl); + else + return false; } -QString AbstractApplication::documentUrl() const +void Application::stop(bool forceKill) { - return info()->documentUrl(); + if (requests.stopRequested) + requests.stopRequested(forceKill); } -bool AbstractApplication::isBuiltIn() const +ApplicationInfo *Application::info() const { - return nonAliasedInfo()->isBuiltIn(); + return m_info.data(); } -bool AbstractApplication::isAlias() const +PackageInfo *Application::packageInfo() const { - return info()->isAlias(); + return m_info->packageInfo(); } -QStringList AbstractApplication::capabilities() const +Package *Application::package() const { - return nonAliasedInfo()->capabilities(); + return m_package; } -QStringList AbstractApplication::supportedMimeTypes() const +QString Application::id() const { - return nonAliasedInfo()->supportedMimeTypes(); + return m_info->id(); } -QStringList AbstractApplication::categories() const +bool Application::isBuiltIn() const { - return nonAliasedInfo()->categories(); + return packageInfo()->isBuiltIn(); } -QVariantMap AbstractApplication::applicationProperties() const +QString Application::runtimeName() const { - return info()->applicationProperties(); + return m_info->runtimeName(); } -bool AbstractApplication::supportsApplicationInterface() const +QVariantMap Application::runtimeParameters() const { - return nonAliasedInfo()->supportsApplicationInterface(); + return m_info->runtimeParameters(); } -QString AbstractApplication::version() const +QStringList Application::capabilities() const { - return nonAliasedInfo()->version(); + return m_info->capabilities(); } -QString AbstractApplication::codeDir() const +QStringList Application::categories() const { - switch (state()) { - default: - case Installed: - return nonAliasedInfo()->codeDir().absolutePath(); - case BeingInstalled: - case BeingUpdated: - return nonAliasedInfo()->codeDir().absolutePath() + QLatin1Char('+'); - case BeingRemoved: - return nonAliasedInfo()->codeDir().absolutePath() + QLatin1Char('-'); - } + return package()->categories(); } -QString AbstractApplication::name(const QString &language) const +QUrl Application::icon() const { - return info()->name(language); + return package()->icon(); } -bool AbstractApplication::start(const QString &documentUrl) +QStringList Application::supportedMimeTypes() const { - if (requests.startRequested) - return requests.startRequested(documentUrl); - else - return false; + return info()->supportedMimeTypes(); } -bool AbstractApplication::debug(const QString &debugWrapper, const QString &documentUrl) +QString Application::name() const { - if (requests.debugRequested) - return requests.debugRequested(debugWrapper, documentUrl); - else - return false; + return package()->name(); } -void AbstractApplication::stop(bool forceKill) +QString Application::name(const QString &language) const { - if (requests.stopRequested) - requests.stopRequested(forceKill); + return package()->names().value(language).toString(); } -QVector<AbstractApplication *> AbstractApplication::fromApplicationInfoVector( - QVector<AbstractApplicationInfo *> &appInfoVector) +bool Application::isBlocked() const { - QVector<AbstractApplication *> apps; - - auto findAppWithId = [&apps] (const QString &id) -> AbstractApplication* - { - for (AbstractApplication *app : apps) { - if (app->id() == id) - return app; - } - return nullptr; - }; - - auto extractBaseId = [] (const QString &id) -> QString - { - return id.section(qL1C('@'), 0, 0); - }; - - for (auto *appInfo : appInfoVector) { - QScopedPointer<AbstractApplication> app; - if (appInfo->isAlias()) { - auto *originalApp = findAppWithId(extractBaseId(appInfo->id())); - if (!originalApp) - throw Exception(Error::Parse, "Could not find base app for alias id %2").arg(appInfo->id()); - Q_ASSERT(!originalApp->isAlias()); - app.reset(new ApplicationAlias(static_cast<Application*>(originalApp), - static_cast<ApplicationAliasInfo*>(appInfo))); - } else { - AbstractApplication *otherAbsApp = findAppWithId(appInfo->id()); - if (otherAbsApp) { - // There's already another ApplicationInfo with the same id. It's probably an update for a - // built-in app, in which case we use the same Application instance to hold both - // ApplicationInfo instances. - bool merged = false; - - if (!otherAbsApp->isAlias()) { - auto otherApp = static_cast<Application*>(otherAbsApp); - auto fullAppInfo = static_cast<ApplicationInfo*>(appInfo); - if (otherApp->isBuiltIn() && !fullAppInfo->isBuiltIn() && !otherApp->updatedInfo()) { - otherApp->setUpdatedInfo(static_cast<ApplicationInfo*>(appInfo)); - merged = true; - } else if (!otherApp->isBuiltIn() && fullAppInfo->isBuiltIn() && !otherApp->updatedInfo()) { - auto currentBaseInfo = otherApp->takeBaseInfo(); - otherApp->setBaseInfo(static_cast<ApplicationInfo*>(appInfo)); - otherApp->setUpdatedInfo(currentBaseInfo); - merged = true; - } - } - - if (!merged) - qCWarning(LogSystem).nospace() << "Found a second application with id " - << appInfo->id() << " which is not an update for a built-in one. Ignoring it."; - } else { - app.reset(new Application(static_cast<ApplicationInfo*>(appInfo))); - } - } - - if (!app.isNull()) - apps << app.take(); - } - - return apps; + return package()->isBlocked(); } -/////////////////////////////////////////////////////////////////////////////////////////////////// -// Application -/////////////////////////////////////////////////////////////////////////////////////////////////// - -Application::Application(ApplicationInfo *info, State initialState) - : AbstractApplication(info) - , m_state(initialState) +QVariantMap Application::applicationProperties() const { + return info()->applicationProperties(); } -void Application::setCurrentRuntime(AbstractRuntime *rt) +bool Application::supportsApplicationInterface() const { - if (m_runtime == rt) - return; - - if (m_runtime) - disconnect(m_runtime, nullptr, this, nullptr); - - m_runtime = rt; - emit runtimeChanged(); + return info()->supportsApplicationInterface(); +} - if (m_runtime) { - connect(m_runtime, &AbstractRuntime::finished, this, &Application::setLastExitCodeAndStatus); - connect(m_runtime, &QObject::destroyed, this, [this]() { - this->setCurrentRuntime(nullptr); - }); - } else - setRunState(Am::NotRunning); +QString Application::codeDir() const +{ + switch (package()->state()) { + default: + case Package::Installed: + return packageInfo()->baseDir().absolutePath(); + case Package::BeingInstalled: + case Package::BeingUpdated: + return packageInfo()->baseDir().absolutePath() + QLatin1Char('+'); + case Package::BeingRemoved: + return packageInfo()->baseDir().absolutePath() + QLatin1Char('-'); + } } -bool Application::isBlocked() const +QString Application::version() const { - return m_blocked.load() == 1; + return packageInfo()->version(); } -bool Application::block() +Application::State Application::state() const { - return m_blocked.testAndSetOrdered(0, 1); + return static_cast<State>(package()->state()); } -bool Application::unblock() +qreal Application::progress() const { - return m_blocked.testAndSetOrdered(1, 0); + return package()->progress(); } void Application::setRunState(Am::RunState runState) @@ -513,24 +436,25 @@ void Application::setRunState(Am::RunState runState) } } -QString Application::runtimeName() const +void Application::setCurrentRuntime(AbstractRuntime *runtime) { - return Application::nonAliasedInfo()->runtimeName(); -} + if (m_runtime == runtime) + return; -QVariantMap Application::runtimeParameters() const -{ - return Application::nonAliasedInfo()->runtimeParameters(); -} + if (m_runtime) + disconnect(m_runtime, nullptr, this, nullptr); -AbstractApplicationInfo *Application::info() const -{ - return m_updatedInfo ? m_updatedInfo.data() : m_info.data(); -} + m_runtime = runtime; + emit runtimeChanged(); -ApplicationInfo *Application::nonAliasedInfo() const -{ - return static_cast<ApplicationInfo*>(Application::info()); + if (m_runtime) { + connect(m_runtime, &AbstractRuntime::finished, this, &Application::setLastExitCodeAndStatus); + connect(m_runtime, &QObject::destroyed, this, [this]() { + this->setCurrentRuntime(nullptr); + }); + } else { + setRunState(Am::NotRunning); + } } void Application::setLastExitCodeAndStatus(int exitCode, Am::ExitStatus exitStatus) @@ -540,88 +464,15 @@ void Application::setLastExitCodeAndStatus(int exitCode, Am::ExitStatus exitStat emit lastExitCodeChanged(); } - Am::ExitStatus newStatus; - if (exitStatus == Am::CrashExit) { -#if defined(Q_OS_UNIX) - newStatus = (exitCode == SIGTERM || exitCode == SIGKILL) ? Am::ForcedExit : Am::CrashExit; -#else - newStatus = Am::CrashExit; -#endif - } else { - newStatus = Am::NormalExit; - } - - if (m_lastExitStatus != newStatus) { - m_lastExitStatus = newStatus; + if (m_lastExitStatus != exitStatus) { + m_lastExitStatus = exitStatus; emit lastExitStatusChanged(); } } -void Application::setBaseInfo(ApplicationInfo *info) -{ - m_info.reset(info); - emit bulkChange(); -} - -ApplicationInfo *Application::takeBaseInfo() -{ - return static_cast<ApplicationInfo*>(m_info.take()); -} - -void Application::setUpdatedInfo(ApplicationInfo* info) -{ - Q_ASSERT(!info || (m_info && info->id() == m_info->id())); - - m_updatedInfo.reset(info); - emit bulkChange(); -} - -void Application::setState(State state) -{ - if (m_state != state) { - m_state = state; - emit stateChanged(m_state); - } -} - -void Application::setProgress(qreal value) -{ - m_progress = value; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// -// ApplicationAlias -/////////////////////////////////////////////////////////////////////////////////////////////////// - -ApplicationAlias::ApplicationAlias(Application* app, ApplicationAliasInfo* info) - : AbstractApplication(info) - , m_application(app) -{ - connect(m_application, &AbstractApplication::runtimeChanged, this, &AbstractApplication::runtimeChanged); - connect(m_application, &AbstractApplication::lastExitCodeChanged, this, &AbstractApplication::lastExitCodeChanged); - connect(m_application, &AbstractApplication::lastExitStatusChanged, this, &AbstractApplication::lastExitStatusChanged); - connect(m_application, &AbstractApplication::stateChanged, this, &AbstractApplication::stateChanged); - connect(m_application, &AbstractApplication::runStateChanged, this, &AbstractApplication::runStateChanged); -} - -QString ApplicationAlias::runtimeName() const -{ - return m_application->runtimeName(); -} - -QVariantMap ApplicationAlias::runtimeParameters() const -{ - return m_application->runtimeParameters(); -} - -ApplicationInfo *ApplicationAlias::nonAliasedInfo() const -{ - return m_application->nonAliasedInfo(); -} - QT_END_NAMESPACE_AM -QDebug operator<<(QDebug debug, const QT_PREPEND_NAMESPACE_AM(AbstractApplication) *app) +QDebug operator<<(QDebug debug, const QT_PREPEND_NAMESPACE_AM(Application) *app) { debug << "Application Object:"; if (app) diff --git a/src/manager-lib/application.h b/src/manager-lib/application.h index 0b081329..9556cc3e 100644 --- a/src/manager-lib/application.h +++ b/src/manager-lib/application.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -44,15 +44,16 @@ #include <QObject> #include <QScopedPointer> +#include <QVariantMap> #include <QUrl> #include <QtAppManApplication/applicationinfo.h> +#include <QtAppManApplication/packageinfo.h> #include <QtAppManManager/amnamespace.h> #include <QtAppManCommon/global.h> QT_BEGIN_NAMESPACE_AM class AbstractRuntime; -class Application; // A place to collect functions used internally by appman without polluting // Application's public QML API. @@ -64,7 +65,9 @@ public: std::function<void(bool forceKill)> stopRequested; }; -class AbstractApplication : public QObject +class Package; + +class Application : public QObject { Q_OBJECT Q_CLASSINFO("AM-QmlType", "QtApplicationManager.SystemUI/ApplicationObject 2.0 UNCREATABLE") @@ -73,12 +76,12 @@ class AbstractApplication : public QObject Q_PROPERTY(QString runtimeName READ runtimeName NOTIFY bulkChange) Q_PROPERTY(QVariantMap runtimeParameters READ runtimeParameters NOTIFY bulkChange) Q_PROPERTY(QUrl icon READ icon NOTIFY bulkChange) - Q_PROPERTY(QString documentUrl READ documentUrl NOTIFY bulkChange) - Q_PROPERTY(bool builtIn READ isBuiltIn CONSTANT) - Q_PROPERTY(bool alias READ isAlias CONSTANT) - Q_PROPERTY(Application* nonAliased READ nonAliased CONSTANT) + Q_PROPERTY(QString documentUrl READ documentUrl NOTIFY bulkChange) // REMOVE + Q_PROPERTY(bool builtIn READ isBuiltIn NOTIFY bulkChange) + Q_PROPERTY(bool alias READ isAlias CONSTANT) // REMOVE + Q_PROPERTY(Application *nonAliased READ nonAliased CONSTANT) // REMOVE Q_PROPERTY(QStringList capabilities READ capabilities NOTIFY bulkChange) - Q_PROPERTY(QStringList supportedMimeTypes READ supportedMimeTypes NOTIFY bulkChange) + Q_PROPERTY(QStringList supportedMimeTypes READ supportedMimeTypes NOTIFY bulkChange) // REMOVE Q_PROPERTY(QStringList categories READ categories NOTIFY bulkChange) Q_PROPERTY(QVariantMap applicationProperties READ applicationProperties NOTIFY bulkChange) Q_PROPERTY(AbstractRuntime *runtime READ currentRuntime NOTIFY runtimeChanged) @@ -89,9 +92,10 @@ class AbstractApplication : public QObject Q_PROPERTY(QString codeDir READ codeDir NOTIFY bulkChange) Q_PROPERTY(State state READ state NOTIFY stateChanged) Q_PROPERTY(QT_PREPEND_NAMESPACE_AM(Am::RunState) runState READ runState NOTIFY runStateChanged) + Q_PROPERTY(bool blocked READ isBlocked NOTIFY blockedChanged) public: - enum State { + enum State { // kept for compatibility ... in reality moved to class Package Installed, BeingInstalled, BeingUpdated, @@ -100,62 +104,51 @@ public: }; Q_ENUM(State) - AbstractApplication(AbstractApplicationInfo *info); + Application(ApplicationInfo *info, Package *package); Q_INVOKABLE bool start(const QString &documentUrl = QString()); Q_INVOKABLE bool debug(const QString &debugWrapper, const QString &documentUrl = QString()); Q_INVOKABLE void stop(bool forceKill = false); - virtual Application *nonAliased() = 0; - - /* - Returns information about this application, which can either - be a full-fledged one (ApplicationInfo) or just an alias - (ApplicationAliasInfo). - - Use info()->isAlias() to check and cast as appropriate. - */ - virtual AbstractApplicationInfo *info() const = 0; + ApplicationInfo *info() const; + PackageInfo *packageInfo() const; + Package *package() const; - /* - Always returns information about the "concrete", non-aliased, application. - This is the same as static_cast<ApplicationInfo*>(nonAliased()->info()) - */ - virtual ApplicationInfo *nonAliasedInfo() const = 0; + // legacy compatibility + bool isAlias() const { return false; } + Application *nonAliased() { return this; } + QStringList categories() const; + QUrl icon() const; + QString documentUrl() const { return QString {}; } + QStringList supportedMimeTypes() const; + QString name() const; + Q_INVOKABLE QString name(const QString &language) const; + bool isBlocked() const; // Properties that mainly forward content from ApplicationInfo QString id() const; - virtual QString runtimeName() const = 0; - virtual QVariantMap runtimeParameters() const = 0; - QUrl icon() const; - QString documentUrl() const; bool isBuiltIn() const; - bool isAlias() const; + QString runtimeName() const; + QVariantMap runtimeParameters() const; QStringList capabilities() const; - QStringList supportedMimeTypes() const; - QStringList categories() const; QVariantMap applicationProperties() const; bool supportsApplicationInterface() const; + QString codeDir() const; QString version() const; - Q_INVOKABLE QString name(const QString &language) const; // Properties present only in Application (not coming from ApplicationInfo) - virtual AbstractRuntime *currentRuntime() const = 0; - virtual State state() const = 0; - QString codeDir() const; - virtual bool isBlocked() const = 0; - virtual bool block() = 0; - virtual bool unblock() = 0; - virtual qreal progress() const = 0; - virtual Am::RunState runState() const = 0; - virtual int lastExitCode() const = 0; - virtual Am::ExitStatus lastExitStatus() const = 0; + + AbstractRuntime *currentRuntime() const { return m_runtime; } + State state() const; + qreal progress() const; + Am::RunState runState() const { return m_runState; } + int lastExitCode() const { return m_lastExitCode; } + Am::ExitStatus lastExitStatus() const { return m_lastExitStatus; } ApplicationRequests requests; - // Creates a list of Applications from a list of ApplicationInfo objects. - // Ownership of the given ApplicationInfo objects is passed to the returned Applications. - static QVector<AbstractApplication *> fromApplicationInfoVector(QVector<AbstractApplicationInfo *> &); + void setRunState(Am::RunState runState); + void setCurrentRuntime(AbstractRuntime *runtime); signals: void bulkChange(); @@ -165,108 +158,24 @@ signals: void activated(); void stateChanged(State state); void runStateChanged(Am::RunState state); - -protected: - QScopedPointer<AbstractApplicationInfo> m_info; -}; - -class Application : public AbstractApplication -{ - Q_OBJECT -public: - Application(ApplicationInfo *info, State initialState = Installed); - - - // Returns the updated info, if there's one. Otherwise - // returns the base info. - AbstractApplicationInfo *info() const override; - - // same as info() - ApplicationInfo *nonAliasedInfo() const override; - - - /* - All applications have a base info. - - Built-in applications, when updated, also get an updated info. - The updated info then overlays the base one. Subsequent updates - just replace the updated info. When requested to be removed, a - built-in application only loses its updated info, returning to - expose the base one. - - Regular applications (ie, non-built-in) only have a base info. When - updated their base info gets replaced and thus there's no way to go - back to a previous version. Regular applications get completely - removed when requested. - */ - void setBaseInfo(ApplicationInfo*); - void setUpdatedInfo(ApplicationInfo*); - ApplicationInfo *updatedInfo() const { return m_updatedInfo.data(); } - ApplicationInfo *takeBaseInfo(); - - void setState(State); - void setProgress(qreal); - void setRunState(Am::RunState); - void setCurrentRuntime(AbstractRuntime *rt); - - Application *nonAliased() override { return this; } - QString runtimeName() const override; - QVariantMap runtimeParameters() const override; - AbstractRuntime *currentRuntime() const override { return m_runtime; } - State state() const override { return m_state; } - bool isBlocked() const override; - bool block() override; - bool unblock() override; - qreal progress() const override { return m_progress; } - Am::RunState runState() const override { return m_runState; } - int lastExitCode() const override { return m_lastExitCode; } - Am::ExitStatus lastExitStatus() const override { return m_lastExitStatus; } + void blockedChanged(bool blocked); private: void setLastExitCodeAndStatus(int exitCode, Am::ExitStatus exitStatus); + QScopedPointer<ApplicationInfo> m_info; + Package *m_package = nullptr; AbstractRuntime *m_runtime = nullptr; - QAtomicInt m_blocked; - QAtomicInt m_mounted; - State m_state = Installed; Am::RunState m_runState = Am::NotRunning; - qreal m_progress = 0; int m_lastExitCode = 0; Am::ExitStatus m_lastExitStatus = Am::NormalExit; - QScopedPointer<ApplicationInfo> m_updatedInfo; -}; - -class ApplicationAlias : public AbstractApplication -{ - Q_OBJECT -public: - ApplicationAlias(Application*, ApplicationAliasInfo*); - - AbstractApplicationInfo *info() const override { return m_info.data(); } - Application *nonAliased() override { return m_application; } - QString runtimeName() const override; - QVariantMap runtimeParameters() const override; - AbstractRuntime *currentRuntime() const override { return m_application->currentRuntime(); } - State state() const override { return m_application->state(); } - bool isBlocked() const override { return m_application->isBlocked(); } - bool block() override { return m_application->block(); } - bool unblock() override { return m_application->unblock(); } - qreal progress() const override { return m_application->progress(); } - Am::RunState runState() const override { return m_application->runState(); } - int lastExitCode() const override { return m_application->lastExitCode(); } - Am::ExitStatus lastExitStatus() const override { return m_application->lastExitStatus(); } -protected: - // Returns info() from the application being aliased - ApplicationInfo *nonAliasedInfo() const override; -private: - Application *m_application; }; QT_END_NAMESPACE_AM -Q_DECLARE_METATYPE(const QT_PREPEND_NAMESPACE_AM(AbstractApplication *)) +Q_DECLARE_METATYPE(const QT_PREPEND_NAMESPACE_AM(Application *)) -QDebug operator<<(QDebug debug, const QT_PREPEND_NAMESPACE_AM(AbstractApplication) *app); +QDebug operator<<(QDebug debug, const QT_PREPEND_NAMESPACE_AM(Application) *app); diff --git a/src/manager-lib/applicationdatabase.cpp b/src/manager-lib/applicationdatabase.cpp deleted file mode 100644 index a6fb8ef3..00000000 --- a/src/manager-lib/applicationdatabase.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2019 Luxoft Sweden AB -** Copyright (C) 2018 Pelagicore AG -** 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 <QFile> -#include <QDataStream> -#include <QTemporaryFile> -#include <QScopedPointer> - -#include "application.h" -#include "applicationdatabase.h" -#include "exception.h" -#include "logging.h" - -QT_BEGIN_NAMESPACE_AM - -class ApplicationDatabasePrivate -{ -public: - void validateWritableFile() - { - if (!file || !file->isOpen() || !file->isWritable()) - throw Exception("application database %1 is not opened for writing").arg(file ? file->fileName() : qSL("<null>")); - if (!file->seek(0)) - throw Exception(*file, "could not not seek to position 0 in the application database"); - if (!file->resize(0)) - throw Exception(*file, "could not truncate the application database"); - } - - QFile *file = nullptr; - - ApplicationDatabasePrivate() - { } - ~ApplicationDatabasePrivate() - { delete file; } -}; - -ApplicationDatabase::ApplicationDatabase(const QString &fileName) - : d(new ApplicationDatabasePrivate()) -{ - d->file = new QFile(fileName); - d->file->open(QFile::ReadWrite); -} - -ApplicationDatabase::ApplicationDatabase() - : d(new ApplicationDatabasePrivate()) -{ - d->file = new QTemporaryFile(qSL("am-apps-db")); - d->file->open(QFile::ReadWrite); -} - -ApplicationDatabase::~ApplicationDatabase() -{ - delete d; -} - -bool ApplicationDatabase::isValid() const -{ - return d->file && d->file->isOpen(); -} - -bool ApplicationDatabase::isTemporary() const -{ - return qobject_cast<QTemporaryFile *>(d->file); -} - -QString ApplicationDatabase::errorString() const -{ - return d->file->errorString(); -} - -QString ApplicationDatabase::name() const -{ - return d->file->fileName(); -} - -QVector<AbstractApplication *> ApplicationDatabase::read() Q_DECL_NOEXCEPT_EXPR(false) -{ - if (!d->file || !d->file->isOpen() || !d->file->isReadable()) - throw Exception("application database %1 is not opened for reading").arg(d->file ? d->file->fileName() : qSL("<null>")); - - QVector<AbstractApplicationInfo *> appInfoVector; - - if (d->file->seek(0)) { - QDataStream ds(d->file); - forever { - QScopedPointer<AbstractApplicationInfo> appInfo(AbstractApplicationInfo::readFromDataStream(ds)); - - if (ds.status() != QDataStream::Ok) { - if (ds.status() != QDataStream::ReadPastEnd) { - qDeleteAll(appInfoVector); - throw Exception("could not read from application database %1").arg(d->file->fileName()); - } - break; - } - - appInfoVector.append(appInfo.take()); - } - } - - return AbstractApplication::fromApplicationInfoVector(appInfoVector); -} - -void ApplicationDatabase::write(const QVector<AbstractApplicationInfo *> &apps) Q_DECL_NOEXCEPT_EXPR(false) -{ - d->validateWritableFile(); - - QDataStream ds(d->file); - for (auto *app : apps) - app->writeToDataStream(ds); - - if (ds.status() != QDataStream::Ok) - throw Exception(*d->file, "could not write to application database"); -} - -void ApplicationDatabase::write(const QVector<AbstractApplication *> &apps) Q_DECL_NOEXCEPT_EXPR(false) -{ - d->validateWritableFile(); - - QDataStream ds(d->file); - for (auto *app : apps) { - app->info()->writeToDataStream(ds); - if (!app->isAlias()) { - auto fullApp = static_cast<Application*>(app); - if (fullApp->updatedInfo()) - fullApp->updatedInfo()->writeToDataStream(ds); - } - } - - if (ds.status() != QDataStream::Ok) - throw Exception(*d->file, "could not write to application database"); - - d->file->flush(); -} - -void ApplicationDatabase::invalidate() -{ - if (d->file) { - if (d->file->isOpen()) - d->file->close(); - d->file->remove(); - d->file = nullptr; - } -} - -QT_END_NAMESPACE_AM diff --git a/src/manager-lib/applicationipcinterface.cpp b/src/manager-lib/applicationipcinterface.cpp index 9b9ec477..aa08991d 100644 --- a/src/manager-lib/applicationipcinterface.cpp +++ b/src/manager-lib/applicationipcinterface.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -100,7 +100,7 @@ QString ApplicationIPCInterface::pathName() const return m_ipcProxy ? m_ipcProxy->pathName() : QString(); } -bool ApplicationIPCInterface::isValidForApplication(AbstractApplication *app) const +bool ApplicationIPCInterface::isValidForApplication(Application *app) const { return m_ipcProxy ? m_ipcProxy->isValidForApplication(app) : false; } @@ -126,7 +126,7 @@ void ApplicationIPCInterface::setServiceObject(QObject *serviceObject) } #if defined(QT_DBUS_LIB) -bool ApplicationIPCInterface::dbusRegister(AbstractApplication *app, QDBusConnection connection, const QString &debugPathPrefix) +bool ApplicationIPCInterface::dbusRegister(Application *app, QDBusConnection connection, const QString &debugPathPrefix) { return m_ipcProxy ? m_ipcProxy->dbusRegister(app, connection, debugPathPrefix) : false; } @@ -432,7 +432,7 @@ QStringList IpcProxyObject::connectionNames() const return m_connectionNamesToApplicationIds.keys(); } -bool IpcProxyObject::isValidForApplication(AbstractApplication *app) const +bool IpcProxyObject::isValidForApplication(Application *app) const { if (!app) return false; @@ -454,7 +454,7 @@ bool IpcProxyObject::isValidForApplication(AbstractApplication *app) const #if defined(QT_DBUS_LIB) -bool IpcProxyObject::dbusRegister(AbstractApplication *app, QDBusConnection connection, const QString &debugPathPrefix) +bool IpcProxyObject::dbusRegister(Application *app, QDBusConnection connection, const QString &debugPathPrefix) { if (m_connectionNamesToApplicationIds.contains(connection.name())) return false; diff --git a/src/manager-lib/applicationipcinterface.h b/src/manager-lib/applicationipcinterface.h index 3a1f8aad..bde98536 100644 --- a/src/manager-lib/applicationipcinterface.h +++ b/src/manager-lib/applicationipcinterface.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE_AM -class AbstractApplication; +class Application; class ApplicationIPCInterfaceAttached; class IpcProxyObject; @@ -70,12 +70,12 @@ public: QString interfaceName() const; QString pathName() const; - bool isValidForApplication(AbstractApplication *app) const; + bool isValidForApplication(Application *app) const; QObject *serviceObject() const; void setServiceObject(QObject *serviceObject); #if defined(QT_DBUS_LIB) - bool dbusRegister(AbstractApplication *app, QDBusConnection connection, const QString &debugPathPrefix = QString()); + bool dbusRegister(Application *app, QDBusConnection connection, const QString &debugPathPrefix = QString()); bool dbusUnregister(QDBusConnection connection); #endif diff --git a/src/manager-lib/applicationipcinterface_p.h b/src/manager-lib/applicationipcinterface_p.h index e4828adb..d47c9ec8 100644 --- a/src/manager-lib/applicationipcinterface_p.h +++ b/src/manager-lib/applicationipcinterface_p.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -54,7 +54,7 @@ QT_BEGIN_NAMESPACE_AM -class AbstractApplication; +class Application; class IpcProxySignalRelay; class IpcProxyObject // clazy:exclude=missing-qobject-macro @@ -75,10 +75,10 @@ public: QString interfaceName() const; QStringList connectionNames() const; - bool isValidForApplication(AbstractApplication *app) const; + bool isValidForApplication(Application *app) const; #if defined(QT_DBUS_LIB) - bool dbusRegister(AbstractApplication *app, QDBusConnection connection, const QString &debugPathPrefix = QString()); + bool dbusRegister(Application *app, QDBusConnection connection, const QString &debugPathPrefix = QString()); bool dbusUnregister(QDBusConnection connection); QString introspect(const QString &path) const override; diff --git a/src/manager-lib/applicationipcmanager.cpp b/src/manager-lib/applicationipcmanager.cpp index 2e0767f3..a4d375db 100644 --- a/src/manager-lib/applicationipcmanager.cpp +++ b/src/manager-lib/applicationipcmanager.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/manager-lib/applicationipcmanager.h b/src/manager-lib/applicationipcmanager.h index 427a6fef..856078b8 100644 --- a/src/manager-lib/applicationipcmanager.h +++ b/src/manager-lib/applicationipcmanager.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/manager-lib/applicationmanager.cpp b/src/manager-lib/applicationmanager.cpp index 734198bc..523211f3 100644 --- a/src/manager-lib/applicationmanager.cpp +++ b/src/manager-lib/applicationmanager.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -58,6 +58,7 @@ #include "global.h" #include "applicationinfo.h" +#include "installationreport.h" #include "logging.h" #include "exception.h" #include "applicationmanager.h" @@ -386,9 +387,9 @@ ApplicationManager *ApplicationManager::createInstance(bool singleProcess) qmlRegisterSingletonType<ApplicationManager>("QtApplicationManager.SystemUI", 2, 0, "ApplicationManager", &ApplicationManager::instanceForQml); qmlRegisterType<ApplicationModel>("QtApplicationManager.SystemUI", 2, 0, "ApplicationModel"); - qmlRegisterUncreatableType<AbstractApplication>("QtApplicationManager.SystemUI", 2, 0, "ApplicationObject", - qSL("Cannot create objects of type ApplicationObject")); - qRegisterMetaType<AbstractApplication*>("AbstractApplication*"); + qmlRegisterUncreatableType<Application>("QtApplicationManager.SystemUI", 2, 0, "ApplicationObject", + qSL("Cannot create objects of type ApplicationObject")); + qRegisterMetaType<Application*>("Application*"); qmlRegisterUncreatableType<AbstractRuntime>("QtApplicationManager.SystemUI", 2, 0, "Runtime", qSL("Cannot create objects of type Runtime")); qRegisterMetaType<AbstractRuntime*>("AbstractRuntime*"); @@ -497,27 +498,27 @@ void ApplicationManager::setWindowManagerCompositorReady(bool ready) } } -QVector<AbstractApplication *> ApplicationManager::applications() const +QVector<Application *> ApplicationManager::applications() const { return d->apps; } -AbstractApplication *ApplicationManager::fromId(const QString &id) const +Application *ApplicationManager::fromId(const QString &id) const { - for (AbstractApplication *app : d->apps) { + for (Application *app : d->apps) { if (app->id() == id) return app; } return nullptr; } -AbstractApplication *ApplicationManager::fromProcessId(qint64 pid) const +Application *ApplicationManager::fromProcessId(qint64 pid) const { // pid could be an indirect child (e.g. when started via gdbserver) qint64 appmanPid = QCoreApplication::applicationPid(); while ((pid > 1) && (pid != appmanPid)) { - for (AbstractApplication *app : d->apps) { + for (Application *app : d->apps) { if (app->currentRuntime() && (app->currentRuntime()->applicationProcessId() == pid)) return app; } @@ -526,26 +527,23 @@ AbstractApplication *ApplicationManager::fromProcessId(qint64 pid) const return nullptr; } -AbstractApplication *ApplicationManager::fromSecurityToken(const QByteArray &securityToken) const +Application *ApplicationManager::fromSecurityToken(const QByteArray &securityToken) const { if (securityToken.size() != AbstractRuntime::SecurityTokenSize) return nullptr; - for (AbstractApplication *app : d->apps) { + for (Application *app : d->apps) { if (app->currentRuntime() && app->currentRuntime()->securityToken() == securityToken) return app; } return nullptr; } -QVector<AbstractApplication *> ApplicationManager::schemeHandlers(const QString &scheme) const +QVector<Application *> ApplicationManager::schemeHandlers(const QString &scheme) const { - QVector<AbstractApplication *> handlers; - - for (AbstractApplication *app : d->apps) { - if (app->isAlias()) - continue; + QVector<Application *> handlers; + for (Application *app : d->apps) { const auto mimeTypes = app->supportedMimeTypes(); for (const QString &mime : mimeTypes) { int pos = mime.indexOf(QLatin1Char('/')); @@ -560,14 +558,11 @@ QVector<AbstractApplication *> ApplicationManager::schemeHandlers(const QString return handlers; } -QVector<AbstractApplication *> ApplicationManager::mimeTypeHandlers(const QString &mimeType) const +QVector<Application *> ApplicationManager::mimeTypeHandlers(const QString &mimeType) const { - QVector<AbstractApplication *> handlers; - - for (AbstractApplication *app : d->apps) { - if (app->isAlias()) - continue; + QVector<Application *> handlers; + for (Application *app : d->apps) { if (app->supportedMimeTypes().contains(mimeType)) handlers << app; } @@ -580,10 +575,7 @@ void ApplicationManager::registerMimeTypes() QSet<QString> schemes; schemes << qSL("file") << qSL("http") << qSL("https"); - for (AbstractApplication *app : qAsConst(d->apps)) { - if (app->isAlias()) - continue; - + for (Application *app : qAsConst(d->apps)) { const auto mimeTypes = app->supportedMimeTypes(); for (const QString &mime : mimeTypes) { int pos = mime.indexOf(QLatin1Char('/')); @@ -613,14 +605,12 @@ bool ApplicationManager::startApplicationInternal(const QString &appId, const QS { if (d->shuttingDown) throw Exception("Cannot start applications during shutdown"); - AbstractApplication *app = fromId(appId); + Application *app = fromId(appId); if (!app) throw Exception("Cannot start application: id '%1' is not known").arg(appId); if (app->isBlocked()) throw Exception("Application %1 is blocked - cannot start").arg( app->id()); - Application* realApp = app->nonAliased(); - AbstractRuntime *runtime = app->currentRuntime(); auto runtimeManager = runtime ? runtime->manager() : RuntimeFactory::instance()->manager(app->runtimeName()); if (!runtimeManager) @@ -668,7 +658,6 @@ bool ApplicationManager::startApplicationInternal(const QString &appId, const QS throw Exception("Application %1 is already running - cannot start with debug-wrapper: %2") .arg(app->id(), debugWrapperSpecification); } - if (!documentUrl.isNull()) runtime->openDocument(documentUrl, documentMimeType); else if (!app->documentUrl().isNull()) @@ -732,7 +721,7 @@ bool ApplicationManager::startApplicationInternal(const QString &appId, const QS cannotUseQuickLaunch = "standard I/O is redirected"; else if (!app->runtimeParameters().value(qSL("environmentVariables")).toMap().isEmpty()) cannotUseQuickLaunch = "the app requests customs environment variables"; - else if (app->nonAliasedInfo()->openGLConfiguration() != runtimeManager->systemOpenGLConfiguration()) + else if (app->info()->openGLConfiguration() != runtimeManager->systemOpenGLConfiguration()) cannotUseQuickLaunch = "the app requests a custom OpenGL configuration"; if (cannotUseQuickLaunch) { @@ -741,12 +730,12 @@ bool ApplicationManager::startApplicationInternal(const QString &appId, const QS } else { // check quicklaunch pool QPair<AbstractContainer *, AbstractRuntime *> quickLaunch = - QuickLauncher::instance()->take(containerId, app->nonAliasedInfo()->runtimeName()); + QuickLauncher::instance()->take(containerId, app->info()->runtimeName()); container = quickLaunch.first; runtime = quickLaunch.second; qCDebug(LogSystem) << "Found a quick-launch entry for container" << containerId - << "and runtime" << app->nonAliasedInfo()->runtimeName() << "->" << container << runtime; + << "and runtime" << app->info()->runtimeName() << "->" << container << runtime; if (!container && runtime) { runtime->deleteLater(); @@ -769,7 +758,7 @@ bool ApplicationManager::startApplicationInternal(const QString &appId, const QS attachRuntime = true; } if (!runtime) - runtime = RuntimeFactory::instance()->create(container, realApp); + runtime = RuntimeFactory::instance()->create(container, app); if (runtime) emit internalSignals.newRuntimeCreated(runtime); @@ -781,27 +770,9 @@ bool ApplicationManager::startApplicationInternal(const QString &appId, const QS } connect(runtime, &AbstractRuntime::stateChanged, this, [this, app](Am::RunState newRuntimeState) { - QVector<AbstractApplication *> apps; - //Always emit the actual starting app/alias first - apps.append(app); - - //Add the original app and all aliases - AbstractApplication *nonAliasedApp = app->nonAliased(); - - if (!apps.contains(nonAliasedApp)) - apps.append(nonAliasedApp); - - for (AbstractApplication *alias : qAsConst(d->apps)) { - if (!apps.contains(alias) && alias->isAlias() && alias->nonAliased() == nonAliasedApp) - apps.append(alias); - } - - static_cast<Application*>(nonAliasedApp)->setRunState(newRuntimeState); - - for (AbstractApplication *app : qAsConst(apps)) { - emit applicationRunStateChanged(app->id(), newRuntimeState); - emitDataChanged(app, QVector<int> { IsRunning, IsStartingUp, IsShuttingDown }); - } + app->setRunState(newRuntimeState); + emit applicationRunStateChanged(app->id(), newRuntimeState); + emitDataChanged(app, QVector<int> { IsRunning, IsStartingUp, IsShuttingDown }); }); if (!documentUrl.isNull()) @@ -826,11 +797,11 @@ bool ApplicationManager::startApplicationInternal(const QString &appId, const QS // Using a state-machine would be one option, but then we would need that state-machine // object plus the per-app state. Relying on 2 lambdas is the easier choice for now. - auto doStartInContainer = [realApp, attachRuntime, runtime]() -> bool { - bool successfullyStarted = attachRuntime ? runtime->attachApplicationToQuickLauncher(realApp) + auto doStartInContainer = [app, attachRuntime, runtime]() -> bool { + bool successfullyStarted = attachRuntime ? runtime->attachApplicationToQuickLauncher(app) : runtime->start(); if (!successfullyStarted) - runtime->deleteLater(); // ~Runtime() will clean realApp->m_runtime + runtime->deleteLater(); // ~Runtime() will clean app->m_runtime return successfullyStarted; }; @@ -866,7 +837,7 @@ bool ApplicationManager::startApplicationInternal(const QString &appId, const QS } } -void ApplicationManager::stopApplicationInternal(AbstractApplication *app, bool forceKill) +void ApplicationManager::stopApplicationInternal(Application *app, bool forceKill) { if (!app) return; @@ -950,12 +921,10 @@ void ApplicationManager::stopApplication(const QString &id, bool forceKill) */ void ApplicationManager::stopAllApplications(bool forceKill) { - for (AbstractApplication *app : qAsConst(d->apps)) { - if (!app->isAlias()) { - AbstractRuntime *rt = app->currentRuntime(); - if (rt) - rt->stop(forceKill); - } + for (Application *app : qAsConst(d->apps)) { + AbstractRuntime *rt = app->currentRuntime(); + if (rt) + rt->stop(forceKill); } } @@ -1000,6 +969,8 @@ void ApplicationManager::stopAllApplications(bool forceKill) */ bool ApplicationManager::openUrl(const QString &urlStr) { + //TODO: relay to a well-known Intent call + // QDesktopServices::openUrl has a special behavior when called recursively, which makes sense // on the desktop, but is completely counter-productive for the AM. static bool recursionGuard = false; @@ -1011,28 +982,13 @@ bool ApplicationManager::openUrl(const QString &urlStr) QUrl url(urlStr); QString mimeTypeName; - QVector<AbstractApplication *> apps; + QVector<Application *> apps; if (url.isValid()) { QString scheme = url.scheme(); - if (scheme != qL1S("file")) { + if (scheme != qL1S("file")) apps = schemeHandlers(scheme); - for (auto it = apps.begin(); it != apps.end(); ++it) { - AbstractApplication *&app = *it; - - // try to find a better matching alias, if available - for (AbstractApplication *alias : d->apps) { - if (alias->isAlias() && alias->nonAliased() == app) { - if (url.toString(QUrl::PrettyDecoded) == alias->documentUrl()) { - app = alias; - break; - } - } - } - } - } - if (apps.isEmpty()) { QMimeDatabase mdb; QMimeType mt = mdb.mimeTypeForUrl(url); @@ -1054,9 +1010,9 @@ bool ApplicationManager::openUrl(const QString &urlStr) } else { ApplicationManagerPrivate::OpenUrlRequest req { QUuid::createUuid().toString(), - urlStr, - mimeTypeName, - QStringList() + urlStr, + mimeTypeName, + QStringList() }; for (const auto &app : qAsConst(apps)) req.possibleAppIds << app->id(); @@ -1149,7 +1105,7 @@ void ApplicationManager::rejectOpenUrlRequest(const QString &requestId) */ QStringList ApplicationManager::capabilities(const QString &id) const { - AbstractApplication *app = fromId(id); + Application *app = fromId(id); return app ? app->capabilities() : QStringList(); } @@ -1163,245 +1119,10 @@ QStringList ApplicationManager::capabilities(const QString &id) const */ QString ApplicationManager::identifyApplication(qint64 pid) const { - AbstractApplication *app = fromProcessId(pid); + Application *app = fromProcessId(pid); return app ? app->id() : QString(); } -bool ApplicationManager::blockApplication(const QString &id) -{ - AbstractApplication *app = fromId(id); - if (!app) - return false; - if (!app->block()) - return false; - emitDataChanged(app, QVector<int> { IsBlocked }); - stopApplicationInternal(app, true); - emitDataChanged(app, QVector<int> { IsRunning }); - return true; -} - -bool ApplicationManager::unblockApplication(const QString &id) -{ - AbstractApplication *app = fromId(id); - if (!app) - return false; - if (!app->unblock()) - return false; - emitDataChanged(app, QVector<int> { IsBlocked }); - return true; -} - -bool ApplicationManager::startingApplicationInstallation(ApplicationInfo *info) -{ - // ownership of info is transferred to ApplicationManager - QScopedPointer<ApplicationInfo> newInfo(info); - - if (!newInfo || newInfo->id().isEmpty()) - return false; - AbstractApplication *absApp = fromId(newInfo->id()); - if (!RuntimeFactory::instance()->manager(newInfo->runtimeName())) - return false; - - if (absApp) { // update - Q_ASSERT(!absApp->isAlias()); - Application *app = static_cast<Application*>(absApp); - - if (!blockApplication(app->id())) - return false; - - if (app->isBuiltIn()) { - // overlay the existing base info - // we will rollback to the base one if this update is removed. - app->setUpdatedInfo(newInfo.take()); - } else { - // overwrite the existing base info - // we're not keeping track of the original. so removing the updated base version removes the - // application entirely. - app->setBaseInfo(newInfo.take()); - } - app->setState(Application::BeingUpdated); - app->setProgress(0); - emitDataChanged(app); - } else { // installation - Application *app = new Application(newInfo.take(), Application::BeingInstalled); - - app->block(); - - beginInsertRows(QModelIndex(), d->apps.count(), d->apps.count()); - addApplication(app); - endInsertRows(); - - emitDataChanged(app); - - emit applicationAdded(app->id()); - } - return true; -} - -bool ApplicationManager::startingApplicationRemoval(const QString &id) -{ - AbstractApplication *absApp = fromId(id); - if (!absApp) - return false; - - Q_ASSERT(!absApp->isAlias()); - - Application *app = static_cast<Application*>(absApp); - if (app->isBlocked() || (app->state() != Application::Installed)) - return false; - - if (app->isBuiltIn() && !app->updatedInfo()) - return false; - - if (!blockApplication(id)) - return false; - - if (app->updatedInfo()) - app->setState(Application::BeingDowngraded); - else - app->setState(Application::BeingRemoved); - - app->setProgress(0); - emitDataChanged(app, QVector<int> { IsUpdating }); - return true; -} - -void ApplicationManager::progressingApplicationInstall(const QString &id, qreal progress) -{ - AbstractApplication *absApp = fromId(id); - if (!absApp) - return; - - Q_ASSERT(!absApp->isAlias()); - Application *app = static_cast<Application*>(absApp); - - if (app->state() == Application::Installed) - return; - app->setProgress(progress); - // Icon will be in a "+" suffixed directory during installation. So notify about a change on its - // location as well. - emitDataChanged(app, QVector<int> { Icon, UpdateProgress }); -} - -bool ApplicationManager::finishedApplicationInstall(const QString &id) -{ - AbstractApplication *absApp = fromId(id); - if (!absApp) - return false; - - Q_ASSERT(!absApp->isAlias()); - Application *app = static_cast<Application*>(absApp); - - switch (app->state()) { - case Application::Installed: - return false; - - case Application::BeingInstalled: - case Application::BeingUpdated: { - // The Application object has been updated right at the start of the installation/update. - // Now's the time to update the InstallationReport that was written by the installer. - QFile irfile(QDir(app->nonAliasedInfo()->manifestDir()).absoluteFilePath(qSL("installation-report.yaml"))); - QScopedPointer<InstallationReport> ir(new InstallationReport(app->id())); - if (!irfile.open(QFile::ReadOnly) || !ir->deserialize(&irfile)) { - qCCritical(LogInstaller) << "Could not read the new installation-report for application" - << app->id() << "at" << irfile.fileName(); - return false; - } - app->nonAliasedInfo()->setInstallationReport(ir.take()); - registerMimeTypes(); - app->setState(Application::Installed); - app->setProgress(0); - - emitDataChanged(app); - - unblockApplication(id); - emit app->bulkChange(); // not ideal, but icon and codeDir have changed - break; - } - case Application::BeingDowngraded: - app->setUpdatedInfo(nullptr); - app->setState(Application::Installed); - registerMimeTypes(); - break; - case Application::BeingRemoved: { - int row = d->apps.indexOf(app); - if (row >= 0) { - emit applicationAboutToBeRemoved(app->id()); - beginRemoveRows(QModelIndex(), row, row); - d->apps.removeAt(row); - endRemoveRows(); - } - delete app; - registerMimeTypes(); - break; - } - } - - emit internalSignals.applicationsChanged(); - - return true; -} - -bool ApplicationManager::canceledApplicationInstall(const QString &id) -{ - AbstractApplication *absApp = fromId(id); - if (!absApp) - return false; - - Q_ASSERT(!absApp->isAlias()); - Application *app = static_cast<Application*>(absApp); - - switch (app->state()) { - case Application::Installed: - return false; - - case Application::BeingInstalled: { - int row = d->apps.indexOf(app); - if (row >= 0) { - emit applicationAboutToBeRemoved(app->id()); - beginRemoveRows(QModelIndex(), row, row); - d->apps.removeAt(row); - endRemoveRows(); - } - delete app; - break; - } - case Application::BeingUpdated: - case Application::BeingDowngraded: - case Application::BeingRemoved: - app->setState(Application::Installed); - app->setProgress(0); - emitDataChanged(app, QVector<int> { IsUpdating }); - - unblockApplication(id); - break; - } - return true; -} - -void ApplicationManager::enableSingleAppMode() -{ - QMetaObject::invokeMethod(this, &ApplicationManager::startSingleAppAndQuitWhenStopped, Qt::QueuedConnection); -} - -void ApplicationManager::startSingleAppAndQuitWhenStopped() -{ - Q_ASSERT(d->apps.count() == 1); - - AbstractApplication *app = d->apps[0]; - - if (!startApplication(app->id())) { - QMetaObject::invokeMethod(qApp, "shutDown", Qt::DirectConnection, Q_ARG(int, 1)); - } else { - connect(this, &ApplicationManager::applicationRunStateChanged, [app](const QString &id, Am::RunState runState) { - if ((id == app->id()) && (runState == Am::NotRunning)) { - QMetaObject::invokeMethod(qApp, "shutDown", Qt::DirectConnection, - Q_ARG(int, app->lastExitCode())); - } - }); - } -} - void ApplicationManager::shutDown() { d->shuttingDown = true; @@ -1409,7 +1130,7 @@ void ApplicationManager::shutDown() auto shutdownHelper = [this]() { bool activeRuntime = false; - for (AbstractApplication *app : qAsConst(d->apps)) { + for (Application *app : qAsConst(d->apps)) { AbstractRuntime *rt = app->currentRuntime(); if (rt) { activeRuntime = true; @@ -1420,7 +1141,7 @@ void ApplicationManager::shutDown() emit shutDownFinished(); }; - for (AbstractApplication *app : qAsConst(d->apps)) { + for (Application *app : qAsConst(d->apps)) { AbstractRuntime *rt = app->currentRuntime(); if (rt) { connect(rt, &AbstractRuntime::destroyed, @@ -1440,7 +1161,7 @@ void ApplicationManager::openUrlRelay(const QUrl &url) openUrl(url.toString()); } -void ApplicationManager::emitDataChanged(AbstractApplication *app, const QVector<int> &roles) +void ApplicationManager::emitDataChanged(Application *app, const QVector<int> &roles) { int row = d->apps.indexOf(app); if (row >= 0) { @@ -1456,9 +1177,9 @@ void ApplicationManager::emitDataChanged(AbstractApplication *app, const QVector } } -void ApplicationManager::emitActivated(AbstractApplication *app) +void ApplicationManager::emitActivated(Application *app) { - emit applicationWasActivated(app->isAlias() ? app->nonAliased()->id() : app->id(), app->id()); + emit applicationWasActivated(app->id(), app->id()); emit app->activated(); } @@ -1476,29 +1197,15 @@ QVariant ApplicationManager::data(const QModelIndex &index, int role) const if (index.parent().isValid() || !index.isValid()) return QVariant(); - AbstractApplication *app = d->apps.at(index.row()); + Application *app = d->apps.at(index.row()); switch (role) { case Id: return app->id(); - case Name: { - QString name; - if (!app->info()->names().isEmpty()) { - name = app->info()->name(d->currentLocale); - if (name.isEmpty()) - name = app->info()->name(qSL("en")); - if (name.isEmpty()) - name = app->info()->name(qSL("en_US")); - if (name.isEmpty()) - name = *app->info()->names().constBegin(); - } else { - name = app->id(); - } - return name; - } + case Name: + return app->name(); case Icon: return app->icon(); - case IsRunning: return app->currentRuntime() ? (app->currentRuntime()->state() == Am::Running) : false; case IsStartingUp: @@ -1513,9 +1220,8 @@ QVariant ApplicationManager::data(const QModelIndex &index, int role) const return app->progress(); case IsRemovable: return !app->isBuiltIn(); - case CodeFilePath: - return app->nonAliasedInfo()->absoluteCodeFilePath(); + return app->info()->absoluteCodeFilePath(); case RuntimeName: return app->runtimeName(); case RuntimeParameters: @@ -1582,7 +1288,7 @@ QVariantMap ApplicationManager::get(int index) const signals or the applicationAboutToBeRemoved signal to get notified if the object is about to be deleted on the C++ side. */ -AbstractApplication *ApplicationManager::application(int index) const +Application *ApplicationManager::application(int index) const { if (index < 0 || index >= count()) { qCWarning(LogSystem) << "ApplicationManager::application(index): invalid index:" << index; @@ -1602,7 +1308,7 @@ AbstractApplication *ApplicationManager::application(int index) const signals or the applicationAboutToBeRemoved signal to get notified if the object is about to be deleted on the C++ side. */ -AbstractApplication *ApplicationManager::application(const QString &id) const +Application *ApplicationManager::application(const QString &id) const { auto index = indexOfApplication(id); return (index < 0) ? nullptr : application(index); @@ -1659,7 +1365,7 @@ Am::RunState ApplicationManager::applicationRunState(const QString &id) const return (index < 0) ? Am::NotRunning : d->apps.at(index)->runState(); } -void ApplicationManager::setApplications(const QVector<AbstractApplication *> &apps) +void ApplicationManager::setApplications(const QVector<Application *> &apps) { Q_ASSERT(d->apps.count() == 0); for (auto app : apps) @@ -1667,7 +1373,7 @@ void ApplicationManager::setApplications(const QVector<AbstractApplication *> &a registerMimeTypes(); } -void ApplicationManager::addApplication(AbstractApplication *app) +void ApplicationManager::addApplication(Application *app) { QQmlEngine::setObjectOwnership(app, QQmlEngine::CppOwnership); @@ -1683,6 +1389,11 @@ void ApplicationManager::addApplication(AbstractApplication *app) stopApplication(app->id(), forceKill); }; + connect(app, &Application::blockedChanged, + this, [this, app]() { + emitDataChanged(app, QVector<int> { IsBlocked }); + }); + d->apps << app; } diff --git a/src/manager-lib/applicationmanager.h b/src/manager-lib/applicationmanager.h index 60b133dd..5513f119 100644 --- a/src/manager-lib/applicationmanager.h +++ b/src/manager-lib/applicationmanager.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -101,21 +101,21 @@ public: // Set the initial application list // To be used only during startup (ie, before exposing ApplicationManager to QML) as // no model update signals are emitted. - void setApplications(const QVector<AbstractApplication *> &apps); + void setApplications(const QVector<Application *> &apps); - QVector<AbstractApplication *> applications() const; + QVector<Application *> applications() const; - AbstractApplication *fromId(const QString &id) const; - AbstractApplication *fromProcessId(qint64 pid) const; - AbstractApplication *fromSecurityToken(const QByteArray &securityToken) const; - QVector<AbstractApplication *> schemeHandlers(const QString &scheme) const; - QVector<AbstractApplication *> mimeTypeHandlers(const QString &mimeType) const; + Application *fromId(const QString &id) const; + Application *fromProcessId(qint64 pid) const; + Application *fromSecurityToken(const QByteArray &securityToken) const; + QVector<Application *> schemeHandlers(const QString &scheme) const; + QVector<Application *> mimeTypeHandlers(const QString &mimeType) const; bool startApplicationInternal(const QString &appId, const QString &documentUrl = QString(), const QString &documentMimeType = QString(), const QString &debugWrapperSpecification = QString(), const QVector<int> &stdioRedirections = QVector<int>()) Q_DECL_NOEXCEPT_EXPR(false); - void stopApplicationInternal(AbstractApplication *app, bool forceKill = false); + void stopApplicationInternal(Application *app, bool forceKill = false); // only use these two functions for development! bool securityChecksEnabled() const; @@ -137,8 +137,8 @@ public: int count() const; Q_INVOKABLE QVariantMap get(int index) const; - Q_INVOKABLE AbstractApplication *application(int index) const; - Q_INVOKABLE AbstractApplication *application(const QString &id) const; + Q_INVOKABLE Application *application(int index) const; + Q_INVOKABLE Application *application(const QString &id) const; Q_INVOKABLE int indexOfApplication(const QString &id) const; Q_INVOKABLE void acknowledgeOpenUrlRequest(const QString &requestId, const QString &appId); @@ -158,8 +158,6 @@ public: ApplicationManagerInternalSignals internalSignals; - void enableSingleAppMode(); - public slots: void shutDown(); @@ -183,29 +181,12 @@ signals: void windowManagerCompositorReadyChanged(bool ready); private slots: - void startSingleAppAndQuitWhenStopped(); void openUrlRelay(const QUrl &url); - void addApplication(AbstractApplication *app); - - // Interface for the installer - //TODO: Find something nicer than private slots with 3 friend classes. - // This is hard though, since the senders live in different threads and - // need to use BlockingQueuedConnections - bool blockApplication(const QString &id); - bool unblockApplication(const QString &id); - bool startingApplicationInstallation(QT_PREPEND_NAMESPACE_AM(ApplicationInfo*) installApp); - bool startingApplicationRemoval(const QString &id); - void progressingApplicationInstall(const QString &id, qreal progress); - bool finishedApplicationInstall(const QString &id); - bool canceledApplicationInstall(const QString &id); - - friend class ApplicationInstaller; - friend class InstallationTask; - friend class DeinstallationTask; + void addApplication(Application *app); private: - void emitDataChanged(AbstractApplication *app, const QVector<int> &roles = QVector<int>()); - void emitActivated(AbstractApplication *app); + void emitDataChanged(Application *app, const QVector<int> &roles = QVector<int>()); + void emitActivated(Application *app); void registerMimeTypes(); ApplicationManager(bool singleProcess, QObject *parent = nullptr); diff --git a/src/manager-lib/applicationmanager_p.h b/src/manager-lib/applicationmanager_p.h index c9d1ad6b..ad0ef7df 100644 --- a/src/manager-lib/applicationmanager_p.h +++ b/src/manager-lib/applicationmanager_p.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -60,7 +60,8 @@ public: bool windowManagerCompositorReady = false; QVariantMap systemProperties; - QVector<AbstractApplication *> apps; + QVector<PackageInfo> packages; + QVector<Application *> apps; QString currentLocale; QHash<int, QByteArray> roleNames; diff --git a/src/manager-lib/applicationmodel.cpp b/src/manager-lib/applicationmodel.cpp index 5fd46ebd..c697087d 100644 --- a/src/manager-lib/applicationmodel.cpp +++ b/src/manager-lib/applicationmodel.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/manager-lib/applicationmodel.h b/src/manager-lib/applicationmodel.h index 5cedb69a..1ec1d503 100644 --- a/src/manager-lib/applicationmodel.h +++ b/src/manager-lib/applicationmodel.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/installer-lib/asynchronoustask.cpp b/src/manager-lib/asynchronoustask.cpp index 53406e0f..4b1b9e67 100644 --- a/src/installer-lib/asynchronoustask.cpp +++ b/src/manager-lib/asynchronoustask.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -103,9 +103,19 @@ bool AsynchronousTask::forceCancel() return cancel(); } -QString AsynchronousTask::applicationId() const +QString AsynchronousTask::packageId() const { - return m_applicationId; + return m_packageId; +} + +bool AsynchronousTask::preExecute() +{ + return true; +} + +bool AsynchronousTask::postExecute() +{ + return true; } void AsynchronousTask::setError(Error errorCode, const QString &errorString) diff --git a/src/installer-lib/asynchronoustask.h b/src/manager-lib/asynchronoustask.h index 86b661c2..5ad8714f 100644 --- a/src/installer-lib/asynchronoustask.h +++ b/src/manager-lib/asynchronoustask.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -83,7 +83,10 @@ public: virtual bool cancel(); bool forceCancel(); // will always work in Queued state - QString applicationId() const; // convenience + QString packageId() const; // convenience + + virtual bool preExecute(); + virtual bool postExecute(); signals: void stateChanged(QT_PREPEND_NAMESPACE_AM(AsynchronousTask::TaskState) newState); @@ -98,10 +101,11 @@ protected: QMutex m_mutex; QString m_id; - QString m_applicationId; + QString m_packageId; TaskState m_state = Queued; Error m_errorCode = Error::None; QString m_errorString; }; + QT_END_NAMESPACE_AM diff --git a/src/manager-lib/containerfactory.cpp b/src/manager-lib/containerfactory.cpp index fbeb2e49..c8ff91c0 100644 --- a/src/manager-lib/containerfactory.cpp +++ b/src/manager-lib/containerfactory.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -83,7 +83,7 @@ AbstractContainerManager *ContainerFactory::manager(const QString &id) return m_containers.value(id); } -AbstractContainer *ContainerFactory::create(const QString &id, AbstractApplication *app, +AbstractContainer *ContainerFactory::create(const QString &id, Application *app, const QVector<int> &stdioRedirections, const QMap<QString, QString> &debugWrapperEnvironment, const QStringList &debugWrapperCommand) diff --git a/src/manager-lib/containerfactory.h b/src/manager-lib/containerfactory.h index 020100d8..102c094c 100644 --- a/src/manager-lib/containerfactory.h +++ b/src/manager-lib/containerfactory.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE_AM -class AbstractApplication; +class Application; class AbstractContainer; class AbstractContainerManager; @@ -64,7 +64,7 @@ public: QStringList containerIds() const; AbstractContainerManager *manager(const QString &id); - AbstractContainer *create(const QString &id, AbstractApplication *app, + AbstractContainer *create(const QString &id, Application *app, const QVector<int> &stdioRedirections = QVector<int>(), const QMap<QString, QString> &debugWrapperEnvironment = QMap<QString, QString>(), const QStringList &debugWrapperCommand = QStringList()); diff --git a/src/manager-lib/debugwrapper.cpp b/src/manager-lib/debugwrapper.cpp index 59eb582e..bb1fc4c3 100644 --- a/src/manager-lib/debugwrapper.cpp +++ b/src/manager-lib/debugwrapper.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/manager-lib/debugwrapper.h b/src/manager-lib/debugwrapper.h index fdfd33f0..14060334 100644 --- a/src/manager-lib/debugwrapper.h +++ b/src/manager-lib/debugwrapper.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/installer-lib/deinstallationtask.cpp b/src/manager-lib/deinstallationtask.cpp index 8f31e3ee..4695add6 100644 --- a/src/installer-lib/deinstallationtask.cpp +++ b/src/manager-lib/deinstallationtask.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -41,26 +41,27 @@ ****************************************************************************/ #include "logging.h" -#include "applicationinstaller.h" -#include "applicationinstaller_p.h" -#include "applicationmanager.h" +#include "packagemanager.h" +#include "packagemanager_p.h" #include "installationreport.h" -#include "applicationinfo.h" +#include "package.h" #include "exception.h" #include "scopeutilities.h" #include "deinstallationtask.h" QT_BEGIN_NAMESPACE_AM -DeinstallationTask::DeinstallationTask(ApplicationInfo *app, const InstallationLocation &installationLocation, - bool forceDeinstallation, bool keepDocuments, QObject *parent) +DeinstallationTask::DeinstallationTask(Package *package, const QString &installationPath, + const QString &documentPath, bool forceDeinstallation, + bool keepDocuments, QObject *parent) : AsynchronousTask(parent) - , m_app(app) - , m_installationLocation(installationLocation) + , m_package(package) + , m_installationPath(installationPath) + , m_documentPath(documentPath) , m_forceDeinstallation(forceDeinstallation) , m_keepDocuments(keepDocuments) { - m_applicationId = m_app->id(); // in base class + m_packageId = m_package->id(); // in base class } bool DeinstallationTask::cancel() @@ -72,30 +73,28 @@ bool DeinstallationTask::cancel() void DeinstallationTask::execute() { - // these have been checked in ApplicationInstaller::removePackage() already - Q_ASSERT(m_app); - Q_ASSERT(m_app->installationReport()); - Q_ASSERT(m_app->installationReport()->installationLocationId() == m_installationLocation.id()); - Q_ASSERT(m_installationLocation.isValid()); + // these have been checked in PackageManager::removePackage() already + Q_ASSERT(m_package); + Q_ASSERT(m_package->info()); + Q_ASSERT(m_package->info()->installationReport()); bool managerApproval = false; try { - // we need to call those ApplicationManager methods in the correct thread - // this will also exclusively lock the application for us - QMetaObject::invokeMethod(ApplicationManager::instance(), - "startingApplicationRemoval", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(bool, managerApproval), - Q_ARG(QString, m_app->id())); + // we need to call those PackageManager methods in the correct thread + // this will also exclusively lock the package for us + QMetaObject::invokeMethod(PackageManager::instance(), [this, &managerApproval]() + { managerApproval = PackageManager::instance()->startingPackageRemoval(m_package->id()); }, + Qt::BlockingQueuedConnection); + if (!managerApproval) - throw Exception("ApplicationManager rejected the removal of app %1").arg(m_app->id()); + throw Exception("PackageManager rejected the removal of package %1").arg(m_package->id()); - // if the app was running before, we now need to wait until is has actually stopped - while (!m_canceled && - (ApplicationManager::instance()->applicationRunState(m_app->id()) != Am::NotRunning)) { + // if any of the apps in the package were running before, we now need to wait until all of + // them have actually stopped + while (!m_canceled && !m_package->areAllApplicationsStoppedDueToBlock()) QThread::msleep(30); - } + // there's a small race condition here, but not doing a planned cancellation isn't harmful m_canBeCanceled = false; if (m_canceled) @@ -103,59 +102,50 @@ void DeinstallationTask::execute() ScopedRenamer docDirRename; ScopedRenamer appDirRename; - ScopedRenamer manifestRename; if (!m_keepDocuments) { - if (!docDirRename.rename(QDir(m_installationLocation.documentPath()).absoluteFilePath(m_app->id()), + if (!docDirRename.rename(QDir(m_documentPath).absoluteFilePath(m_package->id()), ScopedRenamer::NameToNameMinus)) { throw Exception(Error::IO, "could not rename %1 to %1-").arg(docDirRename.baseName()); } } - if (!appDirRename.rename(QDir(m_installationLocation.installationPath()).absoluteFilePath(m_app->id()), + if (!appDirRename.rename(QDir(m_installationPath).absoluteFilePath(m_package->id()), ScopedRenamer::NameToNameMinus)) { throw Exception(Error::IO, "could not rename %1 to %1-").arg(appDirRename.baseName()); } - if (!manifestRename.rename(ApplicationInstaller::instance()->manifestDirectory()->absoluteFilePath(m_app->id()), - ScopedRenamer::NameToNameMinus)) { - throw Exception(Error::IO, "could not rename %1 to %1-").arg(manifestRename.baseName()); - } - - manifestRename.take(); docDirRename.take(); appDirRename.take(); // point of no return - for (ScopedRenamer *toDelete : { &manifestRename, &docDirRename, &appDirRename }) { + for (ScopedRenamer *toDelete : { &docDirRename, &appDirRename }) { if (toDelete->isRenamed()) { if (!removeRecursiveHelper(toDelete->baseName() + qL1C('-'))) qCCritical(LogInstaller) << "ERROR: could not remove" << (toDelete->baseName() + qL1C('-')); } } - // we need to call those ApplicationManager methods in the correct thread + // we need to call those PackageManager methods in the correct thread bool finishOk = false; - QMetaObject::invokeMethod(ApplicationManager::instance(), - "finishedApplicationInstall", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(bool, finishOk), - Q_ARG(QString, m_applicationId)); + QMetaObject::invokeMethod(PackageManager::instance(), [this, &finishOk]() + { finishOk = PackageManager::instance()->finishedPackageInstall(m_package->id()); }, + Qt::BlockingQueuedConnection); + if (!finishOk) - qCWarning(LogInstaller) << "ApplicationManager did not approve deinstallation of " << m_applicationId; + qCWarning(LogInstaller) << "PackageManager did not approve deinstallation of " << m_packageId; } catch (const Exception &e) { // we need to call those ApplicationManager methods in the correct thread if (managerApproval) { bool cancelOk = false; - QMetaObject::invokeMethod(ApplicationManager::instance(), - "canceledApplicationInstall", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(bool, cancelOk), - Q_ARG(QString, m_applicationId)); + QMetaObject::invokeMethod(PackageManager::instance(), [this, &cancelOk]() + { cancelOk = PackageManager::instance()->canceledPackageInstall(m_package->id()); }, + Qt::BlockingQueuedConnection); + if (!cancelOk) - qCWarning(LogInstaller) << "ApplicationManager could not re-enable app" << m_applicationId << "after a failed removal"; + qCWarning(LogInstaller) << "PackageManager could not re-enable package" << m_packageId << "after a failed removal"; } setError(e.errorCode(), e.errorString()); diff --git a/src/installer-lib/deinstallationtask.h b/src/manager-lib/deinstallationtask.h index f990cee7..a7763d27 100644 --- a/src/installer-lib/deinstallationtask.h +++ b/src/manager-lib/deinstallationtask.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -42,11 +42,11 @@ #pragma once -#include <QtAppManInstaller/asynchronoustask.h> +#include <QtAppManManager/asynchronoustask.h> QT_BEGIN_NAMESPACE_AM -class ApplicationInfo; +class Package; class InstallationLocation; class DeinstallationTask : public AsynchronousTask @@ -54,7 +54,7 @@ class DeinstallationTask : public AsynchronousTask Q_OBJECT public: - DeinstallationTask(ApplicationInfo *app, const InstallationLocation &installationLocation, + DeinstallationTask(Package *package, const QString &installationPath, const QString &documentPath, bool forceDeinstallation, bool keepDocuments, QObject *parent = nullptr); bool cancel() override; @@ -63,8 +63,9 @@ protected: void execute() override; private: - ApplicationInfo *m_app; - const InstallationLocation &m_installationLocation; + Package *m_package; + QString m_installationPath; + QString m_documentPath; bool m_forceDeinstallation; bool m_keepDocuments; bool m_canBeCanceled = true; diff --git a/src/manager-lib/inprocesssurfaceitem.cpp b/src/manager-lib/inprocesssurfaceitem.cpp index 9caa228a..7de480ad 100644 --- a/src/manager-lib/inprocesssurfaceitem.cpp +++ b/src/manager-lib/inprocesssurfaceitem.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/manager-lib/inprocesssurfaceitem.h b/src/manager-lib/inprocesssurfaceitem.h index a8c80c30..b9faa923 100644 --- a/src/manager-lib/inprocesssurfaceitem.h +++ b/src/manager-lib/inprocesssurfaceitem.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/installer-lib/installationtask.cpp b/src/manager-lib/installationtask.cpp index eb6186c7..30cbc74a 100644 --- a/src/installer-lib/installationtask.cpp +++ b/src/manager-lib/installationtask.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -44,12 +44,12 @@ #include <QMessageAuthenticationCode> #include "logging.h" -#include "applicationinstaller_p.h" -#include "applicationinfo.h" +#include "packagemanager_p.h" +#include "packageinfo.h" #include "packageextractor.h" -#include "yamlapplicationscanner.h" +#include "yamlpackagescanner.h" #include "exception.h" -#include "applicationmanager.h" +#include "packagemanager.h" #include "sudo.h" #include "utilities.h" #include "signature.h" @@ -62,14 +62,12 @@ Step 1 -- startInstallation() ============================= - delete <manifestdir>/<id>+ - delete <manifestdir>/<id>- delete <location>/<id>+ - create dir <manifestdir>/<id>+ create dir <location>/<id>+ set <extractiondir> to <location>/<id>+ + Step 2 -- unpack files ====================== @@ -81,23 +79,19 @@ if (exists <location>/<id>) set <isupdate> to <true> - create installation report at <manifestDir>/installation-report.yaml + + create installation report at <extractiondir>/.installation-report.yaml if (not <isupdate>) create document directory if (optional uid separation) - chown/chmod recursively in <extractionDir> and document directory - - copy info.yaml and the icon file from <extractiondir> to <manifestdir>/<id>+ + chown/chmod recursively in <extractiondir> and document directory Step 3.1 -- final rename in finishInstallation() ================================================== - rename <manifestdir>/<id> to <manifestdir>/<id>- - rename <manifestdir>/<id>+ to <manifestdir>/<id> - if (<isupdate>) rename <location>/<id> to <location>/<id>- rename <location>/<id>+ to <location>/<id> @@ -128,10 +122,12 @@ private: QMutex InstallationTask::s_serializeFinishInstallation { }; -InstallationTask::InstallationTask(const InstallationLocation &installationLocation, const QUrl &sourceUrl, QObject *parent) +InstallationTask::InstallationTask(const QString &installationPath, const QString &documentPath, + const QUrl &sourceUrl, QObject *parent) : AsynchronousTask(parent) - , m_ai(ApplicationInstaller::instance()) - , m_installationLocation(installationLocation) + , m_pm(PackageManager::instance()) + , m_installationPath(installationPath) + , m_documentPath(documentPath) , m_sourceUrl(sourceUrl) { } @@ -167,8 +163,8 @@ void InstallationTask::acknowledge() void InstallationTask::execute() { try { - if (!m_installationLocation.isValid()) - throw Exception("invalid installation location"); + if (m_installationPath.isEmpty()) + throw Exception("no installation location was configured"); TemporaryDir extractionDir; if (!extractionDir.isValid()) @@ -193,9 +189,9 @@ void InstallationTask::execute() if (!m_foundInfo || !m_foundIcon) throw Exception(Error::Package, "package did not contain a valid info.json and icon file"); - QList<QByteArray> chainOfTrust = m_ai->caCertificates(); + QList<QByteArray> chainOfTrust = m_pm->caCertificates(); - if (ApplicationManager::instance()->securityChecksEnabled()) { + if (!m_pm->allowInstallationOfUnsignedPackages()) { if (!m_extractor->installationReport().storeSignature().isEmpty()) { // normal package from the store QByteArray sigDigest = m_extractor->installationReport().digest(); @@ -203,9 +199,9 @@ void InstallationTask::execute() if (Signature(sigDigest).verify(m_extractor->installationReport().storeSignature(), chainOfTrust)) { sigOk = true; - } else if (!m_ai->hardwareId().isEmpty()) { + } else if (!m_pm->hardwareId().isEmpty()) { // did not verify - if we have a hardware-id, try to verify with it - sigDigest = QMessageAuthenticationCode::hash(sigDigest, m_ai->hardwareId().toUtf8(), QCryptographicHash::Sha256); + sigDigest = QMessageAuthenticationCode::hash(sigDigest, m_pm->hardwareId().toUtf8(), QCryptographicHash::Sha256); if (Signature(sigDigest).verify(m_extractor->installationReport().storeSignature(), chainOfTrust)) sigOk = true; } @@ -213,15 +209,14 @@ void InstallationTask::execute() throw Exception(Error::Package, "could not verify the package's store signature"); } else if (!m_extractor->installationReport().developerSignature().isEmpty()) { // developer package - needs a device in dev mode - if (!m_ai->developmentMode()) + if (!m_pm->developmentMode()) throw Exception(Error::Package, "cannot install development packages on consumer devices"); if (!Signature(m_extractor->installationReport().digest()).verify(m_extractor->installationReport().developerSignature(), chainOfTrust)) throw Exception(Error::Package, "could not verify the package's developer signature"); } else { - if (!m_ai->allowInstallationOfUnsignedPackages()) - throw Exception(Error::Package, "cannot install unsigned packages"); + throw Exception(Error::Package, "cannot install unsigned packages"); } } @@ -248,14 +243,14 @@ void InstallationTask::execute() // At this point, the installation is done, so we cannot throw anymore. - // we need to call those ApplicationManager methods in the correct thread + // we need to call those PackageManager methods in the correct thread bool finishOk = false; - QMetaObject::invokeMethod(ApplicationManager::instance(), - "finishedApplicationInstall", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(bool, finishOk), - Q_ARG(QString, m_applicationId)); + QMetaObject::invokeMethod(PackageManager::instance(), [this, &finishOk]() + { finishOk = PackageManager::instance()->finishedPackageInstall(m_packageId); }, + Qt::BlockingQueuedConnection); + if (!finishOk) - qCWarning(LogInstaller) << "ApplicationManager rejected the installation of " << m_applicationId; + qCWarning(LogInstaller) << "PackageManager rejected the installation of " << m_packageId; } catch (const Exception &e) { setError(e.errorCode(), e.errorString()); @@ -263,13 +258,12 @@ void InstallationTask::execute() if (m_managerApproval) { // we need to call those ApplicationManager methods in the correct thread bool cancelOk = false; - QMetaObject::invokeMethod(ApplicationManager::instance(), - "canceledApplicationInstall", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(bool, cancelOk), - Q_ARG(QString, m_applicationId)); + QMetaObject::invokeMethod(PackageManager::instance(), [this, &cancelOk]() + { cancelOk = PackageManager::instance()->canceledPackageInstall(m_packageId); }, + Qt::BlockingQueuedConnection); + if (!cancelOk) - qCWarning(LogInstaller) << "ApplicationManager could not remove app" << m_applicationId << "after a failed installation"; + qCWarning(LogInstaller) << "PackageManager could not remove package" << m_packageId << "after a failed installation"; } } @@ -291,25 +285,17 @@ void InstallationTask::checkExtractedFile(const QString &file) Q_DECL_NOEXCEPT_E throw Exception(Error::Package, "info.yaml must be the first file in the package. Got %1") .arg(file); - YamlApplicationScanner yas; - m_app.reset(yas.scan(m_extractor->destinationDirectory().absoluteFilePath(file))); - if (m_app->id() != m_extractor->installationReport().applicationId()) - throw Exception(Error::Package, "the application identifiers in --PACKAGE-HEADER--' and info.yaml do not match"); + YamlPackageScanner yps; + m_package.reset(yps.scan(m_extractor->destinationDirectory().absoluteFilePath(file))); + if (m_package->id() != m_extractor->installationReport().packageId()) + throw Exception(Error::Package, "the package identifiers in --PACKAGE-HEADER--' and info.yaml do not match"); - m_iconFileName = m_app->icon(); // store it separately as we will give away ApplicationInfo later on + m_iconFileName = m_package->icon(); // store it separately as we will give away ApplicationInfo later on if (m_iconFileName.isEmpty()) throw Exception(Error::Package, "the 'icon' field in info.yaml cannot be empty or absent."); - InstallationLocation existingLocation = m_ai->installationLocationFromApplication(m_app->id()); - - if (existingLocation.isValid() && (existingLocation != m_installationLocation)) { - throw Exception(Error::Package, "the application %1 cannot be installed to %2, since it is already installed to %3") - .arg(m_app->id(), m_installationLocation.id(), existingLocation.id()); - } - - m_app->m_builtIn = false; - m_applicationId = m_app->id(); + m_packageId = m_package->id(); m_foundInfo = true; } else if (m_extractedFileCount == 2) { @@ -320,7 +306,7 @@ void InstallationTask::checkExtractedFile(const QString &file) Q_DECL_NOEXCEPT_E if (file != m_iconFileName) throw Exception(Error::Package, - "The application icon (as stated in info.yaml) must be the second file in the package." + "The package icon (as stated in info.yaml) must be the second file in the package." " Expected '%1', got '%2'").arg(m_iconFileName, file); QFile icon(m_extractor->destinationDirectory().absoluteFilePath(file)); @@ -334,8 +320,26 @@ void InstallationTask::checkExtractedFile(const QString &file) Q_DECL_NOEXCEPT_E } if (m_foundIcon && m_foundInfo) { - qCDebug(LogInstaller) << "emit taskRequestingInstallationAcknowledge" << id() << "for app" << m_app->id(); - emit m_ai->taskRequestingInstallationAcknowledge(id(), m_app->toVariantMap(), + qCDebug(LogInstaller) << "emit taskRequestingInstallationAcknowledge" << id() << "for package" << m_package->id(); + + QVariantMap nameMap; + auto names = m_package->names(); + for (auto it = names.constBegin(); it != names.constEnd(); ++it) + nameMap.insert(it.key(), it.value()); + + QVariantMap applicationData { + { qSL("id"), m_package->id() }, + { qSL("version"), m_package->version() }, + { qSL("icon"), m_package->icon() }, + { qSL("displayIcon"), m_package->icon() }, // legacy + { qSL("name"), nameMap }, + { qSL("displayName"), nameMap }, // legacy + { qSL("baseDir"), m_package->baseDir().absolutePath() }, + { qSL("codeDir"), m_package->baseDir().absolutePath() }, // 5.12 backward compatibility + { qSL("manifestDir"), m_package->baseDir().absolutePath() }, // 5.12 backward compatibility + { qSL("installationLocationId"), qSL("internal-0") } // 5.13 backward compatibility + }; + emit m_pm->taskRequestingInstallationAcknowledge(id(), applicationData, m_extractor->installationReport().extraMetaData(), m_extractor->installationReport().extraSignedMetaData()); @@ -352,25 +356,22 @@ void InstallationTask::checkExtractedFile(const QString &file) Q_DECL_NOEXCEPT_E QString path = m_extractionDir.absolutePath(); path.chop(1); // remove the '+' - m_app->setManifestDir(m_manifestDir.absolutePath()); - m_app->setCodeDir(path); + m_package->setBaseDir(QDir(path)); } // we need to find a free uid before we call startingApplicationInstallation - m_app->m_uid = m_ai->findUnusedUserId(); - m_applicationUid = m_app->m_uid; + m_package->m_uid = m_pm->findUnusedUserId(); + m_applicationUid = m_package->m_uid; // we need to call those ApplicationManager methods in the correct thread // this will also exclusively lock the application for us - // m_app ownership is transferred to the ApplicationManager - QString appId = m_app->id(); // m_app is gone after the invoke - QMetaObject::invokeMethod(ApplicationManager::instance(), - "startingApplicationInstallation", - Qt::BlockingQueuedConnection, - Q_RETURN_ARG(bool, m_managerApproval), - // ugly, but Q_ARG chokes on QT_PREPEND_NAMESPACE_AM... - QArgument<QT_PREPEND_NAMESPACE_AM(ApplicationInfo *)>(QT_STRINGIFY(QT_PREPEND_NAMESPACE_AM(ApplicationInfo *)), m_app.take())); + // m_package ownership is transferred to the ApplicationManager + QString packageId = m_package->id(); // m_package is gone after the invoke + QMetaObject::invokeMethod(PackageManager::instance(), [this]() + { m_managerApproval = PackageManager::instance()->startingPackageInstallation(m_package.take()); }, + Qt::BlockingQueuedConnection); + if (!m_managerApproval) - throw Exception("Application Manager declined the installation of %1").arg(appId); + throw Exception("PackageManager declined the installation of %1").arg(packageId); // we're not interested in any other files from here on... m_extractor->setFileExtractedCallback(nullptr); @@ -379,36 +380,27 @@ void InstallationTask::checkExtractedFile(const QString &file) Q_DECL_NOEXCEPT_E void InstallationTask::startInstallation() Q_DECL_NOEXCEPT_EXPR(false) { - // 1. delete $manifestDir+ and $manifestDir- - m_manifestDir.setPath(m_ai->manifestDirectory()->absoluteFilePath(m_applicationId)); - removeRecursiveHelper(m_manifestDir.absolutePath() + qL1C('+')); - removeRecursiveHelper(m_manifestDir.absolutePath() + qL1C('-')); - // 2. delete old, partial installation - QDir installationDir = QString(m_installationLocation.installationPath() + qL1C('/')); - QString installationTarget = m_applicationId + qL1C('+'); + QDir installationDir = QString(m_installationPath + qL1C('/')); + QString installationTarget = m_packageId + qL1C('+'); if (installationDir.exists(installationTarget)) { if (!removeRecursiveHelper(installationDir.absoluteFilePath(installationTarget))) throw Exception("could not remove old, partial installation %1/%2").arg(installationDir).arg(installationTarget); } - // 3. create $manifestDir+ - if (!m_manifestDirPlusCreator.create(m_manifestDir.absolutePath() + qL1C('+'))) - throw Exception("could not create manifest sub-directory %1+").arg(m_manifestDir); - // 4. create new installation if (!m_installationDirCreator.create(installationDir.absoluteFilePath(installationTarget))) throw Exception("could not create installation directory %1/%2").arg(installationDir).arg(installationTarget); m_extractionDir = installationDir; if (!m_extractionDir.cd(installationTarget)) throw Exception("could not cd into installation directory %1/%2").arg(installationDir).arg(installationTarget); - m_applicationDir.setPath(installationDir.absoluteFilePath(m_applicationId)); + m_applicationDir.setPath(installationDir.absoluteFilePath(m_packageId)); } void InstallationTask::finishInstallation() Q_DECL_NOEXCEPT_EXPR(false) { - QDir documentDirectory(m_installationLocation.documentPath()); + QDir documentDirectory(m_documentPath); ScopedDirectoryCreator documentDirCreator; enum { Installation, Update } mode = Installation; @@ -418,9 +410,8 @@ void InstallationTask::finishInstallation() Q_DECL_NOEXCEPT_EXPR(false) // create the installation report InstallationReport report = m_extractor->installationReport(); - report.setInstallationLocationId(m_installationLocation.id()); - QFile reportFile(m_manifestDirPlusCreator.dir().absoluteFilePath(qSL("installation-report.yaml"))); + QFile reportFile(m_extractionDir.absoluteFilePath(qSL(".installation-report.yaml"))); if (!reportFile.open(QFile::WriteOnly) || !report.serialize(&reportFile)) throw Exception(reportFile, "could not write the installation report"); reportFile.close(); @@ -428,22 +419,22 @@ void InstallationTask::finishInstallation() Q_DECL_NOEXCEPT_EXPR(false) // create the document directories when installing (not needed on updates) if (mode == Installation) { // this package may have been installed earlier and the document directory may not have been removed - if (!documentDirectory.cd(m_applicationId)) { - if (!documentDirCreator.create(documentDirectory.absoluteFilePath(m_applicationId))) - throw Exception(Error::IO, "could not create the document directory %1").arg(documentDirectory.filePath(m_applicationId)); + if (!documentDirectory.cd(m_packageId)) { + if (!documentDirCreator.create(documentDirectory.absoluteFilePath(m_packageId))) + throw Exception(Error::IO, "could not create the document directory %1").arg(documentDirectory.filePath(m_packageId)); } } #ifdef Q_OS_UNIX // update the owner, group and permission bits on both the installation and document directories SudoClient *root = SudoClient::instance(); - if (m_ai->isApplicationUserIdSeparationEnabled() && root) { + if (m_pm->isApplicationUserIdSeparationEnabled() && root) { uid_t uid = m_applicationUid; - gid_t gid = m_ai->commonApplicationGroupId(); + gid_t gid = m_pm->commonApplicationGroupId(); - if (!root->setOwnerAndPermissionsRecursive(documentDirectory.filePath(m_applicationId), uid, gid, 02700)) { + if (!root->setOwnerAndPermissionsRecursive(documentDirectory.filePath(m_packageId), uid, gid, 02700)) { throw Exception(Error::IO, "could not recursively change the owner to %1:%2 and the permission bits to %3 in %4") - .arg(uid).arg(gid).arg(02700, 0, 8).arg(documentDirectory.filePath(m_applicationId)); + .arg(uid).arg(gid).arg(02700, 0, 8).arg(documentDirectory.filePath(m_packageId)); } if (!root->setOwnerAndPermissionsRecursive(m_extractionDir.path(), uid, gid, 0440)) { @@ -453,26 +444,14 @@ void InstallationTask::finishInstallation() Q_DECL_NOEXCEPT_EXPR(false) } #endif - // copy meta-data to manifest directory - for (const QString &file : { qSL("info.yaml"), m_iconFileName }) - if (!QFile::copy(m_extractionDir.absoluteFilePath(file), m_manifestDirPlusCreator.dir().absoluteFilePath(file))) { - throw Exception(Error::IO, "could not copy %1 from the application directory to the manifest directory").arg(file); - } - // in case we need persistent data in addition to info.yaml and the icon file, - // we could copy these out of the image right now... - // final rename // 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! // The image is a file, so this limitation does not apply! - ScopedRenamer renameManifest; ScopedRenamer renameApplication; - if (!renameManifest.rename(m_manifestDir, (mode == Update ? ScopedRenamer::NameToNameMinus | ScopedRenamer::NamePlusToName : ScopedRenamer::NamePlusToName))) - throw Exception(Error::IO, "could not rename manifest directory %1+ to %1 (including a backup to %1-)").arg(m_manifestDir); - if (mode == Update) { if (!renameApplication.rename(m_applicationDir, ScopedRenamer::NamePlusToName | ScopedRenamer::NameToNameMinus)) throw Exception(Error::IO, "could not rename application directory %1+ to %1 (including a backup to %1-)").arg(m_applicationDir); @@ -486,11 +465,9 @@ void InstallationTask::finishInstallation() Q_DECL_NOEXCEPT_EXPR(false) setState(CleaningUp); renameApplication.take(); - renameManifest.take(); documentDirCreator.take(); m_installationDirCreator.take(); - m_manifestDirPlusCreator.take(); // this should not be necessary, but it also won't hurt if (mode == Update) diff --git a/src/installer-lib/installationtask.h b/src/manager-lib/installationtask.h index 5f5881b3..7d3163d2 100644 --- a/src/installer-lib/installationtask.h +++ b/src/manager-lib/installationtask.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -47,14 +47,14 @@ #include <QWaitCondition> #include <QMutex> -#include <QtAppManInstaller/applicationinstaller.h> #include <QtAppManApplication/installationreport.h> -#include <QtAppManInstaller/asynchronoustask.h> -#include <QtAppManInstaller/scopeutilities.h> +#include <QtAppManManager/asynchronoustask.h> +#include <QtAppManManager/scopeutilities.h> QT_BEGIN_NAMESPACE_AM -class ApplicationInfo; +class PackageInfo; +class PackageManager; class PackageExtractor; @@ -62,8 +62,8 @@ class InstallationTask : public AsynchronousTask { Q_OBJECT public: - InstallationTask(const InstallationLocation &installationLocation, const QUrl &sourceUrl, - QObject *parent = nullptr); + InstallationTask(const QString &installationPath, const QString &documentPath, + const QUrl &sourceUrl, QObject *parent = nullptr); ~InstallationTask() override; void acknowledge(); @@ -81,8 +81,9 @@ private: void checkExtractedFile(const QString &file) Q_DECL_NOEXCEPT_EXPR(false); private: - ApplicationInstaller *m_ai; - const InstallationLocation &m_installationLocation; + PackageManager *m_pm; + QString m_installationPath; + QString m_documentPath; QUrl m_sourceUrl; bool m_foundInfo = false; bool m_foundIcon = false; @@ -90,7 +91,7 @@ private: bool m_locked = false; uint m_extractedFileCount = 0; bool m_managerApproval = false; - QScopedPointer<ApplicationInfo> m_app; + QScopedPointer<PackageInfo> m_package; uint m_applicationUid = uint(-1); // changes to these 4 member variables are protected by m_mutex @@ -101,11 +102,9 @@ private: static QMutex s_serializeFinishInstallation; - QDir m_manifestDir; QDir m_applicationDir; QDir m_extractionDir; - ScopedDirectoryCreator m_manifestDirPlusCreator; ScopedDirectoryCreator m_installationDirCreator; }; diff --git a/src/manager-lib/intentaminterface.cpp b/src/manager-lib/intentaminterface.cpp index 713b2039..f787226a 100644 --- a/src/manager-lib/intentaminterface.cpp +++ b/src/manager-lib/intentaminterface.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -68,6 +68,7 @@ #include "qmlinprocessruntime.h" #include "application.h" #include "applicationmanager.h" +#include "applicationinfo.h" QT_BEGIN_NAMESPACE_AM @@ -115,75 +116,6 @@ IntentServer *IntentAMImplementation::createIntentServerAndClientInstance(const return intentServer; } -void IntentAMImplementation::addApplicationIntents(AbstractApplication *app, IntentServer *intentServer) -{ - if (app->isAlias()) - return; - - QSet<QString> intentIds; - const auto intents = app->nonAliasedInfo()->intents(); - - if (!intents.isEmpty()) - intentServer->addApplication(app->id()); - - for (const auto &intent : intents) { - /* example: - id: io.qt.shareImage - handledBy: main - visibility: public*|private - requiredCapabilities: [ a, b ] - parameterMatch: - mimeType: "^image/.*\.png$" - */ - const QVariantMap map = intent.toMap(); - const QString id = map[qSL("id")].toString(); - Intent::Visibility visibility = Intent::Public; - const QString visibilityStr = map[qSL("visibility")].toString(); - QString handledBy = map[qSL("handledBy")].toString(); - const QStringList capabilities = map[qSL("requiredCapabilities")].toStringList(); - const QVariantMap parameterMatch = map[qSL("parameterMatch")].toMap(); // do we really need that? - - if (id.isEmpty()) - throw Exception(Error::Intents, "intents need to have an id (app %1)").arg(app->id()); - if (intentIds.contains(id)) - throw Exception(Error::Intents, "found two intent handlers for %2 (app %1)").arg(app->id()).arg(id); - intentIds << id; - - if (visibilityStr == qL1S("private")) - visibility = Intent::Private; - else if (!visibilityStr.isEmpty() && (visibilityStr != qL1S("public"))) { - throw Exception(Error::Intents, "intent visibilty %3 is invalid (intent %2, app %1)") - .arg(app->id()).arg(id).arg(visibilityStr); - } - - if (handledBy == qL1S("main")) - handledBy.clear(); - // we do not support bg services yet - if (!handledBy.isEmpty()) { - throw Exception(Error::Intents, "service background handlers for intent are not supported yet (intent %2, app %1)") - .arg(app->id()).arg(id).arg(visibilityStr); - } - - qCDebug(LogSystem).nospace().noquote() << " * " << id << " [app: " << app->id() << "]"; - - if (!intentServer->addIntent(id, app->id(), handledBy, capabilities, - visibility, parameterMatch)) { - throw Exception(Error::Intents, "could not add intent %2 for app %1").arg(app->id()).arg(id); - } - } -} - -void IntentAMImplementation::removeApplicationIntents(AbstractApplication *app, IntentServer *intentServer) -{ - if (app->isAlias()) - return; - auto intents = intentServer->filterByHandlingApplicationId(intentServer->all(), app->id()); - for (const auto &intent : intents) - intentServer->removeIntent(intent); - - intentServer->removeApplication(app->id()); -} - // ^^^ IntentAMImplementation ^^^ ////////////////////////////////////////////////////////////////////////// // vvv IntentServerAMImplementation vvv diff --git a/src/manager-lib/intentaminterface.h b/src/manager-lib/intentaminterface.h index c2db4a44..f026bbd4 100644 --- a/src/manager-lib/intentaminterface.h +++ b/src/manager-lib/intentaminterface.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -60,13 +60,11 @@ class IntentInterfaceAdaptor; QT_BEGIN_NAMESPACE_AM class Application; -class AbstractApplication; +class PackageInfo; class IntentServerRequest; namespace IntentAMImplementation { IntentServer *createIntentServerAndClientInstance(const QMap<QString, int> &timeouts); -void addApplicationIntents(AbstractApplication *app, IntentServer *intentServer); -void removeApplicationIntents(AbstractApplication *app, IntentServer *intentServer); } // the server side diff --git a/src/manager-lib/manager-lib.pro b/src/manager-lib/manager-lib.pro index 170792bd..71fad983 100644 --- a/src/manager-lib/manager-lib.pro +++ b/src/manager-lib/manager-lib.pro @@ -41,7 +41,6 @@ HEADERS += \ application.h \ applicationmanager.h \ applicationmodel.h \ - applicationdatabase.h \ notificationmanager.h \ abstractcontainer.h \ containerfactory.h \ @@ -57,6 +56,9 @@ HEADERS += \ amnamespace.h \ intentaminterface.h \ processstatus.h \ + package.h \ + packagemanager.h \ + packagemanager_p.h \ !headless:HEADERS += \ qmlinprocessapplicationmanagerwindow.h \ @@ -70,7 +72,6 @@ SOURCES += \ application.cpp \ applicationmanager.cpp \ applicationmodel.cpp \ - applicationdatabase.cpp \ notificationmanager.cpp \ abstractcontainer.cpp \ containerfactory.cpp \ @@ -83,6 +84,8 @@ SOURCES += \ debugwrapper.cpp \ intentaminterface.cpp \ processstatus.cpp \ + packagemanager.cpp \ + package.cpp \ !headless:SOURCES += \ qmlinprocessapplicationmanagerwindow.cpp \ @@ -96,4 +99,26 @@ qtHaveModule(qml):SOURCES += \ # compile the moc-data into the exporting binary (appman itself) HEADERS += ../plugin-interfaces/containerinterface.h + +!disable-installer { + + QT_FOR_PRIVATE *= \ + appman_package-private \ + appman_crypto-private \ + + HEADERS += \ + asynchronoustask.h \ + deinstallationtask.h \ + installationtask.h \ + scopeutilities.h \ + sudo.h \ + + SOURCES += \ + asynchronoustask.cpp \ + installationtask.cpp \ + deinstallationtask.cpp \ + scopeutilities.cpp \ + sudo.cpp \ +} + load(qt_module) diff --git a/src/manager-lib/nativeruntime.cpp b/src/manager-lib/nativeruntime.cpp index 3c1865b6..6adcc4d2 100644 --- a/src/manager-lib/nativeruntime.cpp +++ b/src/manager-lib/nativeruntime.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -75,6 +75,7 @@ QT_BEGIN_NAMESPACE_AM QT_END_NAMESPACE_AM # include <dlfcn.h> # include <sys/socket.h> +# include <signal.h> QT_BEGIN_NAMESPACE_AM static qint64 getDBusPeerPid(const QDBusConnection &conn) @@ -215,7 +216,7 @@ bool NativeRuntime::initialize() if (!m_app) return false; - m_container->setProgram(m_app->nonAliasedInfo()->absoluteCodeFilePath()); + m_container->setProgram(m_app->info()->absoluteCodeFilePath()); m_container->setBaseDirectory(m_app->codeDir()); return true; } @@ -223,6 +224,10 @@ bool NativeRuntime::initialize() void NativeRuntime::shutdown(int exitCode, Am::ExitStatus status) { + // see NativeRuntime::stop() below + if ((status == Am::CrashExit) && (exitCode == SIGTERM || exitCode == SIGKILL)) + status = Am::ForcedExit; + if (!m_isQuickLauncher || m_connectedToRuntimeInterface) { qCDebug(LogSystem) << "NativeRuntime (id:" << (m_app ? m_app->id() : qSL("(none)")) << "pid:" << m_process->processId() << ") exited with code:" << exitCode @@ -271,7 +276,7 @@ bool NativeRuntime::start() QVariantMap openGLConfig; if (m_app) - openGLConfig = m_app->nonAliasedInfo()->openGLConfiguration(); + openGLConfig = m_app->info()->openGLConfiguration(); if (openGLConfig.isEmpty()) openGLConfig = manager()->systemOpenGLConfiguration(); if (!openGLConfig.isEmpty()) @@ -392,8 +397,10 @@ void NativeRuntime::stop(bool forceKill) void NativeRuntime::onProcessStarted() { - if (!m_startedViaLauncher && !application()->nonAliasedInfo()->supportsApplicationInterface()) + if (!m_startedViaLauncher + && !(application()->info()->supportsApplicationInterface() || manager()->supportsQuickLaunch())) { setState(Am::Running); + } } void NativeRuntime::onProcessError(Am::ProcessError error) @@ -467,7 +474,7 @@ bool NativeRuntime::startApplicationViaLauncher() return false; QString baseDir = m_container->mapHostPathToContainer(m_app->codeDir()); - QString pathInContainer = m_container->mapHostPathToContainer(m_app->nonAliasedInfo()->absoluteCodeFilePath()); + QString pathInContainer = m_container->mapHostPathToContainer(m_app->info()->absoluteCodeFilePath()); emit m_runtimeInterface->startApplication(baseDir, pathInContainer, m_document, m_mimeType, convertFromJSVariant(QVariant(m_app->info()->toVariantMap())).toMap(), diff --git a/src/manager-lib/nativeruntime.h b/src/manager-lib/nativeruntime.h index 931d8e8b..1fa3638b 100644 --- a/src/manager-lib/nativeruntime.h +++ b/src/manager-lib/nativeruntime.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/manager-lib/nativeruntime_p.h b/src/manager-lib/nativeruntime_p.h index 82fff7bf..2c0e514d 100644 --- a/src/manager-lib/nativeruntime_p.h +++ b/src/manager-lib/nativeruntime_p.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/manager-lib/notificationmanager.cpp b/src/manager-lib/notificationmanager.cpp index 26c804fc..a959fb95 100644 --- a/src/manager-lib/notificationmanager.cpp +++ b/src/manager-lib/notificationmanager.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -207,7 +207,7 @@ enum Roles struct NotificationData { uint id; - AbstractApplication *application; + Application *application; uint priority; QString summary; QString body; @@ -353,7 +353,7 @@ QVariant NotificationManager::data(const QModelIndex &index, int role) const case Icon: if (!n->iconUrl.isEmpty()) return n->iconUrl; - return n->application ? n->application->icon() : QString(); + return n->application ? n->application->info()->packageInfo()->icon() : QString(); case Image: return n->imageUrl; case ShowActionsAsIcons: @@ -580,7 +580,7 @@ uint NotificationManager::notifyHelper(const QString &app_name, uint id, bool re qCDebug(LogNotifications) << " -> adding new notification with id" << id; } - AbstractApplication *app = ApplicationManager::instance()->fromId(app_name); + Application *app = ApplicationManager::instance()->fromId(app_name); if (replaces && app != n->application) { // no hijacking allowed diff --git a/src/manager-lib/notificationmanager.h b/src/manager-lib/notificationmanager.h index b97d4fa5..8a25a81b 100644 --- a/src/manager-lib/notificationmanager.h +++ b/src/manager-lib/notificationmanager.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/manager-lib/package.cpp b/src/manager-lib/package.cpp new file mode 100644 index 00000000..d51ed794 --- /dev/null +++ b/src/manager-lib/package.cpp @@ -0,0 +1,237 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 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 <QLocale> + +#include "package.h" +#include "packageinfo.h" +#include "applicationinfo.h" + +QT_BEGIN_NAMESPACE_AM + +Package::Package(PackageInfo *packageInfo, State initialState) + : m_info(packageInfo) + , m_state(initialState) +{ } + +QString Package::id() const +{ + return info()->id(); +} + +bool Package::isBuiltIn() const +{ + return info()->isBuiltIn(); +} + +QString Package::version() const +{ + return info()->version(); +} + +QString Package::name() const +{ + QString name; + if (!info()->names().isEmpty()) { + name = info()->name(QLocale::system().name()); //TODO: language changes + if (name.isEmpty()) + name = info()->name(qSL("en")); + if (name.isEmpty()) + name = info()->name(qSL("en_US")); + if (name.isEmpty()) + name = *info()->names().constBegin(); + } else { + name = id(); + } + return name; +} + +QVariantMap Package::names() const +{ + QVariantMap names; + for (auto it = info()->names().cbegin(); it != info()->names().cend(); ++it) + names.insert(it.key(), it.value()); + return names; +} + +QString Package::description() const +{ + QString description; + if (!info()->descriptions().isEmpty()) { + description = info()->description(QLocale::system().name()); //TODO: language changes + if (description.isEmpty()) + description = info()->description(qSL("en")); + if (description.isEmpty()) + description = info()->description(qSL("en_US")); + if (description.isEmpty()) + description = *info()->descriptions().constBegin(); + } + return description; +} + +QVariantMap Package::descriptions() const +{ + QVariantMap descriptions; + for (auto it = info()->descriptions().cbegin(); it != info()->descriptions().cend(); ++it) + descriptions.insert(it.key(), it.value()); + return descriptions; +} + +QStringList Package::categories() const +{ + return info()->categories(); +} + +QUrl Package::icon() const +{ + if (info()->icon().isEmpty()) + return QUrl(); + + QDir dir; + switch (state()) { + default: + case Installed: + dir = info()->baseDir(); + break; + case BeingInstalled: + case BeingUpdated: + dir = QDir(info()->baseDir().absolutePath() + QLatin1Char('+')); + break; + case BeingRemoved: + dir = QDir(info()->baseDir().absolutePath() + QLatin1Char('-')); + break; + } + return QUrl::fromLocalFile(dir.absoluteFilePath(info()->icon())); +} + +void Package::setState(State state) +{ + if (m_state != state) { + m_state = state; + emit stateChanged(m_state); + } +} + +void Package::setProgress(qreal progress) +{ + m_progress = progress; +} + + +void Package::setBaseInfo(PackageInfo *info) +{ + m_info.reset(info); + emit bulkChange(); +} + +void Package::setUpdatedInfo(PackageInfo *info) +{ + Q_ASSERT(!info || (m_info && info->id() == m_info->id())); + + m_updatedInfo.reset(info); + emit bulkChange(); +} + +PackageInfo *Package::info() const +{ + return m_updatedInfo ? m_updatedInfo.data() : m_info.data(); +} + +PackageInfo *Package::updatedInfo() const +{ + return m_updatedInfo.data(); +} + +PackageInfo *Package::takeBaseInfo() +{ + return m_info.take(); +} + +bool Package::canBeRevertedToBuiltIn() const +{ + return m_info && m_updatedInfo; +} + +bool Package::isBlocked() const +{ + return m_blocked > 0; +} + +bool Package::block() +{ + bool blockedNow = (m_blocked.fetchAndAddOrdered(1) == 0); + if (blockedNow) { + emit blockedChanged(true); + m_blockedApps = info()->applications(); + } + return blockedNow; +} + +bool Package::unblock() +{ + bool unblockedNow = (m_blocked.fetchAndSubOrdered(1) == 1); + if (unblockedNow) { + m_blockedApps.clear(); + emit blockedChanged(false); + } + return unblockedNow; + +} + +void Package::applicationStoppedDueToBlock(const QString &appId) +{ + if (!isBlocked()) + return; + + auto it = std::find_if(m_blockedApps.cbegin(), m_blockedApps.cend(), [appId](const ApplicationInfo *appInfo) { + return appInfo->id() == appId; + }); + if (it != m_blockedApps.cend()) + m_blockedApps.removeOne(*it); +} + +bool Package::areAllApplicationsStoppedDueToBlock() const +{ + return isBlocked() && m_blockedApps.isEmpty(); +} + +QT_END_NAMESPACE_AM diff --git a/src/manager-lib/package.h b/src/manager-lib/package.h new file mode 100644 index 00000000..bf5fd4c2 --- /dev/null +++ b/src/manager-lib/package.h @@ -0,0 +1,151 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 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 +** +****************************************************************************/ + +#pragma once + +#include <QtAppManCommon/global.h> +#include <QtAppManApplication/packageinfo.h> +#include <QUrl> +#include <QString> +#include <QAtomicInt> +#include <QObject> + +QT_BEGIN_NAMESPACE_AM + + +class Package : public QObject +{ + Q_OBJECT + Q_CLASSINFO("AM-QmlType", "QtApplicationManager.SystemUI/PackageObject 2.0 UNCREATABLE") + Q_PROPERTY(QString id READ id CONSTANT) + Q_PROPERTY(bool builtIn READ isBuiltIn NOTIFY bulkChange) + Q_PROPERTY(QUrl icon READ icon NOTIFY bulkChange) + Q_PROPERTY(QString version READ version NOTIFY bulkChange) + Q_PROPERTY(QString name READ name NOTIFY bulkChange) + Q_PROPERTY(QVariantMap names READ names NOTIFY bulkChange) + Q_PROPERTY(QString description READ version NOTIFY bulkChange) + Q_PROPERTY(QVariantMap descriptions READ descriptions NOTIFY bulkChange) + Q_PROPERTY(QStringList categories READ categories NOTIFY bulkChange) + Q_PROPERTY(State state READ state NOTIFY stateChanged) + Q_PROPERTY(bool blocked READ isBlocked NOTIFY blockedChanged) + +public: + enum State { + Installed, + BeingInstalled, + BeingUpdated, + BeingDowngraded, + BeingRemoved + }; + Q_ENUM(State) + + Package(PackageInfo *packageInfo, State initialState = Installed); + + QString id() const; + bool isBuiltIn() const; + QUrl icon() const; + QString version() const; + QString name() const; + QVariantMap names() const; + QString description() const; + QVariantMap descriptions() const; + QStringList categories() const; + + State state() const { return m_state; } + qreal progress() const { return m_progress; } + + void setState(State state); + void setProgress(qreal progress); + + // Creates a list of Applications from a list of ApplicationInfo objects. + // Ownership of the given ApplicationInfo objects is passed to the returned Applications. + //static QVector<Application *> fromApplicationInfoVector(QVector<ApplicationInfo *> &); + + /* + All packages have a base info. + + Built-in packages, when updated, also get an updated info. + The updated info then overlays the base one. Subsequent updates + just replace the updated info. When requested to be removed, a + built-in packages only loses its updated info, returning to + expose the base one. + + Regular packages (ie, non-built-in) only have a base info. When + updated, their base info gets replaced and thus there's no way to go + back to a previous version. Regular packages get completely + removed when requested. + */ + void setBaseInfo(PackageInfo *info); + void setUpdatedInfo(PackageInfo *info); + + // Returns the updated info, if there's one. Otherwise returns the base info. + PackageInfo *info() const; + PackageInfo *updatedInfo() const; + PackageInfo *takeBaseInfo(); + + bool canBeRevertedToBuiltIn() const; + + bool isBlocked() const; + bool block(); + bool unblock(); + + // function for Application to report it has stopped after getting a block request + void applicationStoppedDueToBlock(const QString &appId); + // query function for the installer to verify that it is safe to manipulate binaries + bool areAllApplicationsStoppedDueToBlock() const; + +signals: + void bulkChange(); + void stateChanged(State state); + void blockedChanged(bool blocked); + +private: + QScopedPointer<PackageInfo> m_info; + QScopedPointer<PackageInfo> m_updatedInfo; + + State m_state = Installed; + qreal m_progress = 0; + QAtomicInt m_blocked; + QVector<ApplicationInfo *> m_blockedApps; +}; + +QT_END_NAMESPACE_AM diff --git a/src/manager-lib/packagemanager.cpp b/src/manager-lib/packagemanager.cpp new file mode 100644 index 00000000..bd0d70f8 --- /dev/null +++ b/src/manager-lib/packagemanager.cpp @@ -0,0 +1,1192 @@ +/**************************************************************************** +** +** Copyright (C) 2019 Luxoft Sweden AB +** Copyright (C) 2018 Pelagicore AG +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 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 <QMetaMethod> +#include <QQmlEngine> +#include <QVersionNumber> +#include "packagemanager.h" +#include "packagedatabase.h" +#include "packagemanager_p.h" +#include "package.h" +#include "logging.h" +#include "installationreport.h" +#include "exception.h" +#include "sudo.h" +#include "utilities.h" + +#if defined(Q_OS_WIN) +# include <Windows.h> +#else +# include <sys/stat.h> +# include <errno.h> +# if defined(Q_OS_ANDROID) +# include <sys/vfs.h> +# define statvfs statfs +# else +# include <sys/statvfs.h> +# endif +#endif + + +QT_BEGIN_NAMESPACE_AM + +enum Roles +{ + Id = Qt::UserRole, + Name, + Description, + Icon, + + IsBlocked, + IsUpdating, + IsRemovable, + + UpdateProgress, + + Version, + PackageItem, +}; + +PackageManager *PackageManager::s_instance = nullptr; +QHash<int, QByteArray> PackageManager::s_roleNames; + +PackageManager *PackageManager::createInstance(PackageDatabase *packageDatabase, + const QString &documentPath) +{ + if (Q_UNLIKELY(s_instance)) + qFatal("PackageManager::createInstance() was called a second time."); + + Q_ASSERT(packageDatabase); + + QScopedPointer<PackageManager> pm(new PackageManager(packageDatabase, documentPath)); + registerQmlTypes(); + + // map all the built-in packages first + const auto builtinPackages = packageDatabase->builtInPackages(); + for (auto packageInfo : builtinPackages) { + auto *package = new Package(packageInfo); + QQmlEngine::setObjectOwnership(package, QQmlEngine::CppOwnership); + pm->d->packages << package; + } + + // next, map all the installed packages, making sure to detect updates to built-in ones + const auto installedPackages = packageDatabase->installedPackages(); + for (auto packageInfo : installedPackages) { + Package *builtInPackage = pm->fromId(packageInfo->id()); + + if (builtInPackage) { // update + if (builtInPackage->updatedInfo()) { // but there already is an update applied!? + throw Exception(Error::Package, "Found more than one update for the built-in package '%1'") + .arg(builtInPackage->id()); + //TODO: can we get the paths to both info.yaml here? + } + builtInPackage->setUpdatedInfo(packageInfo); + } else { + auto *package = new Package(packageInfo); + QQmlEngine::setObjectOwnership(package, QQmlEngine::CppOwnership); + pm->d->packages << package; + } + } + + return s_instance = pm.take(); +} + +PackageManager *PackageManager::instance() +{ + if (!s_instance) + qFatal("PackageManager::instance() was called before createInstance()."); + return s_instance; +} + +QObject *PackageManager::instanceForQml(QQmlEngine *, QJSEngine *) +{ + QQmlEngine::setObjectOwnership(instance(), QQmlEngine::CppOwnership); + return instance(); +} + +QVector<Package *> PackageManager::packages() const +{ + return d->packages; +} + +void PackageManager::registerQmlTypes() +{ + qmlRegisterSingletonType<PackageManager>("QtApplicationManager.SystemUI", 2, 0, "PackageManager", + &PackageManager::instanceForQml); + qmlRegisterUncreatableType<Package>("QtApplicationManager.SystemUI", 2, 0, "PackageObject", + qSL("Cannot create objects of type PackageObject")); + qRegisterMetaType<Package *>("Package*"); + + s_roleNames.insert(Id, "packageId"); + s_roleNames.insert(Name, "name"); + s_roleNames.insert(Description, "description"); + s_roleNames.insert(Icon, "icon"); + s_roleNames.insert(IsBlocked, "isBlocked"); + s_roleNames.insert(IsUpdating, "isUpdating"); + s_roleNames.insert(IsRemovable, "isRemovable"); + s_roleNames.insert(UpdateProgress, "updateProgress"); + s_roleNames.insert(Version, "version"); + s_roleNames.insert(PackageItem, "package"); +} + +PackageManager::PackageManager(PackageDatabase *packageDatabase, + const QString &documentPath) + : QAbstractListModel() + , d(new PackageManagerPrivate()) +{ + d->database = packageDatabase; + d->installationPath = packageDatabase->installedPackagesDir(); + d->documentPath = documentPath; +} + +PackageManager::~PackageManager() +{ + delete d->database; + delete d; + s_instance = nullptr; +} + +Package *PackageManager::fromId(const QString &id) const +{ + for (auto package : d->packages) { + if (package->id() == id) + return package; + } + return nullptr; +} + +void PackageManager::emitDataChanged(Package *package, const QVector<int> &roles) +{ + int row = d->packages.indexOf(package); + if (row >= 0) { + emit dataChanged(index(row), index(row), roles); + + static const auto pkgChanged = QMetaMethod::fromSignal(&PackageManager::packageChanged); + if (isSignalConnected(pkgChanged)) { + QStringList stringRoles; + for (auto role : roles) + stringRoles << qL1S(s_roleNames[role]); + emit packageChanged(package->id(), stringRoles); + } + } +} + +// item model part + +int PackageManager::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + return d->packages.count(); +} + +QVariant PackageManager::data(const QModelIndex &index, int role) const +{ + if (index.parent().isValid() || !index.isValid()) + return QVariant(); + + Package *package = d->packages.at(index.row()); + + switch (role) { + case Id: + return package->id(); + case Name: + return package->name(); + case Description: + return package->description(); + case Icon: + return package->icon(); + case IsBlocked: + return package->isBlocked(); + case IsUpdating: + return package->state() != Package::Installed; + case UpdateProgress: + return package->progress(); + case IsRemovable: + return !package->isBuiltIn(); + case Version: + return package->version(); + case PackageItem: + return QVariant::fromValue(package); + } + return QVariant(); +} + +QHash<int, QByteArray> PackageManager::roleNames() const +{ + return s_roleNames; +} + +int PackageManager::count() const +{ + return rowCount(); +} + +/*! + \qmlmethod object PackageManager::get(int index) + + Retrieves the model data at \a index as a JavaScript object. See the + \l {PackageManager Roles}{role names} for the expected object fields. + + Returns an empty object if the specified \a index is invalid. + + \note This is very inefficient if you only want to access a single property from QML; use + package() instead to access the Package object's properties directly. +*/ +QVariantMap PackageManager::get(int index) const +{ + if (index < 0 || index >= count()) { + qCWarning(LogSystem) << "PackageManager::get(index): invalid index:" << index; + return QVariantMap(); + } + + QVariantMap map; + QHash<int, QByteArray> roles = roleNames(); + for (auto it = roles.begin(); it != roles.end(); ++it) + map.insert(qL1S(it.value()), data(this->index(index), it.key())); + return map; +} + +/*! + \qmlmethod PackageObject PackageManager::package(int index) + + Returns the \l{PackageObject}{package} corresponding to the given \a index in the + model, or \c null if the index is invalid. + + \note The object ownership of the returned Package object stays with the application-manager. + If you want to store this pointer, you can use the PackageManager's QAbstractListModel + signals or the packageAboutToBeRemoved signal to get notified if the object is about + to be deleted on the C++ side. +*/ +Package *PackageManager::package(int index) const +{ + if (index < 0 || index >= count()) { + qCWarning(LogSystem) << "PackageManager::application(index): invalid index:" << index; + return nullptr; + } + return d->packages.at(index); +} + +/*! + \qmlmethod PackageObject PackageManager::package(string id) + + Returns the \l{PackageObject}{package} corresponding to the given package \a id, + or \c null if the id does not exist. + + \note The object ownership of the returned Package object stays with the application-manager. + If you want to store this pointer, you can use the PackageManager's QAbstractListModel + signals or the packageAboutToBeRemoved signal to get notified if the object is about + to be deleted on the C++ side. +*/ +Package *PackageManager::package(const QString &id) const +{ + auto index = indexOfPackage(id); + return (index < 0) ? nullptr : package(index); +} + +/*! + \qmlmethod int PackageManager::indexOfPackage(string id) + + Maps the package \a id to its position within the model. + + Returns \c -1 if the specified \a id is invalid. +*/ +int PackageManager::indexOfPackage(const QString &id) const +{ + for (int i = 0; i < d->packages.size(); ++i) { + if (d->packages.at(i)->id() == id) + return i; + } + return -1; +} + +bool PackageManager::developmentMode() const +{ + return d->developmentMode; +} + +void PackageManager::setDevelopmentMode(bool enable) +{ + d->developmentMode = enable; +} + +bool PackageManager::allowInstallationOfUnsignedPackages() const +{ + return d->allowInstallationOfUnsignedPackages; +} + +void PackageManager::setAllowInstallationOfUnsignedPackages(bool enable) +{ + d->allowInstallationOfUnsignedPackages = enable; +} + +QString PackageManager::hardwareId() const +{ + return d->hardwareId; +} + +void PackageManager::setHardwareId(const QString &hwId) +{ + d->hardwareId = hwId; +} + +bool PackageManager::isApplicationUserIdSeparationEnabled() const +{ + return d->userIdSeparation; +} + +uint PackageManager::commonApplicationGroupId() const +{ + return d->commonGroupId; +} + +bool PackageManager::enableApplicationUserIdSeparation(uint minUserId, uint maxUserId, uint commonGroupId) +{ + if (minUserId >= maxUserId || minUserId == uint(-1) || maxUserId == uint(-1)) + return false; + d->userIdSeparation = true; + d->minUserId = minUserId; + d->maxUserId = maxUserId; + d->commonGroupId = commonGroupId; + return true; +} + +uint PackageManager::findUnusedUserId() const Q_DECL_NOEXCEPT_EXPR(false) +{ + if (!isApplicationUserIdSeparationEnabled()) + return uint(-1); + + for (uint uid = d->minUserId; uid <= d->maxUserId; ++uid) { + bool match = false; + for (Package *package : d->packages) { + if (package->info()->uid() == uid) { + match = true; + break; + } + } + if (!match) + return uid; + } + throw Exception("could not find a free user-id for application separation in the range %1 to %2") + .arg(d->minUserId).arg(d->maxUserId); +} + +QList<QByteArray> PackageManager::caCertificates() const +{ + return d->chainOfTrust; +} + +void PackageManager::setCACertificates(const QList<QByteArray> &chainOfTrust) +{ + d->chainOfTrust = chainOfTrust; +} + +static QVariantMap locationMap(const QString &path) +{ + QString cpath = QFileInfo(path).canonicalPath(); + quint64 bytesTotal = 0; + quint64 bytesFree = 0; + +#if defined(Q_OS_WIN) + GetDiskFreeSpaceExW((LPCWSTR) cpath.utf16(), (ULARGE_INTEGER *) &bytesFree, + (ULARGE_INTEGER *) &bytesTotal, nullptr); + +#else // Q_OS_UNIX + int result; + struct ::statvfs svfs; + + do { + result = ::statvfs(cpath.toLocal8Bit(), &svfs); + if (result == -1 && errno == EINTR) + continue; + } while (false); + + if (result == 0) { + bytesTotal = quint64(svfs.f_frsize) * svfs.f_blocks; + bytesFree = quint64(svfs.f_frsize) * svfs.f_bavail; + } +#endif // Q_OS_WIN + + + return QVariantMap { + { qSL("path"), path }, + { qSL("deviceSize"), bytesTotal }, + { qSL("deviceFree"), bytesFree } + }; +} + +/*! + \qmlproperty object PackageManager::installationLocation + + Returns an object describing the location under which applications are installed in detail. + + The returned object has the following members: + + \table + \header + \li \c Name + \li \c Type + \li Description + \row + \li \c path + \li \c string + \li The absolute file-system path to the base directory. + \row + \li \c deviceSize + \li \c int + \li The size of the device holding \c path in bytes. + \row + \li \c deviceFree + \li \c int + \li The amount of bytes available on the device holding \c path. + \endtable + + Returns an empty object in case the installer component is disabled. +*/ +QVariantMap PackageManager::installationLocation() const +{ + return locationMap(d->installationPath); +} + +/*! + \qmlproperty object PackageManager::documentLocation + + Returns an object describing the location under which per-user document + directories are created in detail. + + The returned object has the same members as described in PackageManager::installationLocation. +*/ +QVariantMap PackageManager::documentLocation() const +{ + return locationMap(d->documentPath); +} + +void PackageManager::cleanupBrokenInstallations() Q_DECL_NOEXCEPT_EXPR(false) +{ + // Check that everything in the app-db is available + // -> if not, remove from app-db + + // key: baseDirPath, value: subDirName/ or fileName + QMultiMap<QString, QString> validPaths; + if (!d->documentPath.isEmpty()) + validPaths.insert(d->documentPath, QString()); + if (!d->installationPath.isEmpty()) + validPaths.insert(d->installationPath, QString()); + + for (Package *pkg : d->packages) { // we want to detach here! + const InstallationReport *ir = pkg->info()->installationReport(); + if (ir) { + bool valid = true; + + QString pkgDir = d->installationPath + pkg->id(); + QStringList checkDirs; + QStringList checkFiles; + + checkFiles << pkgDir + qSL("/info.yaml"); + checkFiles << pkgDir + qSL("/.installation-report.yaml"); + checkDirs << pkgDir; + checkDirs << d->installationPath + pkg->id(); + + for (const QString &checkFile : qAsConst(checkFiles)) { + QFileInfo fi(checkFile); + if (!fi.exists() || !fi.isFile() || !fi.isReadable()) { + valid = false; + qCDebug(LogInstaller) << "cleanup: uninstalling" << pkg->id() << "- file missing:" << checkFile; + break; + } + } + for (const QString &checkDir : checkDirs) { + QFileInfo fi(checkDir); + if (!fi.exists() || !fi.isDir() || !fi.isReadable()) { + valid = false; + qCDebug(LogInstaller) << "cleanup: uninstalling" << pkg->id() << "- directory missing:" << checkDir; + break; + } + } + + if (valid) { + validPaths.insertMulti(d->installationPath, pkg->id() + qL1C('/')); + validPaths.insertMulti(d->documentPath, pkg->id() + qL1C('/')); + } else { + if (startingPackageRemoval(pkg->id())) { + if (finishedPackageInstall(pkg->id())) + continue; + } + throw Exception(Error::Package, "could not remove broken installation of package %1 from database").arg(pkg->id()); + } + } + } + + // Remove everything that is not referenced from the app-db + + for (auto it = validPaths.cbegin(); it != validPaths.cend(); ) { + const QString currentDir = it.key(); + + // collect all values for the unique key currentDir + QVector<QString> validNames; + for ( ; it != validPaths.cend() && it.key() == currentDir; ++it) + validNames << it.value(); + + const QFileInfoList &dirEntries = QDir(currentDir).entryInfoList(QDir::AllEntries | QDir::NoDotAndDotDot); + + // check if there is anything in the filesystem that is NOT listed in the validNames + for (const QFileInfo &fi : dirEntries) { + QString name = fi.fileName(); + if (fi.isDir()) + name.append(qL1C('/')); + + if ((!fi.isDir() && !fi.isFile()) || !validNames.contains(name)) { + qCDebug(LogInstaller) << "cleanup: removing unreferenced inode" << name; + + if (SudoClient::instance()) { + if (!SudoClient::instance()->removeRecursive(fi.absoluteFilePath())) { + throw Exception(Error::IO, "could not remove broken installation leftover %1: %2") + .arg(fi.absoluteFilePath()).arg(SudoClient::instance()->lastError()); + } + } else { + if (!recursiveOperation(fi.absoluteFilePath(), safeRemove)) { + throw Exception(Error::IO, "could not remove broken installation leftover %1 (maybe due to missing root privileges)") + .arg(fi.absoluteFilePath()); + } + } + } + } + } +} + +/*! + \qmlmethod list<string> PackageManager::packageIds() + + Returns a list of all available package ids. This can be used to further query for specific + information via get(). +*/ +QStringList PackageManager::packageIds() const +{ + QStringList ids; + ids.reserve(d->packages.size()); + for (int i = 0; i < d->packages.size(); ++i) + ids << d->packages.at(i)->id(); + return ids; +} + +/*! + \qmlmethod object PackageManager::get(string id) + + Retrieves the model data for the package identified by \a id as a JavaScript object. + See the \l {PackageManager Roles}{role names} for the expected object fields. + + Returns an empty object if the specified \a id is invalid. +*/ +QVariantMap PackageManager::get(const QString &id) const +{ + int index = indexOfPackage(id); + return (index < 0) ? QVariantMap{} : get(index); +} + +/*! + \qmlmethod int PackageManager::installedPackageSize(string packageId) + + Returns the size in bytes that the package identified by \a packageId is occupying on the storage + device. + + Returns \c -1 in case the package \a packageId is not valid, or the package is not installed. +*/ +qint64 PackageManager::installedPackageSize(const QString &packageId) const +{ + if (Package *package = fromId(packageId)) { + if (const InstallationReport *report = package->info()->installationReport()) + return static_cast<qint64>(report->diskSpaceUsed()); + } + return -1; +} + +/*! + \qmlmethod var PackageManager::installedPackageExtraMetaData(string packageId) + + Returns a map of all extra metadata in the package header of the package identified by \a packageId. + + Returns an empty map in case the package \a packageId is not valid, or the package is not installed. +*/ +QVariantMap PackageManager::installedPackageExtraMetaData(const QString &packageId) const +{ + if (Package *package = fromId(packageId)) { + if (const InstallationReport *report = package->info()->installationReport()) + return report->extraMetaData(); + } + return QVariantMap(); +} + +/*! + \qmlmethod var PackageManager::installedPackageExtraSignedMetaData(string packageId) + + Returns a map of all signed extra metadata in the package header of the package identified + by \a packageId. + + Returns an empty map in case the package \a packageId is not valid, or the package is not installed. +*/ +QVariantMap PackageManager::installedPackageExtraSignedMetaData(const QString &packageId) const +{ + if (Package *package = fromId(packageId)) { + if (const InstallationReport *report = package->info()->installationReport()) + return report->extraSignedMetaData(); + } + return QVariantMap(); +} + +/*! \internal + Type safe convenience function, since DBus does not like QUrl +*/ +QString PackageManager::startPackageInstallation(const QUrl &sourceUrl) +{ + AM_TRACE(LogInstaller, sourceUrl); + + return enqueueTask(new InstallationTask(d->installationPath, d->documentPath, sourceUrl)); +} + +/*! + \qmlmethod string PackageManager::startPackageInstallation(string sourceUrl) + + Downloads an application package from \a sourceUrl and installs it. + + The actual download and installation will happen asynchronously in the background. The + PackageManager emits the signals \l taskStarted, \l taskProgressChanged, \l + taskRequestingInstallationAcknowledge, \l taskFinished, \l taskFailed, and \l taskStateChanged + for the returned taskId when applicable. + + \note Simply calling this function is not enough to complete a package installation: The + taskRequestingInstallationAcknowledge() signal needs to be connected to a slot where the + supplied package meta-data can be validated (either programmatically or by asking the user). + If the validation is successful, the installation can be completed by calling + acknowledgePackageInstallation() or, if the validation was unsuccessful, the installation should + be canceled by calling cancelTask(). + Failing to do one or the other will leave an unfinished "zombie" installation. + + Returns a unique \c taskId. This can also be an empty string, if the task could not be + created (in this case, no signals will be emitted). +*/ +QString PackageManager::startPackageInstallation(const QString &sourceUrl) +{ + QUrl url(sourceUrl); + if (url.scheme().isEmpty()) + url = QUrl::fromLocalFile(sourceUrl); + return startPackageInstallation(url); +} + +/*! + \qmlmethod void PackageManager::acknowledgePackageInstallation(string taskId) + + Calling this function enables the installer to complete the installation task identified by \a + taskId. Normally, this function is called after receiving the taskRequestingInstallationAcknowledge() + signal, and the user and/or the program logic decided to proceed with the installation. + + \sa startPackageInstallation() + */ +void PackageManager::acknowledgePackageInstallation(const QString &taskId) +{ + AM_TRACE(LogInstaller, taskId) + + const auto allTasks = d->allTasks(); + + for (AsynchronousTask *task : allTasks) { + if (qobject_cast<InstallationTask *>(task) && (task->id() == taskId)) { + static_cast<InstallationTask *>(task)->acknowledge(); + break; + } + } +} + +/*! + \qmlmethod string PackageManager::removePackage(string packageId, bool keepDocuments, bool force) + + Uninstalls the package identified by \a id. Normally, the documents directory of the + package is deleted on removal, but this can be prevented by setting \a keepDocuments to \c true. + + The actual removal will happen asynchronously in the background. The PackageManager will + emit the signals \l taskStarted, \l taskProgressChanged, \l taskFinished, \l taskFailed and \l + taskStateChanged for the returned \c taskId when applicable. + + Normally, \a force should only be set to \c true if a previous call to removePackage() failed. + This may be necessary if the installation process was interrupted, or or has file-system issues. + + Returns a unique \c taskId. This can also be an empty string, if the task could not be created + (in this case, no signals will be emitted). +*/ +QString PackageManager::removePackage(const QString &packageId, bool keepDocuments, bool force) +{ + AM_TRACE(LogInstaller, packageId, keepDocuments) + + if (Package *package = fromId(packageId)) { + if (package->info()->installationReport()) { + return enqueueTask(new DeinstallationTask(package, d->installationPath, + d->documentPath, force, keepDocuments)); + } + } + return QString(); +} + + +/*! + \qmlmethod enumeration PackageManager::taskState(string taskId) + + Returns the current state of the installation task identified by \a taskId. + \l {TaskStates}{See here} for a list of valid task states. + + Returns \c PackageManager.Invalid if the \a taskId is invalid. +*/ +AsynchronousTask::TaskState PackageManager::taskState(const QString &taskId) const +{ + const auto allTasks = d->allTasks(); + + for (const AsynchronousTask *task : allTasks) { + if (task && (task->id() == taskId)) + return task->state(); + } + return AsynchronousTask::Invalid; +} + +/*! + \qmlmethod string PackageManager::taskPackageId(string taskId) + + Returns the package id associated with the task identified by \a taskId. The task may not + have a valid package id at all times though and in this case the function will return an + empty string (this will be the case for installations before the taskRequestingInstallationAcknowledge + signal has been emitted). + + Returns an empty string if the \a taskId is invalid. +*/ +QString PackageManager::taskPackageId(const QString &taskId) const +{ + const auto allTasks = d->allTasks(); + + for (const AsynchronousTask *task : allTasks) { + if (task && (task->id() == taskId)) + return task->packageId(); + } + return QString(); +} + +/*! + \qmlmethod list<string> PackageManager::activeTaskIds() + + Retuns a list of all currently active (as in not yet finished or failed) installation task ids. +*/ +QStringList PackageManager::activeTaskIds() const +{ + const auto allTasks = d->allTasks(); + + QStringList result; + for (const AsynchronousTask *task : allTasks) + result << task->id(); + return result; +} + +/*! + \qmlmethod bool PackageManager::cancelTask(string taskId) + + Tries to cancel the installation task identified by \a taskId. + + Returns \c true if the task was canceled, \c false otherwise. +*/ +bool PackageManager::cancelTask(const QString &taskId) +{ + AM_TRACE(LogInstaller, taskId) + + // incoming tasks can be forcefully cancelled right away + for (AsynchronousTask *task : qAsConst(d->incomingTaskList)) { + if (task->id() == taskId) { + task->forceCancel(); + task->deleteLater(); + + handleFailure(task); + + d->incomingTaskList.removeOne(task); + triggerExecuteNextTask(); + return true; + } + } + + // the active task and async tasks might be in a state where cancellation is not possible, + // so we have to ask them nicely + if (d->activeTask && d->activeTask->id() == taskId) + return d->activeTask->cancel(); + + for (AsynchronousTask *task : qAsConst(d->installationTaskList)) { + if (task->id() == taskId) + return task->cancel(); + } + return false; +} + +/*! + \qmlmethod int PackageManager::compareVersions(string version1, string version2) + + Convenience method for app-store implementations or taskRequestingInstallationAcknowledge() + callbacks for comparing version numbers, as the actual version comparison algorithm is not + trivial. + + Returns \c -1, \c 0 or \c 1 if \a version1 is smaller than, equal to, or greater than \a + version2 (similar to how \c strcmp() works). +*/ +int PackageManager::compareVersions(const QString &version1, const QString &version2) +{ + int vn1Suffix = -1; + int vn2Suffix = -1; + QVersionNumber vn1 = QVersionNumber::fromString(version1, &vn1Suffix); + QVersionNumber vn2 = QVersionNumber::fromString(version2, &vn2Suffix); + + int d = QVersionNumber::compare(vn1, vn2); + return d < 0 ? -1 : (d > 0 ? 1 : version1.mid(vn1Suffix).compare(version2.mid(vn2Suffix))); +} + +/*! + \qmlmethod int PackageManager::validateDnsName(string name, int minimalPartCount) + + Convenience method for app-store implementations or taskRequestingInstallationAcknowledge() + callbacks for checking if the given \a name is a valid DNS (or reverse-DNS) name according to + RFC 1035/1123. If the optional parameter \a minimalPartCount is specified, this function will + also check if \a name contains at least this amount of parts/sub-domains. + + Returns \c true if the name is a valid DNS name or \c false otherwise. +*/ +bool PackageManager::validateDnsName(const QString &name, int minimalPartCount) +{ + try { + // check if we have enough parts: e.g. "tld.company.app" would have 3 parts + QStringList parts = name.split('.'); + if (parts.size() < minimalPartCount) { + throw Exception(Error::Parse, "the minimum amount of parts (subdomains) is %1 (found %2)") + .arg(minimalPartCount).arg(parts.size()); + } + + // standard RFC compliance tests (RFC 1035/1123) + + auto partCheck = [](const QString &part) { + int len = part.length(); + + if (len < 1 || len > 63) + throw Exception(Error::Parse, "domain parts must consist of at least 1 and at most 63 characters (found %2 characters)").arg(len); + + for (int pos = 0; pos < len; ++pos) { + ushort ch = part.at(pos).unicode(); + bool isFirst = (pos == 0); + bool isLast = (pos == (len - 1)); + bool isDash = (ch == '-'); + bool isDigit = (ch >= '0' && ch <= '9'); + bool isLower = (ch >= 'a' && ch <= 'z'); + + if ((isFirst || isLast || !isDash) && !isDigit && !isLower) + throw Exception(Error::Parse, "domain parts must consist of only the characters '0-9', 'a-z', and '-' (which cannot be the first or last character)"); + } + }; + + for (const QString &part : parts) + partCheck(part); + + return true; + } catch (const Exception &e) { + qCDebug(LogInstaller).noquote() << "validateDnsName failed:" << e.errorString(); + return false; + } +} + +QString PackageManager::enqueueTask(AsynchronousTask *task) +{ + d->incomingTaskList.append(task); + triggerExecuteNextTask(); + return task->id(); +} + +void PackageManager::triggerExecuteNextTask() +{ + if (!QMetaObject::invokeMethod(this, "executeNextTask", Qt::QueuedConnection)) + qCCritical(LogSystem) << "ERROR: failed to invoke method checkQueue"; +} + +void PackageManager::executeNextTask() +{ + if (d->activeTask || d->incomingTaskList.isEmpty()) + return; + + AsynchronousTask *task = d->incomingTaskList.takeFirst(); + + if (task->hasFailed()) { + task->setState(AsynchronousTask::Failed); + + handleFailure(task); + + task->deleteLater(); + triggerExecuteNextTask(); + return; + } + + connect(task, &AsynchronousTask::started, this, [this, task]() { + emit taskStarted(task->id()); + }); + + connect(task, &AsynchronousTask::stateChanged, this, [this, task](AsynchronousTask::TaskState newState) { + emit taskStateChanged(task->id(), newState); + }); + + connect(task, &AsynchronousTask::progress, this, [this, task](qreal p) { + emit taskProgressChanged(task->id(), p); + + Package *package = fromId(task->packageId()); + if (package && (package->state() != Package::Installed)) { + package->setProgress(p); + // Icon will be in a "+" suffixed directory during installation. So notify about a change on its + // location as well. + emitDataChanged(package, QVector<int> { Icon, UpdateProgress }); + } + }); + + connect(task, &AsynchronousTask::finished, this, [this, task]() { + task->setState(task->hasFailed() ? AsynchronousTask::Failed : AsynchronousTask::Finished); + + if (task->hasFailed()) { + handleFailure(task); + } else { + qCDebug(LogInstaller) << "emit finished" << task->id(); + emit taskFinished(task->id()); + } + + if (d->activeTask == task) + d->activeTask = nullptr; + d->installationTaskList.removeOne(task); + + delete task; + triggerExecuteNextTask(); + }); + + if (qobject_cast<InstallationTask *>(task)) { + connect(static_cast<InstallationTask *>(task), &InstallationTask::finishedPackageExtraction, this, [this, task]() { + qCDebug(LogInstaller) << "emit blockingUntilInstallationAcknowledge" << task->id(); + emit taskBlockingUntilInstallationAcknowledge(task->id()); + + // we can now start the next download in parallel - the InstallationTask will take care + // of serializing the final installation steps on its own as soon as it gets the + // required acknowledge (or cancel). + if (d->activeTask == task) + d->activeTask = nullptr; + d->installationTaskList.append(task); + triggerExecuteNextTask(); + }); + } + + + d->activeTask = task; + task->setState(AsynchronousTask::Executing); + task->start(); +} + +void PackageManager::handleFailure(AsynchronousTask *task) +{ + qCDebug(LogInstaller) << "emit failed" << task->id() << task->errorCode() << task->errorString(); + emit taskFailed(task->id(), int(task->errorCode()), task->errorString()); +} + +bool PackageManager::startingPackageInstallation(PackageInfo *info) +{ + // ownership of info is transferred to PackageManager + QScopedPointer<PackageInfo> newInfo(info); + + if (!newInfo || newInfo->id().isEmpty()) + return false; + Package *package = fromId(newInfo->id()); +// if (!RuntimeFactory::instance()->manager(newInfo->runtimeName())) +// return false; + + if (package) { // update + if (!package->block()) + return false; + + if (package->isBuiltIn()) { + // overlay the existing base info + // we will rollback to the base one if this update is removed. + package->setUpdatedInfo(newInfo.take()); + } else { + // overwrite the existing base info + // we're not keeping track of the original. so removing the updated base version removes the + // application entirely. + package->setBaseInfo(newInfo.take()); + } + package->setState(Package::BeingUpdated); + package->setProgress(0); + emitDataChanged(package); + } else { // installation + package = new Package(newInfo.take(), Package::BeingInstalled); + + Q_ASSERT(package->block()); + + beginInsertRows(QModelIndex(), d->packages.count(), d->packages.count()); + + QQmlEngine::setObjectOwnership(package, QQmlEngine::CppOwnership); + d->packages << package; + + endInsertRows(); + + emitDataChanged(package); + + emit packageAdded(package->id()); + } + return true; +} + +bool PackageManager::startingPackageRemoval(const QString &id) +{ + Package *package = fromId(id); + if (!package) + return false; + + if (package->isBlocked() || (package->state() != Package::Installed)) + return false; + + if (package->isBuiltIn() && !package->canBeRevertedToBuiltIn()) + return false; + + if (!package->block()) // this will implicitly stop all apps in this package (asynchronously) + return false; + + package->setState(package->canBeRevertedToBuiltIn() ? Package::BeingDowngraded + : Package::BeingRemoved); + + package->setProgress(0); + emitDataChanged(package, QVector<int> { IsUpdating }); + return true; +} + +bool PackageManager::finishedPackageInstall(const QString &id) +{ + Package *package = fromId(id); + if (!package) + return false; + + switch (package->state()) { + case Package::Installed: + return false; + + case Package::BeingInstalled: + case Package::BeingUpdated: { + // The Package object has been updated right at the start of the installation/update. + // Now's the time to update the InstallationReport that was written by the installer. + QFile irfile(QDir(package->info()->baseDir()).absoluteFilePath(qSL(".installation-report.yaml"))); + QScopedPointer<InstallationReport> ir(new InstallationReport(package->id())); + if (!irfile.open(QFile::ReadOnly) || !ir->deserialize(&irfile)) { + qCCritical(LogInstaller) << "Could not read the new installation-report for package" + << package->id() << "at" << irfile.fileName(); + return false; + } + package->info()->setInstallationReport(ir.take()); + package->setState(Package::Installed); + package->setProgress(0); + + emitDataChanged(package); + + package->unblock(); + emit package->bulkChange(); // not ideal, but icon and codeDir have changed + break; + } + case Package::BeingDowngraded: + package->setUpdatedInfo(nullptr); + package->setState(Package::Installed); + break; + + case Package::BeingRemoved: { + int row = d->packages.indexOf(package); + if (row >= 0) { + emit packageAboutToBeRemoved(package->id()); + beginRemoveRows(QModelIndex(), row, row); + d->packages.removeAt(row); + endRemoveRows(); + } + delete package; + break; + } + } + + //emit internalSignals.applicationsChanged(); + + return true; +} + +bool PackageManager::canceledPackageInstall(const QString &id) +{ + Package *package = fromId(id); + if (!package) + return false; + + switch (package->state()) { + case Package::Installed: + return false; + + case Package::BeingInstalled: { + int row = d->packages.indexOf(package); + if (row >= 0) { + emit packageAboutToBeRemoved(package->id()); + beginRemoveRows(QModelIndex(), row, row); + d->packages.removeAt(row); + endRemoveRows(); + } + delete package; + break; + } + case Package::BeingUpdated: + case Package::BeingDowngraded: + case Package::BeingRemoved: + package->setState(Package::Installed); + package->setProgress(0); + emitDataChanged(package, QVector<int> { IsUpdating }); + + package->unblock(); + break; + } + return true; +} + +bool removeRecursiveHelper(const QString &path) +{ + if (PackageManager::instance()->isApplicationUserIdSeparationEnabled() && SudoClient::instance()) + return SudoClient::instance()->removeRecursive(path); + else + return recursiveOperation(path, safeRemove); +} + +QT_END_NAMESPACE_AM diff --git a/src/installer-lib/applicationinstaller.h b/src/manager-lib/packagemanager.h index 2afaeb85..fb1cb2ee 100644 --- a/src/installer-lib/applicationinstaller.h +++ b/src/manager-lib/packagemanager.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -43,87 +43,106 @@ #pragma once #include <QObject> -#include <QVariant> -#include <QUrl> -#include <QStringList> -#include <QDir> -#include <QtAppManCommon/error.h> -#include <QtAppManInstaller/installationlocation.h> -#include <QtAppManInstaller/asynchronoustask.h> +#include <QAbstractListModel> +#include <QtAppManCommon/global.h> +#include <QtAppManApplication/packageinfo.h> +#include <QtAppManManager/asynchronoustask.h> +#include <QtAppManManager/installationtask.h> +#include <QtAppManManager/deinstallationtask.h> + QT_FORWARD_DECLARE_CLASS(QQmlEngine) QT_FORWARD_DECLARE_CLASS(QJSEngine) QT_BEGIN_NAMESPACE_AM -class ApplicationManager; -class ApplicationInstallerPrivate; -class SudoClient; - +class PackageDatabase; +class Package; +class PackageManagerPrivate; -class ApplicationInstaller : public QObject +class PackageManager : public QAbstractListModel { Q_OBJECT - Q_CLASSINFO("D-Bus Interface", "io.qt.ApplicationInstaller") - Q_CLASSINFO("AM-QmlType", "QtApplicationManager.SystemUI/ApplicationInstaller 2.0 SINGLETON") + Q_PROPERTY(int count READ count NOTIFY countChanged) + Q_CLASSINFO("D-Bus Interface", "io.qt.PackageManager") + Q_CLASSINFO("AM-QmlType", "QtApplicationManager.SystemUI/PackageManager 2.0 SINGLETON") - // both are const on purpose - these should never change in a running system + // these are const on purpose - these should never change in a running system Q_PROPERTY(bool allowInstallationOfUnsignedPackages READ allowInstallationOfUnsignedPackages CONSTANT) Q_PROPERTY(bool developmentMode READ developmentMode CONSTANT) + Q_PROPERTY(QString hardwareId READ hardwareId CONSTANT) + + Q_PROPERTY(QVariantMap installationLocation READ installationLocation CONSTANT) + Q_PROPERTY(QVariantMap documentLocation READ documentLocation CONSTANT) Q_PROPERTY(bool applicationUserIdSeparation READ isApplicationUserIdSeparationEnabled) Q_PROPERTY(uint commonApplicationGroupId READ commonApplicationGroupId) - public: - Q_ENUMS(QT_PREPEND_NAMESPACE_AM(AsynchronousTask::TaskState)) - - ~ApplicationInstaller(); - static ApplicationInstaller *createInstance(const QVector<InstallationLocation> &installationLocations, - const QString &manifestDirPath, - const QString &hardwareId, QString *error); - static ApplicationInstaller *instance(); + enum CacheMode { + NoCache, + UseCache, + RecreateCache + }; + + ~PackageManager() override; + static PackageManager *createInstance(PackageDatabase *packageDatabase, + const QString &documentPath); + static PackageManager *instance(); static QObject *instanceForQml(QQmlEngine *qmlEngine, QJSEngine *); + QVector<Package *> packages() const; + + Package *fromId(const QString &id) const; + + // the item model part + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + QVariant data(const QModelIndex &index, int role) const override; + QHash<int, QByteArray> roleNames() const override; + + int count() const; + Q_INVOKABLE QVariantMap get(int index) const; + Q_INVOKABLE Package *package(int index) const; + Q_INVOKABLE Package *package(const QString &id) const; + Q_INVOKABLE int indexOfPackage(const QString &id) const; + bool developmentMode() const; - void setDevelopmentMode(bool b); + void setDevelopmentMode(bool enable); bool allowInstallationOfUnsignedPackages() const; - void setAllowInstallationOfUnsignedPackages(bool b); + void setAllowInstallationOfUnsignedPackages(bool enable); QString hardwareId() const; + void setHardwareId(const QString &hwId); +// bool securityChecksEnabled() const; +// void setSecurityChecksEnabled(bool enabled); bool isApplicationUserIdSeparationEnabled() const; uint commonApplicationGroupId() const; bool enableApplicationUserIdSeparation(uint minUserId, uint maxUserId, uint commonGroupId); - // Ownership of QDir* stays with ApplicationInstaller - // Never returns null - const QDir *manifestDirectory() const; - - bool setDBusPolicy(const QVariantMap &yamlFragment); void setCACertificates(const QList<QByteArray> &chainOfTrust); - void cleanupBrokenInstallations() const Q_DECL_NOEXCEPT_EXPR(false); + void cleanupBrokenInstallations() Q_DECL_NOEXCEPT_EXPR(false); - // InstallationLocation handling - QVector<InstallationLocation> installationLocations() const; - const InstallationLocation &defaultInstallationLocation() const; - const InstallationLocation &installationLocationFromId(const QString &installationLocationId) const; - const InstallationLocation &installationLocationFromApplication(const QString &id) const; + QVariantMap installationLocation() const; + QVariantMap documentLocation() const; // Q_SCRIPTABLEs are available via both QML and D-Bus - Q_SCRIPTABLE QStringList installationLocationIds() const; - Q_SCRIPTABLE QString installationLocationIdFromApplication(const QString &id) const; - Q_SCRIPTABLE QVariantMap getInstallationLocation(const QString &installationLocationId) const; + Q_SCRIPTABLE QStringList packageIds() const; + Q_SCRIPTABLE QVariantMap get(const QString &id) const; + + Q_SCRIPTABLE qint64 installedPackageSize(const QString &packageId) const; + Q_SCRIPTABLE QVariantMap installedPackageExtraMetaData(const QString &packageId) const; + Q_SCRIPTABLE QVariantMap installedPackageExtraSignedMetaData(const QString &packageId) const; // all QString return values are task-ids - QString startPackageInstallation(const QString &installationLocationId, const QUrl &sourceUrl); - Q_SCRIPTABLE QString startPackageInstallation(const QString &installationLocationId, const QString &sourceUrl); + QString startPackageInstallation(const QUrl &sourceUrl); + Q_SCRIPTABLE QString startPackageInstallation(const QString &sourceUrl); Q_SCRIPTABLE void acknowledgePackageInstallation(const QString &taskId); Q_SCRIPTABLE QString removePackage(const QString &id, bool keepDocuments, bool force = false); Q_SCRIPTABLE AsynchronousTask::TaskState taskState(const QString &taskId) const; - Q_SCRIPTABLE QString taskApplicationId(const QString &taskId) const; + Q_SCRIPTABLE QString taskPackageId(const QString &taskId) const; Q_SCRIPTABLE QStringList activeTaskIds() const; Q_SCRIPTABLE bool cancelTask(const QString &taskId); @@ -131,11 +150,14 @@ public: Q_SCRIPTABLE int compareVersions(const QString &version1, const QString &version2); Q_SCRIPTABLE bool validateDnsName(const QString &name, int minimumParts = 1); - Q_SCRIPTABLE qint64 installedApplicationSize(const QString &id) const; - Q_SCRIPTABLE QVariantMap installedApplicationExtraMetaData(const QString &id) const; - Q_SCRIPTABLE QVariantMap installedApplicationExtraSignedMetaData(const QString &id) const; signals: + Q_SCRIPTABLE void countChanged(); + + Q_SCRIPTABLE void packageAdded(const QString &id); + Q_SCRIPTABLE void packageAboutToBeRemoved(const QString &id); + Q_SCRIPTABLE void packageChanged(const QString &id, const QStringList &changedRoles); + Q_SCRIPTABLE void taskStarted(const QString &taskId); Q_SCRIPTABLE void taskProgressChanged(const QString &taskId, qreal progress); Q_SCRIPTABLE void taskFinished(const QString &taskId); @@ -145,7 +167,7 @@ signals: // installation only Q_SCRIPTABLE void taskRequestingInstallationAcknowledge(const QString &taskId, - const QVariantMap &applicationAsVariantMap, + const QVariantMap &packageAsVariantMap, const QVariantMap &packageExtraMetaData, const QVariantMap &packageExtraSignedMetaData); Q_SCRIPTABLE void taskBlockingUntilInstallationAcknowledge(const QString &taskId); @@ -153,28 +175,36 @@ signals: private slots: void executeNextTask(); +protected: + bool startingPackageInstallation(PackageInfo *info); + bool startingPackageRemoval(const QString &id); + bool finishedPackageInstall(const QString &id); + bool canceledPackageInstall(const QString &id); + private: - void cleanupMounts() const; + void emitDataChanged(Package *package, const QVector<int> &roles = QVector<int>()); + static void registerQmlTypes(); + void triggerExecuteNextTask(); QString enqueueTask(AsynchronousTask *task); void handleFailure(AsynchronousTask *task); QList<QByteArray> caCertificates() const; +private: uint findUnusedUserId() const Q_DECL_NOEXCEPT_EXPR(false); -private: - // Ownership of manifestDir and iamgeMountDir is passed to ApplicationInstaller - ApplicationInstaller(const QVector<InstallationLocation> &installationLocations, QDir *manifestDir, const QString &hardwareId, QObject *parent); - ApplicationInstaller(const ApplicationInstaller &); - static ApplicationInstaller *s_instance; + explicit PackageManager(PackageDatabase *packageDatabase, + const QString &documentPath); + PackageManager(const PackageManager &); + PackageManager &operator=(const PackageManager &); + static PackageManager *s_instance; + static QHash<int, QByteArray> s_roleNames; - ApplicationInstallerPrivate *d; + PackageManagerPrivate *d; friend class InstallationTask; friend class DeinstallationTask; }; QT_END_NAMESPACE_AM - -Q_DECLARE_METATYPE(QT_PREPEND_NAMESPACE_AM(AsynchronousTask::TaskState)) diff --git a/src/installer-lib/applicationinstaller_p.h b/src/manager-lib/packagemanager_p.h index 09fc1324..4e7a158b 100644 --- a/src/installer-lib/applicationinstaller_p.h +++ b/src/manager-lib/packagemanager_p.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -48,17 +48,21 @@ #include <QScopedPointer> #include <QThread> -#include <QtAppManInstaller/applicationinstaller.h> -#include <QtAppManInstaller/sudo.h> +#include <QtAppManManager/packagemanager.h> +#include <QtAppManApplication/packagedatabase.h> +#include <QtAppManManager/asynchronoustask.h> #include <QtAppManCommon/global.h> QT_BEGIN_NAMESPACE_AM bool removeRecursiveHelper(const QString &path); -class ApplicationInstallerPrivate +class PackageManagerPrivate { public: + PackageDatabase *database = nullptr; + QVector<Package *> packages; + bool developmentMode = false; bool allowInstallationOfUnsignedPackages = false; bool userIdSeparation = false; @@ -66,9 +70,8 @@ public: uint maxUserId = uint(-1); uint commonGroupId = uint(-1); - QScopedPointer<QDir> manifestDir; - QVector<InstallationLocation> installationLocations; - InstallationLocation invalidInstallationLocation; + QString installationPath; + QString documentPath; QString error; diff --git a/src/manager-lib/plugincontainer.cpp b/src/manager-lib/plugincontainer.cpp index 2150f8d4..32f334c0 100644 --- a/src/manager-lib/plugincontainer.cpp +++ b/src/manager-lib/plugincontainer.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -61,7 +61,7 @@ bool PluginContainerManager::supportsQuickLaunch() const return m_interface->supportsQuickLaunch(); } -AbstractContainer *PluginContainerManager::create(AbstractApplication *app, const QVector<int> &stdioRedirections, +AbstractContainer *PluginContainerManager::create(Application *app, const QVector<int> &stdioRedirections, const QMap<QString, QString> &debugWrapperEnvironment, const QStringList &debugWrapperCommand) { @@ -133,7 +133,7 @@ AbstractContainerProcess *PluginContainer::start(const QStringList &arguments, c return nullptr; } -PluginContainer::PluginContainer(AbstractContainerManager *manager, AbstractApplication *app, ContainerInterface *containerInterface) +PluginContainer::PluginContainer(AbstractContainerManager *manager, Application *app, ContainerInterface *containerInterface) : AbstractContainer(manager, app) , m_interface(containerInterface) , m_process(new PluginContainerProcess(this)) diff --git a/src/manager-lib/plugincontainer.h b/src/manager-lib/plugincontainer.h index acf250da..c97f2af2 100644 --- a/src/manager-lib/plugincontainer.h +++ b/src/manager-lib/plugincontainer.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -56,7 +56,7 @@ public: static QString defaultIdentifier(); bool supportsQuickLaunch() const override; - AbstractContainer *create(AbstractApplication *app, const QVector<int> &stdioRedirections, + AbstractContainer *create(Application *app, const QVector<int> &stdioRedirections, const QMap<QString, QString> &debugWrapperEnvironment, const QStringList &debugWrapperCommand) override; @@ -108,7 +108,7 @@ public: const QVariantMap &amConfig) override; protected: - explicit PluginContainer(AbstractContainerManager *manager, AbstractApplication *app, ContainerInterface *containerInterface); + explicit PluginContainer(AbstractContainerManager *manager, Application *app, ContainerInterface *containerInterface); ContainerInterface *m_interface; PluginContainerProcess *m_process; bool m_startCalled = false; diff --git a/src/manager-lib/processcontainer.cpp b/src/manager-lib/processcontainer.cpp index 23113239..57420100 100644 --- a/src/manager-lib/processcontainer.cpp +++ b/src/manager-lib/processcontainer.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -183,7 +183,7 @@ void HostProcess::setStopBeforeExec(bool stopBeforeExec) } -ProcessContainer::ProcessContainer(ProcessContainerManager *manager, AbstractApplication *app, +ProcessContainer::ProcessContainer(ProcessContainerManager *manager, Application *app, const QVector<int> &stdioRedirections, const QMap<QString, QString> &debugWrapperEnvironment, const QStringList &debugWrapperCommand) @@ -323,7 +323,7 @@ bool ProcessContainerManager::supportsQuickLaunch() const return true; } -AbstractContainer *ProcessContainerManager::create(AbstractApplication *app, const QVector<int> &stdioRedirections, +AbstractContainer *ProcessContainerManager::create(Application *app, const QVector<int> &stdioRedirections, const QMap<QString, QString> &debugWrapperEnvironment, const QStringList &debugWrapperCommand) { diff --git a/src/manager-lib/processcontainer.h b/src/manager-lib/processcontainer.h index 65d11acb..99348a25 100644 --- a/src/manager-lib/processcontainer.h +++ b/src/manager-lib/processcontainer.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -60,7 +60,7 @@ public: static QString defaultIdentifier(); bool supportsQuickLaunch() const override; - AbstractContainer *create(AbstractApplication *app, const QVector<int> &stdioRedirections, + AbstractContainer *create(Application *app, const QVector<int> &stdioRedirections, const QMap<QString, QString> &debugWrapperEnvironment, const QStringList &debugWrapperCommand) override; }; @@ -100,7 +100,7 @@ class ProcessContainer : public AbstractContainer Q_OBJECT public: - explicit ProcessContainer(ProcessContainerManager *manager, AbstractApplication *app, + explicit ProcessContainer(ProcessContainerManager *manager, Application *app, const QVector<int> &stdioRedirections, const QMap<QString, QString> &debugWrapperEnvironment, const QStringList &debugWrapperCommand); diff --git a/src/manager-lib/processstatus.cpp b/src/manager-lib/processstatus.cpp index 8d6e88c4..25ce85b1 100644 --- a/src/manager-lib/processstatus.cpp +++ b/src/manager-lib/processstatus.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -190,7 +190,7 @@ void ProcessStatus::setApplicationId(const QString &appId) qmlWarning(this) << "Invalid application ID:" << appId; } else { m_application = ApplicationManager::instance()->application(appIndex); - connect(m_application, &AbstractApplication::runStateChanged, this, &ProcessStatus::onRunStateChanged); + connect(m_application, &Application::runStateChanged, this, &ProcessStatus::onRunStateChanged); } } determinePid(); diff --git a/src/manager-lib/processstatus.h b/src/manager-lib/processstatus.h index b233aced..612bb23c 100644 --- a/src/manager-lib/processstatus.h +++ b/src/manager-lib/processstatus.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -105,7 +105,7 @@ private: QVariantMap m_memoryRss; QVariantMap m_memoryPss; - QPointer<AbstractApplication> m_application; + QPointer<Application> m_application; bool m_pendingUpdate = false; QScopedPointer<ProcessReader> m_reader; diff --git a/src/manager-lib/qmlinprocessapplicationinterface.cpp b/src/manager-lib/qmlinprocessapplicationinterface.cpp index a24651b4..caceabe3 100644 --- a/src/manager-lib/qmlinprocessapplicationinterface.cpp +++ b/src/manager-lib/qmlinprocessapplicationinterface.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -78,7 +78,7 @@ QVariantMap QmlInProcessApplicationInterface::name() const { QVariantMap names; if (m_runtime && m_runtime->application()) { - const QMap<QString, QString> &sm = m_runtime->application()->info()->names(); + const QMap<QString, QString> &sm = m_runtime->application()->packageInfo()->names(); for (auto it = sm.cbegin(); it != sm.cend(); ++it) names.insert(it.key(), it.value()); } @@ -88,7 +88,7 @@ QVariantMap QmlInProcessApplicationInterface::name() const QUrl QmlInProcessApplicationInterface::icon() const { if (m_runtime && m_runtime->application()) - return m_runtime->application()->icon(); + return m_runtime->application()->packageInfo()->icon(); return QUrl(); } diff --git a/src/manager-lib/qmlinprocessapplicationinterface.h b/src/manager-lib/qmlinprocessapplicationinterface.h index 87b43bf7..669b1461 100644 --- a/src/manager-lib/qmlinprocessapplicationinterface.h +++ b/src/manager-lib/qmlinprocessapplicationinterface.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/manager-lib/qmlinprocessapplicationmanagerwindow.cpp b/src/manager-lib/qmlinprocessapplicationmanagerwindow.cpp index 8bf809aa..fe368b41 100644 --- a/src/manager-lib/qmlinprocessapplicationmanagerwindow.cpp +++ b/src/manager-lib/qmlinprocessapplicationmanagerwindow.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -182,8 +182,6 @@ void QmlInProcessApplicationManagerWindow::data_clear(QQmlListProperty<QObject> void QmlInProcessApplicationManagerWindow::componentComplete() { - qCDebug(LogSystem) << "QmlInProcessApplicationManagerWindow componentComplete() this:" << this; - if (!m_runtime) m_runtime = QmlInProcessRuntime::determineRuntime(this); diff --git a/src/manager-lib/qmlinprocessapplicationmanagerwindow.h b/src/manager-lib/qmlinprocessapplicationmanagerwindow.h index 5207e3d4..55796cba 100644 --- a/src/manager-lib/qmlinprocessapplicationmanagerwindow.h +++ b/src/manager-lib/qmlinprocessapplicationmanagerwindow.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/manager-lib/qmlinprocessruntime.cpp b/src/manager-lib/qmlinprocessruntime.cpp index 788e22d2..7f769b7d 100644 --- a/src/manager-lib/qmlinprocessruntime.cpp +++ b/src/manager-lib/qmlinprocessruntime.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -107,7 +107,7 @@ bool QmlInProcessRuntime::start() if (m_app->runtimeParameters().value(qSL("loadDummyData")).toBool()) { qCDebug(LogSystem) << "Loading dummy-data"; - loadQmlDummyDataFiles(m_inProcessQmlEngine, QFileInfo(m_app->nonAliasedInfo()->absoluteCodeFilePath()).path()); + loadQmlDummyDataFiles(m_inProcessQmlEngine, QFileInfo(m_app->info()->absoluteCodeFilePath()).path()); } const QStringList importPaths = variantToStringList(configuration().value(qSL("importPaths"))) @@ -120,11 +120,10 @@ bool QmlInProcessRuntime::start() qCDebug(LogSystem) << "Updated Qml import paths:" << m_inProcessQmlEngine->importPathList(); } - m_componentError = false; - QQmlComponent *component = new QQmlComponent(m_inProcessQmlEngine, m_app->nonAliasedInfo()->absoluteCodeFilePath()); + QQmlComponent *component = new QQmlComponent(m_inProcessQmlEngine, m_app->info()->absoluteCodeFilePath()); if (!component->isReady()) { - qCDebug(LogSystem) << "qml-file (" << m_app->nonAliasedInfo()->absoluteCodeFilePath() << "): component not ready:\n" << component->errorString(); + qCDebug(LogSystem) << "qml-file (" << m_app->info()->absoluteCodeFilePath() << "): component not ready:\n" << component->errorString(); return false; } @@ -143,8 +142,8 @@ bool QmlInProcessRuntime::start() QMetaObject::invokeMethod(this, [component, appContext, obj, this]() { component->completeCreate(); - if (!obj || m_componentError) { - qCCritical(LogSystem) << "could not load" << m_app->nonAliasedInfo()->absoluteCodeFilePath() << ": no root object"; + if (!obj) { + qCCritical(LogSystem) << "could not load" << m_app->info()->absoluteCodeFilePath() << ": no root object"; delete obj; delete appContext; delete m_applicationIf; @@ -192,7 +191,7 @@ void QmlInProcessRuntime::stop(bool forceKill) #else int exitCode = 0; #endif - finish(exitCode, Am::CrashExit); + finish(exitCode, Am::ForcedExit); return; } @@ -206,7 +205,7 @@ void QmlInProcessRuntime::stop(bool forceKill) #else int exitCode = 0; #endif - finish(exitCode, Am::CrashExit); + finish(exitCode, Am::ForcedExit); }); } diff --git a/src/manager-lib/qmlinprocessruntime.h b/src/manager-lib/qmlinprocessruntime.h index f2d57eb6..0efc7495 100644 --- a/src/manager-lib/qmlinprocessruntime.h +++ b/src/manager-lib/qmlinprocessruntime.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -100,7 +100,6 @@ private: QString m_document; QmlInProcessApplicationInterface *m_applicationIf = nullptr; - bool m_componentError; bool m_stopIfNoVisibleSurfaces = false; diff --git a/src/manager-lib/quicklauncher.cpp b/src/manager-lib/quicklauncher.cpp index 2cf841d5..2494b840 100644 --- a/src/manager-lib/quicklauncher.cpp +++ b/src/manager-lib/quicklauncher.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/manager-lib/quicklauncher.h b/src/manager-lib/quicklauncher.h index c1a0cb94..8fd74e8c 100644 --- a/src/manager-lib/quicklauncher.h +++ b/src/manager-lib/quicklauncher.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/manager-lib/runtimefactory.cpp b/src/manager-lib/runtimefactory.cpp index c87561ea..bf00c31a 100644 --- a/src/manager-lib/runtimefactory.cpp +++ b/src/manager-lib/runtimefactory.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/manager-lib/runtimefactory.h b/src/manager-lib/runtimefactory.h index 7e41a4d4..66e0222a 100644 --- a/src/manager-lib/runtimefactory.h +++ b/src/manager-lib/runtimefactory.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/installer-lib/scopeutilities.cpp b/src/manager-lib/scopeutilities.cpp index 45fe4742..089e03cf 100644 --- a/src/installer-lib/scopeutilities.cpp +++ b/src/manager-lib/scopeutilities.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -42,7 +42,7 @@ #include "logging.h" #include "scopeutilities.h" -#include "applicationinstaller_p.h" +#include "packagemanager_p.h" #include "utilities.h" QT_BEGIN_NAMESPACE_AM @@ -92,7 +92,6 @@ QDir ScopedDirectoryCreator::dir() return QDir(m_path); } - ScopedRenamer::ScopedRenamer() { } diff --git a/src/installer-lib/scopeutilities.h b/src/manager-lib/scopeutilities.h index f3d30424..7ebe5166 100644 --- a/src/installer-lib/scopeutilities.h +++ b/src/manager-lib/scopeutilities.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/installer-lib/sudo.cpp b/src/manager-lib/sudo.cpp index a9d661fe..ab497d89 100644 --- a/src/installer-lib/sudo.cpp +++ b/src/manager-lib/sudo.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/installer-lib/sudo.h b/src/manager-lib/sudo.h index 357261e6..33215279 100644 --- a/src/installer-lib/sudo.h +++ b/src/manager-lib/sudo.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/monitor-lib/processreader.cpp b/src/monitor-lib/processreader.cpp index b89e9b3c..6cbbe22d 100644 --- a/src/monitor-lib/processreader.cpp +++ b/src/monitor-lib/processreader.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/monitor-lib/processreader.h b/src/monitor-lib/processreader.h index e135101c..cfef25b6 100644 --- a/src/monitor-lib/processreader.h +++ b/src/monitor-lib/processreader.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/monitor-lib/sysfsreader.cpp b/src/monitor-lib/sysfsreader.cpp index d100dc43..2b6e66a1 100644 --- a/src/monitor-lib/sysfsreader.cpp +++ b/src/monitor-lib/sysfsreader.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/monitor-lib/sysfsreader.h b/src/monitor-lib/sysfsreader.h index 8a299177..127ddb2f 100644 --- a/src/monitor-lib/sysfsreader.h +++ b/src/monitor-lib/sysfsreader.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/monitor-lib/systemreader.cpp b/src/monitor-lib/systemreader.cpp index 67692fe1..bc1c8514 100644 --- a/src/monitor-lib/systemreader.cpp +++ b/src/monitor-lib/systemreader.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/monitor-lib/systemreader.h b/src/monitor-lib/systemreader.h index a6879495..df5c48fa 100644 --- a/src/monitor-lib/systemreader.h +++ b/src/monitor-lib/systemreader.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/notification-lib/notification.cpp b/src/notification-lib/notification.cpp index 0df9055f..588513a0 100644 --- a/src/notification-lib/notification.cpp +++ b/src/notification-lib/notification.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/notification-lib/notification.h b/src/notification-lib/notification.h index 5dfcfd81..d4ecc501 100644 --- a/src/notification-lib/notification.h +++ b/src/notification-lib/notification.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/package-lib/package-lib.pro b/src/package-lib/package-lib.pro index d38aa343..056649c2 100644 --- a/src/package-lib/package-lib.pro +++ b/src/package-lib/package-lib.pro @@ -17,17 +17,16 @@ include($$SOURCE_DIR/3rdparty/libarchive.pri) include($$SOURCE_DIR/3rdparty/libz.pri) HEADERS += \ - package_p.h \ packageextractor_p.h \ packageextractor.h \ packagecreator_p.h \ packagecreator.h \ - package.h + packageutilities.h \ + packageutilities_p.h \ SOURCES += \ - package_p.cpp \ packagecreator.cpp \ packageextractor.cpp \ - package.cpp + packageutilities.cpp load(qt_module) diff --git a/src/package-lib/packagecreator.cpp b/src/package-lib/packagecreator.cpp index fcfa5c85..ab1fd448 100644 --- a/src/package-lib/packagecreator.cpp +++ b/src/package-lib/packagecreator.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -51,7 +51,7 @@ #include <archive.h> #include <archive_entry.h> -#include "package_p.h" +#include "packageutilities_p.h" #include "packagecreator.h" #include "packagecreator_p.h" #include "exception.h" @@ -174,18 +174,18 @@ bool PackageCreatorPrivate::create() char buffer[64 * 1024]; try { - if (m_report.applicationId().isNull()) + if (m_report.packageId().isNull()) throw Exception("package identifier is null"); QCryptographicHash digest(QCryptographicHash::Sha256); QVariantMap headerFormat { { qSL("formatType"), qSL("am-package-header") }, - { qSL("formatVersion"), 1 } + { qSL("formatVersion"), 2 } }; m_metaData = QVariantMap { - { qSL("applicationId"), m_report.applicationId() }, + { qSL("packageId"), m_report.packageId() }, { qSL("diskSpaceUsed"), m_report.diskSpaceUsed() } }; if (!m_report.extraMetaData().isEmpty()) @@ -342,7 +342,7 @@ bool PackageCreatorPrivate::create() QVariantMap footerFormat { { qSL("formatType"), qSL("am-package-footer") }, - { qSL("formatVersion"), 1 } + { qSL("formatVersion"), 2 } }; QVariantMap footerData { diff --git a/src/package-lib/packagecreator.h b/src/package-lib/packagecreator.h index 34044760..b3021dce 100644 --- a/src/package-lib/packagecreator.h +++ b/src/package-lib/packagecreator.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/package-lib/packagecreator_p.h b/src/package-lib/packagecreator_p.h index 47016af4..4175559f 100644 --- a/src/package-lib/packagecreator_p.h +++ b/src/package-lib/packagecreator_p.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/package-lib/packageextractor.cpp b/src/package-lib/packageextractor.cpp index 6ecdff0e..d5d18c8f 100644 --- a/src/package-lib/packageextractor.cpp +++ b/src/package-lib/packageextractor.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -54,14 +54,14 @@ #include <archive.h> #include <archive_entry.h> -#include "package_p.h" +#include "packageutilities_p.h" #include "packageextractor.h" #include "packageextractor_p.h" #include "exception.h" #include "error.h" #include "installationreport.h" #include "utilities.h" -#include "applicationinfo.h" +#include "packageinfo.h" #include "qtyaml.h" // archive.h might #define this for Android @@ -463,7 +463,7 @@ void PackageExtractorPrivate::processMetaData(const QByteArray &metadata, QCrypt .arg(error.errorString()).arg(error.line).arg(error.column); try { - checkYamlFormat(docs, -2 /*at least 2 docs*/, { isHeader ? "am-package-header" : "am-package-footer" }, 1); + checkYamlFormat(docs, -2 /*at least 2 docs*/, { isHeader ? "am-package-header" : "am-package-footer" }, 2); } catch (const Exception &e) { throw Exception(Error::Package, "metadata has an invalid format specification: %1").arg(e.errorString()); } @@ -471,12 +471,12 @@ void PackageExtractorPrivate::processMetaData(const QByteArray &metadata, QCrypt QVariantMap map = docs.at(1).toMap(); if (isHeader) { - QString applicationId = map.value(qSL("applicationId")).toString(); + QString packageId = map.value(qSL("packageId")).toString(); quint64 diskSpaceUsed = map.value(qSL("diskSpaceUsed")).toULongLong(); - if (applicationId.isNull() || !ApplicationInfo::isValidApplicationId(applicationId)) - throw Exception(Error::Package, "metadata has an invalid applicationId field (%1)").arg(applicationId); - m_report.setApplicationId(applicationId); + if (packageId.isNull() || !PackageInfo::isValidApplicationId(packageId)) + throw Exception(Error::Package, "metadata has an invalid packageId field (%1)").arg(packageId); + m_report.setPackageId(packageId); if (!diskSpaceUsed) throw Exception(Error::Package, "metadata has an invalid diskSpaceUsed field (%1)").arg(diskSpaceUsed); diff --git a/src/package-lib/packageextractor.h b/src/package-lib/packageextractor.h index eb3b1e7f..13b92871 100644 --- a/src/package-lib/packageextractor.h +++ b/src/package-lib/packageextractor.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/package-lib/packageextractor_p.h b/src/package-lib/packageextractor_p.h index a8f72c8a..5463fcf5 100644 --- a/src/package-lib/packageextractor_p.h +++ b/src/package-lib/packageextractor_p.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/package-lib/package.cpp b/src/package-lib/packageutilities.cpp index 481117e9..f5e80180 100644 --- a/src/package-lib/package.cpp +++ b/src/package-lib/packageutilities.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -40,17 +40,25 @@ ** ****************************************************************************/ + +#include <QFileInfo> +#include <QDataStream> +#include <QCryptographicHash> #include <QByteArray> #include <QString> -#include "package.h" +#include <archive.h> + +#include "packageutilities.h" +#include "packageutilities_p.h" #include "global.h" #include <clocale> + QT_BEGIN_NAMESPACE_AM -bool Package::ensureCorrectLocale(QStringList *warnings) +bool PackageUtilities::ensureCorrectLocale(QStringList *warnings) { // We need to make sure we are running in a Unicode locale, since we are // running into problems when unpacking packages with libarchive that @@ -119,7 +127,7 @@ bool Package::ensureCorrectLocale(QStringList *warnings) } -bool Package::checkCorrectLocale() +bool PackageUtilities::checkCorrectLocale() { // see ensureCorrectLocale() above. Call this after the QApplication // constructor as a sanity check. @@ -131,4 +139,41 @@ bool Package::checkCorrectLocale() #endif } + +ArchiveException::ArchiveException(struct ::archive *ar, const char *errorString) + : Exception(Error::Archive, qSL("[libarchive] ") + qL1S(errorString) + qSL(": ") + QString::fromLocal8Bit(::archive_error_string(ar))) +{ } + + +QVariantMap PackageUtilities::headerDataForDigest = QVariantMap { + { "extraSigned", QVariantMap() } +}; + +void PackageUtilities::addFileMetadataToDigest(const QString &entryFilePath, const QFileInfo &fi, QCryptographicHash &digest) +{ + // (using QDataStream would be more readable, but it would make the algorithm Qt dependent) + QByteArray addToDigest = ((fi.isDir()) ? "D/" : "F/") + + QByteArray::number(fi.isDir() ? 0 : fi.size()) + + '/' + entryFilePath.toUtf8(); + digest.addData(addToDigest); +} + +void PackageUtilities::addHeaderDataToDigest(const QVariantMap &header, QCryptographicHash &digest) Q_DECL_NOEXCEPT_EXPR(false) +{ + for (auto it = headerDataForDigest.constBegin(); it != headerDataForDigest.constEnd(); ++it) { + if (header.contains(it.key())) { + QByteArray ba; + QDataStream ds(&ba, QIODevice::WriteOnly); + + QVariant v = header.value(it.key()); + if (!v.convert(int(it.value().type()))) + throw Exception(Error::Package, "metadata field %1 has invalid type for digest calculation (cannot convert %2 to %3)") + .arg(it.key()).arg(header.value(it.key()).type()).arg(it.value().type()); + ds << v; + + digest.addData(ba); + } + } +} + QT_END_NAMESPACE_AM diff --git a/src/package-lib/package.h b/src/package-lib/packageutilities.h index 44d0561a..2b9c4a8b 100644 --- a/src/package-lib/package.h +++ b/src/package-lib/packageutilities.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -47,7 +47,7 @@ QT_BEGIN_NAMESPACE_AM -namespace Package +namespace PackageUtilities { bool ensureCorrectLocale(QStringList *warnings = nullptr); bool checkCorrectLocale(); diff --git a/src/package-lib/package_p.h b/src/package-lib/packageutilities_p.h index d1218fae..62e1a90a 100644 --- a/src/package-lib/package_p.h +++ b/src/package-lib/packageutilities_p.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -52,14 +52,13 @@ QT_FORWARD_DECLARE_CLASS(QCryptographicHash) QT_BEGIN_NAMESPACE_AM -class PackageUtilities +namespace PackageUtilities { -public: - static void addFileMetadataToDigest(const QString &entryFilePath, const QFileInfo &fi, QCryptographicHash &digest); - static void addHeaderDataToDigest(const QVariantMap &header, QCryptographicHash &digest) Q_DECL_NOEXCEPT_EXPR(false); +void addFileMetadataToDigest(const QString &entryFilePath, const QFileInfo &fi, QCryptographicHash &digest); +void addHeaderDataToDigest(const QVariantMap &header, QCryptographicHash &digest) Q_DECL_NOEXCEPT_EXPR(false); - // key == field name, value == type to choose correct hashing algorithm - static QVariantMap headerDataForDigest; +// key == field name, value == type to choose correct hashing algorithm +extern QVariantMap headerDataForDigest; }; enum PackageEntryType { diff --git a/src/plugin-interfaces/containerinterface.cpp b/src/plugin-interfaces/containerinterface.cpp index d5009720..564bff94 100644 --- a/src/plugin-interfaces/containerinterface.cpp +++ b/src/plugin-interfaces/containerinterface.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -131,10 +131,6 @@ ContainerManagerInterface::~ContainerManagerInterface() { } \row \li \c applicationProperties \li A map with all application properties as seen in the manifest. - \row - \li \c installationLocationId - \li The installation location id, if this application was installed - empty for built-in - applications. \endtable */ diff --git a/src/plugin-interfaces/containerinterface.h b/src/plugin-interfaces/containerinterface.h index 010959c4..64b81a92 100644 --- a/src/plugin-interfaces/containerinterface.h +++ b/src/plugin-interfaces/containerinterface.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/plugin-interfaces/startupinterface.cpp b/src/plugin-interfaces/startupinterface.cpp index 07e27708..73db5db3 100644 --- a/src/plugin-interfaces/startupinterface.cpp +++ b/src/plugin-interfaces/startupinterface.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/plugin-interfaces/startupinterface.h b/src/plugin-interfaces/startupinterface.h index b0125784..a8b710fe 100644 --- a/src/plugin-interfaces/startupinterface.h +++ b/src/plugin-interfaces/startupinterface.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/shared-main-lib/cpustatus.cpp b/src/shared-main-lib/cpustatus.cpp index d192781d..b98891cc 100644 --- a/src/shared-main-lib/cpustatus.cpp +++ b/src/shared-main-lib/cpustatus.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/shared-main-lib/cpustatus.h b/src/shared-main-lib/cpustatus.h index f7e37867..30393fa6 100644 --- a/src/shared-main-lib/cpustatus.h +++ b/src/shared-main-lib/cpustatus.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/shared-main-lib/frametimer.cpp b/src/shared-main-lib/frametimer.cpp index 1805f0ee..7751599b 100644 --- a/src/shared-main-lib/frametimer.cpp +++ b/src/shared-main-lib/frametimer.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/shared-main-lib/frametimer.h b/src/shared-main-lib/frametimer.h index 384f9a09..30c5225d 100644 --- a/src/shared-main-lib/frametimer.h +++ b/src/shared-main-lib/frametimer.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/shared-main-lib/gpustatus.cpp b/src/shared-main-lib/gpustatus.cpp index efa7d2ad..69692ce8 100644 --- a/src/shared-main-lib/gpustatus.cpp +++ b/src/shared-main-lib/gpustatus.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/shared-main-lib/gpustatus.h b/src/shared-main-lib/gpustatus.h index e7e23f7c..2a0df87d 100644 --- a/src/shared-main-lib/gpustatus.h +++ b/src/shared-main-lib/gpustatus.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/shared-main-lib/iostatus.cpp b/src/shared-main-lib/iostatus.cpp index fba8fff6..8c771015 100644 --- a/src/shared-main-lib/iostatus.cpp +++ b/src/shared-main-lib/iostatus.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/shared-main-lib/iostatus.h b/src/shared-main-lib/iostatus.h index b6070fad..0c7f4c3f 100644 --- a/src/shared-main-lib/iostatus.h +++ b/src/shared-main-lib/iostatus.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/shared-main-lib/memorystatus.cpp b/src/shared-main-lib/memorystatus.cpp index 1b6909a7..730f5894 100644 --- a/src/shared-main-lib/memorystatus.cpp +++ b/src/shared-main-lib/memorystatus.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/shared-main-lib/memorystatus.h b/src/shared-main-lib/memorystatus.h index 716c9f82..d9dcc8da 100644 --- a/src/shared-main-lib/memorystatus.h +++ b/src/shared-main-lib/memorystatus.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/shared-main-lib/monitormodel.cpp b/src/shared-main-lib/monitormodel.cpp index 5dbda61d..1433b608 100644 --- a/src/shared-main-lib/monitormodel.cpp +++ b/src/shared-main-lib/monitormodel.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/shared-main-lib/monitormodel.h b/src/shared-main-lib/monitormodel.h index 5def27dd..b7d80e9a 100644 --- a/src/shared-main-lib/monitormodel.h +++ b/src/shared-main-lib/monitormodel.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/shared-main-lib/qmllogger.cpp b/src/shared-main-lib/qmllogger.cpp index 7ec4303c..b40bfc52 100644 --- a/src/shared-main-lib/qmllogger.cpp +++ b/src/shared-main-lib/qmllogger.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/shared-main-lib/qmllogger.h b/src/shared-main-lib/qmllogger.h index ab39412b..a47c31d3 100644 --- a/src/shared-main-lib/qmllogger.h +++ b/src/shared-main-lib/qmllogger.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/shared-main-lib/sharedmain.cpp b/src/shared-main-lib/sharedmain.cpp index 647eb91f..080664b4 100644 --- a/src/shared-main-lib/sharedmain.cpp +++ b/src/shared-main-lib/sharedmain.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/shared-main-lib/sharedmain.h b/src/shared-main-lib/sharedmain.h index 7a4cac85..6e9deb41 100644 --- a/src/shared-main-lib/sharedmain.h +++ b/src/shared-main-lib/sharedmain.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/src.pro b/src/src.pro index 63e95d48..b5e66223 100644 --- a/src/src.pro +++ b/src/src.pro @@ -21,9 +21,7 @@ package_lib.depends = crypto_lib application_lib manager_lib.subdir = manager-lib manager_lib.depends = application_lib notification_lib intent_server_lib intent_client_lib monitor_lib plugin_interfaces - -installer_lib.subdir = installer-lib -installer_lib.depends = package_lib manager_lib +!disable-installer:manager_lib.depends += package_lib crypto_lib window_lib.subdir = window-lib window_lib.depends = manager_lib @@ -44,11 +42,11 @@ launcher_lib.subdir = launcher-lib launcher_lib.depends = application_lib notification_lib shared_main_lib intent_client_lib main_lib.subdir = main-lib -main_lib.depends = shared_main_lib manager_lib installer_lib window_lib monitor_lib +main_lib.depends = shared_main_lib manager_lib window_lib monitor_lib !disable-external-dbus-interfaces:qtHaveModule(dbus) { dbus_lib.subdir = dbus-lib - dbus_lib.depends = manager_lib installer_lib window_lib + dbus_lib.depends = manager_lib window_lib main_lib.depends += dbus_lib } @@ -63,10 +61,10 @@ tools_testrunner.subdir = tools/testrunner tools_testrunner.depends = main_lib tools_dumpqmltypes.subdir = tools/dumpqmltypes -tools_dumpqmltypes.depends = manager_lib installer_lib window_lib shared_main_lib launcher_lib +tools_dumpqmltypes.depends = manager_lib window_lib shared_main_lib main_lib launcher_lib tools_packager.subdir = tools/packager -tools_packager.depends = package_lib +tools_packager.depends = package_lib application_lib crypto_lib tools_uploader.subdir = tools/uploader tools_uploader.depends = common_lib @@ -90,7 +88,6 @@ SUBDIRS = \ qtHaveModule(qml):SUBDIRS += \ notification_lib \ manager_lib \ - installer_lib \ window_lib \ monitor_lib \ shared_main_lib \ @@ -106,16 +103,20 @@ SUBDIRS = \ launcher_lib \ # This tool links against everything to extract the Qml type information - qtHaveModule(qml):qtHaveModule(dbus):!headless:SUBDIRS += \ + !disable-installer:qtHaveModule(qml):qtHaveModule(dbus):!headless:SUBDIRS += \ tools_dumpqmltypes \ multi-process:qtHaveModule(qml):qtHaveModule(dbus):SUBDIRS += \ tools_launcher_qml \ } -!android:SUBDIRS += \ - tools_packager \ - tools_uploader \ +!android { + !disable-installer:SUBDIRS += \ + tools_packager + + SUBDIRS += \ + tools_uploader +} qtHaveModule(dbus):SUBDIRS += \ tools_controller \ diff --git a/src/tools/appman/appman.cpp b/src/tools/appman/appman.cpp index 5523edb9..f1808e89 100644 --- a/src/tools/appman/appman.cpp +++ b/src/tools/appman/appman.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -47,7 +47,7 @@ #include "logging.h" #include "main.h" #include "defaultconfiguration.h" -#include "package.h" +#include "packageutilities.h" #if !defined(AM_DISABLE_INSTALLER) # include "sudo.h" #endif @@ -70,8 +70,8 @@ Q_DECL_EXPORT int main(int argc, char *argv[]) #else QCoreApplication::setApplicationName(qSL("Qt Application Manager")); #endif - QCoreApplication::setOrganizationName(qSL("Luxoft Sweden AB")); - QCoreApplication::setOrganizationDomain(qSL("luxoft.com")); + QCoreApplication::setOrganizationName(qSL("QtProject")); + QCoreApplication::setOrganizationDomain(qSL("qt-project.org")); QCoreApplication::setApplicationVersion(qSL(AM_VERSION)); Logging::initialize(argc, argv); @@ -81,7 +81,7 @@ Q_DECL_EXPORT int main(int argc, char *argv[]) QStringList deploymentWarnings; #if !defined(AM_DISABLE_INSTALLER) - Package::ensureCorrectLocale(&deploymentWarnings); + PackageUtilities::ensureCorrectLocale(&deploymentWarnings); Sudo::forkServer(Sudo::DropPrivilegesPermanently, &deploymentWarnings); StartupTimer::instance()->checkpoint("after sudo server fork"); #endif @@ -103,7 +103,9 @@ Q_DECL_EXPORT int main(int argc, char *argv[]) StartupTimer::instance()->checkpoint("after command line parse"); #if defined(AM_TESTRUNNER) - TestRunner::initialize(cfg.testRunnerArguments()); + TestRunner::initialize(cfg.mainQmlFile(), cfg.testRunnerArguments()); + qInfo().nospace().noquote() << "\nTEST: " << cfg.mainQmlFile() << " in " + << (cfg.forceMultiProcess() ? "multi" : "single") << "-process mode"; cfg.setForceVerbose(qEnvironmentVariableIsSet("VERBOSE_TEST")); qInfo() << "Verbose mode is" << (cfg.verbose() ? "on" : "off") << "(changed by (un)setting $VERBOSE_TEST)"; #endif diff --git a/src/tools/controller/controller.cpp b/src/tools/controller/controller.cpp index 6c8a8e83..71696b87 100644 --- a/src/tools/controller/controller.cpp +++ b/src/tools/controller/controller.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage @@ -49,7 +49,7 @@ #include <QtAppManCommon/dbus-utilities.h> #include "applicationmanager_interface.h" -#include "applicationinstaller_interface.h" +#include "packagemanager_interface.h" #include "interrupthandler.h" @@ -72,13 +72,13 @@ public: m_manager = new IoQtApplicationManagerInterface(qSL("io.qt.ApplicationManager"), qSL("/ApplicationManager"), conn, this); } - void connectToInstaller() Q_DECL_NOEXCEPT_EXPR(false) + void connectToPackager() Q_DECL_NOEXCEPT_EXPR(false) { - if (m_installer) + if (m_packager) return; - auto conn = connectTo(qSL("io.qt.ApplicationInstaller")); - m_installer = new IoQtApplicationInstallerInterface(qSL("io.qt.ApplicationManager"), qSL("/ApplicationInstaller"), conn, this); + auto conn = connectTo(qSL("io.qt.PackageManager")); + m_packager = new IoQtPackageManagerInterface(qSL("io.qt.ApplicationManager"), qSL("/PackageManager"), conn, this); } private: @@ -111,9 +111,9 @@ private: } public: - IoQtApplicationInstallerInterface *installer() const + IoQtPackageManagerInterface *packager() const { - return m_installer; + return m_packager; } IoQtApplicationManagerInterface *manager() const @@ -122,7 +122,7 @@ public: } private: - IoQtApplicationInstallerInterface *m_installer = nullptr; + IoQtPackageManagerInterface *m_packager = nullptr; IoQtApplicationManagerInterface *m_manager = nullptr; }; @@ -137,6 +137,8 @@ enum Command { StopAllApplications, ListApplications, ShowApplication, + ListPackages, + ShowPackage, InstallPackage, RemovePackage, ListInstallationTasks, @@ -157,6 +159,8 @@ static struct { { StopAllApplications, "stop-all-applications", "Stop all applications." }, { ListApplications, "list-applications", "List all installed applications." }, { ShowApplication, "show-application", "Show application meta-data." }, + { ListPackages, "list-packages", "List all installed packages." }, + { ShowPackage, "show-package", "Show package meta-data." }, { InstallPackage, "install-package", "Install a package." }, { RemovePackage, "remove-package", "Remove a package." }, { ListInstallationTasks, "list-installation-tasks", "List all active installation tasks." }, @@ -188,12 +192,14 @@ static void stopApplication(const QString &appId, bool forceKill = false) Q_DECL static void stopAllApplications() Q_DECL_NOEXCEPT_EXPR(false); static void listApplications() Q_DECL_NOEXCEPT_EXPR(false); static void showApplication(const QString &appId, bool asJson = false) Q_DECL_NOEXCEPT_EXPR(false); -static void installPackage(const QString &package, const QString &location, bool acknowledge) Q_DECL_NOEXCEPT_EXPR(false); -static void removePackage(const QString &package, bool keepDocuments, bool force) Q_DECL_NOEXCEPT_EXPR(false); +static void listPackages() Q_DECL_NOEXCEPT_EXPR(false); +static void showPackage(const QString &packageId, bool asJson = false) Q_DECL_NOEXCEPT_EXPR(false); +static void installPackage(const QString &packageUrl, bool acknowledge) Q_DECL_NOEXCEPT_EXPR(false); +static void removePackage(const QString &packageId, bool keepDocuments, bool force) Q_DECL_NOEXCEPT_EXPR(false); static void listInstallationTasks() Q_DECL_NOEXCEPT_EXPR(false); static void cancelInstallationTask(bool all, const QString &taskId) Q_DECL_NOEXCEPT_EXPR(false); static void listInstallationLocations() Q_DECL_NOEXCEPT_EXPR(false); -static void showInstallationLocation(const QString &location, bool asJson = false) Q_DECL_NOEXCEPT_EXPR(false); +static void showInstallationLocation(bool asJson = false) Q_DECL_NOEXCEPT_EXPR(false); class ThrowingApplication : public QCoreApplication // clazy:exclude=missing-qobject-macro { @@ -232,8 +238,8 @@ private: int main(int argc, char *argv[]) { QCoreApplication::setApplicationName(qSL("Qt Application Manager Controller")); - QCoreApplication::setOrganizationName(qSL("Luxoft Sweden AB")); - QCoreApplication::setOrganizationDomain(qSL("luxoft.com")); + QCoreApplication::setOrganizationName(qSL("QtProject")); + QCoreApplication::setOrganizationDomain(qSL("qt-project.org")); QCoreApplication::setApplicationVersion(qSL(AM_VERSION)); ThrowingApplication a(argc, argv); @@ -381,18 +387,37 @@ int main(int argc, char *argv[]) clp.isSet(qSL("json")))); break; + case ListPackages: + clp.process(a); + a.runLater(listPackages); + break; + + case ShowPackage: + clp.addOption({ qSL("json"), qSL("Output in JSON format instead of YAML.") }); + clp.addPositionalArgument(qSL("package-id"), qSL("The id of an installed package.")); + clp.process(a); + + if (clp.positionalArguments().size() != 2) + clp.showHelp(1); + + a.runLater(std::bind(showPackage, + clp.positionalArguments().at(1), + clp.isSet(qSL("json")))); + break; + case InstallPackage: - clp.addOption({ { qSL("l"), qSL("location") }, qSL("Set a custom installation location."), qSL("installation-location"), qSL("internal-0") }); + clp.addOption({ { qSL("l"), qSL("location") }, qSL("Set a custom installation location (deprecated and ignored)."), qSL("installation-location"), qSL("internal-0") }); clp.addOption({ { qSL("a"), qSL("acknowledge") }, qSL("Automatically acknowledge the installation (unattended mode).") }); clp.addPositionalArgument(qSL("package"), qSL("The file name of the package; can be - for stdin.")); clp.process(a); if (clp.positionalArguments().size() != 2) clp.showHelp(1); + if (clp.isSet(qSL("l"))) + fprintf(stderr, "Ignoring the deprecated -l option.\n"); a.runLater(std::bind(installPackage, clp.positionalArguments().at(1), - clp.value(qSL("l")), clp.isSet(qSL("a")))); break; @@ -437,15 +462,16 @@ int main(int argc, char *argv[]) break; case ShowInstallationLocation: - clp.addPositionalArgument(qSL("installation-location"), qSL("The id of an installation location.")); + clp.addPositionalArgument(qSL("installation-location"), qSL("The id of an installation location (deprecated and ignored).")); clp.addOption({ qSL("json"), qSL("Output in JSON format instead of YAML.") }); clp.process(a); - if (clp.positionalArguments().size() != 2) + if (clp.positionalArguments().size() > 2) clp.showHelp(1); + if (clp.positionalArguments().size() == 2) + fprintf(stderr, "Ignoring the deprecated installation-location.\n"); a.runLater(std::bind(showInstallationLocation, - clp.positionalArguments().at(1), clp.isSet(qSL("json")))); break; } @@ -601,7 +627,37 @@ void showApplication(const QString &appId, bool asJson) Q_DECL_NOEXCEPT_EXPR(fal qApp->quit(); } -void installPackage(const QString &package, const QString &location, bool acknowledge) Q_DECL_NOEXCEPT_EXPR(false) +void listPackages() Q_DECL_NOEXCEPT_EXPR(false) +{ + dbus.connectToPackager(); + + auto reply = dbus.packager()->packageIds(); + reply.waitForFinished(); + if (reply.isError()) + throw Exception(Error::IO, "failed to call packageIds via DBus: %1").arg(reply.error().message()); + + const auto packageIds = reply.value(); + for (auto packageId : packageIds) + fprintf(stdout, "%s\n", qPrintable(packageId)); + qApp->quit(); +} + +void showPackage(const QString &packageId, bool asJson) Q_DECL_NOEXCEPT_EXPR(false) +{ + dbus.connectToPackager(); + + auto reply = dbus.packager()->get(packageId); + reply.waitForFinished(); + if (reply.isError()) + throw Exception(Error::IO, "failed to get package via DBus: %1").arg(reply.error().message()); + + QVariant package = reply.value(); + fprintf(stdout, "%s\n", asJson ? QJsonDocument::fromVariant(package).toJson().constData() + : QtYaml::yamlFromVariantDocuments({ package }).constData()); + qApp->quit(); +} + +void installPackage(const QString &package, bool acknowledge) Q_DECL_NOEXCEPT_EXPR(false) { QString packageFile = package; @@ -629,10 +685,10 @@ void installPackage(const QString &package, const QString &location, bool acknow if (!fi.exists() || !fi.isReadable() || !fi.isFile()) throw Exception(Error::IO, "Package file is not readable: %1").arg(packageFile); - fprintf(stdout, "Starting installation of package %s to %s...\n", qPrintable(packageFile), qPrintable(location)); + fprintf(stdout, "Starting installation of package %s ...\n", qPrintable(packageFile)); dbus.connectToManager(); - dbus.connectToInstaller(); + dbus.connectToPackager(); // all the async lambdas below need to share this variable static QString installationId; @@ -640,7 +696,7 @@ void installPackage(const QString &package, const QString &location, bool acknow // as soon as we have the manifest available: get the app id and acknowledge the installation if (acknowledge) { - QObject::connect(dbus.installer(), &IoQtApplicationInstallerInterface::taskRequestingInstallationAcknowledge, + QObject::connect(dbus.packager(), &IoQtPackageManagerInterface::taskRequestingInstallationAcknowledge, [](const QString &taskId, const QVariantMap &metadata) { if (taskId != installationId) return; @@ -648,13 +704,13 @@ void installPackage(const QString &package, const QString &location, bool acknow if (applicationId.isEmpty()) throw Exception(Error::IO, "could not find a valid application id in the package"); fprintf(stdout, "Acknowledging package installation...\n"); - dbus.installer()->acknowledgePackageInstallation(taskId); + dbus.packager()->acknowledgePackageInstallation(taskId); }); } // on failure: quit - QObject::connect(dbus.installer(), &IoQtApplicationInstallerInterface::taskFailed, + QObject::connect(dbus.packager(), &IoQtPackageManagerInterface::taskFailed, [](const QString &taskId, int errorCode, const QString &errorString) { if (taskId != installationId) return; @@ -663,7 +719,7 @@ void installPackage(const QString &package, const QString &location, bool acknow // on success - QObject::connect(dbus.installer(), &IoQtApplicationInstallerInterface::taskFinished, + QObject::connect(dbus.packager(), &IoQtPackageManagerInterface::taskFinished, [](const QString &taskId) { if (taskId != installationId) return; @@ -673,7 +729,7 @@ void installPackage(const QString &package, const QString &location, bool acknow // start the package installation - auto reply = dbus.installer()->startPackageInstallation(location, fi.absoluteFilePath()); + auto reply = dbus.packager()->startPackageInstallation(fi.absoluteFilePath()); reply.waitForFinished(); if (reply.isError()) throw Exception(Error::IO, "failed to call startPackageInstallation via DBus: %1").arg(reply.error().message()); @@ -686,7 +742,7 @@ void installPackage(const QString &package, const QString &location, bool acknow InterruptHandler::install([](int) { fprintf(stdout, "Cancelling package installation.\n"); - auto reply = dbus.installer()->cancelTask(installationId); + auto reply = dbus.packager()->cancelTask(installationId); reply.waitForFinished(); qApp->exit(1); }); @@ -697,14 +753,14 @@ void removePackage(const QString &applicationId, bool keepDocuments, bool force) fprintf(stdout, "Starting removal of package %s...\n", qPrintable(applicationId)); dbus.connectToManager(); - dbus.connectToInstaller(); + dbus.connectToPackager(); // both the async lambdas below need to share this variables static QString installationId; // on failure: quit - QObject::connect(dbus.installer(), &IoQtApplicationInstallerInterface::taskFailed, + QObject::connect(dbus.packager(), &IoQtPackageManagerInterface::taskFailed, [](const QString &taskId, int errorCode, const QString &errorString) { if (taskId != installationId) return; @@ -713,7 +769,7 @@ void removePackage(const QString &applicationId, bool keepDocuments, bool force) // on success - QObject::connect(dbus.installer(), &IoQtApplicationInstallerInterface::taskFinished, + QObject::connect(dbus.packager(), &IoQtPackageManagerInterface::taskFinished, [](const QString &taskId) { if (taskId != installationId) return; @@ -723,7 +779,7 @@ void removePackage(const QString &applicationId, bool keepDocuments, bool force) // start the package installation - auto reply = dbus.installer()->removePackage(applicationId, keepDocuments, force); + auto reply = dbus.packager()->removePackage(applicationId, keepDocuments, force); reply.waitForFinished(); if (reply.isError()) throw Exception(Error::IO, "failed to call removePackage via DBus: %1").arg(reply.error().message()); @@ -735,9 +791,9 @@ void removePackage(const QString &applicationId, bool keepDocuments, bool force) void listInstallationTasks() Q_DECL_NOEXCEPT_EXPR(false) { - dbus.connectToInstaller(); + dbus.connectToPackager(); - auto reply = dbus.installer()->activeTaskIds(); + auto reply = dbus.packager()->activeTaskIds(); reply.waitForFinished(); if (reply.isError()) throw Exception(Error::IO, "failed to call activeTaskIds via DBus: %1").arg(reply.error().message()); @@ -751,16 +807,16 @@ void listInstallationTasks() Q_DECL_NOEXCEPT_EXPR(false) void cancelInstallationTask(bool all, const QString &taskId) Q_DECL_NOEXCEPT_EXPR(false) { - dbus.connectToInstaller(); + dbus.connectToPackager(); // both the async lambdas below need to share this variables static QStringList cancelTaskIds; static int result = 0; if (all) { - dbus.connectToInstaller(); + dbus.connectToPackager(); - auto reply = dbus.installer()->activeTaskIds(); + auto reply = dbus.packager()->activeTaskIds(); reply.waitForFinished(); if (reply.isError()) throw Exception(Error::IO, "failed to call activeTaskIds via DBus: %1").arg(reply.error().message()); @@ -777,7 +833,7 @@ void cancelInstallationTask(bool all, const QString &taskId) Q_DECL_NOEXCEPT_EXP // on task failure - QObject::connect(dbus.installer(), &IoQtApplicationInstallerInterface::taskFailed, + QObject::connect(dbus.packager(), &IoQtPackageManagerInterface::taskFailed, [](const QString &taskId, int errorCode, const QString &errorString) { if (cancelTaskIds.removeOne(taskId)) { if (errorCode != int(Error::Canceled)) { @@ -794,7 +850,7 @@ void cancelInstallationTask(bool all, const QString &taskId) Q_DECL_NOEXCEPT_EXP // on success - QObject::connect(dbus.installer(), &IoQtApplicationInstallerInterface::taskFinished, + QObject::connect(dbus.packager(), &IoQtPackageManagerInterface::taskFinished, [](const QString &taskId) { if (cancelTaskIds.removeOne(taskId)) { fprintf(stdout, "Could not cancel task %s anymore - the installation task already finished successfully.\n", @@ -810,7 +866,7 @@ void cancelInstallationTask(bool all, const QString &taskId) Q_DECL_NOEXCEPT_EXP // cancel the task - auto reply = dbus.installer()->cancelTask(cancelTaskId); + auto reply = dbus.packager()->cancelTask(cancelTaskId); reply.waitForFinished(); if (reply.isError()) throw Exception(Error::IO, "failed to call cancelTask via DBus: %1").arg(reply.error().message()); @@ -822,30 +878,20 @@ void cancelInstallationTask(bool all, const QString &taskId) Q_DECL_NOEXCEPT_EXP void listInstallationLocations() Q_DECL_NOEXCEPT_EXPR(false) { - dbus.connectToInstaller(); + dbus.connectToPackager(); - auto reply = dbus.installer()->installationLocationIds(); - reply.waitForFinished(); - if (reply.isError()) - throw Exception(Error::IO, "failed to call installationLocationIds via DBus: %1").arg(reply.error().message()); - - const auto installationLocationIds = reply.value(); - for (auto installationLocationId : installationLocationIds) - fprintf(stdout, "%s\n", qPrintable(installationLocationId)); + auto installationLocation = dbus.packager()->installationLocation().variant().toMap(); + if (!installationLocation.isEmpty()) + fputs("internal-0\n", stdout); qApp->quit(); } -void showInstallationLocation(const QString &location, bool asJson) Q_DECL_NOEXCEPT_EXPR(false) +void showInstallationLocation(bool asJson) Q_DECL_NOEXCEPT_EXPR(false) { - dbus.connectToInstaller(); - - auto reply = dbus.installer()->getInstallationLocation(location); - reply.waitForFinished(); - if (reply.isError()) - throw Exception(Error::IO, "failed to call getInstallationLocation via DBus: %1").arg(reply.error().message()); + dbus.connectToPackager(); - QVariant app = reply.value(); - fprintf(stdout, "%s\n", asJson ? QJsonDocument::fromVariant(app).toJson().constData() - : QtYaml::yamlFromVariantDocuments({ app }).constData()); + auto installationLocation = dbus.packager()->installationLocation().variant().toMap(); + fprintf(stdout, "%s\n", asJson ? QJsonDocument::fromVariant(installationLocation).toJson().constData() + : QtYaml::yamlFromVariantDocuments({ installationLocation }).constData()); qApp->quit(); } diff --git a/src/tools/controller/controller.pro b/src/tools/controller/controller.pro index 973781b9..43af64db 100644 --- a/src/tools/controller/controller.pro +++ b/src/tools/controller/controller.pro @@ -16,7 +16,7 @@ appmanif.files = ../../dbus-lib/io.qt.applicationmanager.xml appmanif.header_flags = -i dbus-utilities.h DBUS_INTERFACES += \ - ../../dbus-lib/io.qt.applicationinstaller.xml \ + ../../dbus-lib/io.qt.packagemanager.xml \ appmanif load(qt_tool) diff --git a/src/tools/controller/interrupthandler.cpp b/src/tools/controller/interrupthandler.cpp index 032ea23a..82c4a729 100644 --- a/src/tools/controller/interrupthandler.cpp +++ b/src/tools/controller/interrupthandler.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage diff --git a/src/tools/controller/interrupthandler.h b/src/tools/controller/interrupthandler.h index 7674afe2..8bd32d6d 100644 --- a/src/tools/controller/interrupthandler.h +++ b/src/tools/controller/interrupthandler.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage diff --git a/src/tools/dumpqmltypes/dumpqmltypes.cpp b/src/tools/dumpqmltypes/dumpqmltypes.cpp index 4d3999d9..fd6661d6 100644 --- a/src/tools/dumpqmltypes/dumpqmltypes.cpp +++ b/src/tools/dumpqmltypes/dumpqmltypes.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage @@ -27,7 +27,8 @@ ** ****************************************************************************/ -#include <QtAppManInstaller/applicationinstaller.h> +#include <QtAppManManager/packagemanager.h> +#include <QtAppManMain/applicationinstaller.h> #include <QtAppManManager/applicationmanager.h> #include <QtAppManManager/applicationmodel.h> #include <QtAppManManager/amnamespace.h> @@ -72,9 +73,10 @@ static const QVector<const QMetaObject *> all = { // manager-lib &ApplicationManager::staticMetaObject, &ApplicationInstaller::staticMetaObject, + &PackageManager::staticMetaObject, &NotificationManager::staticMetaObject, &ApplicationIPCManager::staticMetaObject, - &AbstractApplication::staticMetaObject, + &Application::staticMetaObject, &AbstractRuntime::staticMetaObject, &AbstractContainer::staticMetaObject, &Notification::staticMetaObject, @@ -250,8 +252,8 @@ int main(int argc, char **argv) { try { QCoreApplication::setApplicationName(qSL("Qt Application Manager QML Types Dumper")); - QCoreApplication::setOrganizationName(qSL("Luxoft Sweden AB")); - QCoreApplication::setOrganizationDomain(qSL("luxoft.com")); + QCoreApplication::setOrganizationName(qSL("QtProject")); + QCoreApplication::setOrganizationDomain(qSL("qt-project.org")); QCoreApplication::setApplicationVersion(qSL(AM_VERSION)); QCoreApplication a(argc, argv); diff --git a/src/tools/dumpqmltypes/dumpqmltypes.pro b/src/tools/dumpqmltypes/dumpqmltypes.pro index 22079782..acde4c97 100644 --- a/src/tools/dumpqmltypes/dumpqmltypes.pro +++ b/src/tools/dumpqmltypes/dumpqmltypes.pro @@ -10,13 +10,13 @@ QT *= \ appman_common-private \ appman_application-private \ appman_manager-private \ - appman_installer-private \ appman_notification-private \ appman_window-private \ appman_launcher-private \ appman_intent_client-private \ appman_intent_server-private \ appman_monitor-private \ + appman_main-private \ appman_shared_main-private \ CONFIG *= console diff --git a/src/tools/launcher-qml/launcher-qml.cpp b/src/tools/launcher-qml/launcher-qml.cpp index 9ff121a7..421eb174 100644 --- a/src/tools/launcher-qml/launcher-qml.cpp +++ b/src/tools/launcher-qml/launcher-qml.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -83,7 +83,7 @@ #include "utilities.h" #include "exception.h" #include "crashhandler.h" -#include "yamlapplicationscanner.h" +#include "yamlpackagescanner.h" #include "applicationinfo.h" #include "startupinterface.h" #include "dbus-utilities.h" @@ -110,8 +110,8 @@ int main(int argc, char *argv[]) StartupTimer::instance()->checkpoint("entered main"); QCoreApplication::setApplicationName(qSL("Qt Application Manager QML Launcher")); - QCoreApplication::setOrganizationName(qSL("Luxoft Sweden AB")); - QCoreApplication::setOrganizationDomain(qSL("luxoft.com")); + QCoreApplication::setOrganizationName(qSL("QtProject")); + QCoreApplication::setOrganizationDomain(qSL("qt-project.org")); QCoreApplication::setApplicationVersion(qSL(AM_VERSION)); if (qEnvironmentVariableIsSet("AM_NO_DLT_LOGGING")) @@ -123,7 +123,7 @@ int main(int argc, char *argv[]) // As we don't know the app-id yet, we are registering a place holder so we are able to see // something in the dlt logs if general errors occur. - Logging::setDltApplicationId("PCLQ", "Luxoft Application-Manager Launcher QML"); + Logging::setDltApplicationId("QTLQ", "Qt Application-Manager Launcher QML"); Logging::setApplicationId("qml-launcher"); Logging::initialize(); @@ -265,10 +265,11 @@ Controller::Controller(LauncherMain *a, bool quickLaunched, const QString &direc } else { QMetaObject::invokeMethod(this, [this, directLoad]() { QFileInfo fi(directLoad); - YamlApplicationScanner yas; + YamlPackageScanner yps; try { - ApplicationInfo *a = yas.scan(directLoad); - startApplication(fi.absolutePath(), a->codeFilePath(), QString(), QString(), a->toVariantMap(), QVariantMap()); + //TODO: how should this work? +// ApplicationInfo *a = yps.scan(directLoad); +// startApplication(fi.absolutePath(), a->codeFilePath(), QString(), QString(), a->toVariantMap(), QVariantMap()); } catch (const Exception &e) { throw Exception("Could not parse info.yaml file: %1").arg(e.what()); } diff --git a/src/tools/launcher-qml/launcher-qml_p.h b/src/tools/launcher-qml/launcher-qml_p.h index e0e54eef..2ae2e8cf 100644 --- a/src/tools/launcher-qml/launcher-qml_p.h +++ b/src/tools/launcher-qml/launcher-qml_p.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/tools/packager/packager.cpp b/src/tools/packager/packager.cpp index 5f81a7f0..5c23fc92 100644 --- a/src/tools/packager/packager.cpp +++ b/src/tools/packager/packager.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage @@ -40,7 +40,7 @@ #include <QtAppManCommon/exception.h> #include <QtAppManCommon/qtyaml.h> #include <QtAppManCommon/utilities.h> -#include <QtAppManPackage/package.h> +#include <QtAppManPackage/packageutilities.h> #include "packagingjob.h" QT_USE_NAMESPACE_AM @@ -87,16 +87,16 @@ static Command command(QCommandLineParser &clp) int main(int argc, char *argv[]) { - Package::ensureCorrectLocale(); + PackageUtilities::ensureCorrectLocale(); QCoreApplication::setApplicationName(qSL("Qt ApplicationManager Packager")); - QCoreApplication::setOrganizationName(qSL("Luxoft Sweden AB")); - QCoreApplication::setOrganizationDomain(qSL("luxoft.com")); + QCoreApplication::setOrganizationName(qSL("QtProject")); + QCoreApplication::setOrganizationDomain(qSL("qt-project.org")); QCoreApplication::setApplicationVersion(qSL(AM_VERSION)); QCoreApplication a(argc, argv); - if (!Package::checkCorrectLocale()) { + if (!PackageUtilities::checkCorrectLocale()) { fprintf(stderr, "ERROR: the packager needs a UTF-8 locale to work correctly:\n" " even automatically switching to C.UTF-8 or en_US.UTF-8 failed.\n"); exit(2); diff --git a/src/tools/packager/packagingjob.cpp b/src/tools/packager/packagingjob.cpp index b2295d44..f8868788 100644 --- a/src/tools/packager/packagingjob.cpp +++ b/src/tools/packager/packagingjob.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage @@ -42,9 +42,11 @@ #include "exception.h" #include "signature.h" #include "qtyaml.h" +#include "packageinfo.h" #include "applicationinfo.h" +#include "intentinfo.h" #include "installationreport.h" -#include "yamlapplicationscanner.h" +#include "yamlpackagescanner.h" #include "packageextractor.h" #include "packagecreator.h" @@ -149,22 +151,38 @@ void PackagingJob::execute() Q_DECL_NOEXCEPT_EXPR(false) throw Exception(Error::Package, "source %1 is not a directory").arg(m_sourceDir); // check metadata - YamlApplicationScanner yas; - QString infoName = yas.metaDataFileName(); - QScopedPointer<ApplicationInfo> app(yas.scan(source.absoluteFilePath(infoName))); + YamlPackageScanner yps; + QString infoName = yps.metaDataFileName(); + QScopedPointer<PackageInfo> package(yps.scan(source.absoluteFilePath(infoName))); // build report - InstallationReport report(app->id()); + InstallationReport report(package->id()); report.addFile(infoName); // check icon - if (!QFile::exists(source.absoluteFilePath(app->icon()))) + if (!QFile::exists(source.absoluteFilePath(package->icon()))) throw Exception(Error::Package, "missing the file referenced by the 'icon' field"); - report.addFile(app->icon()); + report.addFile(package->icon()); + + // check intent icons + auto intents = package->intents(); + for (const auto intent : intents) { + if (!QFile::exists(source.absoluteFilePath(intent->icon()))) { + throw Exception(Error::Package, "missing the file referenced by the 'icon' field for intent '%1'") + .arg(intent->id()); + } + } - // check executable - if (!QFile::exists(source.absoluteFilePath(app->codeFilePath()))) - throw Exception(Error::Package, "missing the file referenced by the 'code' field"); + // check executables + auto applications = package->applications(); + if (applications.isEmpty()) + throw Exception(Error::Package, "no applications defined in package"); + for (const auto application : applications) { + if (!QFile::exists(source.absoluteFilePath(application->codeFilePath()))) { + throw Exception(Error::Package, "missing the file referenced by the 'code' field for application '%1'") + .arg(application->id()); + } + } quint64 estimatedImageSize = 0; QString canonicalSourcePath = source.canonicalPath(); @@ -188,16 +206,16 @@ void PackagingJob::execute() Q_DECL_NOEXCEPT_EXPR(false) if (entryInfo.fileName().startsWith(qL1S("--PACKAGE-"))) throw Exception(Error::Package, "file names starting with --PACKAGE- are reserved by the packager (found: %1)").arg(entryPath); - estimatedImageSize += (entryInfo.size() + Ext2BlockSize - 1) / Ext2BlockSize; + estimatedImageSize += (quint64(entryInfo.size()) + Ext2BlockSize - 1) / Ext2BlockSize; - if (entryPath != infoName && entryPath != app->icon()) + if (entryPath != infoName && entryPath != package->icon()) report.addFile(entryPath); } // we have the estimatedImageSize for the raw content now, but we need to add the inode // overhead still. This algorithm comes from buildroot: // http://git.buildroot.net/buildroot/tree/package/mke2img/mke2img - estimatedImageSize = (500 + (estimatedImageSize + report.files().count() + 400 / 8) * 11 / 10) * Ext2BlockSize; + estimatedImageSize = (500 + (estimatedImageSize + quint64(report.files().count()) + 400 / 8) * 11 / 10) * Ext2BlockSize; report.setDiskSpaceUsed(estimatedImageSize); // set extra metadata @@ -207,11 +225,11 @@ void PackagingJob::execute() Q_DECL_NOEXCEPT_EXPR(false) // finally create the package PackageCreator creator(source, &destination, report); if (!creator.create()) - throw Exception(Error::Package, "could not create package %1: %2").arg(app->id()).arg(creator.errorString()); + throw Exception(Error::Package, "could not create package %1: %2").arg(package->id()).arg(creator.errorString()); QVariantMap md = creator.metaData(); - m_output = m_asJson ? QJsonDocument::fromVariant(md).toJson().constData() - : QtYaml::yamlFromVariantDocuments({ md }).constData(); + m_output = QString::fromUtf8(m_asJson ? QJsonDocument::fromVariant(md).toJson() + : QtYaml::yamlFromVariantDocuments({ md })); break; } case DeveloperSign: @@ -316,8 +334,8 @@ void PackagingJob::execute() Q_DECL_NOEXCEPT_EXPR(false) throw Exception(Error::Package, "could not create package %1: %2").arg(m_destinationName).arg(creator.errorString()); QVariantMap md = creator.metaData(); - m_output = m_asJson ? QJsonDocument::fromVariant(md).toJson().constData() - : QtYaml::yamlFromVariantDocuments({ md }).constData(); + m_output = QString::fromUtf8(m_asJson ? QJsonDocument::fromVariant(md).toJson() + : QtYaml::yamlFromVariantDocuments({ md })); break; } default: diff --git a/src/tools/packager/packagingjob.h b/src/tools/packager/packagingjob.h index a46ac278..9c5125c0 100644 --- a/src/tools/packager/packagingjob.h +++ b/src/tools/packager/packagingjob.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage diff --git a/src/tools/testrunner/testrunner.cpp b/src/tools/testrunner/testrunner.cpp index 33f03a69..ce10cefd 100644 --- a/src/tools/testrunner/testrunner.cpp +++ b/src/tools/testrunner/testrunner.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -47,6 +47,8 @@ #include <QQmlEngine> #include <QRegExp> #include <QRegularExpression> +#include <QDir> +#include <QFileInfo> #include <qlogging.h> #include <QtTest/qtestsystem.h> @@ -168,19 +170,26 @@ static QObject *amTest(QQmlEngine *engine, QJSEngine *jsEngine) return AmTest::instance(); } -void TestRunner::initialize(const QStringList &testRunnerArguments) +void TestRunner::initialize(const QString &testFile, const QStringList &testRunnerArguments) { Q_ASSERT(!testRunnerArguments.isEmpty()); + const QString name = QFileInfo(testRunnerArguments.at(0)).fileName() + "::" + QDir().relativeFilePath(testFile); + static const char *programName = strdup(name.toLocal8Bit().constData()); + QuickTestResult::setProgramName(programName); + // Convert all the arguments back into a char * array. // These need to be alive as long as the program is running! static QVector<char *> testArgV; for (const auto &arg : testRunnerArguments) testArgV << strdup(arg.toLocal8Bit().constData()); - atexit([]() { std::for_each(testArgV.constBegin(), testArgV.constEnd(), free); }); + + atexit([]() { + free(const_cast<char*>(programName)); + std::for_each(testArgV.constBegin(), testArgV.constEnd(), free); + }); QuickTestResult::setCurrentAppname(testArgV.constFirst()); - QuickTestResult::setProgramName(testArgV.constFirst()); // Allocate a QuickTestResult to create QBenchmarkGlobalData, otherwise the benchmark options don't work QuickTestResult result; diff --git a/src/tools/testrunner/testrunner.h b/src/tools/testrunner/testrunner.h index 5cc1a50d..00d2240c 100644 --- a/src/tools/testrunner/testrunner.h +++ b/src/tools/testrunner/testrunner.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE_AM class TestRunner { public: - static void initialize(const QStringList &testRunnerArguments); + static void initialize(const QString &testFile, const QStringList &testRunnerArguments); static int exec(QQmlEngine *engine); }; diff --git a/src/tools/testrunner/testrunner_p.h b/src/tools/testrunner/testrunner_p.h index 614e66c6..bc29c250 100644 --- a/src/tools/testrunner/testrunner_p.h +++ b/src/tools/testrunner/testrunner_p.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/tools/uploader/uploader.cpp b/src/tools/uploader/uploader.cpp index 40d9a66c..9912593c 100644 --- a/src/tools/uploader/uploader.cpp +++ b/src/tools/uploader/uploader.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage @@ -91,8 +91,8 @@ Q_NORETURN void printErrorAndExit(const QString &errorPrefix, const QString &err int main(int argc, char *argv[]) { QCoreApplication::setApplicationName(applicationName); - QCoreApplication::setOrganizationName(qSL("Luxoft")); - QCoreApplication::setOrganizationDomain(qSL("luxoft.com")); + QCoreApplication::setOrganizationName(qSL("QtProject")); + QCoreApplication::setOrganizationDomain(qSL("qt-project.org")); QCoreApplication::setApplicationVersion(qSL(AM_VERSION)); QCoreApplication a(argc, argv); diff --git a/src/wayland-extensions/qtam-extension.xml b/src/wayland-extensions/qtam-extension.xml index a80600a8..73025015 100644 --- a/src/wayland-extensions/qtam-extension.xml +++ b/src/wayland-extensions/qtam-extension.xml @@ -4,7 +4,7 @@ Copyright (C) 2018 Pelagicore AG Contact: https://www.qt.io/licensing/ - This file is part of the Luxoft Application Manager. + This file is part of the Qt Application Manager. $QT_BEGIN_LICENSE:BSD-QTAS$ Commercial License Usage diff --git a/src/window-lib/inprocesswindow.cpp b/src/window-lib/inprocesswindow.cpp index 8b55df29..aa9a4906 100644 --- a/src/window-lib/inprocesswindow.cpp +++ b/src/window-lib/inprocesswindow.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -45,7 +45,7 @@ QT_BEGIN_NAMESPACE_AM -InProcessWindow::InProcessWindow(AbstractApplication *app, const QSharedPointer<InProcessSurfaceItem> &surfaceItem) +InProcessWindow::InProcessWindow(Application *app, const QSharedPointer<InProcessSurfaceItem> &surfaceItem) : Window(app) , m_surfaceItem(surfaceItem) { diff --git a/src/window-lib/inprocesswindow.h b/src/window-lib/inprocesswindow.h index a88c648c..3b4575b3 100644 --- a/src/window-lib/inprocesswindow.h +++ b/src/window-lib/inprocesswindow.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -56,7 +56,7 @@ class InProcessWindow : public Window Q_OBJECT public: - InProcessWindow(AbstractApplication *app, const QSharedPointer<InProcessSurfaceItem> &surfaceItem); + InProcessWindow(Application *app, const QSharedPointer<InProcessSurfaceItem> &surfaceItem); virtual ~InProcessWindow(); bool isInProcess() const override { return true; } diff --git a/src/window-lib/touchemulation.cpp b/src/window-lib/touchemulation.cpp index 6b989069..985887f7 100644 --- a/src/window-lib/touchemulation.cpp +++ b/src/window-lib/touchemulation.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/window-lib/touchemulation.h b/src/window-lib/touchemulation.h index 4dc9e937..caf967b1 100644 --- a/src/window-lib/touchemulation.h +++ b/src/window-lib/touchemulation.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/window-lib/touchemulation_x11.cpp b/src/window-lib/touchemulation_x11.cpp index 419cd1b9..927f8e94 100644 --- a/src/window-lib/touchemulation_x11.cpp +++ b/src/window-lib/touchemulation_x11.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/window-lib/touchemulation_x11_p.h b/src/window-lib/touchemulation_x11_p.h index 7719cb21..14657ac6 100644 --- a/src/window-lib/touchemulation_x11_p.h +++ b/src/window-lib/touchemulation_x11_p.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/window-lib/waylandcompositor.cpp b/src/window-lib/waylandcompositor.cpp index 6bf0d18b..19755649 100644 --- a/src/window-lib/waylandcompositor.cpp +++ b/src/window-lib/waylandcompositor.cpp @@ -5,7 +5,7 @@ ** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/window-lib/waylandcompositor.h b/src/window-lib/waylandcompositor.h index 283db83a..4efe7d3d 100644 --- a/src/window-lib/waylandcompositor.h +++ b/src/window-lib/waylandcompositor.h @@ -5,7 +5,7 @@ ** Copyright (C) 2016 Klarälvdalens Datakonsult AB, a KDAB Group company ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/window-lib/waylandqtamserverextension.cpp b/src/window-lib/waylandqtamserverextension.cpp index cdce4e1e..a383217a 100644 --- a/src/window-lib/waylandqtamserverextension.cpp +++ b/src/window-lib/waylandqtamserverextension.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/window-lib/waylandqtamserverextension_p.h b/src/window-lib/waylandqtamserverextension_p.h index 4ef11d0e..a5756295 100644 --- a/src/window-lib/waylandqtamserverextension_p.h +++ b/src/window-lib/waylandqtamserverextension_p.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/window-lib/waylandwindow.cpp b/src/window-lib/waylandwindow.cpp index 6382bc05..c1d03c26 100644 --- a/src/window-lib/waylandwindow.cpp +++ b/src/window-lib/waylandwindow.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -57,7 +57,7 @@ QT_BEGIN_NAMESPACE_AM bool WaylandWindow::m_watchdogEnabled = true; -WaylandWindow::WaylandWindow(AbstractApplication *app, WindowSurface *surf) +WaylandWindow::WaylandWindow(Application *app, WindowSurface *surf) : Window(app) , m_pingTimer(new QTimer(this)) , m_pongTimer(new QTimer(this)) diff --git a/src/window-lib/waylandwindow.h b/src/window-lib/waylandwindow.h index 33fbea13..ee1bfaa2 100644 --- a/src/window-lib/waylandwindow.h +++ b/src/window-lib/waylandwindow.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -59,7 +59,7 @@ class WaylandWindow : public Window Q_PROPERTY(QWaylandQuickSurface* waylandSurface READ waylandSurface NOTIFY waylandSurfaceChanged) public: - WaylandWindow(AbstractApplication *app, WindowSurface *surface); + WaylandWindow(Application *app, WindowSurface *surface); bool isInProcess() const override { return false; } diff --git a/src/window-lib/window-lib.pro b/src/window-lib/window-lib.pro index a5a43177..918bbe34 100644 --- a/src/window-lib/window-lib.pro +++ b/src/window-lib/window-lib.pro @@ -10,6 +10,7 @@ QT_FOR_PRIVATE *= \ appman_common-private \ appman_application-private \ appman_manager-private \ + appman_monitor-private \ CONFIG *= static internal_module CONFIG -= create_cmake @@ -45,7 +46,6 @@ multi-process:!headless { windowmanager_p.h \ touchemulation.h \ - !headless:SOURCES += \ window.cpp \ windowitem.cpp \ diff --git a/src/window-lib/window.cpp b/src/window-lib/window.cpp index 13bc7053..6598b8b4 100644 --- a/src/window-lib/window.cpp +++ b/src/window-lib/window.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -185,7 +185,7 @@ */ QT_BEGIN_NAMESPACE_AM -Window::Window(AbstractApplication *app) +Window::Window(Application *app) : QObject() , m_application(app) { @@ -196,7 +196,7 @@ Window::~Window() emit _windowDestroyed(); } -AbstractApplication *Window::application() const +Application *Window::application() const { return m_application; } diff --git a/src/window-lib/window.h b/src/window-lib/window.h index e2981cea..e41058fe 100644 --- a/src/window-lib/window.h +++ b/src/window-lib/window.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -66,7 +66,7 @@ class Window : public QObject Q_PROPERTY(QSize size READ size NOTIFY sizeChanged) Q_PROPERTY(ContentState contentState READ contentState NOTIFY contentStateChanged) - Q_PROPERTY(AbstractApplication* application READ application CONSTANT) + Q_PROPERTY(Application* application READ application CONSTANT) Q_PROPERTY(bool popup READ isPopup CONSTANT) Q_PROPERTY(QPoint requestedPopupPosition READ requestedPopupPosition NOTIFY requestedPopupPositionChanged) @@ -79,11 +79,11 @@ public: }; Q_ENUM(ContentState) - Window(AbstractApplication *app); + Window(Application *app); virtual ~Window(); virtual bool isInProcess() const = 0; - virtual AbstractApplication *application() const; + virtual Application *application() const; // Controls how many items (which are views from a model-view perspective) are currently rendering this window void registerItem(WindowItem *item); @@ -125,7 +125,7 @@ signals: void _windowDestroyed(); protected: - QPointer<AbstractApplication> m_application; + QPointer<Application> m_application; QSet<WindowItem*> m_items; WindowItem *m_primaryItem{nullptr}; diff --git a/src/window-lib/windowitem.cpp b/src/window-lib/windowitem.cpp index 5a00bceb..7fb17f69 100644 --- a/src/window-lib/windowitem.cpp +++ b/src/window-lib/windowitem.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/window-lib/windowitem.h b/src/window-lib/windowitem.h index 45bf9c71..4bc4b39b 100644 --- a/src/window-lib/windowitem.h +++ b/src/window-lib/windowitem.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/src/window-lib/windowmanager.cpp b/src/window-lib/windowmanager.cpp index ea9a3027..63d93e8d 100644 --- a/src/window-lib/windowmanager.cpp +++ b/src/window-lib/windowmanager.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -334,7 +334,7 @@ void WindowManager::setSlowAnimations(bool slowAnimations) RuntimeFactory::instance()->setSlowAnimations(d->slowAnimations); // Update already running applications - for (AbstractApplication *application : ApplicationManager::instance()->applications()) { + for (Application *application : ApplicationManager::instance()->applications()) { auto runtime = application->currentRuntime(); if (runtime) runtime->setSlowAnimations(d->slowAnimations); @@ -475,12 +475,53 @@ QVariantMap WindowManager::get(int index) const } /*! + \qmlmethod WindowObject WindowManager::window(int index) + + Returns the \l{WindowObject}{window} corresponding to the given \a index in the + model, or \c null if the index is invalid. + + \note The object ownership of the returned Window object stays with the application-manager. + If you want to store this pointer, you can use the WindowManager's QAbstractListModel + signals or the windowAboutToBeRemoved signal to get notified if the object is about + to be deleted on the C++ side. +*/ +Window *WindowManager::window(int index) const +{ + if (index < 0 || index >= count()) { + qCWarning(LogSystem) << "WindowManager::window(index): invalid index:" << index; + return nullptr; + } + return d->windowsInModel.at(index); +} + +/*! + \qmlmethod list<WindowObject> WindowManager::windowsOfApplication(string applicationId) + + Returns a list of \l{WindowObject}{windows} belonging to the given \a applicationId in the + model, or an empty list if the applicationId is invalid. + + \note The object ownership of the returned Window objects stays with the application-manager. + If you want to store these pointers, you can use the WindowManager's QAbstractListModel + signals or the windowAboutToBeRemoved signal to get notified if the objects are about + to be deleted on the C++ side. +*/ +QList<QObject *> WindowManager::windowsOfApplication(const QString &id) const +{ + QList<QObject *> result; + for (Window *window : d->windowsInModel) { + if (window->application() && window->application()->id() == id) + result << window; + } + return result; +} + +/*! \qmlmethod int WindowManager::indexOfWindow(WindowObject window) Returns the index of the \a window within the WindowManager model, or \c -1 if the window item is not a managed window. */ -int WindowManager::indexOfWindow(Window *window) +int WindowManager::indexOfWindow(Window *window) const { return d->windowsInModel.indexOf(window); } @@ -654,7 +695,7 @@ void WindowManager::inProcessSurfaceItemCreated(QSharedPointer<InProcessSurfaceI qCCritical(LogSystem) << "This function must be called by a signal of Runtime!"; return; } - AbstractApplication *app = rt->application() ? rt->application()->nonAliased() : nullptr; + Application *app = rt->application() ? rt->application()->nonAliased() : nullptr; if (!app) { qCCritical(LogSystem) << "This function must be called by a signal of Runtime which actually has an application attached!"; return; @@ -730,7 +771,7 @@ void WindowManager::waylandSurfaceCreated(QWaylandSurface *surface) void WindowManager::waylandSurfaceMapped(WindowSurface *surface) { qint64 processId = surface->processId(); - AbstractApplication *app = ApplicationManager::instance()->fromProcessId(processId); + Application *app = ApplicationManager::instance()->fromProcessId(processId); if (!app && ApplicationManager::instance()->securityChecksEnabled()) { qCCritical(LogGraphics) << "SECURITY ALERT: an unknown application with pid" << processId @@ -888,8 +929,8 @@ bool WindowManager::makeScreenshot(const QString &filename, const QString &selec // app without System-UI // filter out alias and apps not matching appId (if set) - QVector<AbstractApplication *> apps = ApplicationManager::instance()->applications(); - auto it = std::remove_if(apps.begin(), apps.end(), [appId](AbstractApplication *app) { + QVector<Application *> apps = ApplicationManager::instance()->applications(); + auto it = std::remove_if(apps.begin(), apps.end(), [appId](Application *app) { return app->isAlias() || (!appId.isEmpty() && (appId != app->id())); }); apps.erase(it, apps.end()); @@ -975,7 +1016,7 @@ int WindowManagerPrivate::findWindowByWaylandSurface(QWaylandSurface *waylandSur return -1; } -QString WindowManagerPrivate::applicationId(AbstractApplication *app, WindowSurface *windowSurface) +QString WindowManagerPrivate::applicationId(Application *app, WindowSurface *windowSurface) { if (app) return app->id(); diff --git a/src/window-lib/windowmanager.h b/src/window-lib/windowmanager.h index 194865fe..6e6d5982 100644 --- a/src/window-lib/windowmanager.h +++ b/src/window-lib/windowmanager.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -98,8 +98,9 @@ public: Q_INVOKABLE int count() const; Q_INVOKABLE QVariantMap get(int index) const; - - Q_INVOKABLE int indexOfWindow(Window *window); + Q_INVOKABLE Window *window(int index) const; + Q_INVOKABLE QList<QObject *> windowsOfApplication(const QString &id) const; + Q_INVOKABLE int indexOfWindow(Window *window) const; Q_INVOKABLE QObject *addExtension(QQmlComponent *component) const; bool eventFilter(QObject *watched, QEvent *event) override; @@ -129,8 +130,6 @@ private slots: public: Q_SCRIPTABLE bool makeScreenshot(const QString &filename, const QString &selector); - bool setDBusPolicy(const QVariantMap &yamlFragment); - QList<QQuickWindow *> compositorViews() const; // evil hook to support in-process runtimes diff --git a/src/window-lib/windowmanager_p.h b/src/window-lib/windowmanager_p.h index 7195f541..f692e765 100644 --- a/src/window-lib/windowmanager_p.h +++ b/src/window-lib/windowmanager_p.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -62,7 +62,7 @@ public: WaylandCompositor *waylandCompositor = nullptr; - static QString applicationId(AbstractApplication *app, WindowSurface *windowSurface); + static QString applicationId(Application *app, WindowSurface *windowSurface); #endif QHash<int, QByteArray> roleNames; diff --git a/template-opt/am/config-windows.yaml b/template-opt/am/config-windows.yaml index 0f1325b7..6c160fca 100644 --- a/template-opt/am/config-windows.yaml +++ b/template-opt/am/config-windows.yaml @@ -4,15 +4,6 @@ formatType: am-configuration # installations will go into the standard /opt/am hierarchy applications: - installedAppsManifestDir: "c:/cygwin/opt/am/manifests" - appImageMountDir: "c:/cygwin/opt/am/image-mounts" + installationDir: "c:/cygwin/opt/am/apps" + documentDir: "c:/cygwin/opt/am/docs" database: "c:/cygwin/opt/am/apps.db" - -# simulate an internal and a SD-card installation location - -installationLocations: -- id: "internal-0" - installationPath: "c:/cygwin/opt/am/apps" - documentPath: "c:/cygwin/opt/am/docs" - mountPoint: "c:/cygwin/opt" - isDefault: true diff --git a/template-opt/am/config.yaml b/template-opt/am/config.yaml index 94fc9bcb..38ce6195 100644 --- a/template-opt/am/config.yaml +++ b/template-opt/am/config.yaml @@ -4,20 +4,6 @@ formatType: am-configuration # installations will go into the standard /opt/am hierarchy applications: - installedAppsManifestDir: "/opt/am/manifests" - appImageMountDir: "/opt/am/image-mounts" + installationDir: "/opt/am/apps" + documentDir: "/opt/am/docs" database: "/opt/am/apps.db" - -# simulate an internal and a SD-card installation location - -installationLocations: -- id: "internal-0" - installationPath: "/opt/am/apps" - documentPath: "/opt/am/docs" - mountPoint: "/opt" - isDefault: true - -- id: "removable-0" - installationPath: "/media/sdcard/apps" - documentPath: "/media/sdcard/docs" - mountPoint: "/media/sdcard" diff --git a/tests/application/tst_application.cpp b/tests/application/tst_application.cpp index 8dbe29af..bbfaa6cb 100644 --- a/tests/application/tst_application.cpp +++ b/tests/application/tst_application.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage @@ -33,6 +33,8 @@ #include "global.h" #include "application.h" #include "applicationinfo.h" +#include "packageinfo.h" +#include "package.h" #include "abstractruntime.h" QT_USE_NAMESPACE_AM @@ -48,19 +50,19 @@ public: void setSlowAnimations(bool) override {} - qint64 applicationProcessId() const + qint64 applicationProcessId() const override { return m_state == Am::Running ? 1 : 0; } public slots: - bool start() + bool start() override { m_state = Am::Running; return true; } - void stop(bool forceKill) + void stop(bool forceKill) override { Q_UNUSED(forceKill); m_state = Am::NotRunning; @@ -104,7 +106,10 @@ private slots: // the application no longer holds a reference to it void tst_Application::runtimeDestroyed() { - auto app = new Application(new ApplicationInfo); + auto pi = new PackageInfo; + auto pkg = new Package(pi); + auto ai = new ApplicationInfo(pi); + auto app = new Application(ai, pkg); auto runtimeManager = new TestRuntimeManager(qSL("foo"), qApp); auto runtime = runtimeManager->create(nullptr, app); diff --git a/tests/applicationinfo/tst_applicationinfo.cpp b/tests/applicationinfo/tst_applicationinfo.cpp index 92f1fe3a..f9739dac 100644 --- a/tests/applicationinfo/tst_applicationinfo.cpp +++ b/tests/applicationinfo/tst_applicationinfo.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage @@ -33,8 +33,8 @@ #include "global.h" #include "application.h" #include "applicationinfo.h" -#include "applicationdatabase.h" -#include "yamlapplicationscanner.h" +#include "packageinfo.h" +#include "yamlpackagescanner.h" #include "exception.h" QT_USE_NAMESPACE_AM @@ -49,7 +49,6 @@ public: private slots: void initTestCase(); void cleanupTestCase(); - void database(); void application_data(); void application(); void validApplicationId_data(); @@ -58,7 +57,7 @@ private slots: void validIcon(); private: - QVector<AbstractApplicationInfo *> apps; + QVector<PackageInfo *> m_pkgs; }; tst_ApplicationInfo::tst_ApplicationInfo() @@ -67,100 +66,29 @@ tst_ApplicationInfo::tst_ApplicationInfo() void tst_ApplicationInfo::initTestCase() { - YamlApplicationScanner scanner; + YamlPackageScanner scanner; QDir baseDir(qL1S(AM_TESTDATA_DIR "manifests")); - const QStringList appDirNames = baseDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks); - for (const QString &appDirName : appDirNames) { - QDir dir = baseDir.absoluteFilePath(appDirName); + const QStringList pkgDirNames = baseDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks); + for (const QString &pkgDirName : pkgDirNames) { + QDir dir = baseDir.absoluteFilePath(pkgDirName); try { - ApplicationInfo *a = scanner.scan(dir.absoluteFilePath(qSL("info.yaml"))); - QVERIFY(a); - QCOMPARE(appDirName, a->id()); - apps << a; + PackageInfo *pi = scanner.scan(dir.absoluteFilePath(qSL("info.yaml"))); + QVERIFY(pi); + QCOMPARE(pkgDirName, pi->id()); + m_pkgs << pi; } catch (const std::exception &e) { QFAIL(e.what()); } } - QCOMPARE(apps.size(), 2); + QCOMPARE(m_pkgs.size(), 2); } void tst_ApplicationInfo::cleanupTestCase() { - qDeleteAll(apps); + qDeleteAll(m_pkgs); } -void tst_ApplicationInfo::database() -{ - QString tmpDbPath = QDir::temp().absoluteFilePath(qSL("autotest-appdb-%1").arg(qApp->applicationPid())); - - QFile::remove(tmpDbPath); - QVERIFY(!QFile::exists(tmpDbPath)); - - { - ApplicationDatabase adb(QDir::tempPath()); - QVERIFY(!adb.isValid()); - } - - { - ApplicationDatabase adb(tmpDbPath); - QVERIFY(adb.isValid()); - - try { - QVector<AbstractApplication *> appsInDb = adb.read(); - QVERIFY(appsInDb.isEmpty()); - - adb.write(apps); - qDeleteAll(appsInDb); - } catch (const Exception &e) { - QVERIFY2(false, e.what()); - } - } - - QVERIFY(QFileInfo(tmpDbPath).size() > 0); - - { - ApplicationDatabase adb(tmpDbPath); - QVERIFY(adb.isValid()); - - try { - QVector<AbstractApplication *> appsInDb = adb.read(); - QCOMPARE(appsInDb.size(), apps.size()); - qDeleteAll(appsInDb); - } catch (Exception &e) { - QVERIFY2(false, e.what()); - } - } - - { -#if defined(Q_OS_WIN) - QString nullDb(qSL("\\\\.\\NUL")); -#else - QString nullDb(qSL("/dev/zero")); -#endif - - ApplicationDatabase adb(nullDb); - QVERIFY2(adb.isValid(), qPrintable(adb.errorString())); - - try { - adb.write(apps); - QVERIFY(false); - } catch (const Exception &) { - } - } - - /*{ - ApplicationDatabase adb("/proc/self/sched"); - QVERIFY(adb.isValid()); - - try { - // adb.write(apps); - // QVERIFY(false); - } catch (Exception &) { - } - }*/ - -} void tst_ApplicationInfo::application_data() { QTest::addColumn<QString>("id"); @@ -175,87 +103,79 @@ void tst_ApplicationInfo::application() QString name = QString::fromLatin1(AM_TESTDATA_DIR "manifests/%1/info.yaml").arg(id); - YamlApplicationScanner scanner; - ApplicationInfo *app; + YamlPackageScanner scanner; + PackageInfo *pkg; try { - app = scanner.scan(name); - QVERIFY(app); + pkg = scanner.scan(name); + QVERIFY(pkg); } catch (const std::exception &e) { QFAIL(e.what()); } - QCOMPARE(app->id(), id); - QCOMPARE(QFileInfo(app->icon()).fileName(), qSL("icon.png")); - QCOMPARE(app->names().size(), 2); - QCOMPARE(app->names().value(qSL("en")), qSL("english")); - QCOMPARE(app->names().value(qSL("de")), qSL("deutsch")); - QCOMPARE(app->name(qSL("en")), qSL("english")); + QCOMPARE(pkg->id(), id); + QCOMPARE(QFileInfo(pkg->icon()).fileName(), qSL("icon.png")); + QCOMPARE(pkg->names().size(), 2); + QCOMPARE(pkg->names().value(qSL("en")), qSL("english")); + QCOMPARE(pkg->names().value(qSL("de")), qSL("deutsch")); + QCOMPARE(pkg->name(qSL("en")), qSL("english")); + QCOMPARE(pkg->isBuiltIn(), false); + QCOMPARE(pkg->categories().size(), 2); + QVERIFY(pkg->categories().startsWith(qSL("bar"))); + QVERIFY(pkg->categories().endsWith(qSL("foo"))); + + ApplicationInfo *app = pkg->applications().size() == 1 ? pkg->applications().first() : nullptr; + QVERIFY(app); QCOMPARE(QFileInfo(app->codeFilePath()).fileName(), qSL("Test.qml")); QCOMPARE(app->runtimeName(), qSL("qml")); QCOMPARE(app->runtimeParameters().size(), 1); QCOMPARE(app->runtimeParameters().value(qSL("loadDummyData")).toBool(), true); - QCOMPARE(app->isBuiltIn(), false); - QCOMPARE(app->supportedMimeTypes().size(), 2); - QVERIFY(app->supportedMimeTypes().startsWith(qSL("text/plain"))); - QVERIFY(app->supportedMimeTypes().endsWith(qSL("x-scheme-handler/mailto"))); QCOMPARE(app->capabilities().size(), 2); QVERIFY(app->capabilities().startsWith(qSL("cameraAccess"))); QVERIFY(app->capabilities().endsWith(qSL("locationAccess"))); - QCOMPARE(app->categories().size(), 2); - QVERIFY(app->categories().startsWith(qSL("bar"))); - QVERIFY(app->categories().endsWith(qSL("foo"))); - delete app; + // legacy + QCOMPARE(app->supportedMimeTypes().size(), 2); + QVERIFY(app->supportedMimeTypes().startsWith(qSL("text/plain"))); + QVERIFY(app->supportedMimeTypes().endsWith(qSL("x-scheme-handler/mailto"))); + + delete pkg; } void tst_ApplicationInfo::validApplicationId_data() { QTest::addColumn<QString>("appId"); - QTest::addColumn<bool>("isAlias"); QTest::addColumn<bool>("valid"); // passes - QTest::newRow("normal") << "Test" << false << true; - QTest::newRow("shortest") << "t" << false << true; - QTest::newRow("valid-chars") << "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ,.';[]{}!#$%^&()-_=+" << false << true; - QTest::newRow("longest-name") << "com.012345678901234567890123456789012345678901234567890123456789012.012345678901234567890123456789012345678901234567890123456789012.0123456789012.test" << false << true; - QTest::newRow("alias-normal") << "Test@alias" << true << true; - QTest::newRow("alias-shortest") << "t@a" << true << true; - QTest::newRow("alias-valid-chars") << "1-2@1-a" << true << true; - QTest::newRow("alias-longest-part") << "com.012345678901234567890123456789012345678901234567890123456789012.test@012345678901234567890123456789012345678901234567890123456789012" << true << true; - QTest::newRow("alias-longest-name") << "com.012345678901234567890123456789012345678901234567890123456789012.012345678901234567890123456789012345678901234567890123456789012.0123456789012@test" << true << true; - QTest::newRow("alias-max-part-cnt") << "a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.0.1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.g.h.i.j.k.l.m.n.o.p.q.r.s.t.u.v.w.x.y.z.0.1.2.3.4.5.6.7.8.9.a.0@12" << true << true; + QTest::newRow("normal") << "Test" << true; + QTest::newRow("shortest") << "t" << true; + QTest::newRow("valid-chars") << "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 ,.';[]{}!#$%^&()-_=+@" << true; + QTest::newRow("longest-name") << "com.012345678901234567890123456789012345678901234567890123456789012.012345678901234567890123456789012345678901234567890123456789012.0123456789012.test" << true; // failures - QTest::newRow("empty") << "" << false << false; - QTest::newRow("space-only") << " " << false << false; - QTest::newRow("space-only2") << " " << false << false; - QTest::newRow("name-too-long") << "com.012345678901234567890123456789012345678901234567890123456789012.012345678901234567890123456789012345678901234567890123456789012.0123456789012.xtest" << false << false; - QTest::newRow("empty-alias") << "test@" << true << false; - QTest::newRow("invalid-char@") << "t@" << false << false; - QTest::newRow("invalid-char<") << "t<" << false << false; - QTest::newRow("invalid-char>") << "t>" << false << false; - QTest::newRow("invalid-char:") << "t:" << false << false; - QTest::newRow("invalid-char-quote") << "t\"" << false << false; - QTest::newRow("invalid-char/") << "t/" << false << false; - QTest::newRow("invalid-char\\") << "t\\" << false << false; - QTest::newRow("invalid-char|") << "t|" << false << false; - QTest::newRow("invalid-char?") << "t?" << false << false; - QTest::newRow("invalid-char*") << "t*" << false << false; - QTest::newRow("control-char") << "t\t" << false << false; - QTest::newRow("unicode-char") << QString::fromUtf8("c.p.t@c\xc3\xb6m") << true << false; - QTest::newRow("no-alias") << "t" << true << false; - QTest::newRow("alias-name-too-long") << "com.012345678901234567890123456789012345678901234567890123456789012.012345678901234567890123456789012345678901234567890123456789012.0123456789012@xtest" << true << false; + QTest::newRow("empty") << "" << false; + QTest::newRow("space-only") << " " << false; + QTest::newRow("space-only2") << " " << false; + QTest::newRow("name-too-long") << "com.012345678901234567890123456789012345678901234567890123456789012.012345678901234567890123456789012345678901234567890123456789012.0123456789012.xtest" << false; + QTest::newRow("invalid-char<") << "t<" << false; + QTest::newRow("invalid-char>") << "t>" << false; + QTest::newRow("invalid-char:") << "t:" << false; + QTest::newRow("invalid-char-quote") << "t\"" << false; + QTest::newRow("invalid-char/") << "t/" << false; + QTest::newRow("invalid-char\\") << "t\\" << false; + QTest::newRow("invalid-char|") << "t|" << false; + QTest::newRow("invalid-char?") << "t?" << false; + QTest::newRow("invalid-char*") << "t*" << false; + QTest::newRow("control-char") << "t\t" << false; } void tst_ApplicationInfo::validApplicationId() { QFETCH(QString, appId); - QFETCH(bool, isAlias); QFETCH(bool, valid); QString errorString; - bool result = AbstractApplicationInfo::isValidApplicationId(appId, isAlias, &errorString); + bool result = PackageInfo::isValidApplicationId(appId, &errorString); QVERIFY2(valid == result, qPrintable(errorString)); } @@ -284,7 +204,7 @@ void tst_ApplicationInfo::validIcon() QFETCH(bool, isValid); QString errorString; - bool result = AbstractApplicationInfo::isValidIcon(icon, errorString); + bool result = PackageInfo::isValidIcon(icon, &errorString); QCOMPARE(result, isValid); } diff --git a/tests/applicationinstaller/applicationinstaller.pro b/tests/applicationinstaller/applicationinstaller.pro index 37532e10..b84ffac4 100644 --- a/tests/applicationinstaller/applicationinstaller.pro +++ b/tests/applicationinstaller/applicationinstaller.pro @@ -9,6 +9,5 @@ QT *= \ appman_application-private \ appman_package-private \ appman_manager-private \ - appman_installer-private SOURCES += tst_applicationinstaller.cpp diff --git a/tests/applicationinstaller/tst_applicationinstaller.cpp b/tests/applicationinstaller/tst_applicationinstaller.cpp index c187a088..1a68d357 100644 --- a/tests/applicationinstaller/tst_applicationinstaller.cpp +++ b/tests/applicationinstaller/tst_applicationinstaller.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage @@ -32,16 +32,17 @@ #include <functional> -#include "applicationinstaller.h" +#include "packagemanager.h" +#include "packagedatabase.h" #include "applicationmanager.h" #include "application.h" #include "sudo.h" #include "utilities.h" #include "error.h" -#include "private/package_p.h" +#include "private/packageutilities_p.h" #include "runtimefactory.h" #include "qmlinprocessruntime.h" -#include "package.h" +#include "packageutilities.h" #include "../error-checking.h" @@ -63,41 +64,41 @@ public: }; AllowInstallations(Type t) - : m_oldUnsigned(ApplicationInstaller::instance()->allowInstallationOfUnsignedPackages()) - , m_oldDevMode(ApplicationInstaller::instance()->developmentMode()) + : m_oldUnsigned(PackageManager::instance()->allowInstallationOfUnsignedPackages()) + , m_oldDevMode(PackageManager::instance()->developmentMode()) { switch (t) { case AllowUnsinged: - ApplicationInstaller::instance()->setAllowInstallationOfUnsignedPackages(true); - ApplicationInstaller::instance()->setDevelopmentMode(false); + PackageManager::instance()->setAllowInstallationOfUnsignedPackages(true); + PackageManager::instance()->setDevelopmentMode(false); break; case RequireDevSigned: - ApplicationInstaller::instance()->setAllowInstallationOfUnsignedPackages(false); - ApplicationInstaller::instance()->setDevelopmentMode(true); + PackageManager::instance()->setAllowInstallationOfUnsignedPackages(false); + PackageManager::instance()->setDevelopmentMode(true); break; case RequireStoreSigned: - ApplicationInstaller::instance()->setAllowInstallationOfUnsignedPackages(false); - ApplicationInstaller::instance()->setDevelopmentMode(false); + PackageManager::instance()->setAllowInstallationOfUnsignedPackages(false); + PackageManager::instance()->setDevelopmentMode(false); break; } } ~AllowInstallations() { - ApplicationInstaller::instance()->setAllowInstallationOfUnsignedPackages(m_oldUnsigned); - ApplicationInstaller::instance()->setDevelopmentMode(m_oldDevMode); + PackageManager::instance()->setAllowInstallationOfUnsignedPackages(m_oldUnsigned); + PackageManager::instance()->setDevelopmentMode(m_oldDevMode); } private: bool m_oldUnsigned; bool m_oldDevMode; }; -class tst_ApplicationInstaller : public QObject +class tst_PackageManager : public QObject { Q_OBJECT public: - tst_ApplicationInstaller(QObject *parent = nullptr); - ~tst_ApplicationInstaller(); + tst_PackageManager(QObject *parent = nullptr); + ~tst_PackageManager(); private slots: void initTestCase(); @@ -108,8 +109,6 @@ private slots: //TODO: test AI::cleanupBrokenInstallations() before calling cleanup() the first time! - void installationLocations(); - void packageInstallation_data(); void packageInstallation(); @@ -129,11 +128,8 @@ private slots: public: enum PathLocation { - Manifests = 0, Internal0, Documents0, - Internal1, - Documents1, PathLocationCount }; @@ -148,11 +144,8 @@ private: { QString base; switch (pathLocation) { - case Manifests: base = "manifests"; break; - case Internal0: base = "internal-0"; break; - case Documents0: base = "documents-0"; break; - case Internal1: base = "internal-1"; break; - case Documents1: base = "documents-1"; break; + case Internal0: base = qSL("internal"); break; + case Documents0: base = qSL("documents"); break; default: break; } @@ -194,8 +187,7 @@ private: QTemporaryDir m_workDir; QString m_hardwareId; - QVector<InstallationLocation> m_installationLocations; - ApplicationInstaller *m_ai = nullptr; + PackageManager *m_pm = nullptr; QSignalSpy *m_startedSpy = nullptr; QSignalSpy *m_requestingInstallationAcknowledgeSpy = nullptr; QSignalSpy *m_blockingUntilInstallationAcknowledgeSpy = nullptr; @@ -205,11 +197,11 @@ private: }; -tst_ApplicationInstaller::tst_ApplicationInstaller(QObject *parent) +tst_PackageManager::tst_PackageManager(QObject *parent) : QObject(parent) { } -tst_ApplicationInstaller::~tst_ApplicationInstaller() +tst_PackageManager::~tst_PackageManager() { if (m_workDir.isValid()) { if (m_sudo) @@ -225,79 +217,71 @@ tst_ApplicationInstaller::~tst_ApplicationInstaller() delete m_requestingInstallationAcknowledgeSpy; delete m_startedSpy; - delete m_ai; + delete m_pm; } -void tst_ApplicationInstaller::initTestCase() +void tst_PackageManager::initTestCase() { if (!QDir(qL1S(AM_TESTDATA_DIR "/packages")).exists()) QSKIP("No test packages available in the data/ directory"); bool verbose = qEnvironmentVariableIsSet("VERBOSE_TEST"); if (!verbose) - QLoggingCategory::setFilterRules("am.installer.debug=false"); + QLoggingCategory::setFilterRules(qSL("am.installer.debug=false")); qInfo() << "Verbose mode is" << (verbose ? "on" : "off") << "(changed by (un)setting $VERBOSE_TEST)"; spyTimeout *= timeoutFactor(); - QVERIFY(Package::checkCorrectLocale()); + QVERIFY(PackageUtilities::checkCorrectLocale()); QVERIFY2(startedSudoServer, qPrintable(sudoServerError)); m_sudo = SudoClient::instance(); QVERIFY(m_sudo); m_fakeSudo = m_sudo->isFallbackImplementation(); - // we need a (dummy) ApplicationManager for the installer, since the installer will - // notify the manager during installations - QVERIFY(ApplicationManager::createInstance(true)); - // create a temporary dir (plus sub-dirs) for everything created by this test run - QVERIFY(m_workDir.isValid()); // make sure we have a valid hardware-id - m_hardwareId = "foobar"; + m_hardwareId = qSL("foobar"); for (int i = 0; i < PathLocationCount; ++i) QVERIFY(QDir().mkdir(pathTo(PathLocation(i)))); - // define some installation locations for testing - - QVariantList iloc = QVariantList { - QVariantMap { - { "isDefault", true }, - { "id", "internal-0" }, - { "installationPath", pathTo(Internal0) }, - { "documentPath", pathTo(Documents0) } - }, - QVariantMap { - { "id", "internal-1" }, - { "installationPath", pathTo(Internal1) }, - { "documentPath", pathTo(Documents1) }, - } - }; - - m_installationLocations = InstallationLocation::parseInstallationLocations(iloc, m_hardwareId); - - QCOMPARE(m_installationLocations.size(), 2); - - // finally, instantiate the ApplicationInstaller and a bunch of signal-spies for its signals - - QString installerError; - m_ai = ApplicationInstaller::createInstance(m_installationLocations, pathTo(Manifests), m_hardwareId, &installerError); - QVERIFY2(m_ai, qPrintable(installerError)); + // finally, instantiate the PackageManager and a bunch of signal-spies for its signals + try { + PackageDatabase *pdb = new PackageDatabase(QStringList(), pathTo(Internal0)); + m_pm = PackageManager::createInstance(pdb, pathTo(Documents0)); + m_pm->setHardwareId(m_hardwareId); + } catch (const Exception &e) { + QVERIFY2(false, e.what()); + } - m_startedSpy = new QSignalSpy(m_ai, &ApplicationInstaller::taskStarted); - m_requestingInstallationAcknowledgeSpy = new QSignalSpy(m_ai, &ApplicationInstaller::taskRequestingInstallationAcknowledge); - m_blockingUntilInstallationAcknowledgeSpy = new QSignalSpy(m_ai, &ApplicationInstaller::taskBlockingUntilInstallationAcknowledge); - m_progressSpy = new QSignalSpy(m_ai, &ApplicationInstaller::taskProgressChanged); - m_finishedSpy = new QSignalSpy(m_ai, &ApplicationInstaller::taskFinished); - m_failedSpy = new QSignalSpy(m_ai, &ApplicationInstaller::taskFailed); + const QVariantMap iloc = m_pm->installationLocation(); + QCOMPARE(iloc.size(), 3); + QCOMPARE(iloc.value(qSL("path")).toString(), pathTo(Internal0)); + QVERIFY(iloc.value(qSL("deviceSize")).toLongLong() > 0); + QVERIFY(iloc.value(qSL("deviceFree")).toLongLong() > 0); + QVERIFY(iloc.value(qSL("deviceFree")).toLongLong() < iloc.value(qSL("deviceSize")).toLongLong()); + + const QVariantMap dloc = m_pm->documentLocation(); + QCOMPARE(dloc.size(), 3); + QCOMPARE(dloc.value(qSL("path")).toString(), pathTo(Documents0)); + QVERIFY(dloc.value(qSL("deviceSize")).toLongLong() > 0); + QVERIFY(dloc.value(qSL("deviceFree")).toLongLong() > 0); + QVERIFY(dloc.value(qSL("deviceFree")).toLongLong() < dloc.value(qSL("deviceSize")).toLongLong()); + + m_startedSpy = new QSignalSpy(m_pm, &PackageManager::taskStarted); + m_requestingInstallationAcknowledgeSpy = new QSignalSpy(m_pm, &PackageManager::taskRequestingInstallationAcknowledge); + m_blockingUntilInstallationAcknowledgeSpy = new QSignalSpy(m_pm, &PackageManager::taskBlockingUntilInstallationAcknowledge); + m_progressSpy = new QSignalSpy(m_pm, &PackageManager::taskProgressChanged); + m_finishedSpy = new QSignalSpy(m_pm, &PackageManager::taskFinished); + m_failedSpy = new QSignalSpy(m_pm, &PackageManager::taskFailed); // crypto stuff - we need to load the root CA and developer CA certificates - QFile devcaFile(AM_TESTDATA_DIR "certificates/devca.crt"); - QFile storecaFile(AM_TESTDATA_DIR "certificates/store.crt"); - QFile caFile(AM_TESTDATA_DIR "certificates/ca.crt"); + QFile devcaFile(qL1S(AM_TESTDATA_DIR "certificates/devca.crt")); + QFile storecaFile(qL1S(AM_TESTDATA_DIR "certificates/store.crt")); + QFile caFile(qL1S(AM_TESTDATA_DIR "certificates/ca.crt")); QVERIFY2(devcaFile.open(QIODevice::ReadOnly), qPrintable(devcaFile.errorString())); QVERIFY2(storecaFile.open(QIODevice::ReadOnly), qPrintable(storecaFile.errorString())); QVERIFY2(caFile.open(QIODevice::ReadOnly), qPrintable(caFile.errorString())); @@ -306,24 +290,24 @@ void tst_ApplicationInstaller::initTestCase() chainOfTrust << devcaFile.readAll() << caFile.readAll(); QVERIFY(!chainOfTrust.at(0).isEmpty()); QVERIFY(!chainOfTrust.at(1).isEmpty()); - m_ai->setCACertificates(chainOfTrust); + m_pm->setCACertificates(chainOfTrust); // we do not require valid store signatures for this test run - m_ai->setDevelopmentMode(true); + m_pm->setDevelopmentMode(true); // make sure we have a valid runtime available. The important part is // that we have a runtime called "native" - the functionality does not matter. RuntimeFactory::instance()->registerRuntime(new QmlInProcessRuntimeManager(qSL("native"))); } -void tst_ApplicationInstaller::cleanupTestCase() +void tst_PackageManager::cleanupTestCase() { - // the real cleanup happens in ~tst_ApplicationInstaller, since we also need + // the real cleanup happens in ~tst_PackageManager, since we also need // to call this cleanup from the crash handler } -void tst_ApplicationInstaller::init() +void tst_PackageManager::init() { // start with a fresh App1 dir on each test run @@ -331,13 +315,13 @@ void tst_ApplicationInstaller::init() QVERIFY(QDir().mkdir(pathTo(Internal0))); } -void tst_ApplicationInstaller::cleanup() +void tst_PackageManager::cleanup() { // this helps with reducing the amount of cleanup work required // at the end of each test try { - m_ai->cleanupBrokenInstallations(); + m_pm->cleanupBrokenInstallations(); } catch (const Exception &e) { QFAIL(e.what()); } @@ -346,47 +330,10 @@ void tst_ApplicationInstaller::cleanup() recursiveOperation(pathTo(Internal0), safeRemove); } -void tst_ApplicationInstaller::installationLocations() -{ - QVERIFY(!InstallationLocation().isValid()); - - const QVector<InstallationLocation> loclist = m_ai->installationLocations(); - - QCOMPARE(loclist.size(), m_installationLocations.size()); - for (const InstallationLocation &loc : loclist) - QVERIFY(m_installationLocations.contains(loc)); - - QVector<InstallationLocation> locationList = InstallationLocation::parseInstallationLocations(QVariantList { - QVariantMap { - { "id", "internal-0" }, - { "installationPath", QDir::tempPath() }, - { "documentPath", QDir::tempPath() }, - { "isDefault", true } - }, - }, m_hardwareId); - QCOMPARE(locationList.size(), 1); - InstallationLocation &tmp = locationList.first(); - QVariantMap map = tmp.toVariantMap(); - QVERIFY(!map.isEmpty()); - - QCOMPARE(map.value("id").toString(), tmp.id()); - QCOMPARE(map.value("index").toInt(), tmp.index()); - QCOMPARE(map.value("installationPath").toString(), tmp.installationPath()); - QCOMPARE(map.value("documentPath").toString(), tmp.documentPath()); - QCOMPARE(map.value("isDefault").toBool(), tmp.isDefault()); - QVERIFY(map.value("installationDeviceSize").toLongLong() > 0); - QVERIFY(map.value("installationDeviceFree").toLongLong() > 0); - QVERIFY(map.value("documentDeviceSize").toLongLong() > 0); - QVERIFY(map.value("documentDeviceFree").toLongLong() > 0); -} - - -void tst_ApplicationInstaller::packageInstallation_data() +void tst_PackageManager::packageInstallation_data() { QTest::addColumn<QString>("packageName"); - QTest::addColumn<QString>("installationLocationId"); QTest::addColumn<QString>("updatePackageName"); - QTest::addColumn<QString>("updateInstallationLocationId"); QTest::addColumn<bool>("devSigned"); QTest::addColumn<bool>("storeSigned"); QTest::addColumn<bool>("expectedSuccess"); @@ -410,73 +357,65 @@ void tst_ApplicationInstaller::packageInstallation_data() }; QTest::newRow("normal") \ - << "test.appkg" << "internal-0" << "test-update.appkg" << "internal-0" + << "test.appkg" << "test-update.appkg" << false << false << true << true << nomd<< ""; QTest::newRow("no-dev-signed") \ - << "test.appkg" << "internal-0" << "" << "" + << "test.appkg" << "" << true << false << false << false << nomd << "cannot install unsigned packages"; QTest::newRow("dev-signed") \ - << "test-dev-signed.appkg" << "internal-0" << "test-update-dev-signed.appkg" << "internal-0" + << "test-dev-signed.appkg" << "test-update-dev-signed.appkg" << true << false << true << true << nomd << ""; QTest::newRow("no-store-signed") \ - << "test.appkg" << "internal-0" << "" << "" + << "test.appkg" << "" << false << true << false << false << nomd << "cannot install unsigned packages"; QTest::newRow("no-store-but-dev-signed") \ - << "test-dev-signed.appkg" << "internal-0" << "" << "" + << "test-dev-signed.appkg" << "" << false << true << false << false << nomd << "cannot install development packages on consumer devices"; QTest::newRow("store-signed") \ - << "test-store-signed.appkg" << "internal-0" << "" << "" + << "test-store-signed.appkg" << "" << false << true << true << false << nomd << ""; QTest::newRow("extra-metadata") \ - << "test-extra.appkg" << "internal-0" << "" << "" + << "test-extra.appkg" << "" << false << false << true << false << extramd << ""; QTest::newRow("extra-metadata-dev-signed") \ - << "test-extra-dev-signed.appkg" << "internal-0" << "" << "" + << "test-extra-dev-signed.appkg" << "" << true << false << true << false << extramd << ""; - QTest::newRow("update-to-different-location") \ - << "test.appkg" << "internal-0" << "test-update.appkg" << "internal-1" - << false << false << true << false << nomd << "the application com.pelagicore.test cannot be installed to internal-1, since it is already installed to internal-0"; - QTest::newRow("invalid-location") \ - << "test.appkg" << "internal-42" << "" << "" - << false << false << false << false << nomd << "invalid installation location"; QTest::newRow("invalid-file-order") \ - << "test-invalid-file-order.appkg" << "internal-0" << "" << "" - << false << false << false << false << nomd << "The application icon (as stated in info.yaml) must be the second file in the package. Expected 'icon.png', got 'test'"; + << "test-invalid-file-order.appkg" << "" + << false << false << false << false << nomd << "The package icon (as stated in info.yaml) must be the second file in the package. Expected 'icon.png', got 'test'"; QTest::newRow("invalid-header-format") \ - << "test-invalid-header-formatversion.appkg" << "internal-0" << "" << "" - << false << false << false << false << nomd << "metadata has an invalid format specification: wrong formatVersion header: expected 1, got 2"; + << "test-invalid-header-formatversion.appkg" << "" + << false << false << false << false << nomd << "metadata has an invalid format specification: wrong formatVersion header: expected 2, got 0"; QTest::newRow("invalid-header-diskspaceused") \ - << "test-invalid-header-diskspaceused.appkg" << "internal-0" << "" << "" + << "test-invalid-header-diskspaceused.appkg" << "" << false << false << false << false << nomd << "metadata has an invalid diskSpaceUsed field (0)"; QTest::newRow("invalid-header-id") \ - << "test-invalid-header-id.appkg" << "internal-0" << "" << "" - << false << false << false << false << nomd << "metadata has an invalid applicationId field (:invalid)"; + << "test-invalid-header-id.appkg" << "" + << false << false << false << false << nomd << "metadata has an invalid packageId field (:invalid)"; QTest::newRow("non-matching-header-id") \ - << "test-non-matching-header-id.appkg" << "internal-0" << "" << "" - << false << false << false << false << nomd << "the application identifiers in --PACKAGE-HEADER--' and info.yaml do not match"; + << "test-non-matching-header-id.appkg" << "" + << false << false << false << false << nomd << "the package identifiers in --PACKAGE-HEADER--' and info.yaml do not match"; QTest::newRow("tampered-extra-signed-header") \ - << "test-tampered-extra-signed-header.appkg" << "internal-0" << "" << "" + << "test-tampered-extra-signed-header.appkg" << "" << false << false << false << false << nomd << "~package digest mismatch.*"; QTest::newRow("invalid-info.yaml") \ - << "test-invalid-info.appkg" << "internal-0" << "" << "" + << "test-invalid-info.appkg" << "" << false << false << false << false << nomd << "~.*YAML parse error at line \\d+, column \\d+: did not find expected key"; QTest::newRow("invalid-info.yaml-id") \ - << "test-invalid-info-id.appkg" << "internal-0" << "" << "" - << false << false << false << false << nomd << "~.*the identifier \\(:invalid\\) is not a valid application-id: must consist of printable ASCII characters only, except any of .*"; + << "test-invalid-info-id.appkg" << "" + << false << false << false << false << nomd << "~.*the identifier \\(:invalid\\) is not a valid package-id: must consist of printable ASCII characters only, except any of .*"; QTest::newRow("invalid-footer-signature") \ - << "test-invalid-footer-signature.appkg" << "internal-0" << "" << "" + << "test-invalid-footer-signature.appkg" << "" << true << false << false << false << nomd << "could not verify the package's developer signature"; } // this test function is a bit of a kitchen sink, but the basic boiler plate // code of testing the results of an installation is the biggest part and it // is always the same. -void tst_ApplicationInstaller::packageInstallation() +void tst_PackageManager::packageInstallation() { QFETCH(QString, packageName); - QFETCH(QString, installationLocationId); QFETCH(QString, updatePackageName); - QFETCH(QString, updateInstallationLocationId); QFETCH(bool, devSigned); QFETCH(bool, storeSigned); QFETCH(bool, expectedSuccess); @@ -484,6 +423,9 @@ void tst_ApplicationInstaller::packageInstallation() QFETCH(QVariantMap, extraMetaData); QFETCH(QString, errorString); + QString installationDir = m_pm->installationLocation().value(qSL("path")).toString(); + QString documentDir = m_pm->documentLocation().value(qSL("path")).toString(); + AllowInstallations allow(storeSigned ? AllowInstallations::RequireStoreSigned : (devSigned ? AllowInstallations::RequireDevSigned : AllowInstallations::AllowUnsinged)); @@ -491,8 +433,6 @@ void tst_ApplicationInstaller::packageInstallation() 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) { - const InstallationLocation &il = m_ai->installationLocationFromId(pass == 1 ? installationLocationId : updateInstallationLocationId); - // this makes the results a bit ugly to look at, but it helps with debugging a lot if (pass > 1) qInfo("Pass %d", pass); @@ -500,9 +440,9 @@ void tst_ApplicationInstaller::packageInstallation() // install (or update) the package QUrl url = QUrl::fromLocalFile(AM_TESTDATA_DIR "packages/" + (pass == 1 ? packageName : updatePackageName)); - QString taskId = m_ai->startPackageInstallation(il.id(), url); + QString taskId = m_pm->startPackageInstallation(url); QVERIFY(!taskId.isEmpty()); - m_ai->acknowledgePackageInstallation(taskId); + m_pm->acknowledgePackageInstallation(taskId); // check received signals... @@ -524,16 +464,19 @@ void tst_ApplicationInstaller::packageInstallation() // check files - QVERIFY(QFile::exists(pathTo(Manifests, "com.pelagicore.test/installation-report.yaml"))); - QVERIFY(QDir(pathTo(il.documentPath() + "/com.pelagicore.test")).exists()); + //TODO: remove system((QString::fromUtf8("find ") + m_workDir.path()).toLocal8Bit().constData()); - QString fileCheckPath = il.installationPath() + "/com.pelagicore.test"; + QVERIFY(QFile::exists(installationDir + qSL("/com.pelagicore.test/.installation-report.yaml"))); + QVERIFY(QDir(documentDir + qSL("/com.pelagicore.test")).exists()); + + QString fileCheckPath = installationDir + "/com.pelagicore.test"; // now check the installed files QStringList files = QDir(fileCheckPath).entryList(QDir::AllEntries | QDir::NoDotAndDotDot); files.sort(); - QVERIFY2(files == QStringList({ "icon.png", "info.yaml", "test", QString::fromUtf8("t\xc3\xa4st") }), qPrintable(files.join(", "))); + QVERIFY2(files == QStringList({ qSL("icon.png"), qSL("info.yaml"), qSL("test"), QString::fromUtf8("t\xc3\xa4st") }), + qPrintable(files.join(qSL(", ")))); QFile f(fileCheckPath + "/test"); QVERIFY(f.open(QFile::ReadOnly)); @@ -544,28 +487,28 @@ void tst_ApplicationInstaller::packageInstallation() QCOMPARE(m_requestingInstallationAcknowledgeSpy->count(), 1); QVariantMap extra = m_requestingInstallationAcknowledgeSpy->first()[2].toMap(); QVariantMap extraSigned = m_requestingInstallationAcknowledgeSpy->first()[3].toMap(); - if (extraMetaData.value("extra").toMap() != extra) { + if (extraMetaData.value(qSL("extra")).toMap() != extra) { qDebug() << "Actual: " << extra; - qDebug() << "Expected: " << extraMetaData.value("extra").toMap(); + qDebug() << "Expected: " << extraMetaData.value(qSL("extra")).toMap(); QVERIFY(extraMetaData == extra); } - if (extraMetaData.value("extraSigned").toMap() != extraSigned) { + if (extraMetaData.value(qSL("extraSigned")).toMap() != extraSigned) { qDebug() << "Actual: " << extraSigned; - qDebug() << "Expected: " << extraMetaData.value("extraSigned").toMap(); + qDebug() << "Expected: " << extraMetaData.value(qSL("extraSigned")).toMap(); QVERIFY(extraMetaData == extraSigned); } // check if the meta-data was saved to the installation report correctly - QVERIFY2(m_ai->installedApplicationExtraMetaData("com.pelagicore.test") == extra, + QVERIFY2(m_pm->installedPackageExtraMetaData(qSL("com.pelagicore.test")) == extra, "Extra meta-data was not correctly saved to installation report"); - QVERIFY2(m_ai->installedApplicationExtraSignedMetaData("com.pelagicore.test") == extraSigned, + QVERIFY2(m_pm->installedPackageExtraSignedMetaData(qSL("com.pelagicore.test")) == extraSigned, "Extra signed meta-data was not correctly saved to installation report"); } if (pass == lastPass && expectedSuccess) { // remove package again clearSignalSpies(); - taskId = m_ai->removePackage("com.pelagicore.test", false); + taskId = m_pm->removePackage(qSL("com.pelagicore.test"), false); QVERIFY(!taskId.isEmpty()); // check signals @@ -577,9 +520,9 @@ void tst_ApplicationInstaller::packageInstallation() } // check that all files are gone - for (PathLocation pl: { Manifests, Internal0, Internal1, Documents0, Documents1 }) { - QStringList entries = QDir(pathTo(pl)).entryList({ "com.pelagicore.test*" }); - QVERIFY2(entries.isEmpty(), qPrintable(pathTo(pl) + ": " + entries.join(", "))); + for (PathLocation pl: { Internal0, Documents0 }) { + QStringList entries = QDir(pathTo(pl)).entryList({ qSL("com.pelagicore.test*") }); + QVERIFY2(entries.isEmpty(), qPrintable(pathTo(pl) + qSL(": ") + entries.join(qSL(", ")))); } } @@ -588,34 +531,27 @@ Q_DECLARE_METATYPE(std::function<bool()>) typedef QMultiMap<QString, std::function<bool()>> FunctionMap; Q_DECLARE_METATYPE(FunctionMap) -void tst_ApplicationInstaller::simulateErrorConditions_data() +void tst_PackageManager::simulateErrorConditions_data() { - QTest::addColumn<QString>("installationLocation"); QTest::addColumn<bool>("testUpdate"); QTest::addColumn<QString>("errorString"); QTest::addColumn<FunctionMap>("functions"); #ifdef Q_OS_LINUX - QTest::newRow("manifests-dir-read-only") \ - << "internal-0" << false << "~could not create manifest sub-directory .*" \ - << FunctionMap { { "before-start", [this]() { return chmod(pathTo(Manifests).toLocal8Bit(), 0000) == 0; } }, - { "after-failed", [this]() { return chmod(pathTo(Manifests).toLocal8Bit(), 0777) == 0; } } }; - QTest::newRow("applications-dir-read-only") \ - << "internal-0" << false << "~could not create installation directory .*" \ + << false << "~could not create installation directory .*" \ << FunctionMap { { "before-start", [this]() { return chmod(pathTo(Internal0).toLocal8Bit(), 0000) == 0; } }, { "after-failed", [this]() { return chmod(pathTo(Internal0).toLocal8Bit(), 0777) == 0; } } }; QTest::newRow("documents-dir-read-only") \ - << "internal-0" << false << "~could not create the document directory .*" \ + << false << "~could not create the document directory .*" \ << FunctionMap { { "before-start", [this]() { return chmod(pathTo(Documents0).toLocal8Bit(), 0000) == 0; } }, { "after-failed", [this]() { return chmod(pathTo(Documents0).toLocal8Bit(), 0777) == 0; } } }; #endif } -void tst_ApplicationInstaller::simulateErrorConditions() +void tst_PackageManager::simulateErrorConditions() { - QFETCH(QString, installationLocation); QFETCH(bool, testUpdate); QFETCH(QString, errorString); QFETCH(FunctionMap, functions); @@ -625,34 +561,34 @@ void tst_ApplicationInstaller::simulateErrorConditions() if (testUpdate) { // the check will run when updating a package, so we need to install it first - taskId = m_ai->startPackageInstallation(installationLocation, QUrl::fromLocalFile(AM_TESTDATA_DIR "packages/test-dev-signed.appkg")); + taskId = m_pm->startPackageInstallation(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/test-dev-signed.appkg"))); QVERIFY(!taskId.isEmpty()); - m_ai->acknowledgePackageInstallation(taskId); + m_pm->acknowledgePackageInstallation(taskId); QVERIFY(m_finishedSpy->wait(spyTimeout)); QCOMPARE(m_finishedSpy->first()[0].toString(), taskId); clearSignalSpies(); } - foreach (const auto &f, functions.values("before-start")) + foreach (const auto &f, functions.values(qSL("before-start"))) QVERIFY(f()); - taskId = m_ai->startPackageInstallation(installationLocation, QUrl::fromLocalFile(AM_TESTDATA_DIR "packages/test-dev-signed.appkg")); + taskId = m_pm->startPackageInstallation(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/test-dev-signed.appkg"))); - foreach (const auto &f, functions.values("after-start")) + foreach (const auto &f, functions.values(qSL("after-start"))) QVERIFY(f()); - m_ai->acknowledgePackageInstallation(taskId); + m_pm->acknowledgePackageInstallation(taskId); QVERIFY(m_failedSpy->wait(spyTimeout)); QCOMPARE(m_failedSpy->first()[0].toString(), taskId); AM_CHECK_ERRORSTRING(m_failedSpy->first()[2].toString(), errorString); clearSignalSpies(); - foreach (const auto &f, functions.values("after-failed")) + foreach (const auto &f, functions.values(qSL("after-failed"))) QVERIFY(f()); if (testUpdate) { - taskId = m_ai->removePackage("com.pelagicore.test", false); + taskId = m_pm->removePackage(qSL("com.pelagicore.test"), false); QVERIFY(m_finishedSpy->wait(spyTimeout)); QCOMPARE(m_finishedSpy->first()[0].toString(), taskId); @@ -660,7 +596,7 @@ void tst_ApplicationInstaller::simulateErrorConditions() } -void tst_ApplicationInstaller::cancelPackageInstallation_data() +void tst_PackageManager::cancelPackageInstallation_data() { QTest::addColumn<bool>("expectedResult"); @@ -672,28 +608,28 @@ void tst_ApplicationInstaller::cancelPackageInstallation_data() QTest::newRow("after-finished-signal") << false; } -void tst_ApplicationInstaller::cancelPackageInstallation() +void tst_PackageManager::cancelPackageInstallation() { QFETCH(bool, expectedResult); - QString taskId = m_ai->startPackageInstallation("internal-0", QUrl::fromLocalFile(AM_TESTDATA_DIR "packages/test-dev-signed.appkg")); + QString taskId = m_pm->startPackageInstallation(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/test-dev-signed.appkg"))); QVERIFY(!taskId.isEmpty()); if (isDataTag("before-started-signal")) { - QCOMPARE(m_ai->cancelTask(taskId), expectedResult); + QCOMPARE(m_pm->cancelTask(taskId), expectedResult); } else if (isDataTag("after-started-signal")) { QVERIFY(m_startedSpy->wait(spyTimeout)); QCOMPARE(m_startedSpy->first()[0].toString(), taskId); - QCOMPARE(m_ai->cancelTask(taskId), expectedResult); + QCOMPARE(m_pm->cancelTask(taskId), expectedResult); } else if (isDataTag("after-blocking-until-installation-acknowledge-signal")) { QVERIFY(m_blockingUntilInstallationAcknowledgeSpy->wait(spyTimeout)); QCOMPARE(m_blockingUntilInstallationAcknowledgeSpy->first()[0].toString(), taskId); - QCOMPARE(m_ai->cancelTask(taskId), expectedResult); + QCOMPARE(m_pm->cancelTask(taskId), expectedResult); } else if (isDataTag("after-finished-signal")) { - m_ai->acknowledgePackageInstallation(taskId); + m_pm->acknowledgePackageInstallation(taskId); QVERIFY(m_finishedSpy->wait(spyTimeout)); QCOMPARE(m_finishedSpy->first()[0].toString(), taskId); - QCOMPARE(m_ai->cancelTask(taskId), expectedResult); + QCOMPARE(m_pm->cancelTask(taskId), expectedResult); } if (expectedResult) { @@ -705,7 +641,7 @@ void tst_ApplicationInstaller::cancelPackageInstallation() } else { clearSignalSpies(); - taskId = m_ai->removePackage("com.pelagicore.test", false); + taskId = m_pm->removePackage(qSL("com.pelagicore.test"), false); QVERIFY(!taskId.isEmpty()); QVERIFY(m_finishedSpy->wait(spyTimeout)); QCOMPARE(m_finishedSpy->first()[0].toString(), taskId); @@ -713,46 +649,28 @@ void tst_ApplicationInstaller::cancelPackageInstallation() clearSignalSpies(); } -void tst_ApplicationInstaller::parallelPackageInstallation() +void tst_PackageManager::parallelPackageInstallation() { - QString task1Id = m_ai->startPackageInstallation("internal-0", QUrl::fromLocalFile(AM_TESTDATA_DIR "packages/test-dev-signed.appkg")); + QString task1Id = m_pm->startPackageInstallation(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/test-dev-signed.appkg"))); QVERIFY(!task1Id.isEmpty()); QVERIFY(m_blockingUntilInstallationAcknowledgeSpy->wait(spyTimeout)); QCOMPARE(m_blockingUntilInstallationAcknowledgeSpy->first()[0].toString(), task1Id); - QString task2Id = m_ai->startPackageInstallation("internal-0", QUrl::fromLocalFile(AM_TESTDATA_DIR "packages/bigtest-dev-signed.appkg")); + QString task2Id = m_pm->startPackageInstallation(QUrl::fromLocalFile(qL1S(AM_TESTDATA_DIR "packages/bigtest-dev-signed.appkg"))); QVERIFY(!task2Id.isEmpty()); - m_ai->acknowledgePackageInstallation(task2Id); + m_pm->acknowledgePackageInstallation(task2Id); QVERIFY(m_finishedSpy->wait(spyTimeout)); QCOMPARE(m_finishedSpy->first()[0].toString(), task2Id); clearSignalSpies(); - m_ai->acknowledgePackageInstallation(task1Id); + m_pm->acknowledgePackageInstallation(task1Id); QVERIFY(m_finishedSpy->wait(spyTimeout)); QCOMPARE(m_finishedSpy->first()[0].toString(), task1Id); clearSignalSpies(); } - -static tst_ApplicationInstaller *tstApplicationInstaller = nullptr; - -int main(int argc, char **argv) -{ - Package::ensureCorrectLocale(); - - try { - Sudo::forkServer(Sudo::DropPrivilegesPermanently); - startedSudoServer = true; - } catch (...) { } - - QCoreApplication a(argc, argv); - tstApplicationInstaller = new tst_ApplicationInstaller(&a); - - return QTest::qExec(tstApplicationInstaller, argc, argv); -} - -void tst_ApplicationInstaller::validateDnsName_data() +void tst_PackageManager::validateDnsName_data() { QTest::addColumn<QString>("dnsName"); QTest::addColumn<int>("minParts"); @@ -783,19 +701,19 @@ void tst_ApplicationInstaller::validateDnsName_data() QTest::newRow("part-too-long") << "com.x012345678901234567890123456789012345678901234567890123456789012.test" << 3 << false; } -void tst_ApplicationInstaller::validateDnsName() +void tst_PackageManager::validateDnsName() { QFETCH(QString, dnsName); QFETCH(int, minParts); QFETCH(bool, valid); QString errorString; - bool result = m_ai->validateDnsName(dnsName, minParts); + bool result = m_pm->validateDnsName(dnsName, minParts); QVERIFY2(valid == result, qPrintable(errorString)); } -void tst_ApplicationInstaller::compareVersions_data() +void tst_PackageManager::compareVersions_data() { QTest::addColumn<QString>("version1"); QTest::addColumn<QString>("version2"); @@ -826,19 +744,36 @@ void tst_ApplicationInstaller::compareVersions_data() QTest::newRow("21") << "12.403.51-alpha2+git" << "13.403.51-alpha2+git" << -1; } -void tst_ApplicationInstaller::compareVersions() +void tst_PackageManager::compareVersions() { QFETCH(QString, version1); QFETCH(QString, version2); QFETCH(int, result); - int cmp = m_ai->compareVersions(version1, version2); + int cmp = m_pm->compareVersions(version1, version2); QCOMPARE(cmp, result); if (result) { - cmp = m_ai->compareVersions(version2, version1); + cmp = m_pm->compareVersions(version2, version1); QCOMPARE(cmp, -result); } } +static tst_PackageManager *tstPackageManager = nullptr; + +int main(int argc, char **argv) +{ + PackageUtilities::ensureCorrectLocale(); + + try { + Sudo::forkServer(Sudo::DropPrivilegesPermanently); + startedSudoServer = true; + } catch (...) { } + + QCoreApplication a(argc, argv); + tstPackageManager = new tst_PackageManager(&a); + + return QTest::qExec(tstPackageManager, argc, argv); +} + #include "tst_applicationinstaller.moc" diff --git a/tests/cryptography/tst_cryptography.cpp b/tests/cryptography/tst_cryptography.cpp index 21f679ca..874b8eb2 100644 --- a/tests/cryptography/tst_cryptography.cpp +++ b/tests/cryptography/tst_cryptography.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage diff --git a/tests/data/certificates/create-test-certificates.sh b/tests/data/certificates/create-test-certificates.sh index 0615418e..960b736f 100755 --- a/tests/data/certificates/create-test-certificates.sh +++ b/tests/data/certificates/create-test-certificates.sh @@ -5,7 +5,7 @@ ## Copyright (C) 2018 Pelagicore AG ## Contact: https://www.qt.io/licensing/ ## -## This file is part of the Luxoft Application Manager. +## This file is part of the Qt Application Manager. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ## Commercial License Usage diff --git a/tests/data/create-test-packages.sh b/tests/data/create-test-packages.sh index 8355e462..eab20672 100755 --- a/tests/data/create-test-packages.sh +++ b/tests/data/create-test-packages.sh @@ -5,7 +5,7 @@ ## Copyright (C) 2018 Pelagicore AG ## Contact: https://www.qt.io/licensing/ ## -## This file is part of the Luxoft Application Manager. +## This file is part of the Qt Application Manager. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ## Commercial License Usage @@ -78,8 +78,10 @@ mkdir -p "$src" packager() { + set +e packagerOutput=`"$PACKAGER" "$@" 2>&1` packagerResult=$? + set -e if [ $packagerResult -ne 0 ]; then echo -e "`basename $PACKAGER`$R failed with exit code $packagerResult$W. The executed command was:" echo @@ -185,7 +187,7 @@ echo "invalid" >"$dst/test-invalid-format.appkg" info "Create a package with an invalid formatVersion header field" mv "$src"/--PACKAGE-HEADER--{,.orig} -echo '{formatType: "am-package-header", formatVersion: 2}' >$src/--PACKAGE-HEADER-- +sed <"$src/--PACKAGE-HEADER--.orig" >"$src/--PACKAGE-HEADER--" 's/formatVersion: 2/formatVersion: X/' tar -C "$src" -cf "$dst/test-invalid-header-formatversion.appkg" -- --PACKAGE-HEADER-- info.yaml icon.png test --PACKAGE-FOOTER-- mv "$src"/--PACKAGE-HEADER--{.orig,} @@ -197,13 +199,13 @@ mv "$src"/--PACKAGE-HEADER--{.orig,} info "Create a package with an invalid id header field" mv "$src"/--PACKAGE-HEADER--{,.orig} -sed <"$src/--PACKAGE-HEADER--.orig" >"$src/--PACKAGE-HEADER--" "s/applicationId: '[a-z0-9.-]*'/applicationId: ':invalid'/" +sed <"$src/--PACKAGE-HEADER--.orig" >"$src/--PACKAGE-HEADER--" "s/packageId: '[a-z0-9.-]*'/packageId: ':invalid'/" tar -C "$src" -cf "$dst/test-invalid-header-id.appkg" -- --PACKAGE-HEADER-- info.yaml icon.png test --PACKAGE-FOOTER-- mv "$src"/--PACKAGE-HEADER--{.orig,} info "Create a package with a non-matching id header field" mv "$src"/--PACKAGE-HEADER--{,.orig} -sed <"$src/--PACKAGE-HEADER--.orig" >"$src/--PACKAGE-HEADER--" "s/applicationId: '[a-z0-9.-]*'/applicationId: 'non-matching'/" +sed <"$src/--PACKAGE-HEADER--.orig" >"$src/--PACKAGE-HEADER--" "s/packageId: '[a-z0-9.-]*'/packageId: 'non-matching'/" tar -C "$src" -cf "$dst/test-non-matching-header-id.appkg" -- --PACKAGE-HEADER-- info.yaml icon.png test --PACKAGE-FOOTER-- mv "$src"/--PACKAGE-HEADER--{.orig,} diff --git a/tests/data/utilities.sh b/tests/data/utilities.sh index add548f2..9d6b8ad9 100755 --- a/tests/data/utilities.sh +++ b/tests/data/utilities.sh @@ -4,7 +4,7 @@ ## Copyright (C) 2018 Pelagicore AG ## Contact: https://www.qt.io/licensing/ ## -## This file is part of the Luxoft Application Manager. +## This file is part of the Qt Application Manager. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ## Commercial License Usage diff --git a/tests/debugwrapper/tst_debugwrapper.cpp b/tests/debugwrapper/tst_debugwrapper.cpp index bb1525ca..3d85c2be 100644 --- a/tests/debugwrapper/tst_debugwrapper.cpp +++ b/tests/debugwrapper/tst_debugwrapper.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage diff --git a/tests/error-checking.h b/tests/error-checking.h index 7b25a776..19259b3b 100644 --- a/tests/error-checking.h +++ b/tests/error-checking.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage diff --git a/tests/installationreport/tst_installationreport.cpp b/tests/installationreport/tst_installationreport.cpp index 81a25443..c2abb17b 100644 --- a/tests/installationreport/tst_installationreport.cpp +++ b/tests/installationreport/tst_installationreport.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage @@ -62,16 +62,14 @@ void tst_InstallationReport::test() ir.setDigest("##digest##"); QVERIFY(ir.isValid()); ir.addFiles(files.mid(1)); - ir.setInstallationLocationId(qSL("test-42")); ir.setDeveloperSignature("%%dev-sig%%"); ir.setStoreSignature("$$store-sig$$"); QVERIFY(ir.isValid()); - QCOMPARE(ir.applicationId(), qSL("com.pelagicore.test")); + QCOMPARE(ir.packageId(), qSL("com.pelagicore.test")); QCOMPARE(ir.files(), files); QCOMPARE(ir.diskSpaceUsed(), 42ULL); QCOMPARE(ir.digest().constData(), "##digest##"); - QCOMPARE(ir.installationLocationId(), qSL("test-42")); QCOMPARE(ir.developerSignature().constData(), "%%dev-sig%%"); QCOMPARE(ir.storeSignature().constData(), "$$store-sig$$"); @@ -85,11 +83,10 @@ void tst_InstallationReport::test() buffer.seek(0); QVERIFY(ir2.isValid()); - QCOMPARE(ir2.applicationId(), qSL("com.pelagicore.test")); + QCOMPARE(ir2.packageId(), qSL("com.pelagicore.test")); QCOMPARE(ir2.files(), files); QCOMPARE(ir2.diskSpaceUsed(), 42ULL); QCOMPARE(ir2.digest().constData(), "##digest##"); - QCOMPARE(ir2.installationLocationId(), qSL("test-42")); QCOMPARE(ir2.developerSignature().constData(), "%%dev-sig%%"); QCOMPARE(ir2.storeSignature().constData(), "$$store-sig$$"); diff --git a/tests/main/am-config.yaml b/tests/main/am-config.yaml index a7a60179..73e8bb2c 100644 --- a/tests/main/am-config.yaml +++ b/tests/main/am-config.yaml @@ -3,12 +3,9 @@ formatType: am-configuration --- applications: builtinAppsManifestDir: "${CONFIG_PWD}/builtin-apps" - installedAppsManifestDir: "/tmp/am-test-main/manifests" + installationDir: "/tmp/am-test-main/apps" + documentDir: "/tmp/am-test-main/docs" database: "/tmp/am-test-main/apps.db" -installationLocations: -- id: "internal-0" - installationPath: "/tmp/am-test-main/apps" - documentPath: "/tmp/am-test-main/docs" - mountPoint: "/tmp" - isDefault: true +ui: + mainQml: "${CONFIG_PWD}/dummy.qml" diff --git a/tests/main/dummy.qml b/tests/main/dummy.qml new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/tests/main/dummy.qml diff --git a/tests/main/main.pro b/tests/main/main.pro index af74b450..c5ede8e7 100644 --- a/tests/main/main.pro +++ b/tests/main/main.pro @@ -12,3 +12,5 @@ QT *= appman_manager-private \ appman_main-private \ SOURCES += tst_main.cpp + +RESOURCES = main.qrc diff --git a/tests/main/main.qrc b/tests/main/main.qrc new file mode 100644 index 00000000..8cae2bbb --- /dev/null +++ b/tests/main/main.qrc @@ -0,0 +1,5 @@ +<RCC> + <qresource prefix="/foo"> + <file>dummy.qml</file> + </qresource> +</RCC> diff --git a/tests/main/tst_main.cpp b/tests/main/tst_main.cpp index 7ec32116..c227b9cf 100644 --- a/tests/main/tst_main.cpp +++ b/tests/main/tst_main.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage @@ -33,7 +33,7 @@ #include <QString> #include <QStringList> -#include "applicationinstaller.h" +#include "packagemanager.h" #include "applicationmanager.h" #include "logging.h" #include "main.h" @@ -57,7 +57,8 @@ private slots: void installAndRemoveUpdateForBuiltIn(); void updateForBuiltInAlreadyInstalled(); void loadDatabaseWithUpdatedBuiltInApp(); - void nonExistentMainQmlFile(); + void mainQmlFile_data(); + void mainQmlFile(); private: void cleanUpInstallationDir(); @@ -76,13 +77,11 @@ private: tst_Main::tst_Main() { argc = 3; - argv = new char*[3]; - argv[0] = new char[255]; - sprintf(argv[0], "tst_update-builtin-app"); - argv[1] = new char[255]; - sprintf(argv[1], "--dbus"); - argv[2] = new char[255]; - sprintf(argv[2], "none"); + argv = new char*[argc + 1]; + argv[0] = qstrdup("tst_update-builtin-app"); + argv[1] = qstrdup("--dbus"); + argv[2] = qstrdup("none"); + argv[3] = nullptr; } tst_Main::~tst_Main() @@ -149,7 +148,7 @@ void tst_Main::initMain() if (m_verbose) Logging::setFilterRules(Logging::filterRules() += qSL("am.installer.debug=true")); - ApplicationInstaller::instance()->setAllowInstallationOfUnsignedPackages(true); + PackageManager::instance()->setAllowInstallationOfUnsignedPackages(true); } void tst_Main::destroyMain() @@ -172,40 +171,40 @@ void tst_Main::cleanup() void tst_Main::installPackage(const QString &pkgPath) { - auto appInstaller = ApplicationInstaller::instance(); + auto packageManager = PackageManager::instance(); bool installationFinished = false; - connect(appInstaller, &ApplicationInstaller::taskRequestingInstallationAcknowledge, - this, [this, appInstaller](const QString &taskId, const QVariantMap &, - const QVariantMap &, const QVariantMap &) { - appInstaller->acknowledgePackageInstallation(taskId); + connect(packageManager, &PackageManager::taskRequestingInstallationAcknowledge, + this, [this, packageManager](const QString &taskId, const QVariantMap &, + const QVariantMap &, const QVariantMap &) { + packageManager->acknowledgePackageInstallation(taskId); }); - connect(appInstaller, &ApplicationInstaller::taskFinished, + connect(packageManager, &PackageManager::taskFinished, this, [this, &installationFinished](const QString &) { installationFinished = true; }); - appInstaller->startPackageInstallation(qSL("internal-0"), QUrl::fromLocalFile(pkgPath)); + packageManager->startPackageInstallation(QUrl::fromLocalFile(pkgPath)); - QTRY_COMPARE(installationFinished, true); + QTRY_VERIFY(installationFinished); } void tst_Main::removePackage(const QString &id) { - auto appInstaller = ApplicationInstaller::instance(); + auto packageManager = PackageManager::instance(); bool removalFinished = false; - connect(appInstaller, &ApplicationInstaller::taskFinished, + connect(packageManager, &PackageManager::taskFinished, this, [this, &removalFinished](const QString &) { removalFinished = true; }); - appInstaller->removePackage(id, false /* keepDocuments */); + packageManager->removePackage(id, false /* keepDocuments */); - QTRY_COMPARE(removalFinished, true); + QTRY_VERIFY(removalFinished); } /* @@ -289,34 +288,54 @@ void tst_Main::loadDatabaseWithUpdatedBuiltInApp() QCOMPARE(app->name(qSL("en")), qSL("Hello Updated Red")); } -/* - When the "main QML file" parameter contains a relative filepath like "foo/bar.qml", - Main should treat it as a local file (instead of a remote url) and complain that it - doesn't exist. - */ -void tst_Main::nonExistentMainQmlFile() +void tst_Main::mainQmlFile_data() +{ + QTest::addColumn<QString>("mainQml"); + QTest::addColumn<QString>("expectedErrorMsg"); + + QTest::newRow("none") << "" << "No main QML file specified"; + + QTest::newRow("invalid") << "foo/bar.qml" << "Invalid main QML file specified: foo/bar.qml"; + QTest::newRow("invalid-dir") << "." << "Invalid main QML file specified: ."; + QTest::newRow("invalid-qrc1") << ":/bar.qml" << "Invalid main QML file specified: :/bar.qml"; + // "://bar.qml" yields an absolute file path of ":" and QFile::exists() would always return true + QTest::newRow("invalid-qrc2") << "://bar.qml" << "Invalid main QML file specified: ://bar.qml"; + QTest::newRow("invalid-qrc-dir") << ":/foo" << "Invalid main QML file specified: :/foo"; + + QTest::newRow("valid-native") << QFINDTESTDATA("dummy.qml") << ""; + QTest::newRow("valid-qrc-file") << ":/foo/dummy.qml" << ""; + QTest::newRow("valid-qrc-url") << "qrc:///foo/dummy.qml" << ""; + + // Passes unchecked: + QTest::newRow("https") << "https://www.qt.io/foo/bar.qml" << ""; + QTest::newRow("assets") << "assets:///foo/bar.qml" << ""; +} + +void tst_Main::mainQmlFile() { + QFETCH(QString, mainQml); + QFETCH(QString, expectedErrorMsg); + QStringList arguments; arguments << "tst_update-builtin-app"; arguments << "--dbus"; arguments << "none"; - arguments << "foo/bar.qml"; - - QString errorMsg; + arguments << mainQml; main = new Main(argc, argv); - config = new DefaultConfiguration; + config = new DefaultConfiguration(QStringList(QFINDTESTDATA("am-config.yaml")), QString()); config->parseWithArguments(arguments); + QString errorMsg; + try { main->setup(config); } catch (const std::exception &e) { errorMsg.append(e.what()); } - QVERIFY(errorMsg.startsWith("no/invalid main QML file specified:")); - QVERIFY(errorMsg.contains("bar.qml")); + QCOMPARE(errorMsg, expectedErrorMsg); delete config; config = nullptr; diff --git a/tests/manual/manual.pro b/tests/manual/manual.pro new file mode 100644 index 00000000..49d5c3b4 --- /dev/null +++ b/tests/manual/manual.pro @@ -0,0 +1,6 @@ +requires(false) # visible in QtCreator, but not built by default + +TEMPLATE = subdirs + +SUBDIRS = \ + monitormodel \ diff --git a/tests/manual/monitormodel/PropertyField.qml b/tests/manual/monitormodel/PropertyField.qml index d40a5358..042b7545 100644 --- a/tests/manual/monitormodel/PropertyField.qml +++ b/tests/manual/monitormodel/PropertyField.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/manual/monitormodel/SystemMonitorChart.qml b/tests/manual/monitormodel/SystemMonitorChart.qml index 264c9dcf..8a45d584 100644 --- a/tests/manual/monitormodel/SystemMonitorChart.qml +++ b/tests/manual/monitormodel/SystemMonitorChart.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/manual/monitormodel/main.qml b/tests/manual/monitormodel/main.qml index 3ac2c727..688810d9 100644 --- a/tests/manual/monitormodel/main.qml +++ b/tests/manual/monitormodel/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage @@ -45,7 +45,7 @@ import QtQuick.Controls 2.4 import QtQuick.Layouts 1.11 import QtQuick.Window 2.11 -import QtApplicationManager.SystemUI 2.0 +import QtApplicationManager 2.0 Window { width: 1200 diff --git a/tests/manual/monitormodel/monitormodel.pro b/tests/manual/monitormodel/monitormodel.pro new file mode 100644 index 00000000..7c2e33bc --- /dev/null +++ b/tests/manual/monitormodel/monitormodel.pro @@ -0,0 +1,5 @@ +TEMPLATE = aux + +OTHER_FILES = \ + *.qml \ + README \ diff --git a/tests/packagecreator/tst_packagecreator.cpp b/tests/packagecreator/tst_packagecreator.cpp index 1b030168..0f1af7e1 100644 --- a/tests/packagecreator/tst_packagecreator.cpp +++ b/tests/packagecreator/tst_packagecreator.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage @@ -31,7 +31,7 @@ #include "global.h" #include "installationreport.h" -#include "package.h" +#include "packageutilities.h" #include "packagecreator.h" #include "utilities.h" @@ -80,7 +80,7 @@ void tst_PackageCreator::initTestCase() m_isCygwin = tar.readAllStandardOutput().contains("Cygwin"); - QVERIFY(Package::checkCorrectLocale()); + QVERIFY(PackageUtilities::checkCorrectLocale()); } void tst_PackageCreator::createAndVerify_data() @@ -173,7 +173,7 @@ QString tst_PackageCreator::escapeFilename(const QString &name) int main(int argc, char *argv[]) { - Package::ensureCorrectLocale(); + PackageUtilities::ensureCorrectLocale(); QCoreApplication app(argc, argv); app.setAttribute(Qt::AA_Use96Dpi, true); tst_PackageCreator tc; diff --git a/tests/packageextractor/tst_packageextractor.cpp b/tests/packageextractor/tst_packageextractor.cpp index 950639e0..32979bb9 100644 --- a/tests/packageextractor/tst_packageextractor.cpp +++ b/tests/packageextractor/tst_packageextractor.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage @@ -41,7 +41,7 @@ #include "global.h" #include "packageextractor.h" #include "installationreport.h" -#include "package.h" +#include "packageutilities.h" #include "../error-checking.h" @@ -80,7 +80,7 @@ void tst_PackageExtractor::initTestCase() if (!QDir(qL1S(AM_TESTDATA_DIR "/packages")).exists()) QSKIP("No test packages available in the data/ directory"); - QVERIFY(Package::checkCorrectLocale()); + QVERIFY(PackageUtilities::checkCorrectLocale()); } void tst_PackageExtractor::init() @@ -300,7 +300,7 @@ void tst_PackageExtractor::extractFromFifo() int main(int argc, char *argv[]) { - Package::ensureCorrectLocale(); + PackageUtilities::ensureCorrectLocale(); QCoreApplication app(argc, argv); app.setAttribute(Qt::AA_Use96Dpi, true); tst_PackageExtractor tc; diff --git a/tests/packager-tool/packager-tool.pro b/tests/packager-tool/packager-tool.pro index b4c11d94..08876ac6 100644 --- a/tests/packager-tool/packager-tool.pro +++ b/tests/packager-tool/packager-tool.pro @@ -8,9 +8,8 @@ QT *= \ appman_application-private \ appman_package-private \ appman_manager-private \ - appman_installer-private \ -INCLUDEPATH += ../../src/tools/packager -SOURCES += ../../src/tools/packager/packagingjob.cpp +INCLUDEPATH += $$PWD/../../src/tools/packager +SOURCES += $$PWD/../../src/tools/packager/packagingjob.cpp SOURCES += tst_packager-tool.cpp diff --git a/tests/packager-tool/tst_packager-tool.cpp b/tests/packager-tool/tst_packager-tool.cpp index e890f066..dc2ca94f 100644 --- a/tests/packager-tool/tst_packager-tool.cpp +++ b/tests/packager-tool/tst_packager-tool.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage @@ -31,13 +31,13 @@ #include <QCoreApplication> #include "global.h" -#include "installationlocation.h" #include "applicationmanager.h" #include "application.h" #include "qtyaml.h" #include "exception.h" +#include "packagedatabase.h" +#include "packagemanager.h" #include "packagingjob.h" -#include "applicationinstaller.h" #include "qmlinprocessruntime.h" #include "runtimefactory.h" #include "utilities.h" @@ -74,7 +74,7 @@ private: void installPackage(const QString &filePath); - ApplicationInstaller *m_ai = nullptr; + PackageManager *m_pm = nullptr; QTemporaryDir m_workDir; QString m_devPassword; @@ -93,23 +93,18 @@ void tst_PackagerTool::initTestCase() spyTimeout *= timeoutFactor(); QVERIFY(m_workDir.isValid()); - - QVERIFY(QDir::root().mkpath(pathTo("manifests"))); QVERIFY(QDir::root().mkpath(pathTo("internal-0"))); QVERIFY(QDir::root().mkpath(pathTo("documents-0"))); - m_hardwareId = "foobar"; - - QVariantMap internalLocation { - { "id", "internal-0" }, - { "installationPath", pathTo("internal-0") }, - { "documentPath", pathTo("documents-0") }, - }; - QVector<InstallationLocation> locations = InstallationLocation::parseInstallationLocations({ internalLocation }, m_hardwareId); + m_hardwareId = qSL("foobar"); - QString errorString; - m_ai = ApplicationInstaller::createInstance(locations, pathTo("manifests"), m_hardwareId, &errorString); - QVERIFY2(m_ai, qPrintable(errorString)); + PackageDatabase *pdb = new PackageDatabase({}, pathTo("internal-0")); + try { + m_pm = PackageManager::createInstance(pdb, pathTo("documents-0")); + m_pm->setHardwareId(m_hardwareId); + } catch (const Exception &e) { + QVERIFY2(false, e.what()); + } QVERIFY(ApplicationManager::createInstance(true)); @@ -125,7 +120,7 @@ void tst_PackagerTool::initTestCase() chainOfTrust << devcaFile.readAll() << caFile.readAll(); QVERIFY(!chainOfTrust.at(0).isEmpty()); QVERIFY(!chainOfTrust.at(1).isEmpty()); - m_ai->setCACertificates(chainOfTrust); + m_pm->setCACertificates(chainOfTrust); m_caFiles << devcaFile.fileName() << caFile.fileName(); @@ -139,7 +134,6 @@ void tst_PackagerTool::initTestCase() void tst_PackagerTool::cleanup() { - recursiveOperation(pathTo("manifests"), safeRemove); recursiveOperation(pathTo("internal-0"), safeRemove); recursiveOperation(pathTo("documents-0"), safeRemove); @@ -284,10 +278,10 @@ void tst_PackagerTool::brokenMetadata_data() QTest::addColumn<QVariant>("yamlValue"); QTest::addColumn<QString>("errorString"); - QTest::newRow("missing-name") << "name" << QVariant("") << "~.*the 'name' field must not be empty"; - QTest::newRow("missing-runtime") << "runtime" << QVariant("") << "~.*the 'runtimeName' field must not be empty"; - QTest::newRow("missing-identifier") << "id" << QVariant("") << "~.*the identifier \\(\\) is not a valid application-id: must not be empty"; - QTest::newRow("missing-code") << "code" << QVariant("") << "~.*the 'code' field must not be empty"; + QTest::newRow("missing-name") << qSL("name") << QVariant() << "~.*the 'name' field must not be empty"; + QTest::newRow("missing-runtime") << qSL("runtime") << QVariant() << "~.*the 'runtimeName' field must not be empty.*"; + QTest::newRow("missing-identifier") << qSL("id") << QVariant() << "~.*packages need to have an id.*"; + QTest::newRow("missing-code") << qSL("code") << QVariant() << "~.*the 'code' field must not be empty.*"; } void tst_PackagerTool::brokenMetadata() @@ -318,18 +312,18 @@ void tst_PackagerTool::iconFileName() QTemporaryDir tmp; QString errorString; - createInfoYaml(tmp, "icon", "foo.bar"); + createInfoYaml(tmp, qSL("icon"), qSL("foo.bar")); createCode(tmp); - createDummyFile(tmp, "foo.bar", "this-is-a-dummy-icon-file"); + createDummyFile(tmp, qSL("foo.bar"), "this-is-a-dummy-icon-file"); QVERIFY2(packagerCheck(PackagingJob::create(pathTo("test-foobar-icon.appkg"), tmp.path()), errorString), qPrintable(errorString)); // see if the package installs correctly - m_ai->setAllowInstallationOfUnsignedPackages(true); + m_pm->setAllowInstallationOfUnsignedPackages(true); installPackage(pathTo("test-foobar-icon.appkg")); - m_ai->setAllowInstallationOfUnsignedPackages(false); + m_pm->setAllowInstallationOfUnsignedPackages(false); QDir checkDir(pathTo("internal-0")); QVERIFY(checkDir.cd(qSL("com.pelagicore.test"))); @@ -387,23 +381,22 @@ void tst_PackagerTool::createDummyFile(QTemporaryDir &tmp, const QString &fileNa auto written = code.write(data); - QCOMPARE(written, (qint64)strlen(data)); + QCOMPARE(written, static_cast<qint64>(strlen(data))); } void tst_PackagerTool::installPackage(const QString &filePath) { - QSignalSpy finishedSpy(m_ai, &ApplicationInstaller::taskFinished); + QSignalSpy finishedSpy(m_pm, &PackageManager::taskFinished); - m_ai->setDevelopmentMode(true); // allow packages without store signature + m_pm->setDevelopmentMode(true); // allow packages without store signature - QString taskId = m_ai->startPackageInstallation(qSL("internal-0"), - QUrl::fromLocalFile(filePath)); - m_ai->acknowledgePackageInstallation(taskId); + QString taskId = m_pm->startPackageInstallation(QUrl::fromLocalFile(filePath)); + m_pm->acknowledgePackageInstallation(taskId); QVERIFY(finishedSpy.wait(2 * spyTimeout)); QCOMPARE(finishedSpy.first()[0].toString(), taskId); - m_ai->setDevelopmentMode(false); + m_pm->setDevelopmentMode(false); } QTEST_GUILESS_MAIN(tst_PackagerTool) diff --git a/tests/processreader/tst_processreader.cpp b/tests/processreader/tst_processreader.cpp index 978770a0..1bfc0db0 100644 --- a/tests/processreader/tst_processreader.cpp +++ b/tests/processreader/tst_processreader.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage diff --git a/tests/qml/configs/apps/test.configs.app/app.qml b/tests/qml/configs/apps/test.configs.app/app.qml index 8ce11a63..402364ce 100644 --- a/tests/qml/configs/apps/test.configs.app/app.qml +++ b/tests/qml/configs/apps/test.configs.app/app.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/configs/configs.pro b/tests/qml/configs/configs.pro index 1ba0ab11..86604d5e 100644 --- a/tests/qml/configs/configs.pro +++ b/tests/qml/configs/configs.pro @@ -2,6 +2,7 @@ load(am-config) AM_CONFIG = am-config.yaml TEST_FILES = tst_configs.qml +TEST_APPS = test.configs.app TEST_CONFIGURATIONS = "--force-single-process" \ "--force-single-process --single-app $$_PRO_FILE_PWD_/apps/test.configs.app/info.yaml" multi-process { diff --git a/tests/qml/configs/tst_configs.qml b/tests/qml/configs/tst_configs.qml index 0dac7b3b..5acbeca1 100644 --- a/tests/qml/configs/tst_configs.qml +++ b/tests/qml/configs/tst_configs.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/crash/apps/tld.test.crash/app.qml b/tests/qml/crash/apps/tld.test.crash/app.qml index 262b0802..447b5bef 100644 --- a/tests/qml/crash/apps/tld.test.crash/app.qml +++ b/tests/qml/crash/apps/tld.test.crash/app.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.cpp b/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.cpp index 64210f63..ae03e600 100644 --- a/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.cpp +++ b/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage diff --git a/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.h b/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.h index d8fabbf9..5d59d6ea 100644 --- a/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.h +++ b/tests/qml/crash/apps/tld.test.crash/terminator2/qmlterminator2.h @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage diff --git a/tests/qml/crash/crash.pro b/tests/qml/crash/crash.pro index 160c90af..b3bff364 100644 --- a/tests/qml/crash/crash.pro +++ b/tests/qml/crash/crash.pro @@ -1,4 +1,6 @@ AM_CONFIG = am-config.yaml TEST_FILES = tst_crash.qml +TEST_APPS = tld.test.crash load(am-qml-testcase) + diff --git a/tests/qml/crash/tst_crash.qml b/tests/qml/crash/tst_crash.qml index 89ae9a9b..29ebd011 100644 --- a/tests/qml/crash/tst_crash.qml +++ b/tests/qml/crash/tst_crash.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/installer/tst_installer.qml b/tests/qml/installer/tst_installer.qml index 8bfcc246..82ba5419 100644 --- a/tests/qml/installer/tst_installer.qml +++ b/tests/qml/installer/tst_installer.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/intents/apps/intents1/intents1.qml b/tests/qml/intents/apps/intents1/intents1.qml index 560cdb3a..eb53a84c 100644 --- a/tests/qml/intents/apps/intents1/intents1.qml +++ b/tests/qml/intents/apps/intents1/intents1.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/intents/apps/intents2/intents2.qml b/tests/qml/intents/apps/intents2/intents2.qml index 7c989a17..d77ac506 100644 --- a/tests/qml/intents/apps/intents2/intents2.qml +++ b/tests/qml/intents/apps/intents2/intents2.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/intents/intents.pro b/tests/qml/intents/intents.pro index ae6415a6..797f96e8 100644 --- a/tests/qml/intents/intents.pro +++ b/tests/qml/intents/intents.pro @@ -1,7 +1,5 @@ AM_CONFIG = am-config.yaml TEST_FILES = tst_intents.qml - -APPS = intents1 intents2 cannot-start -for (app, APPS): OTHER_FILES += apps/$${app}/*.yaml apps/$${app}/*.qml apps/$${app}/*.png +TEST_APPS = intents1 intents2 cannot-start load(am-qml-testcase) diff --git a/tests/qml/intents/tst_intents.qml b/tests/qml/intents/tst_intents.qml index 9ab11a7a..b574dee4 100644 --- a/tests/qml/intents/tst_intents.qml +++ b/tests/qml/intents/tst_intents.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/quicklaunch/apps/tld.test.quicklaunch/app.qml b/tests/qml/quicklaunch/apps/tld.test.quicklaunch/app.qml index 1c203d4f..9defde81 100644 --- a/tests/qml/quicklaunch/apps/tld.test.quicklaunch/app.qml +++ b/tests/qml/quicklaunch/apps/tld.test.quicklaunch/app.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/quicklaunch/quicklaunch.pro b/tests/qml/quicklaunch/quicklaunch.pro index 4c6b8f74..2d990a4b 100644 --- a/tests/qml/quicklaunch/quicklaunch.pro +++ b/tests/qml/quicklaunch/quicklaunch.pro @@ -1,4 +1,5 @@ AM_CONFIG = am-config.yaml TEST_FILES = tst_quicklaunch.qml +TEST_APPS = tld.test.quicklaunch load(am-qml-testcase) diff --git a/tests/qml/quicklaunch/tst_quicklaunch.qml b/tests/qml/quicklaunch/tst_quicklaunch.qml index b840e691..1e4e4e5d 100644 --- a/tests/qml/quicklaunch/tst_quicklaunch.qml +++ b/tests/qml/quicklaunch/tst_quicklaunch.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/simple/apps/tld.test.simple1/app1.qml b/tests/qml/simple/apps/tld.test.simple1/app1.qml index fb38c958..f0402209 100644 --- a/tests/qml/simple/apps/tld.test.simple1/app1.qml +++ b/tests/qml/simple/apps/tld.test.simple1/app1.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/simple/apps/tld.test.simple2/app.qml b/tests/qml/simple/apps/tld.test.simple2/app.qml index 2a09855d..b0506e1f 100644 --- a/tests/qml/simple/apps/tld.test.simple2/app.qml +++ b/tests/qml/simple/apps/tld.test.simple2/app.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/simple/simple.pro b/tests/qml/simple/simple.pro index 375f62c5..72dbea95 100644 --- a/tests/qml/simple/simple.pro +++ b/tests/qml/simple/simple.pro @@ -1,4 +1,5 @@ AM_CONFIG = am-config.yaml TEST_FILES = tst_applicationmanager.qml +TEST_APPS = tld.test.simple1 tld.test.simple2 load(am-qml-testcase) diff --git a/tests/qml/simple/tst_applicationmanager.qml b/tests/qml/simple/tst_applicationmanager.qml index d945c477..71878d5f 100644 --- a/tests/qml/simple/tst_applicationmanager.qml +++ b/tests/qml/simple/tst_applicationmanager.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/windowitem/apps/test.windowitem.app/main.qml b/tests/qml/windowitem/apps/test.windowitem.app/main.qml index 8f64f980..ee12db6f 100644 --- a/tests/qml/windowitem/apps/test.windowitem.app/main.qml +++ b/tests/qml/windowitem/apps/test.windowitem.app/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/windowitem/apps/test.windowitem.multiwin/main.qml b/tests/qml/windowitem/apps/test.windowitem.multiwin/main.qml index f12323be..7d1b0600 100644 --- a/tests/qml/windowitem/apps/test.windowitem.multiwin/main.qml +++ b/tests/qml/windowitem/apps/test.windowitem.multiwin/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/windowitem/tst_windowitem.qml b/tests/qml/windowitem/tst_windowitem.qml index ea835267..15cd4f5b 100644 --- a/tests/qml/windowitem/tst_windowitem.qml +++ b/tests/qml/windowitem/tst_windowitem.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/windowitem/windowitem.pro b/tests/qml/windowitem/windowitem.pro index d2755653..fcc1b1f6 100644 --- a/tests/qml/windowitem/windowitem.pro +++ b/tests/qml/windowitem/windowitem.pro @@ -1,4 +1,5 @@ AM_CONFIG = am-config.yaml TEST_FILES = tst_windowitem.qml +TEST_APPS = test.windowitem.app test.windowitem.multiwin load(am-qml-testcase) diff --git a/tests/qml/windowitem2/apps/test.windowitem2.app/main.qml b/tests/qml/windowitem2/apps/test.windowitem2.app/main.qml index 84dfdb3e..ab891bb8 100644 --- a/tests/qml/windowitem2/apps/test.windowitem2.app/main.qml +++ b/tests/qml/windowitem2/apps/test.windowitem2.app/main.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/windowitem2/tst_windowitem2.qml b/tests/qml/windowitem2/tst_windowitem2.qml index 5c411805..98d4ef30 100644 --- a/tests/qml/windowitem2/tst_windowitem2.qml +++ b/tests/qml/windowitem2/tst_windowitem2.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/windowitem2/windowitem2.pro b/tests/qml/windowitem2/windowitem2.pro index fe1ab58a..022ea053 100644 --- a/tests/qml/windowitem2/windowitem2.pro +++ b/tests/qml/windowitem2/windowitem2.pro @@ -1,4 +1,5 @@ AM_CONFIG = am-config.yaml TEST_FILES = tst_windowitem2.qml +TEST_APPS = test.windowitem2.app load(am-qml-testcase) diff --git a/tests/qml/windowmanager/IviApplicationExtension.qml b/tests/qml/windowmanager/IviApplicationExtension.qml index f85f147d..3e4a9700 100644 --- a/tests/qml/windowmanager/IviApplicationExtension.qml +++ b/tests/qml/windowmanager/IviApplicationExtension.qml @@ -3,7 +3,7 @@ ** Copyright (C) 2019 Luxoft Sweden AB ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/windowmanager/tst_windowmanager.qml b/tests/qml/windowmanager/tst_windowmanager.qml index c2a556cd..11cb9265 100644 --- a/tests/qml/windowmanager/tst_windowmanager.qml +++ b/tests/qml/windowmanager/tst_windowmanager.qml @@ -3,7 +3,7 @@ ** Copyright (C) 2019 Luxoft Sweden AB ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/windowmanager/windowmanager.pro b/tests/qml/windowmanager/windowmanager.pro index d9b687eb..1e291c00 100644 --- a/tests/qml/windowmanager/windowmanager.pro +++ b/tests/qml/windowmanager/windowmanager.pro @@ -1,4 +1,6 @@ AM_CONFIG = am-config.yaml TEST_FILES = tst_windowmanager.qml +OTHER_FILES += IviApplicationExtension.qml + load(am-qml-testcase) diff --git a/tests/qml/windowmapping/apps/test.winmap.amwin/amwin.qml b/tests/qml/windowmapping/apps/test.winmap.amwin/amwin.qml index 470d6dc0..a93f30d4 100644 --- a/tests/qml/windowmapping/apps/test.winmap.amwin/amwin.qml +++ b/tests/qml/windowmapping/apps/test.winmap.amwin/amwin.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/windowmapping/apps/test.winmap.amwin2/amwin2.qml b/tests/qml/windowmapping/apps/test.winmap.amwin2/amwin2.qml index 8c104a05..b10709d3 100644 --- a/tests/qml/windowmapping/apps/test.winmap.amwin2/amwin2.qml +++ b/tests/qml/windowmapping/apps/test.winmap.amwin2/amwin2.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/windowmapping/apps/test.winmap.loader/SubWin.qml b/tests/qml/windowmapping/apps/test.winmap.loader/SubWin.qml index af0001d6..8ba50e22 100644 --- a/tests/qml/windowmapping/apps/test.winmap.loader/SubWin.qml +++ b/tests/qml/windowmapping/apps/test.winmap.loader/SubWin.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/windowmapping/apps/test.winmap.loader/loader.qml b/tests/qml/windowmapping/apps/test.winmap.loader/loader.qml index 569fef1a..0a65690e 100644 --- a/tests/qml/windowmapping/apps/test.winmap.loader/loader.qml +++ b/tests/qml/windowmapping/apps/test.winmap.loader/loader.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/windowmapping/apps/test.winmap.ping/ping.qml b/tests/qml/windowmapping/apps/test.winmap.ping/ping.qml index 59267c04..6fa9ba23 100644 --- a/tests/qml/windowmapping/apps/test.winmap.ping/ping.qml +++ b/tests/qml/windowmapping/apps/test.winmap.ping/ping.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/windowmapping/apps/test.winmap.qtobject/qtobject.qml b/tests/qml/windowmapping/apps/test.winmap.qtobject/qtobject.qml index c1c8ba3d..325c04de 100644 --- a/tests/qml/windowmapping/apps/test.winmap.qtobject/qtobject.qml +++ b/tests/qml/windowmapping/apps/test.winmap.qtobject/qtobject.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/windowmapping/apps/test.winmap.rectangle/rectangle.qml b/tests/qml/windowmapping/apps/test.winmap.rectangle/rectangle.qml index 718b787d..fe6cdee3 100644 --- a/tests/qml/windowmapping/apps/test.winmap.rectangle/rectangle.qml +++ b/tests/qml/windowmapping/apps/test.winmap.rectangle/rectangle.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/windowmapping/apps/test.winmap.window/window.qml b/tests/qml/windowmapping/apps/test.winmap.window/window.qml index c10a57b0..a0832d15 100644 --- a/tests/qml/windowmapping/apps/test.winmap.window/window.qml +++ b/tests/qml/windowmapping/apps/test.winmap.window/window.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/windowmapping/tst_windowmapping.qml b/tests/qml/windowmapping/tst_windowmapping.qml index 00a6e582..dda075e5 100644 --- a/tests/qml/windowmapping/tst_windowmapping.qml +++ b/tests/qml/windowmapping/tst_windowmapping.qml @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:LGPL-QTAS$ ** Commercial License Usage diff --git a/tests/qml/windowmapping/windowmapping.pro b/tests/qml/windowmapping/windowmapping.pro index 59fa55b0..e29aba28 100644 --- a/tests/qml/windowmapping/windowmapping.pro +++ b/tests/qml/windowmapping/windowmapping.pro @@ -1,4 +1,12 @@ AM_CONFIG = am-config.yaml TEST_FILES = tst_windowmapping.qml +TEST_APPS = \ + test.winmap.amwin \ + test.winmap.amwin2 \ + test.winmap.loader \ + test.winmap.ping \ + test.winmap.qtobject \ + test.winmap.rectangle \ + test.winmap.window \ load(am-qml-testcase) diff --git a/tests/runtime/tst_runtime.cpp b/tests/runtime/tst_runtime.cpp index 615417e4..dd3a2b4a 100644 --- a/tests/runtime/tst_runtime.cpp +++ b/tests/runtime/tst_runtime.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage @@ -31,7 +31,8 @@ #include <QQmlEngine> #include "application.h" -#include "yamlapplicationscanner.h" +#include "package.h" +#include "yamlpackagescanner.h" #include "abstractruntime.h" #include "runtimefactory.h" #include "exception.h" @@ -62,19 +63,19 @@ public: void setSlowAnimations(bool) override {} - qint64 applicationProcessId() const + qint64 applicationProcessId() const override { return m_state == Am::Running ? 1 : 0; } public slots: - bool start() + bool start() override { m_state = Am::Running; return true; } - void stop(bool forceKill) + void stop(bool forceKill) override { Q_UNUSED(forceKill); m_state = Am::NotRunning; @@ -137,7 +138,10 @@ void tst_Runtime::factory() Application *a = nullptr; try { - a = new Application(YamlApplicationScanner().scan(temp.fileName())); + PackageInfo *pi = YamlPackageScanner().scan(temp.fileName()); + QVERIFY(pi); + Package *p = new Package(pi); + a = new Application(pi->applications().first(), p); } catch (const Exception &e) { QVERIFY2(false, qPrintable(e.errorString())); } diff --git a/tests/signature/create-test-data.sh b/tests/signature/create-test-data.sh index 943ade2a..d599d18d 100755 --- a/tests/signature/create-test-data.sh +++ b/tests/signature/create-test-data.sh @@ -5,7 +5,7 @@ ## Copyright (C) 2018 Pelagicore AG ## Contact: https://www.qt.io/licensing/ ## -## This file is part of the Luxoft Application Manager. +## This file is part of the Qt Application Manager. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ## Commercial License Usage diff --git a/tests/signature/signature.pro b/tests/signature/signature.pro index 77ff71f1..43bb3d47 100644 --- a/tests/signature/signature.pro +++ b/tests/signature/signature.pro @@ -6,4 +6,6 @@ QT *= appman_common-private appman_crypto-private SOURCES += tst_signature.cpp +OTHER_FILES += create-test-data.sh + RESOURCES += tst_signature.qrc diff --git a/tests/signature/tst_signature.cpp b/tests/signature/tst_signature.cpp index c8713457..9f48590a 100644 --- a/tests/signature/tst_signature.cpp +++ b/tests/signature/tst_signature.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage diff --git a/tests/sudo/sudo.pro b/tests/sudo/sudo.pro index 9745e2fc..95be319b 100644 --- a/tests/sudo/sudo.pro +++ b/tests/sudo/sudo.pro @@ -6,6 +6,6 @@ include($$PWD/../tests.pri) QT *= \ appman_common-private \ - appman_installer-private \ + appman_manager-private \ SOURCES += tst_sudo.cpp diff --git a/tests/sudo/tst_sudo.cpp b/tests/sudo/tst_sudo.cpp index 6ce7685e..0fb2b2ad 100644 --- a/tests/sudo/tst_sudo.cpp +++ b/tests/sudo/tst_sudo.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage diff --git a/tests/systemreader/tst_systemreader.cpp b/tests/systemreader/tst_systemreader.cpp index 48c75c23..d69478ee 100644 --- a/tests/systemreader/tst_systemreader.cpp +++ b/tests/systemreader/tst_systemreader.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage diff --git a/tests/tests.pro b/tests/tests.pro index 0b9409df..6cfe294b 100644 --- a/tests/tests.pro +++ b/tests/tests.pro @@ -1,6 +1,7 @@ TEMPLATE = subdirs SUBDIRS = \ + manual \ application \ applicationinfo \ main \ @@ -25,6 +26,7 @@ OTHER_FILES += \ tests.pri \ data/create-test-packages.sh \ data/certificates/create-test-certificates.sh \ + data/utilities.sh \ # sadly, the appman-packager is too complex to build as a host tool !cross_compile { diff --git a/tests/utilities/tst_utilities.cpp b/tests/utilities/tst_utilities.cpp index 47689907..5b4ed8e4 100644 --- a/tests/utilities/tst_utilities.cpp +++ b/tests/utilities/tst_utilities.cpp @@ -4,7 +4,7 @@ ** Copyright (C) 2018 Pelagicore AG ** Contact: https://www.qt.io/licensing/ ** -** This file is part of the Luxoft Application Manager. +** This file is part of the Qt Application Manager. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ** Commercial License Usage diff --git a/util/bash/appman-prompt b/util/bash/appman-prompt index cd85278f..c1f37766 100644 --- a/util/bash/appman-prompt +++ b/util/bash/appman-prompt @@ -4,7 +4,7 @@ ## Copyright (C) 2018 Pelagicore AG ## Contact: https://www.qt.io/licensing/ ## -## This file is part of the Luxoft Application Manager. +## This file is part of the Qt Application Manager. ## ## $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$ ## Commercial License Usage @@ -44,7 +44,7 @@ _appman() COMPREPLY=( $( compgen -f -- ${cur}) ) fi } -complete -o filenames -F _appman appman +complete -o filenames -F _appman appman appman-qmltestrunner _appman-controller() { |