diff options
| -rw-r--r-- | .cmake.conf | 2 | ||||
| -rw-r--r-- | dependencies.yaml | 8 | ||||
| -rw-r--r-- | src/common-lib/qtyaml.cpp | 157 | ||||
| -rw-r--r-- | src/dbus-lib/packagemanagerdbuscontextadaptor.cpp | 8 | ||||
| -rw-r--r-- | src/manager-lib/applicationmanager.cpp | 25 | ||||
| -rw-r--r-- | src/manager-lib/applicationmanager.h | 2 | ||||
| -rw-r--r-- | src/manager-lib/installationtask.cpp | 48 |
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; |
