summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTarja Sundqvist <tarja.sundqvist@qt.io>2025-08-28 14:58:07 +0300
committerTarja Sundqvist <tarja.sundqvist@qt.io>2025-08-28 14:58:07 +0300
commit49bae824cb78fb9dc3040d00c7fe9621c5cd2ee1 (patch)
tree773aa6b2db895a73de5d42c9760d6e16e3889f31
parent2e99fae3237f3afcef57ad5ef6dfb8da2ef8af2f (diff)
parent2241a8a48df702da9001415334a77afc530b8ca2 (diff)
Merge "Merge tag 'v6.2.13-lts' into tqtc/lts-6.2-opensource"v6.2.13-lts-lgpl6.2
-rw-r--r--.cmake.conf2
-rw-r--r--dependencies.yaml8
-rw-r--r--src/common-lib/qtyaml.cpp157
-rw-r--r--src/dbus-lib/packagemanagerdbuscontextadaptor.cpp8
-rw-r--r--src/manager-lib/applicationmanager.cpp25
-rw-r--r--src/manager-lib/applicationmanager.h2
-rw-r--r--src/manager-lib/installationtask.cpp48
7 files changed, 143 insertions, 107 deletions
diff --git a/.cmake.conf b/.cmake.conf
index 897ec4a3..b7810022 100644
--- a/.cmake.conf
+++ b/.cmake.conf
@@ -1 +1 @@
-set(QT_REPO_MODULE_VERSION "6.2.12")
+set(QT_REPO_MODULE_VERSION "6.2.13")
diff --git a/dependencies.yaml b/dependencies.yaml
index 8c25ace8..16025636 100644
--- a/dependencies.yaml
+++ b/dependencies.yaml
@@ -1,13 +1,13 @@
dependencies:
../tqtc-qtbase:
- ref: 3a82051eade32b34c2f4f6f652a9d8ef0db96c71
+ ref: a963a536e623499cc56b0231c35dc5790a4bbc29
required: true
../tqtc-qtdeclarative:
- ref: a7c766a9863605eb81e8f0cdb4d2b93e087b5bde
+ ref: c6fdadd916a7568c1d71b750e054ca9aa2fd5dfc
required: true
../tqtc-qttools:
- ref: a78a36d69a792ae66fc062e461b83c28152a6856
+ ref: d000041a232a428ba08e31323840d484642f5886
required: false
../tqtc-qtwayland:
- ref: 9cb8ef7847d8f06d3fcdde74dd3ceb2e045ca6a0
+ ref: 185031c88a95597bb8ebbd865da14af17ecef1e5
required: false
diff --git a/src/common-lib/qtyaml.cpp b/src/common-lib/qtyaml.cpp
index 5f5f931c..d2531d71 100644
--- a/src/common-lib/qtyaml.cpp
+++ b/src/common-lib/qtyaml.cpp
@@ -47,6 +47,77 @@ QT_BEGIN_NAMESPACE_AM
namespace QtYaml {
+enum ValueIndex {
+ ValueNull,
+ ValueTrue,
+ ValueFalse,
+ ValueNaN,
+ ValueInf
+};
+
+struct StaticMapping
+{
+ QString text;
+ ValueIndex index = ValueNull;
+};
+
+static const StaticMapping staticMappings[] = { // keep this sorted for bsearch !!
+ { qSL(".INF"), ValueInf },
+ { qSL(".Inf"), ValueInf },
+ { qSL(".NAN"), ValueNaN },
+ { qSL(".NaN"), ValueNaN },
+ { qSL(".inf"), ValueInf },
+ { qSL(".nan"), ValueNaN },
+ { qSL("FALSE"), ValueFalse },
+ { qSL("False"), ValueFalse },
+ { qSL("N"), ValueFalse },
+ { qSL("NO"), ValueFalse },
+ { qSL("NULL"), ValueNull },
+ { qSL("No"), ValueFalse },
+ { qSL("Null"), ValueNull },
+ { qSL("OFF"), ValueFalse },
+ { qSL("Off"), ValueFalse },
+ { qSL("ON"), ValueTrue },
+ { qSL("On"), ValueTrue },
+ { qSL("TRUE"), ValueTrue },
+ { qSL("True"), ValueTrue },
+ { qSL("Y"), ValueTrue },
+ { qSL("YES"), ValueTrue },
+ { qSL("Yes"), ValueTrue },
+ { qSL("false"), ValueFalse },
+ { qSL("n"), ValueFalse },
+ { qSL("no"), ValueFalse },
+ { qSL("null"), ValueNull },
+ { qSL("off"), ValueFalse },
+ { qSL("on"), ValueTrue },
+ { qSL("true"), ValueTrue },
+ { qSL("y"), ValueTrue },
+ { qSL("yes"), ValueTrue },
+ { qSL("~"), ValueNull }
+};
+
+
+static inline StaticMapping *findStaticMapping(const QString &str)
+{
+ static const QString firstCharStaticMappings = qSL(".FNOTYfnoty~");
+ const QChar firstChar = str.isEmpty() ? QChar(0) : str.at(0);
+
+ if (firstCharStaticMappings.contains(firstChar)) { // cheap check to avoid expensive bsearch
+ StaticMapping key { str, ValueNull };
+ auto found = bsearch(&key,
+ staticMappings,
+ sizeof(staticMappings) / sizeof(staticMappings[0]),
+ sizeof(staticMappings[0]),
+ [](const void *m1, const void *m2) {
+ return static_cast<const StaticMapping *>(m1)->text.compare(static_cast<const StaticMapping *>(m2)->text);
+ });
+
+ return static_cast<StaticMapping *>(found);
+ }
+ return nullptr;
+};
+
+
static inline void yerr(int result) Q_DECL_NOEXCEPT_EXPR(false)
{
if (!result)
@@ -112,7 +183,16 @@ static void emitYaml(yaml_emitter_t *e, const QVariant &value, YamlStyle style)
QVariantMap map = value.toMap();
for (auto it = map.constBegin(); it != map.constEnd(); ++it) {
- emitYamlScalar(e, it.key().toUtf8());
+ const QString &key = it.key();
+ // We could just quote everything, but this would break backwards compatibility
+ // inside the AM itself (e.g. HMAC calculations for installation-report.yaml)
+ bool needsQuoting = key.isEmpty() || findStaticMapping(key);
+ if (!needsQuoting) {
+ char16_t firstChar = key.at(0).unicode();
+ needsQuoting = ((firstChar >= u'0' && firstChar <= u'9')
+ || firstChar == u'+' || firstChar == u'-' || firstChar == u'.');
+ }
+ emitYamlScalar(e, key.toUtf8(), needsQuoting);
emitYaml(e, it.value(), style);
}
@@ -169,6 +249,7 @@ QByteArray yamlFromVariantDocuments(const QVector<QVariant> &documents, YamlStyl
} // namespace QtYaml
+using namespace QtYaml;
class YamlParserPrivate
{
@@ -321,20 +402,6 @@ QVariant YamlParser::parseScalar() const
return scalar;
}
- enum ValueIndex {
- ValueNull,
- ValueTrue,
- ValueFalse,
- ValueNaN,
- ValueInf
- };
-
- struct StaticMapping
- {
- QString text;
- ValueIndex index;
- };
-
static const QVariant staticValues[] = {
QVariant::fromValue(nullptr), // ValueNull
QVariant(true), // ValueTrue
@@ -343,61 +410,15 @@ QVariant YamlParser::parseScalar() const
QVariant(qInf()), // ValueInf
};
- static const StaticMapping staticMappings[] = { // keep this sorted for bsearch !!
- { qSL(""), ValueNull },
- { qSL(".INF"), ValueInf },
- { qSL(".Inf"), ValueInf },
- { qSL(".NAN"), ValueNaN },
- { qSL(".NaN"), ValueNaN },
- { qSL(".inf"), ValueInf },
- { qSL(".nan"), ValueNaN },
- { qSL("FALSE"), ValueFalse },
- { qSL("False"), ValueFalse },
- { qSL("N"), ValueFalse },
- { qSL("NO"), ValueFalse },
- { qSL("NULL"), ValueNull },
- { qSL("No"), ValueFalse },
- { qSL("Null"), ValueNull },
- { qSL("OFF"), ValueFalse },
- { qSL("Off"), ValueFalse },
- { qSL("ON"), ValueTrue },
- { qSL("On"), ValueTrue },
- { qSL("TRUE"), ValueTrue },
- { qSL("True"), ValueTrue },
- { qSL("Y"), ValueTrue },
- { qSL("YES"), ValueTrue },
- { qSL("Yes"), ValueTrue },
- { qSL("false"), ValueFalse },
- { qSL("n"), ValueFalse },
- { qSL("no"), ValueFalse },
- { qSL("null"), ValueNull },
- { qSL("off"), ValueFalse },
- { qSL("on"), ValueTrue },
- { qSL("true"), ValueTrue },
- { qSL("y"), ValueTrue },
- { qSL("yes"), ValueTrue },
- { qSL("~"), ValueNull }
- };
+ if (scalar.isEmpty())
+ return staticValues[ValueNull];
- static const char *firstCharStaticMappings = ".FNOTYfnoty~";
- char firstChar = scalar.isEmpty() ? 0 : scalar.at(0).toLatin1();
-
- if (strchr(firstCharStaticMappings, firstChar)) { // cheap check to avoid expensive bsearch
- StaticMapping key { scalar, ValueNull };
- auto found = bsearch(&key,
- staticMappings,
- sizeof(staticMappings) / sizeof(staticMappings[0]),
- sizeof(staticMappings[0]),
- [](const void *m1, const void *m2) {
- return static_cast<const StaticMapping *>(m1)->text.compare(static_cast<const StaticMapping *>(m2)->text);
- });
-
- if (found)
- return staticValues[static_cast<StaticMapping *>(found)->index];
- }
+ if (auto sm = findStaticMapping(scalar))
+ return staticValues[sm->index];
- if ((firstChar >= '0' && firstChar <= '9') // cheap check to avoid expensive regexps
- || firstChar == '+' || firstChar == '-' || firstChar == '.') {
+ char16_t firstChar = scalar.at(0).unicode();
+ if ((firstChar >= u'0' && firstChar <= u'9') // cheap check to avoid expensive regexps
+ || firstChar == u'+' || firstChar == u'-' || firstChar == u'.') {
// We are using QRegularExpressions in multiple threads here, although the class is not
// marked thread-safe. We are relying on the const match() function to behave thread-safe
// which it does. There's an autotest (tst_yaml / parallel) to make sure we catch changes
diff --git a/src/dbus-lib/packagemanagerdbuscontextadaptor.cpp b/src/dbus-lib/packagemanagerdbuscontextadaptor.cpp
index 7f640ae9..6b67b60a 100644
--- a/src/dbus-lib/packagemanagerdbuscontextadaptor.cpp
+++ b/src/dbus-lib/packagemanagerdbuscontextadaptor.cpp
@@ -82,10 +82,10 @@ PackageManagerAdaptor::PackageManagerAdaptor(QObject *parent)
const auto apps = package->applications(); // these are QObject * (legacy API)
QVariantList appList;
appList.reserve(apps.size());
- for (const auto *obj : apps) {
- QVariantMap app = ApplicationManager::instance()->get(obj->property("id").toString());
- app.remove(qSL("application")); // cannot marshall QObject *
- appList.append(app);
+ for (auto *app : apps) {
+ QVariantMap appMap = ApplicationManager::instance()->get(qobject_cast<Application *>(app));
+ appMap.remove(qSL("application")); // cannot marshall QObject *
+ appList.append(appMap);
}
map.insert(qSL("applications"), appList);
diff --git a/src/manager-lib/applicationmanager.cpp b/src/manager-lib/applicationmanager.cpp
index 958ba265..17535122 100644
--- a/src/manager-lib/applicationmanager.cpp
+++ b/src/manager-lib/applicationmanager.cpp
@@ -580,6 +580,17 @@ QVector<Application *> ApplicationManager::mimeTypeHandlers(const QString &mimeT
return handlers;
}
+QVariantMap ApplicationManager::get(Application *app) const
+{
+ QVariantMap map;
+ if (app) {
+ const QHash<int, QByteArray> roles = roleNames();
+ for (auto it = roles.begin(); it != roles.end(); ++it)
+ map.insert(QString::fromLatin1(it.value()), dataForRole(app, it.key()));
+ }
+ return map;
+}
+
void ApplicationManager::registerMimeTypes()
{
#if defined(QT_GUI_LIB)
@@ -1246,7 +1257,11 @@ QVariant ApplicationManager::data(const QModelIndex &index, int role) const
return QVariant();
Application *app = d->apps.at(index.row());
+ return dataForRole(app, role);
+}
+QVariant ApplicationManager::dataForRole(Application *app, int role) const
+{
switch (role) {
case Id:
return app->id();
@@ -1317,12 +1332,7 @@ QVariantMap ApplicationManager::get(int index) const
qCWarning(LogSystem) << "ApplicationManager::get(index): invalid index:" << index;
return QVariantMap();
}
-
- QVariantMap map;
- QHash<int, QByteArray> roles = roleNames();
- for (auto it = roles.begin(); it != roles.end(); ++it)
- map.insert(qL1S(it.value()), data(this->index(index), it.key()));
- return map;
+ return get(d->apps.at(index));
}
/*!
@@ -1413,8 +1423,7 @@ QStringList ApplicationManager::applicationIds() const
*/
QVariantMap ApplicationManager::get(const QString &id) const
{
- int index = indexOfApplication(id);
- return (index < 0) ? QVariantMap{} : get(index);
+ return get(application(id));
}
Am::RunState ApplicationManager::applicationRunState(const QString &id) const
diff --git a/src/manager-lib/applicationmanager.h b/src/manager-lib/applicationmanager.h
index e67bf61c..b85c8896 100644
--- a/src/manager-lib/applicationmanager.h
+++ b/src/manager-lib/applicationmanager.h
@@ -93,6 +93,7 @@ public:
Application *fromSecurityToken(const QByteArray &securityToken) const;
QVector<Application *> schemeHandlers(const QString &scheme) const;
QVector<Application *> mimeTypeHandlers(const QString &mimeType) const;
+ QVariantMap get(Application *app) const;
bool startApplicationInternal(const QString &appId, const QString &documentUrl = QString(),
const QString &documentMimeType = QString(),
@@ -116,6 +117,7 @@ public:
// the item model part
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
+ QVariant dataForRole(Application *app, int role) const;
QHash<int, QByteArray> roleNames() const override;
int count() const;
diff --git a/src/manager-lib/installationtask.cpp b/src/manager-lib/installationtask.cpp
index a76f7d04..47f104cd 100644
--- a/src/manager-lib/installationtask.cpp
+++ b/src/manager-lib/installationtask.cpp
@@ -172,8 +172,7 @@ void InstallationTask::execute()
connect(m_extractor, &PackageExtractor::progress, this, &AsynchronousTask::progress);
- m_extractor->setFileExtractedCallback(std::bind(&InstallationTask::checkExtractedFile,
- this, std::placeholders::_1));
+ m_extractor->setFileExtractedCallback([this](const QString &f) { checkExtractedFile(f); });
if (!m_extractor->extract())
throw Exception(m_extractor->errorCode(), m_extractor->errorString());
@@ -311,6 +310,9 @@ void InstallationTask::checkExtractedFile(const QString &file) Q_DECL_NOEXCEPT_E
}
if (m_foundIcon && m_foundInfo) {
+ // we're not interested in any other files from here on...
+ m_extractor->setFileExtractedCallback(nullptr);
+
bool doubleInstallation = false;
QMetaObject::invokeMethod(PackageManager::instance(), [this, &doubleInstallation]() {
doubleInstallation = PackageManager::instance()->isPackageInstallationActive(m_packageId);
@@ -318,22 +320,6 @@ void InstallationTask::checkExtractedFile(const QString &file) Q_DECL_NOEXCEPT_E
if (doubleInstallation)
throw Exception(Error::Package, "Cannot install the same package %1 multiple times in parallel").arg(m_packageId);
- qCDebug(LogInstaller) << "emit taskRequestingInstallationAcknowledge" << id() << "for package" << m_package->id();
-
- // this is a temporary just for the signal emission below
- m_tempPackageForAcknowledge.reset(new Package(m_package.get(), Package::BeingInstalled));
- m_tempPackageForAcknowledge->moveToThread(m_pm->thread());
- const auto &applicationInfos = m_package.get()->applications();
- for (const auto &applicationInfo : applicationInfos) {
- auto tempApp = new Application(applicationInfo, m_tempPackageForAcknowledge.get());
- tempApp->moveToThread(m_pm->thread());
- m_tempPackageForAcknowledge->addApplication(tempApp);
- m_tempApplicationsForAcknowledge.emplace_back(tempApp);
- }
- emit m_pm->taskRequestingInstallationAcknowledge(id(), m_tempPackageForAcknowledge.get(),
- m_extractor->installationReport().extraMetaData(),
- m_extractor->installationReport().extraSignedMetaData());
-
QDir oldDestinationDirectory = m_extractor->destinationDirectory();
startInstallation();
@@ -366,6 +352,28 @@ void InstallationTask::checkExtractedFile(const QString &file) Q_DECL_NOEXCEPT_E
if (!m_managerApproval)
throw Exception("PackageManager declined the installation of %1").arg(packageId);
+ qCDebug(LogInstaller) << "emit taskRequestingInstallationAcknowledge" << id() << "for package" << packageId;
+
+ // Create temporary objects for QML just for the signal emission.
+ // The problem here is that the PackageInfo instance backing the Package object is also
+ // temporary and the ownership is with the C++ side of the PackageManager.
+ // Ideally we should have kept the 'package' parameter as a dumb QVariantMap, but changing
+ // that back would be a huge API break nowadays as the QML APIs are fully typed.
+ // At least we have to make sure NOT to change anything in the PackageInfo instance after
+ // the signal emission below.
+ m_tempPackageForAcknowledge.reset(new Package(newPackage->info(), Package::BeingInstalled));
+ m_tempPackageForAcknowledge->moveToThread(m_pm->thread());
+ const auto &applicationInfos = newPackage->info()->applications();
+ for (const auto &applicationInfo : applicationInfos) {
+ auto tempApp = new Application(applicationInfo, m_tempPackageForAcknowledge.get());
+ tempApp->moveToThread(m_pm->thread());
+ m_tempPackageForAcknowledge->addApplication(tempApp);
+ m_tempApplicationsForAcknowledge.emplace_back(tempApp);
+ }
+ emit m_pm->taskRequestingInstallationAcknowledge(id(), m_tempPackageForAcknowledge.get(),
+ m_extractor->installationReport().extraMetaData(),
+ m_extractor->installationReport().extraSignedMetaData());
+
// if any of the apps in the package were running before, we now need to wait until all of
// them have actually stopped
while (!m_canceled && newPackage && !newPackage->areAllApplicationsStoppedDueToBlock())
@@ -373,9 +381,6 @@ void InstallationTask::checkExtractedFile(const QString &file) Q_DECL_NOEXCEPT_E
if (m_canceled || newPackage.isNull())
throw Exception(Error::Canceled, "canceled");
-
- // we're not interested in any other files from here on...
- m_extractor->setFileExtractedCallback(nullptr);
}
}
@@ -449,7 +454,6 @@ void InstallationTask::finishInstallation() Q_DECL_NOEXCEPT_EXPR(false)
// POSIX cannot atomically rename directories, if the destination directory exists
// and is non-empty. We need to do a double-rename in this case, which might fail!
- // The image is a file, so this limitation does not apply!
ScopedRenamer renameApplication;