summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRobert Griebl <robert.griebl@pelagicore.com>2019-08-07 12:09:43 +0200
committerRobert Griebl <robert.griebl@qt.io>2019-10-28 14:11:37 +0100
commit0a1cccfccd8f76014bc697c5c9006c5ebb9723e8 (patch)
tree250203807b296f32ffbebae798d48316113a51d8
parent0120c4c892c3765fba18b15e3a28d446bf1a3f38 (diff)
Add new package abstraction, part 2
The first commit in this series was b4aee167d3bc6b9f64229317fbc428b3f3b83c0d. This update fixes all the known bugs introduced in the change of the architecture, adds basic documentation and examples. The changes in the intent sub-system are in a separate patch for easier review, although they both depend on each other due to changes in the API. Change-Id: Ia78da7e10e2eb7adfa30625554af275453065a90 Reviewed-by: Dominik Holland <dominik.holland@qt.io>
-rw-r--r--examples/applicationmanager/application-features/doc/src/application-features.qdoc2
-rw-r--r--qmake-features/am-qml-testcase.prf5
-rw-r--r--src/application-lib/installationreport.cpp42
-rw-r--r--src/application-lib/installationreport.h3
-rw-r--r--src/application-lib/intentinfo.cpp19
-rw-r--r--src/application-lib/intentinfo.h5
-rw-r--r--src/application-lib/packagedatabase.cpp68
-rw-r--r--src/application-lib/packagedatabase.h21
-rw-r--r--src/application-lib/packageinfo.cpp43
-rw-r--r--src/application-lib/packageinfo.h15
-rw-r--r--src/application-lib/packagescanner.h3
-rw-r--r--src/application-lib/yamlpackagescanner.cpp59
-rw-r--r--src/application-lib/yamlpackagescanner.h2
-rw-r--r--src/intent-server-lib/intent.cpp10
-rw-r--r--src/intent-server-lib/intent.h2
-rw-r--r--src/main-lib/applicationinstaller.h3
-rw-r--r--src/main-lib/main.cpp77
-rw-r--r--src/main-lib/main.h2
-rw-r--r--src/manager-lib/application.cpp9
-rw-r--r--src/manager-lib/application.h27
-rw-r--r--src/manager-lib/applicationmanager.cpp56
-rw-r--r--src/manager-lib/applicationmanager.h11
-rw-r--r--src/manager-lib/applicationmanager_p.h2
-rw-r--r--src/manager-lib/installationtask.cpp5
-rw-r--r--src/manager-lib/intentaminterface.cpp51
-rw-r--r--src/manager-lib/intentaminterface.h6
-rw-r--r--src/manager-lib/package.cpp49
-rw-r--r--src/manager-lib/package.h21
-rw-r--r--src/manager-lib/packagemanager.cpp278
-rw-r--r--src/manager-lib/packagemanager.h25
-rw-r--r--src/manager-lib/packagemanager_p.h3
-rw-r--r--src/src.pro2
-rw-r--r--src/tools/launcher-qml/launcher-qml.cpp60
-rw-r--r--src/tools/launcher-qml/launcher-qml_p.h4
-rw-r--r--src/tools/packager/packagingjob.cpp7
-rw-r--r--tests/application/application.pro3
-rw-r--r--tests/application/icon.pngbin0 -> 68 bytes
-rw-r--r--tests/application/info.yaml10
-rw-r--r--tests/application/tst_application.cpp3
-rw-r--r--tests/application/tst_application.qrc5
-rw-r--r--tests/applicationinstaller/tst_applicationinstaller.cpp15
-rw-r--r--tests/installationreport/tst_installationreport.cpp14
-rw-r--r--tests/main/builtin-apps/hello-world.red/info.yaml21
-rw-r--r--tests/main/dir-with-update-already-installed/apps/hello-world.red/.installation-report.yaml (renamed from tests/main/dir-with-update-already-installed/manifests/hello-world.red/installation-report.yaml)7
-rw-r--r--tests/main/main.pro4
-rw-r--r--tests/main/tst_main.cpp69
-rw-r--r--tests/packager-tool/tst_packager-tool.cpp3
-rw-r--r--tests/qml/installer/appv1.pkgbin10240 -> 0 bytes
-rw-r--r--tests/qml/installer/appv2.pkgbin10240 -> 0 bytes
-rw-r--r--tests/qml/installer/installer.pro2
-rw-r--r--tests/qml/installer/tst_installer.qml65
-rw-r--r--tests/qml/intents/tst_intents.qml59
-rw-r--r--tests/qml/simple/apps/tld.test.simple1/info-alias.yaml9
-rw-r--r--tests/qml/simple/tst_applicationmanager.qml73
-rw-r--r--tests/runtime/tst_runtime.cpp4
55 files changed, 856 insertions, 507 deletions
diff --git a/examples/applicationmanager/application-features/doc/src/application-features.qdoc b/examples/applicationmanager/application-features/doc/src/application-features.qdoc
index 7535551e..17abff0c 100644
--- a/examples/applicationmanager/application-features/doc/src/application-features.qdoc
+++ b/examples/applicationmanager/application-features/doc/src/application-features.qdoc
@@ -73,7 +73,7 @@ The QML code for the nested compositor application is as follows:
\quotefromfile applicationmanager/application-features/apps/compositor/compositor.qml
\skipto import QtQuick 2.11
-\printuntil -platform wayland"); }
+\printuntil /^\}/
\section2 Crash Simulation and Recovery
diff --git a/qmake-features/am-qml-testcase.prf b/qmake-features/am-qml-testcase.prf
index 923920fe..6958f1bc 100644
--- a/qmake-features/am-qml-testcase.prf
+++ b/qmake-features/am-qml-testcase.prf
@@ -60,6 +60,11 @@ for(config, AM_CONFIG) {
}
OTHER_FILES += $$AM_CONFIG
+# Make AM_TESTDATA_DIR known
+!isEmpty(AM_TESTDATA_DIR) {
+ COMMAND += -o \'systemProperties: { public: { AM_TESTDATA_DIR: $$AM_TESTDATA_DIR } }\'
+}
+
!isEmpty(TESTRUN_CWD):!contains(TESTRUN_CWD, ^\\./?): \
COMMAND = cd $$shell_path($$TESTRUN_CWD) && $$eval(COMMAND)
diff --git a/src/application-lib/installationreport.cpp b/src/application-lib/installationreport.cpp
index b52d772c..099c757f 100644
--- a/src/application-lib/installationreport.cpp
+++ b/src/application-lib/installationreport.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -163,10 +164,10 @@ bool InstallationReport::isValid() const
return PackageInfo::isValidApplicationId(m_packageId) && !m_digest.isEmpty() && !m_files.isEmpty();
}
-bool InstallationReport::deserialize(QIODevice *from)
+void InstallationReport::deserialize(QIODevice *from)
{
if (!from || !from->isReadable() || (from->size() > 2*1024*1024))
- return false;
+ throw Exception("Installation report is invalid");
m_digest.clear();
m_files.clear();
@@ -175,13 +176,9 @@ bool InstallationReport::deserialize(QIODevice *from)
QVector<QVariant> docs = QtYaml::variantDocumentsFromYaml(from->readAll(), &error);
if (error.error != QJsonParseError::NoError)
- return false;
+ throw Exception("Failed to parse YAML: %1").arg(error.errorString());
- try {
- checkYamlFormat(docs, 3 /*number of expected docs*/, { "am-installation-report" }, 3 /*version*/);
- } catch (const Exception &) {
- return false;
- }
+ checkYamlFormat(docs, 3 /*number of expected docs*/, { "am-installation-report" }, 3 /*version*/);
const QVariantMap &root = docs.at(1).toMap();
@@ -189,43 +186,44 @@ bool InstallationReport::deserialize(QIODevice *from)
if (m_packageId.isEmpty()) {
m_packageId = root[qSL("packageId")].toString();
if (m_packageId.isEmpty())
- throw false;
+ throw Exception("packageId is empty");
} else if (root[qSL("packageId")].toString() != m_packageId) {
- throw false;
+ throw Exception("packageId does not match: expected '%1', but got '%2'")
+ .arg(m_packageId).arg(root[qSL("packageId")].toString());
}
m_diskSpaceUsed = root[qSL("diskSpaceUsed")].toULongLong();
m_digest = QByteArray::fromHex(root[qSL("digest")].toString().toLatin1());
if (m_digest.isEmpty())
- throw false;
+ throw Exception("digest is empty");
auto devSig = root.find(qSL("developerSignature"));
if (devSig != root.end()) {
m_developerSignature = QByteArray::fromBase64(devSig.value().toString().toLatin1());
if (m_developerSignature.isEmpty())
- throw false;
+ throw Exception("developerSignature is empty");
}
auto storeSig = root.find(qSL("storeSignature"));
if (storeSig != root.end()) {
m_storeSignature = QByteArray::fromBase64(storeSig.value().toString().toLatin1());
if (m_storeSignature.isEmpty())
- throw false;
+ throw Exception("storeSignature is empty");
}
auto extra = root.find(qSL("extra"));
if (extra != root.end()) {
m_extraMetaData = extra.value().toMap();
if (m_extraMetaData.isEmpty())
- throw false;
+ throw Exception("extra metadata is empty");
}
auto extraSigned = root.find(qSL("extraSigned"));
if (extraSigned != root.end()) {
m_extraSignedMetaData = extraSigned.value().toMap();
if (m_extraSignedMetaData.isEmpty())
- throw false;
+ throw Exception("extraSigned metadata is empty");
}
m_files = root[qSL("files")].toStringList();
if (m_files.isEmpty())
- throw false;
+ throw Exception("No files");
// see if the file has been tampered with by checking the hmac
QByteArray hmacFile = QByteArray::fromHex(docs[2].toMap().value(qSL("hmac")).toString().toLatin1());
@@ -235,16 +233,16 @@ bool InstallationReport::deserialize(QIODevice *from)
hmacKey,
QCryptographicHash::Sha256);
- if (hmacFile != hmacCalc)
- throw false;
-
- return true;
- } catch (bool) {
+ if (hmacFile != hmacCalc) {
+ throw Exception("HMAC does not match: expected '%1', but got '%2'")
+ .arg(hmacCalc.toHex()).arg(hmacFile.toHex());
+ }
+ } catch (const Exception &) {
m_digest.clear();
m_diskSpaceUsed = 0;
m_files.clear();
- return false;
+ throw;
}
}
diff --git a/src/application-lib/installationreport.h b/src/application-lib/installationreport.h
index 87fa56c1..aa01f658 100644
--- a/src/application-lib/installationreport.h
+++ b/src/application-lib/installationreport.h
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -83,7 +84,7 @@ public:
bool isValid() const;
- bool deserialize(QIODevice *from);
+ void deserialize(QIODevice *from);
bool serialize(QIODevice *to) const;
private:
diff --git a/src/application-lib/intentinfo.cpp b/src/application-lib/intentinfo.cpp
index ef53ce7e..8ce17a1d 100644
--- a/src/application-lib/intentinfo.cpp
+++ b/src/application-lib/intentinfo.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Contact: https://www.qt.io/licensing/
**
@@ -86,27 +87,27 @@ QStringList IntentInfo::categories() const
QMap<QString, QString> IntentInfo::names() const
{
- return m_name;
+ return m_names.isEmpty() ? m_packageInfo->names() : m_names;
}
QString IntentInfo::name(const QString &language) const
{
- return m_name.value(language);
+ return m_names.isEmpty() ? m_packageInfo->name(language) : m_names.value(language);
}
QMap<QString, QString> IntentInfo::descriptions() const
{
- return m_description;
+ return m_descriptions;
}
QString IntentInfo::description(const QString &language) const
{
- return m_description.value(language);
+ return m_descriptions.value(language);
}
QString IntentInfo::icon() const
{
- return m_icon;
+ return m_icon.isEmpty() ? m_packageInfo->icon() : m_icon;
}
void IntentInfo::writeToDataStream(QDataStream &ds) const
@@ -117,8 +118,8 @@ void IntentInfo::writeToDataStream(QDataStream &ds) const
<< m_parameterMatch
<< m_handlingApplicationId
<< m_categories
- << m_name
- << m_description
+ << m_names
+ << m_descriptions
<< m_icon;
}
@@ -133,8 +134,8 @@ IntentInfo *IntentInfo::readFromDataStream(PackageInfo *pkg, QDataStream &ds)
>> intent->m_parameterMatch
>> intent->m_handlingApplicationId
>> intent->m_categories
- >> intent->m_name
- >> intent->m_description
+ >> intent->m_names
+ >> intent->m_descriptions
>> intent->m_icon;
intent->m_visibility = (visibilityStr == qSL("public")) ? Public : Private;
diff --git a/src/application-lib/intentinfo.h b/src/application-lib/intentinfo.h
index aee5b8ab..9834e42c 100644
--- a/src/application-lib/intentinfo.h
+++ b/src/application-lib/intentinfo.h
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Contact: https://www.qt.io/licensing/
**
@@ -93,8 +94,8 @@ private:
QString m_handlingApplicationId;
QStringList m_categories;
- QMap<QString, QString> m_name; // language -> name
- QMap<QString, QString> m_description; // language -> description
+ QMap<QString, QString> m_names; // language -> name
+ QMap<QString, QString> m_descriptions; // language -> description
QString m_icon; // relative to info.json location
friend class YamlPackageScanner;
diff --git a/src/application-lib/packagedatabase.cpp b/src/application-lib/packagedatabase.cpp
index 3496faa7..4c927569 100644
--- a/src/application-lib/packagedatabase.cpp
+++ b/src/application-lib/packagedatabase.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Contact: https://www.qt.io/licensing/
**
@@ -65,6 +66,12 @@ PackageDatabase::PackageDatabase(const QString &singlePackagePath)
Q_ASSERT(!singlePackagePath.isEmpty());
}
+PackageDatabase::~PackageDatabase()
+{
+ qDeleteAll(m_builtInPackages);
+ qDeleteAll(m_installedPackages);
+}
+
QString PackageDatabase::installedPackagesDir() const
{
return m_installedPackagesDir;
@@ -95,21 +102,21 @@ void PackageDatabase::saveToCache()
//TODO: write cache file
}
-bool PackageDatabase::canBeRevertedToBuiltIn(PackageInfo *pi)
+bool PackageDatabase::builtInHasRemovableUpdate(PackageInfo *packageInfo) const
{
- if (!pi || pi->isBuiltIn() || !m_installedPackages.contains(pi))
+ if (!packageInfo || packageInfo->isBuiltIn() || !m_installedPackages.contains(packageInfo))
return false;
- for (auto it = m_builtInPackages.cbegin(); it != m_builtInPackages.cend(); ++it) {
- if (it.key()->id() == pi->id())
+ for (const auto *pi : m_builtInPackages) {
+ if (pi->id() == packageInfo->id())
return true;
}
return false;
}
-QMap<PackageInfo *, QString> PackageDatabase::loadManifestsFromDir(YamlPackageScanner *yps, const QString &manifestDir, bool scanningBuiltInApps)
+QVector<PackageInfo *> PackageDatabase::loadManifestsFromDir(const QString &manifestDir, bool scanningBuiltInApps)
{
- QMap<PackageInfo *, QString> result;
+ QVector<PackageInfo *> result;
auto flags = scanningBuiltInApps ? QDir::Dirs | QDir::NoDotAndDotDot
: QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks;
@@ -137,8 +144,8 @@ QMap<PackageInfo *, QString> PackageDatabase::loadManifestsFromDir(YamlPackageSc
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));
+ QString manifestPath = pkgDir.absoluteFilePath(qSL("info.yaml"));
+ QScopedPointer<PackageInfo> pkg(PackageInfo::fromManifest(manifestPath));
if (pkg->id() != pkgDir.dirName()) {
throw Exception("an info.yaml must be in a directory that has"
@@ -152,13 +159,16 @@ QMap<PackageInfo *, QString> PackageDatabase::loadManifestsFromDir(YamlPackageSc
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");
+ try {
+ report->deserialize(&f);
+ } catch (const Exception &e) {
+ throw Exception("Failed to deserialize the installation report %1: %2")
+ .arg(f.fileName()).arg(e.errorString());
+ }
pkg->setInstallationReport(report.take());
- pkg->setBaseDir(QDir(m_installedPackagesDir).filePath(pkg->id()));
}
- result.insert(pkg.take(), manifestPath);
+ result.append(pkg.take());
} catch (const Exception &e) {
qCDebug(LogSystem) << "Ignoring package" << pkgDirName << ":" << e.what();
}
@@ -166,17 +176,6 @@ QMap<PackageInfo *, QString> PackageDatabase::loadManifestsFromDir(YamlPackageSc
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)
@@ -188,34 +187,43 @@ void PackageDatabase::parse()
return;
}
- YamlPackageScanner yps;
-
if (!m_singlePackagePath.isEmpty()) {
try {
- m_builtInPackages.insert(loadManifest(&yps, m_singlePackagePath), m_singlePackagePath);
+ m_builtInPackages.append(PackageInfo::fromManifest(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));
+ m_builtInPackages.append(loadManifestsFromDir(dir, true));
if (!m_installedPackagesDir.isEmpty())
- m_installedPackages = loadManifestsFromDir(&yps, m_installedPackagesDir, false);
+ m_installedPackages = loadManifestsFromDir(m_installedPackagesDir, false);
}
if (m_saveToCache)
saveToCache();
}
+void PackageDatabase::addPackageInfo(PackageInfo *package)
+{
+ m_installedPackages.append(package);
+}
+
+void PackageDatabase::removePackageInfo(PackageInfo *package)
+{
+ if (m_installedPackages.removeAll(package))
+ delete package;
+}
+
QVector<PackageInfo *> PackageDatabase::installedPackages() const
{
- return m_installedPackages.keys().toVector();
+ return m_installedPackages;
}
QVector<PackageInfo *> PackageDatabase::builtInPackages() const
{
- return m_builtInPackages.keys().toVector();
+ return m_builtInPackages;
}
QT_END_NAMESPACE_AM
diff --git a/src/application-lib/packagedatabase.h b/src/application-lib/packagedatabase.h
index ce1610db..7b6b3584 100644
--- a/src/application-lib/packagedatabase.h
+++ b/src/application-lib/packagedatabase.h
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Contact: https://www.qt.io/licensing/
**
@@ -50,7 +51,6 @@
QT_BEGIN_NAMESPACE_AM
class PackageInfo;
-class YamlPackageScanner;
class PackageDatabase
@@ -58,6 +58,7 @@ class PackageDatabase
public:
PackageDatabase(const QStringList &builtInPackagesDirs, const QString &installedPackagesDir = QString());
PackageDatabase(const QString &singlePackagePath);
+ ~PackageDatabase();
QString installedPackagesDir() const;
@@ -69,14 +70,14 @@ public:
QVector<PackageInfo *> builtInPackages() const;
QVector<PackageInfo *> installedPackages() const;
- //TODO: runtime installations
- //void addPackage(PackageInfo *package);
- //void removePackage(PackageInfo *package);
- //void updatePackage(PackageInfo *oldPackage, PackageInfo *newPackage);
+ // runtime installations
+ void addPackageInfo(PackageInfo *package);
+ void removePackageInfo(PackageInfo *package);
private:
- PackageInfo *loadManifest(YamlPackageScanner *yps, const QString &manifestPath);
- QMap<PackageInfo *, QString> loadManifestsFromDir(YamlPackageScanner *yps, const QString &manifestDir, bool scanningBuiltInApps);
+ Q_DISABLE_COPY(PackageDatabase)
+
+ QVector<PackageInfo *> loadManifestsFromDir(const QString &manifestDir, bool scanningBuiltInApps);
bool loadFromCache();
void saveToCache();
@@ -88,10 +89,10 @@ private:
QString m_installedPackagesDir;
QString m_singlePackagePath;
- QMap<PackageInfo *, QString> m_builtInPackages;
- QMap<PackageInfo *, QString> m_installedPackages;
+ QVector<PackageInfo *> m_builtInPackages;
+ QVector<PackageInfo *> m_installedPackages;
- bool canBeRevertedToBuiltIn(PackageInfo *pi);
+ bool builtInHasRemovableUpdate(PackageInfo *packageInfo) const;
};
QT_END_NAMESPACE_AM
diff --git a/src/application-lib/packageinfo.cpp b/src/application-lib/packageinfo.cpp
index ee306431..32ac528a 100644
--- a/src/application-lib/packageinfo.cpp
+++ b/src/application-lib/packageinfo.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Contact: https://www.qt.io/licensing/
**
@@ -47,6 +48,7 @@
#include "intentinfo.h"
#include "exception.h"
#include "installationreport.h"
+#include "yamlpackagescanner.h"
QT_BEGIN_NAMESPACE_AM
@@ -55,7 +57,10 @@ PackageInfo::PackageInfo()
{ }
PackageInfo::~PackageInfo()
-{ }
+{
+ qDeleteAll(m_intents);
+ qDeleteAll(m_applications);
+}
void PackageInfo::validate() const Q_DECL_NOEXCEPT_EXPR(false)
{
@@ -63,11 +68,14 @@ void PackageInfo::validate() const Q_DECL_NOEXCEPT_EXPR(false)
if (!isValidApplicationId(id(), &errorMsg))
throw Exception(Error::Parse, "the identifier (%1) is not a valid package-id: %2").arg(id()).arg(errorMsg);
+ if (m_applications.isEmpty())
+ throw Exception(Error::Parse, "package contains no applications");
+
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())
+ if (app->codeFilePath().isEmpty())
throw Exception(Error::Parse, "the 'code' field must not be empty on application %1").arg(app->id());
if (app->runtimeName().isEmpty())
@@ -82,22 +90,22 @@ QString PackageInfo::id() const
QMap<QString, QString> PackageInfo::names() const
{
- return m_name;
+ return m_names;
}
QString PackageInfo::name(const QString &language) const
{
- return m_name.value(language);
+ return m_names.value(language);
}
QMap<QString, QString> PackageInfo::descriptions() const
{
- return m_description;
+ return m_descriptions;
}
QString PackageInfo::description(const QString &language) const
{
- return m_description.value(language);
+ return m_descriptions.value(language);
}
QString PackageInfo::icon() const
@@ -131,6 +139,7 @@ QVariantMap PackageInfo::dltConfiguration() const
}
const QDir &PackageInfo::baseDir() const
+
{
return m_baseDir;
}
@@ -171,9 +180,9 @@ void PackageInfo::writeToDataStream(QDataStream &ds) const
}
ds << m_id
- << m_name
+ << m_names
<< m_icon
- << m_description
+ << m_descriptions
<< m_categories
<< m_version
<< m_builtIn
@@ -199,9 +208,9 @@ PackageInfo *PackageInfo::readFromDataStream(QDataStream &ds)
QByteArray installationReport;
ds >> pkg->m_id
- >> pkg->m_name
+ >> pkg->m_names
>> pkg->m_icon
- >> pkg->m_description
+ >> pkg->m_descriptions
>> pkg->m_categories
>> pkg->m_version
>> pkg->m_builtIn
@@ -216,8 +225,11 @@ PackageInfo *PackageInfo::readFromDataStream(QDataStream &ds)
QBuffer buffer(&installationReport);
buffer.open(QBuffer::ReadOnly);
pkg->m_installationReport.reset(new InstallationReport(pkg->id()));
- if (!pkg->m_installationReport->deserialize(&buffer))
+ try {
+ pkg->m_installationReport->deserialize(&buffer);
+ } catch (...) {
pkg->m_installationReport.reset();
+ }
}
return pkg.take();
@@ -279,5 +291,14 @@ bool PackageInfo::isValidIcon(const QString &icon, QString *errorString)
}
}
+QString PackageInfo::manifestPath() const
+{
+ return m_baseDir.filePath(m_manifestName);
+}
+
+PackageInfo *PackageInfo::fromManifest(const QString &manifestPath)
+{
+ return YamlPackageScanner().scan(manifestPath);
+}
QT_END_NAMESPACE_AM
diff --git a/src/application-lib/packageinfo.h b/src/application-lib/packageinfo.h
index 777526f6..dc1708e1 100644
--- a/src/application-lib/packageinfo.h
+++ b/src/application-lib/packageinfo.h
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Contact: https://www.qt.io/licensing/
**
@@ -52,6 +53,8 @@
QT_FORWARD_DECLARE_CLASS(QDataStream)
+class tst_Application;
+
QT_BEGIN_NAMESPACE_AM
class InstallationReport;
@@ -62,7 +65,6 @@ class YamlPackageScanner;
class PackageInfo
{
public:
- PackageInfo();
~PackageInfo();
void validate() const Q_DECL_NOEXCEPT_EXPR(false);
@@ -97,10 +99,17 @@ public:
static bool isValidApplicationId(const QString &appId, QString *errorString = nullptr);
static bool isValidIcon(const QString &icon, QString *errorString = nullptr);
+ QString manifestPath() const;
+
+ static PackageInfo *fromManifest(const QString &manifestPath);
+
private:
+ PackageInfo();
+
+ QString m_manifestName;
QString m_id;
- QMap<QString, QString> m_name; // language -> name
- QMap<QString, QString> m_description; // language -> description
+ QMap<QString, QString> m_names; // language -> name
+ QMap<QString, QString> m_descriptions; // language -> description
QStringList m_categories;
QString m_icon; // relative to info.json location
QString m_version;
diff --git a/src/application-lib/packagescanner.h b/src/application-lib/packagescanner.h
index 55e9ff3a..9e5956d9 100644
--- a/src/application-lib/packagescanner.h
+++ b/src/application-lib/packagescanner.h
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -55,8 +56,6 @@ public:
virtual PackageInfo *scan(const QString &filePath) Q_DECL_NOEXCEPT_EXPR(false) = 0;
- virtual QString metaDataFileName() const = 0;
-
protected:
PackageScanner() = default;
diff --git a/src/application-lib/yamlpackagescanner.cpp b/src/application-lib/yamlpackagescanner.cpp
index 9adbd627..54b937bc 100644
--- a/src/application-lib/yamlpackagescanner.cpp
+++ b/src/application-lib/yamlpackagescanner.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -115,7 +116,11 @@ PackageInfo *YamlPackageScanner::scan(const QString &filePath) Q_DECL_NOEXCEPT_E
QStringList appIds; // duplicate check
QScopedPointer<PackageInfo> pkgInfo(new PackageInfo);
- pkgInfo->setBaseDir(QFileInfo(f).absoluteDir());
+ {
+ QFileInfo fi(f);
+ pkgInfo->m_baseDir = fi.absoluteDir();
+ pkgInfo->m_manifestName = fi.fileName();
+ }
QScopedPointer<ApplicationInfo> legacyAppInfo(legacy ? new ApplicationInfo(pkgInfo.data()) : nullptr);
@@ -136,16 +141,16 @@ PackageInfo *YamlPackageScanner::scan(const QString &filePath) Q_DECL_NOEXCEPT_E
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());
+ pkgInfo->m_names.insert(it.key(), it.value().toString());
- if (pkgInfo->m_name.isEmpty())
+ if (pkgInfo->m_names.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());
+ pkgInfo->m_descriptions.insert(it.key(), it.value().toString());
});
}
fields.emplace_back("categories", false, [&pkgInfo](const QVariant &v) {
@@ -233,9 +238,9 @@ PackageInfo *YamlPackageScanner::scan(const QString &filePath) Q_DECL_NOEXCEPT_E
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");
+ throw Exception(Error::Parse, "applications need to have an id");
if (appIds.contains(id))
- throw Exception(Error::Intents, "found two applications with id %1").arg(id);
+ throw Exception(Error::Parse, "found two applications with the same id %1").arg(id);
appInfo->m_id = id;
});
appFields.emplace_back("code", true, [&appInfo](const QVariant &v) {
@@ -281,6 +286,7 @@ PackageInfo *YamlPackageScanner::scan(const QString &filePath) Q_DECL_NOEXCEPT_E
});
parseMap(appsIt->toMap(), appFields);
+ appIds << appInfo->id();
pkgInfo->m_applications << appInfo.take();
}
});
@@ -313,23 +319,13 @@ PackageInfo *YamlPackageScanner::scan(const QString &filePath) Q_DECL_NOEXCEPT_E
.arg(intentInfo->m_id).arg(visibilityStr);
}
});
- intentFields.emplace_back(legacy ? "handledBy" : "handlingApplicationId", legacy ? false : true, [&pkgInfo, &intentInfo, &appIds](const QVariant &v) {
+ intentFields.emplace_back(legacy ? "handledBy" : "handlingApplicationId", false, [&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);
- }
+ if (appIds.contains(appId)) {
+ intentInfo->m_handlingApplicationId = appId;
} 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);
- }
+ 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) {
@@ -344,12 +340,12 @@ PackageInfo *YamlPackageScanner::scan(const QString &filePath) Q_DECL_NOEXCEPT_E
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());
+ intentInfo->m_names.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());
+ intentInfo->m_descriptions.insert(it.key(), it.value().toString());
});
intentFields.emplace_back("categories", false, [&intentInfo](const QVariant &v) {
intentInfo->m_categories = variantToStringList(v);
@@ -357,6 +353,18 @@ PackageInfo *YamlPackageScanner::scan(const QString &filePath) Q_DECL_NOEXCEPT_E
});
parseMap(intentsIt->toMap(), intentFields);
+
+ if (intentInfo->handlingApplicationId().isEmpty()) {
+ if (legacy) {
+ intentInfo->m_handlingApplicationId = pkgInfo->id();
+ } else 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);
+ }
+ }
+
pkgInfo->m_intents << intentInfo.take();
}
});
@@ -374,10 +382,5 @@ PackageInfo *YamlPackageScanner::scan(const QString &filePath) Q_DECL_NOEXCEPT_E
}
}
-QString YamlPackageScanner::metaDataFileName() const
-{
- return qSL("info.yaml");
-}
-
QT_END_NAMESPACE_AM
diff --git a/src/application-lib/yamlpackagescanner.h b/src/application-lib/yamlpackagescanner.h
index d8eb4e22..cbd8cfcd 100644
--- a/src/application-lib/yamlpackagescanner.h
+++ b/src/application-lib/yamlpackagescanner.h
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -53,7 +54,6 @@ public:
YamlPackageScanner();
PackageInfo *scan(const QString &filePath) Q_DECL_NOEXCEPT_EXPR(false) override;
- QString metaDataFileName() const override;
};
QT_END_NAMESPACE_AM
diff --git a/src/intent-server-lib/intent.cpp b/src/intent-server-lib/intent.cpp
index 4ee207a8..7115050c 100644
--- a/src/intent-server-lib/intent.cpp
+++ b/src/intent-server-lib/intent.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -106,15 +107,6 @@ QT_BEGIN_NAMESPACE_AM
Intent::Intent()
{ }
-Intent::Intent(const Intent &other)
- : m_intentId(other.m_intentId)
- , m_visibility(other.m_visibility)
- , m_requiredCapabilities(other.m_requiredCapabilities)
- , m_parameterMatch(other.m_parameterMatch)
- , m_applicationId(other.m_applicationId)
- , m_backgroundHandlerId(other.m_backgroundHandlerId)
-{ }
-
Intent::Intent(const QString &id, const QString &applicationId, const QString &backgroundHandlerId,
const QStringList &capabilities, Intent::Visibility visibility, const QVariantMap &parameterMatch)
: m_intentId(id)
diff --git a/src/intent-server-lib/intent.h b/src/intent-server-lib/intent.h
index 10f1c8c8..a8d3996e 100644
--- a/src/intent-server-lib/intent.h
+++ b/src/intent-server-lib/intent.h
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -69,7 +70,6 @@ public:
Q_ENUM(Visibility)
Intent();
- Intent(const Intent &other);
QString intentId() const;
Visibility visibility() const;
diff --git a/src/main-lib/applicationinstaller.h b/src/main-lib/applicationinstaller.h
index 978f6ce1..f83ddadb 100644
--- a/src/main-lib/applicationinstaller.h
+++ b/src/main-lib/applicationinstaller.h
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -95,7 +96,7 @@ public:
Q_SCRIPTABLE QString installationLocationIdFromApplication(const QString &applicationId) const
{
auto app = ApplicationManager::instance()->fromId(applicationId);
- if (app && ((!app->package()->isBuiltIn() || app->package()->canBeRevertedToBuiltIn())))
+ if (app && ((!app->package()->isBuiltIn() || app->package()->builtInHasRemovableUpdate())))
return qL1S("internal-0");
return QString();
}
diff --git a/src/main-lib/main.cpp b/src/main-lib/main.cpp
index 1dcfa10f..ce5ff211 100644
--- a/src/main-lib/main.cpp
+++ b/src/main-lib/main.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -94,12 +95,8 @@
#include "logging.h"
#include "main.h"
#include "defaultconfiguration.h"
-#include "applicationinfo.h"
-#include "intentinfo.h"
-#include "packageinfo.h"
#include "applicationmanager.h"
#include "packagemanager.h"
-#include "package.h"
#include "packagedatabase.h"
#include "installationreport.h"
#include "yamlpackagescanner.h"
@@ -245,6 +242,11 @@ void Main::setup(const DefaultConfiguration *cfg, const QStringList &deploymentW
setupSingletons(cfg->containerSelectionConfiguration(), cfg->quickLaunchRuntimesPerContainer(),
cfg->quickLaunchIdleLoad());
+ if (!cfg->disableIntents())
+ setupIntents(cfg->intentTimeouts());
+
+ registerPackages();
+
if (m_installationDir.isEmpty() || cfg->disableInstaller()) {
StartupTimer::instance()->checkpoint("skipping installer");
} else {
@@ -252,9 +254,6 @@ void Main::setup(const DefaultConfiguration *cfg, const QStringList &deploymentW
std::bind(&DefaultConfiguration::applicationUserIdSeparation, cfg,
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
}
- if (!cfg->disableIntents())
- setupIntents(cfg->intentTimeouts());
-
setLibraryPaths(libraryPaths() + cfg->pluginPaths());
setupQmlEngine(cfg->importPaths(), cfg->style());
setupWindowTitle(QString(), cfg->windowIcon());
@@ -459,30 +458,9 @@ void Main::loadPackageDatabase(bool recreateDatabase, const QString &singlePacka
void Main::setupIntents(const QMap<QString, int> &timeouts) Q_DECL_NOEXCEPT_EXPR(false)
{
- m_intentServer = IntentAMImplementation::createIntentServerAndClientInstance(timeouts);
-
- qCDebug(LogSystem) << "Registering intents:";
-
- 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");
+ m_intentServer = IntentAMImplementation::createIntentServerAndClientInstance(m_packageManager,
+ timeouts);
+ StartupTimer::instance()->checkpoint("after IntentServer instantiation");
}
void Main::setupSingletons(const QList<QPair<QString, QString>> &containerSelectionConfiguration,
@@ -490,28 +468,17 @@ void Main::setupSingletons(const QList<QPair<QString, QString>> &containerSelect
qreal quickLaunchIdleLoad) Q_DECL_NOEXCEPT_EXPR(false)
{
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();
- }
- }
-
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!
+ connect(&m_packageManager->internalSignals, &PackageManagerInternalSignals::registerApplication,
+ m_applicationManager, [this](ApplicationInfo *applicationInfo, Package *package) {
+ m_applicationManager->addApplication(applicationInfo, package);
+ qCDebug(LogSystem).nospace().noquote() << " ++ application: " << applicationInfo->id() << " [package: " << package->id() << "]";
+ });
+ connect(&m_packageManager->internalSignals, &PackageManagerInternalSignals::unregisterApplication,
+ m_applicationManager, [this](ApplicationInfo *applicationInfo, Package *package) {
+ m_applicationManager->removeApplication(applicationInfo, package);
+ qCDebug(LogSystem).nospace().noquote() << " -- application: " << applicationInfo->id() << " [package: " << package->id() << "]";
});
if (m_noSecurity)
@@ -590,13 +557,19 @@ 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_packageManager->cleanupBrokenInstallations();
- StartupTimer::instance()->checkpoint("after PackageManager instantiation");
+ StartupTimer::instance()->checkpoint("after installer setup");
#else
Q_UNUSED(caCertificatePaths)
Q_UNUSED(userIdSeparation)
#endif // AM_DISABLE_INSTALLER
}
+void Main::registerPackages()
+{
+ m_packageManager->registerPackages();
+ StartupTimer::instance()->checkpoint("after package registration");
+}
+
void Main::setupQmlEngine(const QStringList &importPaths, const QString &quickControlsStyle)
{
if (!quickControlsStyle.isEmpty())
diff --git a/src/main-lib/main.h b/src/main-lib/main.h
index 703ee7ca..084c6747 100644
--- a/src/main-lib/main.h
+++ b/src/main-lib/main.h
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -121,6 +122,7 @@ protected:
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);
+ void registerPackages();
void setupQmlEngine(const QStringList &importPaths, const QString &quickControlsStyle = QString());
void setupWindowTitle(const QString &title, const QString &iconPath);
diff --git a/src/manager-lib/application.cpp b/src/manager-lib/application.cpp
index 432cc86e..f1a83d10 100644
--- a/src/manager-lib/application.cpp
+++ b/src/manager-lib/application.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -284,6 +285,7 @@ Application::Application(ApplicationInfo *info, Package *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))
@@ -295,6 +297,11 @@ Application::Application(ApplicationInfo *info, Package *package)
if (isBlocked() && (runState == Am::NotRunning))
this->package()->applicationStoppedDueToBlock(id());
});
+
+ connect(package, &Package::stateChanged, this, [this]() {
+ emit stateChanged(state());
+ });
+ connect(package, &Package::bulkChange, this, &Application::bulkChange);
}
bool Application::start(const QString &documentUrl)
@@ -321,7 +328,7 @@ void Application::stop(bool forceKill)
ApplicationInfo *Application::info() const
{
- return m_info.data();
+ return m_info;
}
PackageInfo *Application::packageInfo() const
diff --git a/src/manager-lib/application.h b/src/manager-lib/application.h
index f7ddeae5..46616b1e 100644
--- a/src/manager-lib/application.h
+++ b/src/manager-lib/application.h
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -73,25 +74,27 @@ class Application : public QObject
Q_CLASSINFO("AM-QmlType", "QtApplicationManager.SystemUI/ApplicationObject 2.0 UNCREATABLE")
Q_PROPERTY(QString id READ id CONSTANT)
- Q_PROPERTY(QString runtimeName READ runtimeName NOTIFY bulkChange)
- Q_PROPERTY(QVariantMap runtimeParameters READ runtimeParameters NOTIFY bulkChange)
+ Q_PROPERTY(QString runtimeName READ runtimeName CONSTANT)
+ Q_PROPERTY(QVariantMap runtimeParameters READ runtimeParameters CONSTANT)
Q_PROPERTY(QUrl icon READ icon NOTIFY bulkChange)
- Q_PROPERTY(QString documentUrl READ documentUrl NOTIFY bulkChange) // REMOVE
- Q_PROPERTY(bool builtIn READ isBuiltIn NOTIFY bulkChange)
+ Q_PROPERTY(QString documentUrl READ documentUrl CONSTANT) // REMOVE
+ Q_PROPERTY(bool builtIn READ isBuiltIn CONSTANT)
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) // REMOVE
- Q_PROPERTY(QStringList categories READ categories NOTIFY bulkChange)
- Q_PROPERTY(QVariantMap applicationProperties READ applicationProperties NOTIFY bulkChange)
+ Q_PROPERTY(QStringList capabilities READ capabilities CONSTANT)
+ Q_PROPERTY(QStringList supportedMimeTypes READ supportedMimeTypes CONSTANT) // REMOVE
+ Q_PROPERTY(QStringList categories READ categories CONSTANT)
+ Q_PROPERTY(QVariantMap applicationProperties READ applicationProperties CONSTANT)
Q_PROPERTY(AbstractRuntime *runtime READ currentRuntime NOTIFY runtimeChanged)
Q_PROPERTY(int lastExitCode READ lastExitCode NOTIFY lastExitCodeChanged)
Q_PROPERTY(QT_PREPEND_NAMESPACE_AM(Am::ExitStatus) lastExitStatus READ lastExitStatus NOTIFY lastExitStatusChanged)
- Q_PROPERTY(QString version READ version NOTIFY bulkChange)
- Q_PROPERTY(bool supportsApplicationInterface READ supportsApplicationInterface NOTIFY bulkChange)
+ Q_PROPERTY(QString version READ version CONSTANT)
+ Q_PROPERTY(bool supportsApplicationInterface READ supportsApplicationInterface CONSTANT)
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)
+
+ // legacy, forwarded to Package
+ Q_PROPERTY(State state READ state NOTIFY stateChanged)
Q_PROPERTY(bool blocked READ isBlocked NOTIFY blockedChanged)
public:
@@ -163,7 +166,7 @@ signals:
private:
void setLastExitCodeAndStatus(int exitCode, Am::ExitStatus exitStatus);
- QScopedPointer<ApplicationInfo> m_info;
+ ApplicationInfo *m_info = nullptr;
Package *m_package = nullptr;
AbstractRuntime *m_runtime = nullptr;
diff --git a/src/manager-lib/applicationmanager.cpp b/src/manager-lib/applicationmanager.cpp
index 523211f3..c5cea56d 100644
--- a/src/manager-lib/applicationmanager.cpp
+++ b/src/manager-lib/applicationmanager.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -1365,16 +1366,18 @@ Am::RunState ApplicationManager::applicationRunState(const QString &id) const
return (index < 0) ? Am::NotRunning : d->apps.at(index)->runState();
}
-void ApplicationManager::setApplications(const QVector<Application *> &apps)
+void ApplicationManager::addApplication(ApplicationInfo *appInfo, Package *package)
{
- Q_ASSERT(d->apps.count() == 0);
- for (auto app : apps)
- addApplication(app);
- registerMimeTypes();
-}
+ // check for id clashes outside of the package (the scanner made sure the package itself is
+ // consistent and doesn't have duplicates already)
+ for (Application *checkApp : qAsConst(d->apps)) {
+ if ((checkApp->id() == appInfo->id()) && (checkApp->package() != package)) {
+ throw Exception("found an application with the same id in package %1")
+ .arg(checkApp->packageInfo()->id());
+ }
+ }
-void ApplicationManager::addApplication(Application *app)
-{
+ auto app = new Application(appInfo, package);
QQmlEngine::setObjectOwnership(app, QQmlEngine::CppOwnership);
app->requests.startRequested = [this, app](const QString &documentUrl) {
@@ -1393,8 +1396,45 @@ void ApplicationManager::addApplication(Application *app)
this, [this, app]() {
emitDataChanged(app, QVector<int> { IsBlocked });
});
+ connect(app, &Application::bulkChange,
+ this, [this, app]() {
+ emitDataChanged(app);
+ });
+ beginInsertRows(QModelIndex(), d->apps.count(), d->apps.count());
d->apps << app;
+
+ endInsertRows();
+
+ registerMimeTypes();
+ emit applicationAdded(appInfo->id());
+}
+
+void ApplicationManager::removeApplication(ApplicationInfo *appInfo, Package *package)
+{
+ int index = -1;
+
+ for (int i = 0; i < d->apps.size(); ++i) {
+ if (d->apps.at(i)->info() == appInfo) {
+ index = i;
+ break;
+ }
+ }
+ if (index < 0)
+ return;
+
+ Q_ASSERT(d->apps.at(index)->package() == package);
+
+ emit applicationAboutToBeRemoved(appInfo->id());
+
+ beginRemoveRows(QModelIndex(), index, index);
+ auto app = d->apps.takeAt(index);
+
+ endRemoveRows();
+
+ registerMimeTypes();
+
+ delete app;
}
QT_END_NAMESPACE_AM
diff --git a/src/manager-lib/applicationmanager.h b/src/manager-lib/applicationmanager.h
index 5513f119..9835d126 100644
--- a/src/manager-lib/applicationmanager.h
+++ b/src/manager-lib/applicationmanager.h
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -65,8 +66,6 @@ class ApplicationManagerInternalSignals : public QObject
{
Q_OBJECT
signals:
- // Emitted after an application is installed, updated, downgraded or removed
- void applicationsChanged();
// Emitted every time a new Runtime object is created
void newRuntimeCreated(QT_PREPEND_NAMESPACE_AM(AbstractRuntime) *runtime);
};
@@ -98,11 +97,8 @@ public:
QVariantMap systemProperties() const;
void setSystemProperties(const QVariantMap &map);
- // 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<Application *> &apps);
-
+ void addApplication(ApplicationInfo *appInfo, Package *package);
+ void removeApplication(ApplicationInfo *appInfo, Package *package);
QVector<Application *> applications() const;
Application *fromId(const QString &id) const;
@@ -182,7 +178,6 @@ signals:
private slots:
void openUrlRelay(const QUrl &url);
- void addApplication(Application *app);
private:
void emitDataChanged(Application *app, const QVector<int> &roles = QVector<int>());
diff --git a/src/manager-lib/applicationmanager_p.h b/src/manager-lib/applicationmanager_p.h
index ad0ef7df..5ba28b3d 100644
--- a/src/manager-lib/applicationmanager_p.h
+++ b/src/manager-lib/applicationmanager_p.h
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -60,7 +61,6 @@ public:
bool windowManagerCompositorReady = false;
QVariantMap systemProperties;
- QVector<PackageInfo> packages;
QVector<Application *> apps;
QString currentLocale;
diff --git a/src/manager-lib/installationtask.cpp b/src/manager-lib/installationtask.cpp
index 30cbc74a..ef907eb5 100644
--- a/src/manager-lib/installationtask.cpp
+++ b/src/manager-lib/installationtask.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -47,7 +48,6 @@
#include "packagemanager_p.h"
#include "packageinfo.h"
#include "packageextractor.h"
-#include "yamlpackagescanner.h"
#include "exception.h"
#include "packagemanager.h"
#include "sudo.h"
@@ -285,8 +285,7 @@ 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);
- YamlPackageScanner yps;
- m_package.reset(yps.scan(m_extractor->destinationDirectory().absoluteFilePath(file)));
+ m_package.reset(PackageInfo::fromManifest(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");
diff --git a/src/manager-lib/intentaminterface.cpp b/src/manager-lib/intentaminterface.cpp
index f787226a..fe1ea01c 100644
--- a/src/manager-lib/intentaminterface.cpp
+++ b/src/manager-lib/intentaminterface.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -68,6 +69,8 @@
#include "qmlinprocessruntime.h"
#include "application.h"
#include "applicationmanager.h"
+#include "package.h"
+#include "packagemanager.h"
#include "applicationinfo.h"
QT_BEGIN_NAMESPACE_AM
@@ -79,7 +82,8 @@ static QString sysUiId = qSL(":sysui:");
// vvv IntentAMImplementation vvv
-IntentServer *IntentAMImplementation::createIntentServerAndClientInstance(const QMap<QString, int> &timeouts)
+IntentServer *IntentAMImplementation::createIntentServerAndClientInstance(PackageManager *packageManager,
+ const QMap<QString, int> &timeouts)
{
auto intentServerAMInterface = new IntentServerAMImplementation;
auto intentClientAMInterface = new IntentClientAMImplementation(intentServerAMInterface);
@@ -108,14 +112,55 @@ IntentServer *IntentAMImplementation::createIntentServerAndClientInstance(const
if (it != timeouts.cend())
intentClient->setReplyFromSystemTimeout(it.value());
-
-
// this way, deleting the server (the return value of this factory function) will get rid
// of both client and server as well as both their AM interfaces
intentClient->setParent(intentServer);
+
+ // connect the APIs of the PackageManager and the IntentServer
+ // the Intent API does not use AM internal types, so we have to translate using id strings:
+ // the idea behind this is that the Intent subsystem could be useful outside of the AM as well,
+ // so we try not to use AM specific classes in the intent-server and intent-client modules.
+ QObject::connect(packageManager, &PackageManager::packageAdded,
+ intentServer, &IntentServer::addPackage);
+ QObject::connect(packageManager, &PackageManager::packageAboutToBeRemoved,
+ intentServer, &IntentServer::removePackage);
+
+ QObject::connect(&packageManager->internalSignals, &PackageManagerInternalSignals::registerApplication,
+ intentServer, [intentServer](ApplicationInfo *applicationInfo, Package *package) {
+ intentServer->addApplication(applicationInfo->id(), package->id());
+ });
+ QObject::connect(&packageManager->internalSignals, &PackageManagerInternalSignals::unregisterApplication,
+ intentServer, [intentServer](ApplicationInfo *applicationInfo, Package *package) {
+ intentServer->removeApplication(applicationInfo->id(), package->id());
+ });
+
+ QObject::connect(&packageManager->internalSignals, &PackageManagerInternalSignals::registerIntent,
+ intentServer, [intentServer](IntentInfo *intentInfo, Package *package) {
+
+ if (!intentServer->addIntent(intentInfo->id(), package->id(), intentInfo->handlingApplicationId(),
+ intentInfo->requiredCapabilities(),
+ intentInfo->visibility() == IntentInfo::Public ? Intent::Public
+ : Intent::Private,
+ intentInfo->parameterMatch(), intentInfo->names(),
+ QUrl::fromLocalFile(package->info()->baseDir().absoluteFilePath(intentInfo->icon())),
+ intentInfo->categories())) {
+ throw Exception(Error::Intents, "could not add intent %1 for package %2")
+ .arg(intentInfo->id()).arg(package->id());
+ }
+ qCDebug(LogSystem).nospace().noquote() << " ++ intent: " << intentInfo->id() << " [package: " << package->id() << "]";
+ });
+ QObject::connect(&packageManager->internalSignals, &PackageManagerInternalSignals::unregisterIntent,
+ intentServer, [intentServer](IntentInfo *intentInfo, Package *package) {
+ Intent *intent = intentServer->packageIntent(intentInfo->id(), package->id(),
+ intentInfo->parameterMatch());
+ qCDebug(LogSystem).nospace().noquote() << " -- intent: " << intentInfo->id() << " [package: " << package->id() << "]";
+ Q_ASSERT(intent);
+ intentServer->removeIntent(intent);
+ });
return intentServer;
}
+
// ^^^ IntentAMImplementation ^^^
//////////////////////////////////////////////////////////////////////////
// vvv IntentServerAMImplementation vvv
diff --git a/src/manager-lib/intentaminterface.h b/src/manager-lib/intentaminterface.h
index f026bbd4..6363516e 100644
--- a/src/manager-lib/intentaminterface.h
+++ b/src/manager-lib/intentaminterface.h
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -54,17 +55,18 @@
#include <QtAppManCommon/global.h>
#include <QtAppManIntentServer/intentserversysteminterface.h>
#include <QtAppManIntentClient/intentclientsysteminterface.h>
+#include <QtAppManApplication/intentinfo.h>
class IntentInterfaceAdaptor;
QT_BEGIN_NAMESPACE_AM
class Application;
-class PackageInfo;
+class PackageManager;
class IntentServerRequest;
namespace IntentAMImplementation {
-IntentServer *createIntentServerAndClientInstance(const QMap<QString, int> &timeouts);
+IntentServer *createIntentServerAndClientInstance(PackageManager *packageManager, const QMap<QString, int> &timeouts);
}
// the server side
diff --git a/src/manager-lib/package.cpp b/src/manager-lib/package.cpp
index d51ed794..7ad4b1cf 100644
--- a/src/manager-lib/package.cpp
+++ b/src/manager-lib/package.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -60,7 +61,12 @@ QString Package::id() const
bool Package::isBuiltIn() const
{
- return info()->isBuiltIn();
+ return m_info->isBuiltIn();
+}
+
+bool Package::builtInHasRemovableUpdate() const
+{
+ return isBuiltIn() && m_updatedInfo;
}
QString Package::version() const
@@ -156,39 +162,40 @@ void Package::setProgress(qreal progress)
m_progress = progress;
}
-
-void Package::setBaseInfo(PackageInfo *info)
-{
- m_info.reset(info);
- emit bulkChange();
-}
-
-void Package::setUpdatedInfo(PackageInfo *info)
+PackageInfo *Package::info() const
{
- Q_ASSERT(!info || (m_info && info->id() == m_info->id()));
-
- m_updatedInfo.reset(info);
- emit bulkChange();
+ return m_updatedInfo ? m_updatedInfo : m_info;
}
-PackageInfo *Package::info() const
+PackageInfo *Package::baseInfo() const
{
- return m_updatedInfo ? m_updatedInfo.data() : m_info.data();
+ return m_info;
}
PackageInfo *Package::updatedInfo() const
{
- return m_updatedInfo.data();
+ return m_updatedInfo;
}
-PackageInfo *Package::takeBaseInfo()
+PackageInfo *Package::setUpdatedInfo(PackageInfo *info)
{
- return m_info.take();
+ Q_ASSERT(!info || (m_info && info->id() == m_info->id()));
+ Q_ASSERT(info != m_updatedInfo);
+
+ auto old = m_updatedInfo;
+ m_updatedInfo = info;
+ emit bulkChange();
+ return old;
}
-bool Package::canBeRevertedToBuiltIn() const
+PackageInfo *Package::setBaseInfo(PackageInfo *info)
{
- return m_info && m_updatedInfo;
+ Q_ASSERT(info != m_info);
+
+ auto old = m_info;
+ m_info = info;
+ emit bulkChange();
+ return old;
}
bool Package::isBlocked() const
@@ -200,8 +207,8 @@ bool Package::block()
{
bool blockedNow = (m_blocked.fetchAndAddOrdered(1) == 0);
if (blockedNow) {
- emit blockedChanged(true);
m_blockedApps = info()->applications();
+ emit blockedChanged(true);
}
return blockedNow;
}
diff --git a/src/manager-lib/package.h b/src/manager-lib/package.h
index bf5fd4c2..690059f0 100644
--- a/src/manager-lib/package.h
+++ b/src/manager-lib/package.h
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -58,11 +59,12 @@ class Package : public QObject
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(bool builtInHasRemovableUpdate READ builtInHasRemovableUpdate 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(QString description READ description 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)
@@ -82,6 +84,7 @@ public:
QString id() const;
bool isBuiltIn() const;
+ bool builtInHasRemovableUpdate() const;
QUrl icon() const;
QString version() const;
QString name() const;
@@ -96,10 +99,6 @@ public:
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.
@@ -114,15 +113,13 @@ public:
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 *baseInfo() const;
PackageInfo *updatedInfo() const;
- PackageInfo *takeBaseInfo();
-
- bool canBeRevertedToBuiltIn() const;
+ PackageInfo *setUpdatedInfo(PackageInfo *info);
+ PackageInfo *setBaseInfo(PackageInfo *info);
bool isBlocked() const;
bool block();
@@ -139,8 +136,8 @@ signals:
void blockedChanged(bool blocked);
private:
- QScopedPointer<PackageInfo> m_info;
- QScopedPointer<PackageInfo> m_updatedInfo;
+ PackageInfo *m_info = nullptr;
+ PackageInfo *m_updatedInfo = nullptr;
State m_state = Installed;
qreal m_progress = 0;
diff --git a/src/manager-lib/packagemanager.cpp b/src/manager-lib/packagemanager.cpp
index bd0d70f8..1a8dcaca 100644
--- a/src/manager-lib/packagemanager.cpp
+++ b/src/manager-lib/packagemanager.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -46,6 +47,8 @@
#include "packagemanager.h"
#include "packagedatabase.h"
#include "packagemanager_p.h"
+#include "applicationinfo.h"
+#include "intentinfo.h"
#include "package.h"
#include "logging.h"
#include "installationreport.h"
@@ -100,47 +103,147 @@ PackageManager *PackageManager::createInstance(PackageDatabase *packageDatabase,
QScopedPointer<PackageManager> pm(new PackageManager(packageDatabase, documentPath));
registerQmlTypes();
+ 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();
+}
+
+void PackageManager::registerPackages()
+{
+ qCDebug(LogSystem) << "Registering packages:";
+
+ // collect all updates to builtin first, so we can avoid re-creating a lot of objects,
+ // if we find an update to a builin app later on
+ QMap<QString, QPair<PackageInfo *, PackageInfo *>> pkgs;
+
// map all the built-in packages first
- const auto builtinPackages = packageDatabase->builtInPackages();
+ const auto builtinPackages = d->database->builtInPackages();
for (auto packageInfo : builtinPackages) {
- auto *package = new Package(packageInfo);
- QQmlEngine::setObjectOwnership(package, QQmlEngine::CppOwnership);
- pm->d->packages << package;
+ if (Package *existingPackage = fromId(packageInfo->id())) {
+ throw Exception(Error::Package, "Found more than one built-in package with id '%1': here: %2 and there: %3")
+ .arg(packageInfo->id())
+ .arg(existingPackage->info()->manifestPath())
+ .arg(packageInfo->manifestPath());
+ }
+ pkgs.insert(packageInfo->id(), qMakePair(packageInfo, nullptr));
}
// next, map all the installed packages, making sure to detect updates to built-in ones
- const auto installedPackages = packageDatabase->installedPackages();
+ const auto installedPackages = d->database->installedPackages();
for (auto packageInfo : installedPackages) {
- Package *builtInPackage = pm->fromId(packageInfo->id());
+ auto existingPackageInfos = pkgs.value(packageInfo->id());
+ if (existingPackageInfos.first) {
+ if (existingPackageInfos.first->isBuiltIn()) { // update
+ if (existingPackageInfos.second) { // but there already is an update applied!?
+ throw Exception(Error::Package, "Found more than one update for the built-in package with id '%1' here: %2 and there: %3")
+ .arg(packageInfo->id())
+ .arg(existingPackageInfos.second->manifestPath())
+ .arg(packageInfo->manifestPath());
+ }
+ pkgs[packageInfo->id()] = qMakePair(existingPackageInfos.first, packageInfo);
- 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?
+ } else {
+ throw Exception(Error::Package, "Found more than one installed package with the same id '%1' here: %2 and there: %3")
+ .arg(packageInfo->id())
+ .arg(existingPackageInfos.first->manifestPath())
+ .arg(packageInfo->manifestPath());
}
- builtInPackage->setUpdatedInfo(packageInfo);
} else {
- auto *package = new Package(packageInfo);
- QQmlEngine::setObjectOwnership(package, QQmlEngine::CppOwnership);
- pm->d->packages << package;
+ pkgs.insert(packageInfo->id(), qMakePair(packageInfo, nullptr));
}
}
+ for (auto it = pkgs.constBegin(); it != pkgs.constEnd(); ++it)
+ registerPackage(it.value().first, it.value().second);
+}
+
+void PackageManager::registerPackage(PackageInfo *packageInfo, PackageInfo *updatedPackageInfo,
+ bool currentlyBeingInstalled)
+{
+ auto *package = new Package(packageInfo, currentlyBeingInstalled ? Package::BeingInstalled
+ : Package::Installed);
+ if (updatedPackageInfo)
+ package->setUpdatedInfo(updatedPackageInfo);
+
+ QQmlEngine::setObjectOwnership(package, QQmlEngine::CppOwnership);
+
+ if (currentlyBeingInstalled) {
+ Q_ASSERT(package->block());
+
+ beginInsertRows(QModelIndex(), d->packages.count(), d->packages.count());
+ qCDebug(LogSystem) << "Installing package:";
+ }
- return s_instance = pm.take();
+ d->packages << package;
+
+ qCDebug(LogSystem).nospace().noquote() << " + package: " << package->id() << " [at: "
+ << QDir().relativeFilePath(package->info()->baseDir().path()) << "]";
+
+ if (currentlyBeingInstalled) {
+ endInsertRows();
+ emitDataChanged(package);
+ }
+
+ emit packageAdded(package->id());
+
+ if (!currentlyBeingInstalled)
+ registerApplicationsAndIntentsOfPackage(package);
}
-PackageManager *PackageManager::instance()
+void PackageManager::registerApplicationsAndIntentsOfPackage(Package *package)
{
- if (!s_instance)
- qFatal("PackageManager::instance() was called before createInstance().");
- return s_instance;
+ const auto appInfos = package->info()->applications();
+ for (auto appInfo : appInfos) {
+ try {
+ emit internalSignals.registerApplication(appInfo, package);
+ } catch (const Exception &e) {
+ qCWarning(LogSystem) << "Cannot register application" << appInfo->id() << ":"
+ << e.errorString();
+ }
+ }
+
+ const auto intentInfos = package->info()->intents();
+ for (auto intentInfo : intentInfos) {
+ try {
+ emit internalSignals.registerIntent(intentInfo, package);
+ } catch (const Exception &e) {
+ qCWarning(LogSystem) << "Cannot register intent" << intentInfo->id() << ":"
+ << e.errorString();
+ }
+ }
}
-QObject *PackageManager::instanceForQml(QQmlEngine *, QJSEngine *)
+void PackageManager::unregisterApplicationsAndIntentsOfPackage(Package *package)
{
- QQmlEngine::setObjectOwnership(instance(), QQmlEngine::CppOwnership);
- return instance();
+ const auto intentInfos = package->info()->intents();
+ for (auto intentInfo : intentInfos) {
+ try {
+ emit internalSignals.unregisterIntent(intentInfo, package); // not throwing ATM
+ } catch (const Exception &e) {
+ qCWarning(LogSystem) << "Cannot unregister intent" << intentInfo->id() << ":"
+ << e.errorString();
+ }
+ }
+
+ const auto appInfos = package->info()->applications();
+ for (auto appInfo : appInfos) {
+ try {
+ emit internalSignals.unregisterApplication(appInfo, package); // not throwing ATM
+ } catch (const Exception &e) {
+ qCWarning(LogSystem) << "Cannot unregister application" << appInfo->id() << ":"
+ << e.errorString();
+ }
+ }
}
QVector<Package *> PackageManager::packages() const
@@ -180,6 +283,7 @@ PackageManager::PackageManager(PackageDatabase *packageDatabase,
PackageManager::~PackageManager()
{
+ qDeleteAll(d->packages);
delete d->database;
delete d;
s_instance = nullptr;
@@ -517,14 +621,13 @@ void PackageManager::cleanupBrokenInstallations() Q_DECL_NOEXCEPT_EXPR(false)
if (ir) {
bool valid = true;
- QString pkgDir = d->installationPath + pkg->id();
+ QString pkgDir = d->installationPath + QDir::separator() + 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);
@@ -544,8 +647,8 @@ void PackageManager::cleanupBrokenInstallations() Q_DECL_NOEXCEPT_EXPR(false)
}
if (valid) {
- validPaths.insertMulti(d->installationPath, pkg->id() + qL1C('/'));
- validPaths.insertMulti(d->documentPath, pkg->id() + qL1C('/'));
+ validPaths.insertMulti(d->installationPath, pkg->id() + QDir::separator());
+ validPaths.insertMulti(d->documentPath, pkg->id() + QDir::separator());
} else {
if (startingPackageRemoval(pkg->id())) {
if (finishedPackageInstall(pkg->id()))
@@ -572,7 +675,7 @@ void PackageManager::cleanupBrokenInstallations() Q_DECL_NOEXCEPT_EXPR(false)
for (const QFileInfo &fi : dirEntries) {
QString name = fi.fileName();
if (fi.isDir())
- name.append(qL1C('/'));
+ name.append(QDir::separator());
if ((!fi.isDir() && !fi.isFile()) || !validNames.contains(name)) {
qCDebug(LogInstaller) << "cleanup: removing unreferenced inode" << name;
@@ -1030,42 +1133,22 @@ bool PackageManager::startingPackageInstallation(PackageInfo *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());
- }
+ // do not overwrite the base-info / update-info yet - only after a successful installation
+ d->pendingPackageInfoUpdates.insert(package, 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());
+ // add a new package to the model and block it
+ registerPackage(newInfo.take(), nullptr, true);
}
return true;
}
@@ -1079,14 +1162,14 @@ bool PackageManager::startingPackageRemoval(const QString &id)
if (package->isBlocked() || (package->state() != Package::Installed))
return false;
- if (package->isBuiltIn() && !package->canBeRevertedToBuiltIn())
+ if (package->isBuiltIn() && !package->builtInHasRemovableUpdate())
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->setState(package->builtInHasRemovableUpdate() ? Package::BeingDowngraded
+ : Package::BeingRemoved);
package->setProgress(0);
emitDataChanged(package, QVector<int> { IsUpdating });
@@ -1103,33 +1186,73 @@ bool PackageManager::finishedPackageInstall(const QString &id)
case Package::Installed:
return false;
+ case Package::BeingUpdated:
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;
+ case Package::BeingDowngraded: {
+ bool isUpdate = (package->state() == Package::BeingUpdated);
+ bool isDowngrade = (package->state() == Package::BeingDowngraded);
+
+ // figure out what the new info is
+ PackageInfo *newPackageInfo;
+ if (isUpdate)
+ newPackageInfo = d->pendingPackageInfoUpdates.take(package);
+ else if (isDowngrade)
+ newPackageInfo = nullptr;
+ else
+ newPackageInfo = package->baseInfo();
+
+ // attach the installation report (unless we're just downgrading a built-in)
+ if (!isDowngrade) {
+ QFile irfile(newPackageInfo->baseDir().absoluteFilePath(qSL(".installation-report.yaml")));
+ QScopedPointer<InstallationReport> ir(new InstallationReport(package->id()));
+ irfile.open(QFile::ReadOnly);
+ try {
+ ir->deserialize(&irfile);
+ } catch (const Exception &e) {
+ qCCritical(LogInstaller) << "Could not read the new installation-report for package"
+ << package->id() << "at" << irfile.fileName() << ":"
+ << e.errorString();
+ return false;
+ }
+ newPackageInfo->setInstallationReport(ir.take());
}
- package->info()->setInstallationReport(ir.take());
+
+ if (isUpdate || isDowngrade) {
+ // unregister all the old apps & intents
+ unregisterApplicationsAndIntentsOfPackage(package);
+
+ // update the correct base/updated info pointer
+ PackageInfo *oldPackageInfo;
+ if (package->isBuiltIn())
+ oldPackageInfo = package->setUpdatedInfo(newPackageInfo);
+ else
+ oldPackageInfo = package->setBaseInfo(newPackageInfo);
+
+ if (oldPackageInfo)
+ d->database->removePackageInfo(oldPackageInfo);
+ }
+
+ // add the new info to the package db
+ if (newPackageInfo)
+ d->database->addPackageInfo(newPackageInfo);
+
+ // register all the apps & intents
+ registerApplicationsAndIntentsOfPackage(package);
+
+ // boiler-plate cleanup code
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: {
+ // unregister all the apps & intents
+ unregisterApplicationsAndIntentsOfPackage(package);
+
+ // remove the package from the model
int row = d->packages.indexOf(package);
if (row >= 0) {
emit packageAboutToBeRemoved(package->id());
@@ -1137,13 +1260,17 @@ bool PackageManager::finishedPackageInstall(const QString &id)
d->packages.removeAt(row);
endRemoveRows();
}
+
+ // cleanup
+ package->unblock();
delete package;
+
+ // remove the package from the package db
+ d->database->removePackageInfo(package->info());
break;
}
}
- //emit internalSignals.applicationsChanged();
-
return true;
}
@@ -1165,6 +1292,7 @@ bool PackageManager::canceledPackageInstall(const QString &id)
d->packages.removeAt(row);
endRemoveRows();
}
+ package->unblock();
delete package;
break;
}
diff --git a/src/manager-lib/packagemanager.h b/src/manager-lib/packagemanager.h
index fb1cb2ee..082fc5e3 100644
--- a/src/manager-lib/packagemanager.h
+++ b/src/manager-lib/packagemanager.h
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -60,6 +61,21 @@ class PackageDatabase;
class Package;
class PackageManagerPrivate;
+// A place to collect signals used internally by appman without polluting
+// PackageManager's public QML API.
+class PackageManagerInternalSignals : public QObject
+{
+ Q_OBJECT
+signals:
+ // the slots connected to these signals are allowed to throw Exception objects, if the
+ // connection is direct!
+ void registerApplication(ApplicationInfo *applicationInfo, Package *package);
+ void unregisterApplication(ApplicationInfo *applicationInfo, Package *package);
+
+ void registerIntent(IntentInfo *intentInfo, Package *package);
+ void unregisterIntent(IntentInfo *intentInfo, Package *package);
+};
+
class PackageManager : public QAbstractListModel
{
Q_OBJECT
@@ -79,6 +95,8 @@ class PackageManager : public QAbstractListModel
Q_PROPERTY(uint commonApplicationGroupId READ commonApplicationGroupId)
public:
+ Q_ENUMS(QT_PREPEND_NAMESPACE_AM(AsynchronousTask::TaskState))
+
enum CacheMode {
NoCache,
UseCache,
@@ -91,6 +109,8 @@ public:
static PackageManager *instance();
static QObject *instanceForQml(QQmlEngine *qmlEngine, QJSEngine *);
+ void registerPackages();
+
QVector<Package *> packages() const;
Package *fromId(const QString &id) const;
@@ -150,6 +170,7 @@ public:
Q_SCRIPTABLE int compareVersions(const QString &version1, const QString &version2);
Q_SCRIPTABLE bool validateDnsName(const QString &name, int minimumParts = 1);
+ PackageManagerInternalSignals internalSignals;
signals:
Q_SCRIPTABLE void countChanged();
@@ -183,6 +204,10 @@ protected:
private:
void emitDataChanged(Package *package, const QVector<int> &roles = QVector<int>());
+ void registerPackage(PackageInfo *packageInfo, PackageInfo *updatedPackageInfo,
+ bool currentlyBeingInstalled = false);
+ void registerApplicationsAndIntentsOfPackage(Package *package);
+ void unregisterApplicationsAndIntentsOfPackage(Package *package);
static void registerQmlTypes();
void triggerExecuteNextTask();
diff --git a/src/manager-lib/packagemanager_p.h b/src/manager-lib/packagemanager_p.h
index 4e7a158b..b841a3c1 100644
--- a/src/manager-lib/packagemanager_p.h
+++ b/src/manager-lib/packagemanager_p.h
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -63,6 +64,8 @@ public:
PackageDatabase *database = nullptr;
QVector<Package *> packages;
+ QMap<Package *, PackageInfo *> pendingPackageInfoUpdates;
+
bool developmentMode = false;
bool allowInstallationOfUnsignedPackages = false;
bool userIdSeparation = false;
diff --git a/src/src.pro b/src/src.pro
index b5e66223..17746233 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -61,7 +61,7 @@ tools_testrunner.subdir = tools/testrunner
tools_testrunner.depends = main_lib
tools_dumpqmltypes.subdir = tools/dumpqmltypes
-tools_dumpqmltypes.depends = manager_lib window_lib shared_main_lib main_lib launcher_lib
+tools_dumpqmltypes.depends = manager_lib intent_server_lib window_lib shared_main_lib launcher_lib main_lib
tools_packager.subdir = tools/packager
tools_packager.depends = package_lib application_lib crypto_lib
diff --git a/src/tools/launcher-qml/launcher-qml.cpp b/src/tools/launcher-qml/launcher-qml.cpp
index c3eb49db..bbcf6d58 100644
--- a/src/tools/launcher-qml/launcher-qml.cpp
+++ b/src/tools/launcher-qml/launcher-qml.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -84,6 +85,7 @@
#include "exception.h"
#include "crashhandler.h"
#include "yamlpackagescanner.h"
+#include "packageinfo.h"
#include "applicationinfo.h"
#include "startupinterface.h"
#include "dbus-utilities.h"
@@ -134,13 +136,13 @@ int main(int argc, char *argv[])
clp.addHelpOption();
clp.addOption({ qSL("qml-debug"), qSL("Enables QML debugging and profiling.") });
clp.addOption({ qSL("quicklaunch"), qSL("Starts the launcher in the quicklaunching mode.") });
- clp.addOption({ qSL("directload") , qSL("The info.yaml to start."), qSL("info.yaml") });
+ clp.addOption({ qSL("directload") , qSL("The info.yaml to start (you can add '@<appid>' to start a specific app within the package, instead of the first one)."), qSL("info.yaml") });
clp.process(a);
bool quicklaunched = clp.isSet(qSL("quicklaunch"));
- QString directLoad = clp.value(qSL("directload"));
+ QString directLoadManifest = clp.value(qSL("directload"));
- if (directLoad.isEmpty())
+ if (directLoadManifest.isEmpty())
a.loadConfiguration();
CrashHandler::setCrashActionConfiguration(a.runtimeConfiguration().value(qSL("crashAction")).toMap());
@@ -152,17 +154,25 @@ int main(int argc, char *argv[])
StartupTimer::instance()->checkpoint("after basic initialization");
- if (!directLoad.isEmpty()) {
- QFileInfo fi(directLoad);
+ if (!directLoadManifest.isEmpty()) {
+ QString directLoadAppId;
+ int appPos = directLoadManifest.indexOf(qSL("@"));
+ if (appPos > 0) {
+ directLoadAppId = directLoadManifest.mid(appPos + 1);
+ directLoadManifest.truncate(appPos);
+ }
+
+ QFileInfo fi(directLoadManifest);
if (!fi.exists() || fi.fileName() != qSL("info.yaml"))
throw Exception("--directload needs a valid info.yaml file as parameter");
- directLoad = fi.absoluteFilePath();
+ directLoadManifest = fi.absoluteFilePath();
+ new Controller(&a, quicklaunched, qMakePair(directLoadManifest, directLoadAppId));
} else {
a.setupDBusConnections();
StartupTimer::instance()->checkpoint("after dbus initialization");
+ new Controller(&a, quicklaunched);
}
- new Controller(&a, quicklaunched, directLoad);
return a.exec();
} catch (const std::exception &e) {
@@ -171,8 +181,11 @@ int main(int argc, char *argv[])
}
}
+Controller::Controller(LauncherMain *a, bool quickLaunched)
+ : Controller(a, quickLaunched, qMakePair(QString{}, QString{}))
+{ }
-Controller::Controller(LauncherMain *a, bool quickLaunched, const QString &directLoad)
+Controller::Controller(LauncherMain *a, bool quickLaunched, const QPair<QString, QString> &directLoad)
: QObject(a)
, m_quickLaunched(quickLaunched)
{
@@ -271,7 +284,7 @@ Controller::Controller(LauncherMain *a, bool quickLaunched, const QString &direc
}
}
- if (directLoad.isEmpty()) {
+ if (directLoad.first.isEmpty()) {
m_applicationInterface = new QmlApplicationInterface(a->p2pDBusName(), a->notificationDBusName(), this);
connect(m_applicationInterface, &QmlApplicationInterface::startApplication,
this, &Controller::startApplication);
@@ -280,15 +293,32 @@ Controller::Controller(LauncherMain *a, bool quickLaunched, const QString &direc
} else {
QMetaObject::invokeMethod(this, [this, directLoad]() {
- QFileInfo fi(directLoad);
- YamlPackageScanner yps;
+ PackageInfo *pi;
try {
- //TODO: how should this work?
-// ApplicationInfo *a = yps.scan(directLoad);
-// startApplication(fi.absolutePath(), a->codeFilePath(), QString(), QString(), a->toVariantMap(), QVariantMap());
+ pi = YamlPackageScanner().scan(directLoad.first);
} catch (const Exception &e) {
- throw Exception("Could not parse info.yaml file: %1").arg(e.what());
+ qCCritical(LogQmlRuntime) << "Could not parse info.yaml file:" << e.what();
+ QCoreApplication::exit(20);
+ return;
}
+ const auto apps = pi->applications();
+ const ApplicationInfo *a = apps.constFirst();
+ if (!directLoad.second.isEmpty()) {
+ auto it = std::find_if(apps.cbegin(), apps.cend(),
+ [appId = directLoad.second](ApplicationInfo *appInfo) -> bool {
+ return (appInfo->id() == appId);
+ });
+ if (it == apps.end()) {
+ qCCritical(LogQmlRuntime) << "Could not find the requested application id"
+ << directLoad.second << "within the info.yaml file";
+ QCoreApplication::exit(21);
+ return;
+ }
+ a = *it;
+ }
+
+ startApplication(QFileInfo(directLoad.first).absolutePath(), a->codeFilePath(),
+ QString(), QString(), a->toVariantMap(), QVariantMap());
}, Qt::QueuedConnection);
}
diff --git a/src/tools/launcher-qml/launcher-qml_p.h b/src/tools/launcher-qml/launcher-qml_p.h
index 2ae2e8cf..abacfa57 100644
--- a/src/tools/launcher-qml/launcher-qml_p.h
+++ b/src/tools/launcher-qml/launcher-qml_p.h
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -74,7 +75,8 @@ class Controller : public QObject
Q_OBJECT
public:
- Controller(LauncherMain *a, bool quickLaunched, const QString &directLoad = QString());
+ Controller(LauncherMain *a, bool quickLaunched);
+ Controller(LauncherMain *a, bool quickLaunched, const QPair<QString, QString> &directLoad);
public slots:
void startApplication(const QString &baseDir, const QString &qmlFile, const QString &document,
diff --git a/src/tools/packager/packagingjob.cpp b/src/tools/packager/packagingjob.cpp
index f8868788..53c35a7f 100644
--- a/src/tools/packager/packagingjob.cpp
+++ b/src/tools/packager/packagingjob.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -46,7 +47,6 @@
#include "applicationinfo.h"
#include "intentinfo.h"
#include "installationreport.h"
-#include "yamlpackagescanner.h"
#include "packageextractor.h"
#include "packagecreator.h"
@@ -151,9 +151,8 @@ void PackagingJob::execute() Q_DECL_NOEXCEPT_EXPR(false)
throw Exception(Error::Package, "source %1 is not a directory").arg(m_sourceDir);
// check metadata
- YamlPackageScanner yps;
- QString infoName = yps.metaDataFileName();
- QScopedPointer<PackageInfo> package(yps.scan(source.absoluteFilePath(infoName)));
+ QString infoName = qSL("info.yaml");
+ QScopedPointer<PackageInfo> package(PackageInfo::fromManifest(source.absoluteFilePath(infoName)));
// build report
InstallationReport report(package->id());
diff --git a/tests/application/application.pro b/tests/application/application.pro
index cc13702e..2bdaf9c5 100644
--- a/tests/application/application.pro
+++ b/tests/application/application.pro
@@ -8,3 +8,6 @@ QT *= \
appman_manager-private \
SOURCES += tst_application.cpp
+
+OTHER_FILES += info.yaml
+RESOURCES += tst_application.qrc
diff --git a/tests/application/icon.png b/tests/application/icon.png
new file mode 100644
index 00000000..909c66db
--- /dev/null
+++ b/tests/application/icon.png
Binary files differ
diff --git a/tests/application/info.yaml b/tests/application/info.yaml
new file mode 100644
index 00000000..08329bb8
--- /dev/null
+++ b/tests/application/info.yaml
@@ -0,0 +1,10 @@
+formatType: am-package
+formatVersion: 1
+---
+id: pkg.test
+name: { en: "Test Package" }
+icon: icon.png
+applications:
+- id: app.test
+ runtime: qml
+ code: info.yaml # just to make the test simpler
diff --git a/tests/application/tst_application.cpp b/tests/application/tst_application.cpp
index bbfaa6cb..20ae20ac 100644
--- a/tests/application/tst_application.cpp
+++ b/tests/application/tst_application.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -106,7 +107,7 @@ private slots:
// the application no longer holds a reference to it
void tst_Application::runtimeDestroyed()
{
- auto pi = new PackageInfo;
+ auto pi = PackageInfo::fromManifest(qL1S(":/info.yaml"));
auto pkg = new Package(pi);
auto ai = new ApplicationInfo(pi);
auto app = new Application(ai, pkg);
diff --git a/tests/application/tst_application.qrc b/tests/application/tst_application.qrc
new file mode 100644
index 00000000..a24bcd9a
--- /dev/null
+++ b/tests/application/tst_application.qrc
@@ -0,0 +1,5 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>info.yaml</file>
+</qresource>
+</RCC>
diff --git a/tests/applicationinstaller/tst_applicationinstaller.cpp b/tests/applicationinstaller/tst_applicationinstaller.cpp
index 1a68d357..2ac84814 100644
--- a/tests/applicationinstaller/tst_applicationinstaller.cpp
+++ b/tests/applicationinstaller/tst_applicationinstaller.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -34,8 +35,8 @@
#include "packagemanager.h"
#include "packagedatabase.h"
-#include "applicationmanager.h"
-#include "application.h"
+#include "package.h"
+#include "applicationinfo.h"
#include "sudo.h"
#include "utilities.h"
#include "error.h"
@@ -252,6 +253,15 @@ void tst_PackageManager::initTestCase()
PackageDatabase *pdb = new PackageDatabase(QStringList(), pathTo(Internal0));
m_pm = PackageManager::createInstance(pdb, pathTo(Documents0));
m_pm->setHardwareId(m_hardwareId);
+
+ // simulate the ApplicationManager stopping blocked applications
+ connect(&m_pm->internalSignals, &PackageManagerInternalSignals::registerApplication,
+ this, [this](ApplicationInfo *ai, Package *package) {
+ connect(package, &Package::blockedChanged, this, [ai, package](bool blocked) {
+ if (blocked)
+ package->applicationStoppedDueToBlock(ai->id());
+ });
+ });
} catch (const Exception &e) {
QVERIFY2(false, e.what());
}
@@ -512,7 +522,6 @@ void tst_PackageManager::packageInstallation()
QVERIFY(!taskId.isEmpty());
// check signals
-
QVERIFY(m_finishedSpy->wait(spyTimeout));
QCOMPARE(m_finishedSpy->first()[0].toString(), taskId);
}
diff --git a/tests/installationreport/tst_installationreport.cpp b/tests/installationreport/tst_installationreport.cpp
index c2abb17b..6e7e4cd8 100644
--- a/tests/installationreport/tst_installationreport.cpp
+++ b/tests/installationreport/tst_installationreport.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -31,6 +32,7 @@
#include <QtTest>
#include "global.h"
+#include "exception.h"
#include "installationreport.h"
QT_USE_NAMESPACE_AM
@@ -79,7 +81,11 @@ void tst_InstallationReport::test()
buffer.seek(0);
InstallationReport ir2;
- QVERIFY(ir2.deserialize(&buffer));
+ try {
+ ir2.deserialize(&buffer);
+ } catch (const Exception &e) {
+ QVERIFY2(false, e.what());
+ }
buffer.seek(0);
QVERIFY(ir2.isValid());
@@ -100,7 +106,11 @@ void tst_InstallationReport::test()
yaml.replace(pos, hmac.size(), hmac);
QCOMPARE(yaml.mid(pos + hmac.size(), 2).constData(), "'\n");
- QVERIFY(!ir2.deserialize(&buffer));
+ try {
+ ir2.deserialize(&buffer);
+ QVERIFY(false);
+ } catch (...) {
+ }
}
QTEST_APPLESS_MAIN(tst_InstallationReport)
diff --git a/tests/main/builtin-apps/hello-world.red/info.yaml b/tests/main/builtin-apps/hello-world.red/info.yaml
index fe0be9af..fa52180e 100644
--- a/tests/main/builtin-apps/hello-world.red/info.yaml
+++ b/tests/main/builtin-apps/hello-world.red/info.yaml
@@ -1,9 +1,24 @@
formatVersion: 1
-formatType: am-application
+formatType: am-package
---
id: 'hello-world.red'
icon: 'icon.png'
-code: 'main.qml'
-runtime: 'qml'
name:
en: 'Hello Red'
+
+applications:
+- id: red1
+ runtime: 'qml'
+ code: 'main.qml'
+
+- id: red2
+ runtime: 'qml'
+ code: 'main2.qml'
+
+intents:
+- id: red.intent1
+ handlingApplicationId: red1
+ categories: [ launcher, one ]
+- id: red.intent2
+ handlingApplicationId: red2
+ categories: [ launcher, two ]
diff --git a/tests/main/dir-with-update-already-installed/manifests/hello-world.red/installation-report.yaml b/tests/main/dir-with-update-already-installed/apps/hello-world.red/.installation-report.yaml
index 872f97d6..ec57b3d7 100644
--- a/tests/main/dir-with-update-already-installed/manifests/hello-world.red/installation-report.yaml
+++ b/tests/main/dir-with-update-already-installed/apps/hello-world.red/.installation-report.yaml
@@ -1,15 +1,14 @@
%YAML 1.1
---
formatType: 'am-installation-report'
-formatVersion: 1
+formatVersion: 3
---
-applicationId: 'hello-world.red'
+packageId: 'hello-world.red'
digest: '45ca0f9dfbddca129687900ae3260fe4a35ca09efd189581e196c0a75da47a0f'
diskSpaceUsed: 575488
files:
- 'info.yaml'
- 'icon.png'
- 'main.qml'
-installationLocationId: 'internal-0'
---
-hmac: '98cc78740bf87707de6163879b611f96f8fd2faf592218afa4f5361836d81caf'
+hmac: '48fce75b29a2b621f1a1462b434e6de0cac78837fe733bc12ab8e727363c5226'
diff --git a/tests/main/main.pro b/tests/main/main.pro
index c5ede8e7..e60ec75f 100644
--- a/tests/main/main.pro
+++ b/tests/main/main.pro
@@ -10,7 +10,11 @@ QT *= appman_manager-private \
appman_application-private \
appman_common-private \
appman_main-private \
+ appman_intent_server-private \
SOURCES += tst_main.cpp
RESOURCES = main.qrc
+
+OTHER_FILES += am-config.yaml
+
diff --git a/tests/main/tst_main.cpp b/tests/main/tst_main.cpp
index c227b9cf..f62054b5 100644
--- a/tests/main/tst_main.cpp
+++ b/tests/main/tst_main.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -37,6 +38,8 @@
#include "applicationmanager.h"
#include "logging.h"
#include "main.h"
+#include "intentserver.h"
+#include "intent.h"
#include <QtAppManMain/defaultconfiguration.h>
@@ -111,7 +114,7 @@ void tst_Main::copyRecursively(const QString &sourcePath, const QString &destPat
copyRecursively(sourceDir.filePath(subdirName), destDir.filePath(subdirName));
}
- QStringList fileNames = sourceDir.entryList(QDir::Files);
+ QStringList fileNames = sourceDir.entryList(QDir::Files | QDir::Hidden);
for (auto fileName : fileNames)
QFile::copy(sourceDir.filePath(fileName), destDir.filePath(fileName));
}
@@ -143,10 +146,10 @@ void tst_Main::initMain()
config = new DefaultConfiguration(pathList, QString());
config->parse(&deploymentWarnings);
+ if (m_verbose)
+ config->setForceVerbose(true);
main->setup(config, deploymentWarnings);
- if (m_verbose)
- Logging::setFilterRules(Logging::filterRules() += qSL("am.installer.debug=true"));
PackageManager::instance()->setAllowInstallationOfUnsignedPackages(true);
}
@@ -219,26 +222,62 @@ void tst_Main::installAndRemoveUpdateForBuiltIn()
initMain();
auto appMan = ApplicationManager::instance();
- QCOMPARE(appMan->count(), 1);
-
- auto app = appMan->application(0);
- QCOMPARE(app->name(qSL("en")), qSL("Hello Red"));
+ QCOMPARE(appMan->count(), 2);
+ auto intents = IntentServer::instance();
+ QCOMPARE(intents->count(), 2);
+
+ auto app1 = appMan->application(0);
+ QCOMPARE(app1->name(qSL("en")), qSL("Hello Red"));
+ QCOMPARE(app1->id(), qSL("red1"));
+ auto app2 = appMan->application(1);
+ QCOMPARE(app2->name(qSL("en")), qSL("Hello Red"));
+ QCOMPARE(app2->id(), qSL("red2"));
+
+ auto intent1 = intents->applicationIntent(qSL("red.intent1"), qSL("red1"));
+ QVERIFY(intent1);
+ QCOMPARE(intent1->intentId(), qSL("red.intent1"));
+ QCOMPARE(intent1->applicationId(), qSL("red1"));
+ QCOMPARE(intent1->packageId(), qSL("hello-world.red"));
+ QVERIFY(intent1->categories().contains(qSL("one")));
+ QVERIFY(intent1->categories().contains(qSL("launcher")));
+
+ auto intent2 = intents->applicationIntent(qSL("red.intent2"), qSL("red2"));
+ QVERIFY(intent2);
+ QCOMPARE(intent2->intentId(), qSL("red.intent2"));
+ QCOMPARE(intent2->applicationId(), qSL("red2"));
+ QCOMPARE(intent2->packageId(), qSL("hello-world.red"));
+ QVERIFY(intent2->categories().contains(qSL("two")));
+ QVERIFY(intent2->categories().contains(qSL("launcher")));
installPackage(qL1S(AM_TESTDATA_DIR "packages/hello-world.red.appkg"));
QCOMPARE(appMan->count(), 1);
- // it must still be the same Application instance as before the installation
- QCOMPARE(appMan->application(0), app);
+ QCOMPARE(intents->count(), 0);
+
+ // it must still be a different Application instance as before the installation, but quite
+ // often we get the same pointer back because it's a delete/new back-to-back
+ app1 = appMan->application(0);
+
// but with different contents
- QCOMPARE(app->name(qSL("en")), qSL("Hello Updated Red"));
+ QCOMPARE(app1->name(qSL("en")), qSL("Hello Updated Red"));
+ intent1 = intents->applicationIntent(qSL("red.intent1"), qSL("red1"));
+ QVERIFY(!intent1);
removePackage(qSL("hello-world.red"));
// After removal of the updated version all data in Application should be as before the
// installation took place.
- QCOMPARE(appMan->count(), 1);
- QCOMPARE(appMan->application(0), app);
- QCOMPARE(app->name(qSL("en")), qSL("Hello Red"));
+ QCOMPARE(appMan->count(), 2);
+ QCOMPARE(intents->count(), 2);
+
+ app1 = appMan->application(0);
+ QCOMPARE(app1->name(qSL("en")), qSL("Hello Red"));
+ intent1 = intents->applicationIntent(qSL("red.intent1"), qSL("red1"));
+ QVERIFY(intent1);
+ QCOMPARE(intent1->intentId(), qSL("red.intent1"));
+ intent2 = intents->applicationIntent(qSL("red.intent2"), qSL("red2"));
+ QVERIFY(intent2);
+ QCOMPARE(intent2->intentId(), qSL("red.intent2"));
}
/*
@@ -271,14 +310,10 @@ void tst_Main::updateForBuiltInAlreadyInstalled()
*/
void tst_Main::loadDatabaseWithUpdatedBuiltInApp()
{
- QCOMPARE(QFile::exists("/tmp/am-test-main/apps.db"), false);
-
initMain();
installPackage(qL1S(AM_TESTDATA_DIR "packages/hello-world.red.appkg"));
destroyMain();
- QCOMPARE(QFile::exists("/tmp/am-test-main/apps.db"), true);
-
initMain();
auto appMan = ApplicationManager::instance();
diff --git a/tests/packager-tool/tst_packager-tool.cpp b/tests/packager-tool/tst_packager-tool.cpp
index dc2ca94f..ce376ee6 100644
--- a/tests/packager-tool/tst_packager-tool.cpp
+++ b/tests/packager-tool/tst_packager-tool.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -299,7 +300,7 @@ void tst_PackagerTool::brokenMetadata()
// check if packaging actually fails with the expected error
QString error;
- QVERIFY(!packagerCheck(PackagingJob::create(pathTo("test.appkg"), tmp.path()), error));
+ QVERIFY2(!packagerCheck(PackagingJob::create(pathTo("test.appkg"), tmp.path()), error), qPrintable(error));
AM_CHECK_ERRORSTRING(error, errorString);
}
diff --git a/tests/qml/installer/appv1.pkg b/tests/qml/installer/appv1.pkg
deleted file mode 100644
index d2c5355f..00000000
--- a/tests/qml/installer/appv1.pkg
+++ /dev/null
Binary files differ
diff --git a/tests/qml/installer/appv2.pkg b/tests/qml/installer/appv2.pkg
deleted file mode 100644
index 5eb1a5b2..00000000
--- a/tests/qml/installer/appv2.pkg
+++ /dev/null
Binary files differ
diff --git a/tests/qml/installer/installer.pro b/tests/qml/installer/installer.pro
index d85f1607..2adfb2a4 100644
--- a/tests/qml/installer/installer.pro
+++ b/tests/qml/installer/installer.pro
@@ -1,6 +1,6 @@
AM_CONFIG = am-config.yaml
TEST_FILES = tst_installer.qml
-FILES = appv1.pkg appv2.pkg
+AM_TESTDATA_DIR=\"$$PWD/../../data/\"
load(am-qml-testcase)
diff --git a/tests/qml/installer/tst_installer.qml b/tests/qml/installer/tst_installer.qml
index 82ba5419..a51a26b8 100644
--- a/tests/qml/installer/tst_installer.qml
+++ b/tests/qml/installer/tst_installer.qml
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -51,19 +52,19 @@ TestCase {
SignalSpy {
id: taskFinishedSpy
- target: ApplicationInstaller
+ target: PackageManager
signalName: "taskFinished"
}
SignalSpy {
id: taskStateChangedSpy
- target: ApplicationInstaller
+ target: PackageManager
signalName: "taskStateChanged"
}
SignalSpy {
id: taskRequestingInstallationAcknowledgeSpy
- target: ApplicationInstaller
+ target: PackageManager
signalName: "taskRequestingInstallationAcknowledge"
}
@@ -72,28 +73,29 @@ TestCase {
function test_states() {
// App could potentially be installed already. Remove it.
- if (ApplicationInstaller.removePackage("test.install.app", false, true)) {
+ if (PackageManager.removePackage("com.pelagicore.test", false, true)) {
taskFinishedSpy.wait(spyTimeout);
compare(taskFinishedSpy.count, 1);
taskFinishedSpy.clear();
}
- ApplicationManager.applicationAdded.connect(function(appId) {
- var app = ApplicationManager.application(appId);
- stateList.push(app.state)
- app.stateChanged.connect(function(state) {
- compare(state, app.state)
+ PackageManager.packageAdded.connect(function(pkgId) {
+ var pkg = PackageManager.package(pkgId);
+ stateList.push(pkg.state)
+ pkg.stateChanged.connect(function(state) {
+ compare(state, pkg.state)
stateList.push(state)
})
})
- var id = ApplicationInstaller.startPackageInstallation("internal-0", "appv1.pkg")
+ var id = PackageManager.startPackageInstallation(ApplicationManager.systemProperties.AM_TESTDATA_DIR
+ + "/packages/test-dev-signed.appkg")
taskRequestingInstallationAcknowledgeSpy.wait(spyTimeout);
compare(taskRequestingInstallationAcknowledgeSpy.count, 1);
compare(taskRequestingInstallationAcknowledgeSpy.signalArguments[0][0], id);
- var appId = taskRequestingInstallationAcknowledgeSpy.signalArguments[0][1].id
+ var pkgId = taskRequestingInstallationAcknowledgeSpy.signalArguments[0][1].id
taskRequestingInstallationAcknowledgeSpy.clear();
- ApplicationInstaller.acknowledgePackageInstallation(id);
+ PackageManager.acknowledgePackageInstallation(id);
if (!taskFinishedSpy.count)
taskFinishedSpy.wait(spyTimeout);
@@ -101,46 +103,47 @@ TestCase {
taskFinishedSpy.clear();
compare(stateList.length, 2);
- compare(stateList[0], ApplicationObject.BeingInstalled)
- compare(stateList[1], ApplicationObject.Installed)
+ compare(stateList[0], PackageObject.BeingInstalled)
+ compare(stateList[1], PackageObject.Installed)
stateList = []
- id = ApplicationInstaller.startPackageInstallation("internal-0", "appv2.pkg")
+ id = PackageManager.startPackageInstallation(ApplicationManager.systemProperties.AM_TESTDATA_DIR
+ + "/packages/test-update-dev-signed.appkg")
taskRequestingInstallationAcknowledgeSpy.wait(spyTimeout);
compare(taskRequestingInstallationAcknowledgeSpy.count, 1);
compare(taskRequestingInstallationAcknowledgeSpy.signalArguments[0][0], id);
- ApplicationInstaller.acknowledgePackageInstallation(id);
+ PackageManager.acknowledgePackageInstallation(id);
taskFinishedSpy.wait(spyTimeout);
compare(taskFinishedSpy.count, 1);
taskFinishedSpy.clear();
- compare(stateList[0], ApplicationObject.BeingUpdated)
- compare(stateList[1], ApplicationObject.Installed)
+ compare(stateList[0], PackageObject.BeingUpdated)
+ compare(stateList[1], PackageObject.Installed)
stateList = []
- id = ApplicationInstaller.removePackage(appId, false, false);
+ id = PackageManager.removePackage(pkgId, false, false);
taskFinishedSpy.wait(spyTimeout);
compare(taskFinishedSpy.count, 1);
taskFinishedSpy.clear();
- compare(stateList[0], ApplicationObject.BeingRemoved)
+ compare(stateList[0], PackageObject.BeingRemoved)
stateList = []
// Cannot compare app.state any more, since app might already be dead
verify(taskStateChangedSpy.count > 10);
- var taskStates = [ ApplicationInstaller.Executing,
- ApplicationInstaller.AwaitingAcknowledge,
- ApplicationInstaller.Installing,
- ApplicationInstaller.CleaningUp,
- ApplicationInstaller.Finished,
- ApplicationInstaller.Executing,
- ApplicationInstaller.AwaitingAcknowledge,
- ApplicationInstaller.Installing,
- ApplicationInstaller.CleaningUp,
- ApplicationInstaller.Finished,
- ApplicationInstaller.Executing ]
+ var taskStates = [ PackageManager.Executing,
+ PackageManager.AwaitingAcknowledge,
+ PackageManager.Installing,
+ PackageManager.CleaningUp,
+ PackageManager.Finished,
+ PackageManager.Executing,
+ PackageManager.AwaitingAcknowledge,
+ PackageManager.Installing,
+ PackageManager.CleaningUp,
+ PackageManager.Finished,
+ PackageManager.Executing ]
for (var i = 0; i < taskStates.length; i++)
compare(taskStateChangedSpy.signalArguments[i][1], taskStates[i], "- index: " + i);
}
diff --git a/tests/qml/intents/tst_intents.qml b/tests/qml/intents/tst_intents.qml
index b574dee4..880e94ca 100644
--- a/tests/qml/intents/tst_intents.qml
+++ b/tests/qml/intents/tst_intents.qml
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -74,66 +75,51 @@ TestCase {
signalName: "replyReceived"
}
- function test_intent_gadget() {
- var allIntents = IntentServer.intentList
- verify(allIntents.length > 0)
+ function test_intent_object() {
+ verify(IntentServer.count> 0)
// test intent properties
- var intent = IntentServer.find("both", "intents1")
- verify(intent.valid)
+ var intent = IntentServer.applicationIntent("both", "intents1")
+ verify(intent)
compare(intent.intentId, "both")
compare(intent.applicationId, "intents1")
compare(intent.visibility, Intent.Public)
compare(intent.requiredCapabilities, [])
compare(intent.parameterMatch, {})
- // test comparison operators
- var pos = allIntents.indexOf(intent)
- verify(pos >= 0)
- var intent1 = IntentServer.find("both", "intents1")
- var intent2 = IntentServer.find("both", "intents2")
- verify(intent1.valid)
- verify(intent2.valid)
- verify(intent1 == intent)
- verify(intent1 === intent)
- verify(intent1 != intent2)
- verify(intent1 !== intent2)
- verify(intent1 < intent2)
- verify(intent2 > intent1)
-
- verify(!IntentServer.find("both", "intents3").valid)
- verify(!IntentServer.find("bothx", "intents1").valid)
- verify(!IntentServer.find("both", "").valid)
- verify(!IntentServer.find("", "intents1").valid)
- verify(!IntentServer.find("", "").valid)
+ verify(!IntentServer.applicationIntent("both", "intents3"))
+ verify(!IntentServer.applicationIntent("bothx", "intents1"))
+ verify(!IntentServer.applicationIntent("both", ""))
+ verify(!IntentServer.applicationIntent("", "intents1"))
+ verify(!IntentServer.applicationIntent("", ""))
}
function test_match() {
// first, check the matching on the server API
- var intent = IntentServer.find("match", "intents1")
- verify(!intent.valid)
- intent = IntentServer.find("match", "intents1", matchParams)
- verify(intent.valid)
+ var intent = IntentServer.applicationIntent("match", "intents1")
+ verify(!intent)
+ intent = IntentServer.applicationIntent("match", "intents1", matchParams)
+ verify(intent)
compare(intent.parameterMatch, { "list": [ "a", "b" ], "int": 42, "string": "^foo_.*_bar$", "complex": { "a": 1 } })
var params = matchParams
params.list = "c"
- verify(!IntentServer.find("match", "intents1", params).valid)
+ verify(!IntentServer.applicationIntent("match", "intents1", params))
params.list = "b"
- verify(IntentServer.find("match", "intents1", params).valid)
+ verify(IntentServer.applicationIntent("match", "intents1", params))
params.int = 2
- verify(!IntentServer.find("match", "intents1", params).valid)
+ verify(!IntentServer.applicationIntent("match", "intents1", params))
params.int = 42
params.string = "foo"
- verify(!IntentServer.find("match", "intents1", params).valid)
+ verify(!IntentServer.applicationIntent("match", "intents1", params))
params.string = "foo_test_bar"
- verify(IntentServer.find("match", "intents1", params).valid)
+ verify(IntentServer.applicationIntent("match", "intents1", params))
params.complex = "string"
- verify(!IntentServer.find("match", "intents1", params).valid)
+ verify(!IntentServer.applicationIntent("match", "intents1", params))
params.complex = matchParams.complex
}
@@ -241,8 +227,9 @@ TestCase {
break
case "acknowledge":
var intent = possibleIntents[0]
- if (data.acknowledgeIntentId)
- intent = IntentServer.find(data.acknowledgeIntentId, possibleIntents[0].applicationId)
+ if (data.acknowledgeIntentId) {
+ intent = IntentServer.applicationIntent(data.acknowledgeIntentId, possibleIntents[0].applicationId)
+ }
IntentServer.acknowledgeDisambiguationRequest(disambiguateSpy.signalArguments[0][0], intent)
break
}
diff --git a/tests/qml/simple/apps/tld.test.simple1/info-alias.yaml b/tests/qml/simple/apps/tld.test.simple1/info-alias.yaml
deleted file mode 100644
index ec600862..00000000
--- a/tests/qml/simple/apps/tld.test.simple1/info-alias.yaml
+++ /dev/null
@@ -1,9 +0,0 @@
-formatVersion: 1
-formatType: am-application-alias
----
-aliasId: 'tld.test.simple1@alias'
-icon: 'icon2.png'
-name:
- en: 'Simple1 Alias'
-
-documentUrl: "x-test:alias"
diff --git a/tests/qml/simple/tst_applicationmanager.qml b/tests/qml/simple/tst_applicationmanager.qml
index 71878d5f..8b62425f 100644
--- a/tests/qml/simple/tst_applicationmanager.qml
+++ b/tests/qml/simple/tst_applicationmanager.qml
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -51,10 +52,10 @@ TestCase {
name: "ApplicationManager"
property var simpleApplication
- property var applicationAlias
property var capsApplication
// Either appman is build in single-process mode or it was started with --force-single-process
- property bool singleProcess : Qt.application.arguments.indexOf("--force-single-process") !== -1 || buildConfig[0].CONFIG.indexOf("multi-process") === -1
+ property bool singleProcess : Qt.application.arguments.indexOf("--force-single-process") !== -1
+ || buildConfig[0].CONFIG.indexOf("multi-process") === -1
property QtObject windowHandler: QtObject {
function windowAddedHandler(window) {
console.info("window " + window + " added");
@@ -84,10 +85,9 @@ TestCase {
WindowManager.windowAdded.connect(windowHandler.windowAddedHandler)
WindowManager.windowContentStateChanged.connect(windowHandler.windowContentStateChangedHandler)
- compare(ApplicationManager.count, 3)
+ compare(ApplicationManager.count, 2)
simpleApplication = ApplicationManager.application(0);
- applicationAlias = ApplicationManager.application(1);
- capsApplication = ApplicationManager.application(2);
+ capsApplication = ApplicationManager.application(1);
}
function test_properties() {
@@ -152,23 +152,10 @@ TestCase {
compare(simpleApplication.applicationProperties.pri1, undefined)
}
- function test_applicationAlias() {
- // Test that the alias has the same info, be indentified as an alias and points to the original app
- compare(applicationAlias.id, "tld.test.simple1@alias")
- compare(applicationAlias.alias, true)
- compare(applicationAlias.nonAliased, simpleApplication)
- //TODO this should be a Url instead, as this is what's used in QML usually
- compare(applicationAlias.icon.toString(), Qt.resolvedUrl("apps/tld.test.simple1/icon2.png"))
- compare(applicationAlias.documentUrl, "x-test:alias")
- compare(applicationAlias.runtimeName, simpleApplication.runtimeName)
- compare(applicationAlias.capabilities, simpleApplication.capabilities)
- compare(applicationAlias.supportedMimeTypes, simpleApplication.supportedMimeTypes)
- }
-
function test_indexOfApplication() {
// Test index of
compare(ApplicationManager.indexOfApplication(simpleApplication.id), 0)
- compare(ApplicationManager.indexOfApplication(applicationAlias.id), 1)
+ compare(ApplicationManager.indexOfApplication(capsApplication.id), 1)
compare(ApplicationManager.indexOfApplication("error"), -1)
}
@@ -177,7 +164,7 @@ TestCase {
var apps = ApplicationManager.applicationIds()
compare(apps.length, ApplicationManager.count)
compare(ApplicationManager.applicationIds()[0], simpleApplication.id)
- compare(ApplicationManager.applicationIds()[1], applicationAlias.id)
+ compare(ApplicationManager.applicationIds()[1], capsApplication.id)
}
function test_capabilities() {
@@ -214,18 +201,15 @@ TestCase {
}
function test_applicationModel() {
- compare(appModel.count, 3);
+ compare(appModel.count, 2);
compare(appModel.indexOfApplication(capsApplication.id), 0);
- compare(appModel.indexOfApplication(applicationAlias.id), 1);
- compare(appModel.indexOfApplication(simpleApplication.id), 2);
+ compare(appModel.indexOfApplication(simpleApplication.id), 1);
compare(appModel.mapToSource(0), ApplicationManager.indexOfApplication(capsApplication.id));
- compare(appModel.mapFromSource(ApplicationManager.indexOfApplication(simpleApplication.id)), 2);
+ compare(appModel.mapFromSource(ApplicationManager.indexOfApplication(simpleApplication.id)), 1);
appModel.sortFunction = undefined;
compare(appModel.indexOfApplication(simpleApplication.id),
ApplicationManager.indexOfApplication(simpleApplication.id));
- compare(appModel.indexOfApplication(applicationAlias.id),
- ApplicationManager.indexOfApplication(applicationAlias.id));
compare(appModel.indexOfApplication(capsApplication.id),
ApplicationManager.indexOfApplication(capsApplication.id));
@@ -235,7 +219,6 @@ TestCase {
compare(appModelCountSpy.count, 1);
compare(appModel.count, 1);
compare(appModel.indexOfApplication(capsApplication.id), 0);
- compare(appModel.indexOfApplication(applicationAlias.id), -1);
compare(appModel.indexOfApplication(simpleApplication.id), -1);
listView.model = appModel;
@@ -243,21 +226,11 @@ TestCase {
compare(listView.currentItem.modelData.name, "Caps");
listView.model = ApplicationManager;
- var criteria = false;
- appModel.filterFunction = function(app) { return app.alias === criteria; };
- appModelCountSpy.wait(1000);
- compare(appModelCountSpy.count, 2);
- compare(appModel.count, 2);
- compare(appModel.indexOfApplication(applicationAlias.id), -1);
- criteria = true;
- appModel.invalidate();
- compare(appModel.count, 1);
-
appModel.filterFunction = function() {};
compare(appModel.count, 0);
appModel.filterFunction = undefined;
- compare(appModel.count, 3);
+ compare(appModel.count, 2);
}
function test_get_data() {
@@ -318,11 +291,16 @@ TestCase {
function test_startAndStopApplication_data() {
return [
- {tag: "StartStop", appId: "tld.test.simple1", index: 0, forceKill: false, exitCode: 0, exitStatus: Am.NormalExit },
- {tag: "StartStopAlias", appId: "tld.test.simple1@alias", index: 0, forceKill: false, exitCode: 0, exitStatus: Am.NormalExit },
- {tag: "Debug", appId: "tld.test.simple1", index: 0, forceKill: false, exitCode: 0, exitStatus: Am.NormalExit },
- {tag: "ForceKill", appId: "tld.test.simple2", index: 2, forceKill: true, exitCode: Qt.platform.os !== 'windows' ? 9 : 0, exitStatus: Qt.platform.os !== 'windows' ? Am.ForcedExit : Am.CrashExit },
- {tag: "AutoTerminate", appId: "tld.test.simple2", index: 2, forceKill: false, exitCode: Qt.platform.os !== 'windows' ? 15 : 0, exitStatus: Qt.platform.os !== 'windows' ? Am.ForcedExit : Am.CrashExit }
+ {tag: "StartStop", appId: "tld.test.simple1", index: 0, forceKill: false,
+ exitCode: 0, exitStatus: Am.NormalExit },
+ {tag: "Debug", appId: "tld.test.simple1", index: 0, forceKill: false,
+ exitCode: 0, exitStatus: Am.NormalExit },
+ {tag: "ForceKill", appId: "tld.test.simple2", index: 1, forceKill: true,
+ exitCode: Qt.platform.os !== 'windows' ? 9 : 0,
+ exitStatus: Qt.platform.os !== 'windows' ? Am.ForcedExit : Am.CrashExit },
+ {tag: "AutoTerminate", appId: "tld.test.simple2", index: 1, forceKill: false,
+ exitCode: Qt.platform.os !== 'windows' ? 15 : 0,
+ exitStatus: Qt.platform.os !== 'windows' ? Am.ForcedExit : Am.CrashExit }
];
}
@@ -369,7 +347,9 @@ TestCase {
function test_startAndStopAllApplications_data() {
return [
- {tag: "StopAllApplications", appId1: "tld.test.simple1", index1: 0, appId2: "tld.test.simple2", index2: 2, forceKill: false, exitCode: 0, exitStatus: Am.NormalExit }
+ {tag: "StopAllApplications", appId1: "tld.test.simple1", index1: 0,
+ appId2: "tld.test.simple2", index2: 1, forceKill: false, exitCode: 0,
+ exitStatus: Am.NormalExit }
];
}
@@ -408,12 +388,12 @@ TestCase {
ApplicationManager.stopAllApplications(data.forceKill);
- while (runStateChangedSpy.count < 6)
+ while (runStateChangedSpy.count < 4)
runStateChangedSpy.wait(10000);
var args = runStateChangedSpy.signalArguments
- for (var i = 0; i < 6; ++i) {
+ for (var i = 0; i < 4; ++i) {
var id = args[i][0]
var state = args[i][1]
@@ -460,7 +440,6 @@ TestCase {
function test_openUrl_data() {
return [
{tag: "customMimeType", url: "x-test://12345", expectedApp: simpleApplication.id },
- {tag: "openAlias", url: "x-test:alias", expectedApp: applicationAlias.id },
{tag: "text/plain", url: "file://text-file.txt", expectedApp: simpleApplication.id }
];
}
diff --git a/tests/runtime/tst_runtime.cpp b/tests/runtime/tst_runtime.cpp
index dd3a2b4a..d64014e2 100644
--- a/tests/runtime/tst_runtime.cpp
+++ b/tests/runtime/tst_runtime.cpp
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2019 The Qt Company Ltd.
** Copyright (C) 2019 Luxoft Sweden AB
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
@@ -32,7 +33,6 @@
#include "application.h"
#include "package.h"
-#include "yamlpackagescanner.h"
#include "abstractruntime.h"
#include "runtimefactory.h"
#include "exception.h"
@@ -138,7 +138,7 @@ void tst_Runtime::factory()
Application *a = nullptr;
try {
- PackageInfo *pi = YamlPackageScanner().scan(temp.fileName());
+ PackageInfo *pi = PackageInfo::fromManifest(temp.fileName());
QVERIFY(pi);
Package *p = new Package(pi);
a = new Application(pi->applications().first(), p);