summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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
33 files changed, 641 insertions, 349 deletions
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());