From d369782ae182d1127a9ebdc6c181543409149cbd Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Fri, 22 Aug 2014 18:48:26 +0200 Subject: [PATCH 01/14] ntroduce the concept of package fallback --- src/plasma/package.cpp | 19 +++++++++++++++---- src/plasma/private/package_p.h | 2 ++ 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/plasma/package.cpp b/src/plasma/package.cpp index 6ad332167..cc93f4829 100644 --- a/src/plasma/package.cpp +++ b/src/plasma/package.cpp @@ -49,6 +49,7 @@ Package::Package(PackageStructure *structure) : d(new PackagePrivate()) { d->structure = structure; + d->fallbackPackage = Package(structure); if (d->structure) { d->structure.data()->initPackage(this); } @@ -290,7 +291,7 @@ QString Package::filePath(const char *fileType, const QString &filename) const { if (!d->valid) { //qDebug() << "package is not valid"; - return QString(); + return d->fallbackFilePath(fileType, filename); } const QString discoveryKey(fileType + filename); @@ -305,7 +306,7 @@ QString Package::filePath(const char *fileType, const QString &filename) const //qDebug()<contents.keys(); if (!d->contents.contains(fileType)) { //qDebug() << "package does not contain" << fileType << filename; - return QString(); + return d->fallbackFilePath(fileType, filename); } paths = d->contents[fileType].paths; @@ -313,7 +314,7 @@ QString Package::filePath(const char *fileType, const QString &filename) const if (paths.isEmpty()) { //qDebug() << "no matching path came of it, while looking for" << fileType << filename; d->discoveries.insert(discoveryKey, QString()); - return QString(); + return d->fallbackFilePath(fileType, filename); } } else { //when filetype is empty paths is always empty, so try with an empty string @@ -356,7 +357,7 @@ QString Package::filePath(const char *fileType, const QString &filename) const } //qDebug() << fileType << filename << "does not exist in" << prefixes << "at root" << d->path; - return QString(); + return d->fallbackFilePath(fileType, filename); } QStringList Package::entryList(const char *key) const @@ -792,6 +793,7 @@ PackagePrivate &PackagePrivate::operator=(const PackagePrivate &rhs) } structure = rhs.structure; + fallbackPackage = Package(structure.data()); path = rhs.path; contentsPrefixPaths = rhs.contentsPrefixPaths; servicePrefix = rhs.servicePrefix; @@ -871,4 +873,13 @@ void PackagePrivate::createPackageMetadata(const QString &path) metadata = new KPluginInfo(metadataPath); } +QString PackagePrivate::fallbackFilePath(const char *key, const QString &filename) const +{ + if (fallbackPackage.isValid()) { + return fallbackPackage.filePath(key, filename); + } else { + return QString(); + } +} + } // Namespace diff --git a/src/plasma/private/package_p.h b/src/plasma/private/package_p.h index d902eb11c..72fe03561 100644 --- a/src/plasma/private/package_p.h +++ b/src/plasma/private/package_p.h @@ -73,6 +73,7 @@ public: void createPackageMetadata(const QString &path); QString unpack(const QString &filePath); void updateHash(const QString &basePath, const QString &subPath, const QDir &dir, QCryptographicHash &hash); + QString fallbackFilePath(const char *key, const QString &filename = QString()) const; QWeakPointer structure; QString path; @@ -82,6 +83,7 @@ public: QString servicePrefix; QHash discoveries; QHash contents; + Package fallbackPackage; #ifndef PLASMA_NO_PACKAGE_EXTRADATA QStringList mimeTypes; #endif From e0db15c96d6eca6018ec9c1b3f8a4e6f0451f0e9 Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Fri, 22 Aug 2014 19:25:49 +0200 Subject: [PATCH 02/14] crash-- use a pointer, so we don't do infinite stack recursion create the fallback in the proper place --- .../data/servicetypes/plasma-shell.desktop | 2 ++ src/plasma/package.cpp | 26 ++++++++++++++++--- src/plasma/private/package_p.h | 2 +- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/plasma/data/servicetypes/plasma-shell.desktop b/src/plasma/data/servicetypes/plasma-shell.desktop index e2c83ba8b..b3b395d8e 100644 --- a/src/plasma/data/servicetypes/plasma-shell.desktop +++ b/src/plasma/data/servicetypes/plasma-shell.desktop @@ -57,3 +57,5 @@ Comment[uk]=Компоненти оболонки Плазми Comment[x-test]=xxPlasma Shell Componentsxx Comment[zh_TW]=Plasma Shell 組件 +[PropertyDef::X-KDE-fallbackPackage] +Type=QString diff --git a/src/plasma/package.cpp b/src/plasma/package.cpp index cc93f4829..633c66c25 100644 --- a/src/plasma/package.cpp +++ b/src/plasma/package.cpp @@ -49,7 +49,7 @@ Package::Package(PackageStructure *structure) : d(new PackagePrivate()) { d->structure = structure; - d->fallbackPackage = Package(structure); + if (d->structure) { d->structure.data()->initPackage(this); } @@ -498,6 +498,7 @@ void Package::setPath(const QString &path) } } + // if nothing did change, then we go back to the old dptr if (d->path == previousPath) { d = oldD; @@ -509,6 +510,21 @@ void Package::setPath(const QString &path) delete d->metadata; d->metadata = 0; + QString fallback; + + if (metadata().isValid()) { + fallback = metadata().property("X-KDE-fallbackPackage").toString(); + } + if (!fallback.isEmpty()) { + if (!d->fallbackPackage) { + d->fallbackPackage = new Package(d->structure.data()); + } + d->fallbackPackage->setPath(fallback); + } else { + delete d->fallbackPackage; + d->fallbackPackage = 0; + } + // uh-oh, but we didn't end up with anything valid, so we sadly reset ourselves // to futility. if (!d->valid) { @@ -762,6 +778,7 @@ KJob *Package::uninstall(const QString &packageName, const QString &packageRoot) PackagePrivate::PackagePrivate() : QSharedData(), servicePrefix("plasma-applet-"), + fallbackPackage(0), metadata(0), externalPaths(false), valid(false), @@ -793,7 +810,7 @@ PackagePrivate &PackagePrivate::operator=(const PackagePrivate &rhs) } structure = rhs.structure; - fallbackPackage = Package(structure.data()); + fallbackPackage = rhs.fallbackPackage; path = rhs.path; contentsPrefixPaths = rhs.contentsPrefixPaths; servicePrefix = rhs.servicePrefix; @@ -875,8 +892,9 @@ void PackagePrivate::createPackageMetadata(const QString &path) QString PackagePrivate::fallbackFilePath(const char *key, const QString &filename) const { - if (fallbackPackage.isValid()) { - return fallbackPackage.filePath(key, filename); + //don't fallback if the package isn't valid and never fallback the metadata file + if (fallbackPackage && fallbackPackage->isValid() && key != "metadata") { + return fallbackPackage->filePath(key, filename); } else { return QString(); } diff --git a/src/plasma/private/package_p.h b/src/plasma/private/package_p.h index 72fe03561..786847506 100644 --- a/src/plasma/private/package_p.h +++ b/src/plasma/private/package_p.h @@ -83,7 +83,7 @@ public: QString servicePrefix; QHash discoveries; QHash contents; - Package fallbackPackage; + Package *fallbackPackage; #ifndef PLASMA_NO_PACKAGE_EXTRADATA QStringList mimeTypes; #endif From 11094417a354779038e0e46fe7eae1605a090b7a Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Fri, 22 Aug 2014 19:27:09 +0200 Subject: [PATCH 03/14] delete the fallback --- src/plasma/package.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plasma/package.cpp b/src/plasma/package.cpp index 633c66c25..1a4f94731 100644 --- a/src/plasma/package.cpp +++ b/src/plasma/package.cpp @@ -801,6 +801,7 @@ PackagePrivate::~PackagePrivate() dir.removeRecursively(); } delete metadata; + delete fallbackPackage; } PackagePrivate &PackagePrivate::operator=(const PackagePrivate &rhs) From 5b9bb128d862ed25cb6449d25de153e75a673fad Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Wed, 27 Aug 2014 17:39:32 +0200 Subject: [PATCH 04/14] ckeck for loops or too deep fallback chains --- src/plasma/package.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/plasma/package.cpp b/src/plasma/package.cpp index 1a4f94731..5303e24b7 100644 --- a/src/plasma/package.cpp +++ b/src/plasma/package.cpp @@ -514,12 +514,27 @@ void Package::setPath(const QString &path) if (metadata().isValid()) { fallback = metadata().property("X-KDE-fallbackPackage").toString(); + if (fallback == metadata().pluginName()) { + fallback = QString(); + } } if (!fallback.isEmpty()) { if (!d->fallbackPackage) { d->fallbackPackage = new Package(d->structure.data()); } d->fallbackPackage->setPath(fallback); + Plasma::Package *pkg = d->fallbackPackage; + int depth = 0; + while (pkg->d->fallbackPackage) { + //cycle or too deep? + if (depth > 10 || pkg->d->fallbackPackage->metadata().pluginName() == metadata().pluginName()) { + delete pkg->d->fallbackPackage; + pkg->d->fallbackPackage = 0; + break; + } + pkg = pkg->d->fallbackPackage; + ++depth; + } } else { delete d->fallbackPackage; d->fallbackPackage = 0; From aba4dcb915832ed749e03c2fdadfb0a244f96f01 Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Mon, 1 Sep 2014 14:00:06 +0200 Subject: [PATCH 05/14] introduce setFallbackPackagePath the fallback package would then be decided by the packagestructure --- src/plasma/package.cpp | 70 ++++++++++++++++++++-------------- src/plasma/package.h | 15 ++++++++ src/plasma/private/package_p.h | 2 + 3 files changed, 59 insertions(+), 28 deletions(-) diff --git a/src/plasma/package.cpp b/src/plasma/package.cpp index 5303e24b7..720ad83d5 100644 --- a/src/plasma/package.cpp +++ b/src/plasma/package.cpp @@ -189,6 +189,21 @@ void Package::setDefaultPackageRoot(const QString &packageRoot) } } +void Package::setFallbackPackagePath(const QString &path) +{ + if (d->fallbackPackagePath == path) { + return; + } + + d->fallbackPackagePath = path; + d->updateFallbackPackage(); +} + +QString Package::fallbackPackagePath() const +{ + return d->fallbackPackagePath; +} + QString Package::servicePrefix() const { return d->servicePrefix; @@ -512,33 +527,7 @@ void Package::setPath(const QString &path) QString fallback; - if (metadata().isValid()) { - fallback = metadata().property("X-KDE-fallbackPackage").toString(); - if (fallback == metadata().pluginName()) { - fallback = QString(); - } - } - if (!fallback.isEmpty()) { - if (!d->fallbackPackage) { - d->fallbackPackage = new Package(d->structure.data()); - } - d->fallbackPackage->setPath(fallback); - Plasma::Package *pkg = d->fallbackPackage; - int depth = 0; - while (pkg->d->fallbackPackage) { - //cycle or too deep? - if (depth > 10 || pkg->d->fallbackPackage->metadata().pluginName() == metadata().pluginName()) { - delete pkg->d->fallbackPackage; - pkg->d->fallbackPackage = 0; - break; - } - pkg = pkg->d->fallbackPackage; - ++depth; - } - } else { - delete d->fallbackPackage; - d->fallbackPackage = 0; - } + d->updateFallbackPackage(); // uh-oh, but we didn't end up with anything valid, so we sadly reset ourselves // to futility. @@ -819,6 +808,31 @@ PackagePrivate::~PackagePrivate() delete fallbackPackage; } +void PackagePrivate::updateFallbackPackage() +{ + if (!fallbackPackagePath.isEmpty() && fallbackPackagePath != path) { + if (!fallbackPackage) { + fallbackPackage = new Package(structure.data()); + } + fallbackPackage->setPath(fallbackPackagePath); + Plasma::Package *pkg = fallbackPackage; + int depth = 0; + while (pkg->d->fallbackPackage) { + //cycle or too deep? + if (depth > 10 || (metadata && metadata->isValid() && pkg->d->fallbackPackage->metadata().pluginName() == metadata->pluginName())) { + delete pkg->d->fallbackPackage; + pkg->d->fallbackPackage = 0; + break; + } + pkg = pkg->d->fallbackPackage; + ++depth; + } + } else { + delete fallbackPackage; + fallbackPackage = 0; + } +} + PackagePrivate &PackagePrivate::operator=(const PackagePrivate &rhs) { if (&rhs == this) { @@ -909,7 +923,7 @@ void PackagePrivate::createPackageMetadata(const QString &path) QString PackagePrivate::fallbackFilePath(const char *key, const QString &filename) const { //don't fallback if the package isn't valid and never fallback the metadata file - if (fallbackPackage && fallbackPackage->isValid() && key != "metadata") { + if (fallbackPackage && fallbackPackage->isValid() && strcmp(key, "metadata") != 0) { return fallbackPackage->filePath(key, filename); } else { return QString(); diff --git a/src/plasma/package.h b/src/plasma/package.h index 2c686d784..3fc89022e 100644 --- a/src/plasma/package.h +++ b/src/plasma/package.h @@ -290,6 +290,20 @@ public: */ void setDefaultPackageRoot(const QString &packageRoot); + /** + * Sets the fallback package root path + * If a file won't be found in this package, it will search it in the package + * with the same structure identified by path + * It is intended to be used by the packageStructure + * @param path package root path @see setPath + */ + void setFallbackPackagePath(const QString &path); + + /** + * @return The fallback package root path + */ + QString fallbackPackagePath() const; + // Content structure description methods /** * @return all directories registered as part of this Package's structure @@ -328,6 +342,7 @@ public: private: QExplicitlySharedDataPointer d; + friend class PackagePrivate; }; } diff --git a/src/plasma/private/package_p.h b/src/plasma/private/package_p.h index 786847506..29e694ce7 100644 --- a/src/plasma/private/package_p.h +++ b/src/plasma/private/package_p.h @@ -74,6 +74,7 @@ public: QString unpack(const QString &filePath); void updateHash(const QString &basePath, const QString &subPath, const QDir &dir, QCryptographicHash &hash); QString fallbackFilePath(const char *key, const QString &filename = QString()) const; + void updateFallbackPackage(); QWeakPointer structure; QString path; @@ -83,6 +84,7 @@ public: QString servicePrefix; QHash discoveries; QHash contents; + QString fallbackPackagePath; Package *fallbackPackage; #ifndef PLASMA_NO_PACKAGE_EXTRADATA QStringList mimeTypes; From 21cf68dbd2547ea6ec32d935aafd46d83e12f1a1 Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Mon, 1 Sep 2014 14:54:10 +0200 Subject: [PATCH 06/14] set directly the fallback package not its path --- src/plasma/package.cpp | 46 +++++++++------------------------- src/plasma/package.h | 4 +-- src/plasma/private/package_p.h | 2 -- 3 files changed, 14 insertions(+), 38 deletions(-) diff --git a/src/plasma/package.cpp b/src/plasma/package.cpp index 720ad83d5..e1826311f 100644 --- a/src/plasma/package.cpp +++ b/src/plasma/package.cpp @@ -189,19 +189,24 @@ void Package::setDefaultPackageRoot(const QString &packageRoot) } } -void Package::setFallbackPackagePath(const QString &path) +void Package::setFallbackPackage(const Plasma::Package &package) { - if (d->fallbackPackagePath == path) { + if ((d->fallbackPackage && d->fallbackPackage->path() == package.path() && d->fallbackPackage->metadata() == package.metadata()) || + //can't be fallback of itself + (package.path() == path() && package.metadata() == metadata())) { return; } - d->fallbackPackagePath = path; - d->updateFallbackPackage(); + (*d->fallbackPackage) = package; } -QString Package::fallbackPackagePath() const +Plasma::Package Package::fallbackPackage() const { - return d->fallbackPackagePath; + if (d->fallbackPackage) { + return (*d->fallbackPackage); + } else { + return Package(); + } } QString Package::servicePrefix() const @@ -527,8 +532,6 @@ void Package::setPath(const QString &path) QString fallback; - d->updateFallbackPackage(); - // uh-oh, but we didn't end up with anything valid, so we sadly reset ourselves // to futility. if (!d->valid) { @@ -808,31 +811,6 @@ PackagePrivate::~PackagePrivate() delete fallbackPackage; } -void PackagePrivate::updateFallbackPackage() -{ - if (!fallbackPackagePath.isEmpty() && fallbackPackagePath != path) { - if (!fallbackPackage) { - fallbackPackage = new Package(structure.data()); - } - fallbackPackage->setPath(fallbackPackagePath); - Plasma::Package *pkg = fallbackPackage; - int depth = 0; - while (pkg->d->fallbackPackage) { - //cycle or too deep? - if (depth > 10 || (metadata && metadata->isValid() && pkg->d->fallbackPackage->metadata().pluginName() == metadata->pluginName())) { - delete pkg->d->fallbackPackage; - pkg->d->fallbackPackage = 0; - break; - } - pkg = pkg->d->fallbackPackage; - ++depth; - } - } else { - delete fallbackPackage; - fallbackPackage = 0; - } -} - PackagePrivate &PackagePrivate::operator=(const PackagePrivate &rhs) { if (&rhs == this) { @@ -840,7 +818,7 @@ PackagePrivate &PackagePrivate::operator=(const PackagePrivate &rhs) } structure = rhs.structure; - fallbackPackage = rhs.fallbackPackage; + (*fallbackPackage) = (*rhs.fallbackPackage); path = rhs.path; contentsPrefixPaths = rhs.contentsPrefixPaths; servicePrefix = rhs.servicePrefix; diff --git a/src/plasma/package.h b/src/plasma/package.h index 3fc89022e..28f8b08a1 100644 --- a/src/plasma/package.h +++ b/src/plasma/package.h @@ -297,12 +297,12 @@ public: * It is intended to be used by the packageStructure * @param path package root path @see setPath */ - void setFallbackPackagePath(const QString &path); + void setFallbackPackage(const Plasma::Package &package); /** * @return The fallback package root path */ - QString fallbackPackagePath() const; + Plasma::Package fallbackPackage() const; // Content structure description methods /** diff --git a/src/plasma/private/package_p.h b/src/plasma/private/package_p.h index 29e694ce7..786847506 100644 --- a/src/plasma/private/package_p.h +++ b/src/plasma/private/package_p.h @@ -74,7 +74,6 @@ public: QString unpack(const QString &filePath); void updateHash(const QString &basePath, const QString &subPath, const QDir &dir, QCryptographicHash &hash); QString fallbackFilePath(const char *key, const QString &filename = QString()) const; - void updateFallbackPackage(); QWeakPointer structure; QString path; @@ -84,7 +83,6 @@ public: QString servicePrefix; QHash discoveries; QHash contents; - QString fallbackPackagePath; Package *fallbackPackage; #ifndef PLASMA_NO_PACKAGE_EXTRADATA QStringList mimeTypes; From 55a609513877d04ee4984b918f050184bcbb1bab Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Mon, 1 Sep 2014 15:15:54 +0200 Subject: [PATCH 07/14] use Floyd cycle detection --- src/plasma/package.cpp | 26 +++++++++++++++++++++++++- src/plasma/private/package_p.h | 1 + 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/plasma/package.cpp b/src/plasma/package.cpp index e1826311f..4fa5150ca 100644 --- a/src/plasma/package.cpp +++ b/src/plasma/package.cpp @@ -193,7 +193,8 @@ void Package::setFallbackPackage(const Plasma::Package &package) { if ((d->fallbackPackage && d->fallbackPackage->path() == package.path() && d->fallbackPackage->metadata() == package.metadata()) || //can't be fallback of itself - (package.path() == path() && package.metadata() == metadata())) { + (package.path() == path() && package.metadata() == metadata()) || + d->hasCycle(package)) { return; } @@ -908,4 +909,27 @@ QString PackagePrivate::fallbackFilePath(const char *key, const QString &filenam } } +bool PackagePrivate::hasCycle(const Plasma::Package &package) +{ + if (!package.d->fallbackPackage) { + return false; + } + + //This is the Floyd cycle detection algorithm + //http://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare + const Plasma::Package *slowPackage = &package; + const Plasma::Package *fastPackage = &package; + + while (fastPackage && fastPackage->d->fallbackPackage) { + //consider two packages the same if they have the same metadata + if ((fastPackage->d->fallbackPackage->metadata().isValid() && fastPackage->d->fallbackPackage->metadata() == slowPackage->metadata()) || + (fastPackage->d->fallbackPackage->d->fallbackPackage->metadata().isValid() && fastPackage->d->fallbackPackage->d->fallbackPackage->metadata() == slowPackage->metadata())) { + return true; + } + fastPackage = fastPackage->d->fallbackPackage->d->fallbackPackage; + slowPackage = slowPackage->d->fallbackPackage; + } + return false; +} + } // Namespace diff --git a/src/plasma/private/package_p.h b/src/plasma/private/package_p.h index 786847506..ddf2bdb84 100644 --- a/src/plasma/private/package_p.h +++ b/src/plasma/private/package_p.h @@ -74,6 +74,7 @@ public: QString unpack(const QString &filePath); void updateHash(const QString &basePath, const QString &subPath, const QDir &dir, QCryptographicHash &hash); QString fallbackFilePath(const char *key, const QString &filename = QString()) const; + bool hasCycle(const Plasma::Package &package); QWeakPointer structure; QString path; From 5ceb8d1197c87c1a871845a3e058bbbff98c0062 Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Mon, 1 Sep 2014 15:51:05 +0200 Subject: [PATCH 08/14] add an autotest for fallback correct a couple of problems the test catched --- autotests/CMakeLists.txt | 1 + .../testfallbackpackage/contents/ui/main.qml | 7 ++ .../data/testfallbackpackage/metadata.desktop | 15 ++++ .../testpackage/contents/ui/otherfile.qml | 7 ++ autotests/fallbackpackagetest.cpp | 68 +++++++++++++++++++ autotests/fallbackpackagetest.h | 46 +++++++++++++ src/plasma/package.cpp | 8 ++- 7 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 autotests/data/testfallbackpackage/contents/ui/main.qml create mode 100644 autotests/data/testfallbackpackage/metadata.desktop create mode 100644 autotests/data/testpackage/contents/ui/otherfile.qml create mode 100644 autotests/fallbackpackagetest.cpp create mode 100644 autotests/fallbackpackagetest.h diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index 4e64f38dc..544834c0c 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -37,6 +37,7 @@ MACRO(PLASMA_UNIT_TESTS) ENDMACRO(PLASMA_UNIT_TESTS) PLASMA_UNIT_TESTS( + fallbackpackagetest packagestructuretest packageurlinterceptortest pluginloadertest diff --git a/autotests/data/testfallbackpackage/contents/ui/main.qml b/autotests/data/testfallbackpackage/contents/ui/main.qml new file mode 100644 index 000000000..cde850a9d --- /dev/null +++ b/autotests/data/testfallbackpackage/contents/ui/main.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 + +Rectangle { + id: root + color: "darkblue" +} + diff --git a/autotests/data/testfallbackpackage/metadata.desktop b/autotests/data/testfallbackpackage/metadata.desktop new file mode 100644 index 000000000..f39f4947d --- /dev/null +++ b/autotests/data/testfallbackpackage/metadata.desktop @@ -0,0 +1,15 @@ +[Desktop Entry] +Encoding=UTF-8 +Keywords= +Name=Test Fallback Package +Type=Service + +X-KDE-ParentApp= +X-KDE-PluginInfo-Author=Marco Martin +X-KDE-PluginInfo-Category= +X-KDE-PluginInfo-Email=mart@kde.org +X-KDE-PluginInfo-License=GPLv2+ +X-KDE-PluginInfo-Name=org.kde.testfallbackpackage +X-KDE-PluginInfo-Version= +X-KDE-PluginInfo-Website= +X-Plasma-MainScript=ui/main.qml diff --git a/autotests/data/testpackage/contents/ui/otherfile.qml b/autotests/data/testpackage/contents/ui/otherfile.qml new file mode 100644 index 000000000..cde850a9d --- /dev/null +++ b/autotests/data/testpackage/contents/ui/otherfile.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 + +Rectangle { + id: root + color: "darkblue" +} + diff --git a/autotests/fallbackpackagetest.cpp b/autotests/fallbackpackagetest.cpp new file mode 100644 index 000000000..f44a0eaba --- /dev/null +++ b/autotests/fallbackpackagetest.cpp @@ -0,0 +1,68 @@ +/****************************************************************************** +* Copyright 2007 by Aaron Seigo * +* Copyright 2014 Marco Martin * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Library General Public * +* License as published by the Free Software Foundation; either * +* version 2 of the License, or (at your option) any later version. * +* * +* This library is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * +* Library General Public License for more details. * +* * +* You should have received a copy of the GNU Library General Public License * +* along with this library; see the file COPYING.LIB. If not, write to * +* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * +* Boston, MA 02110-1301, USA. * +*******************************************************************************/ + +#include "fallbackpackagetest.h" + + +#include + +#include "packagestructure.h" +#include "pluginloader.h" + +void FallbackPackageTest::initTestCase() +{ + m_packagePath = QFINDTESTDATA("data/testpackage"); + m_pkg = Plasma::PluginLoader::self()->loadPackage("Plasma/Generic"); + m_pkg.setPath(m_packagePath); + + m_fallPackagePath = QFINDTESTDATA("data/testfallbackpackage"); + m_fallPkg = Plasma::PluginLoader::self()->loadPackage("Plasma/Generic"); + m_fallPkg.setPath(m_fallPackagePath); +} + +void FallbackPackageTest::beforeFallback() +{ + QVERIFY(m_pkg.hasValidStructure()); + QVERIFY(m_fallPkg.hasValidStructure()); + + QVERIFY(!m_pkg.filePath("ui", "otherfile.qml").isEmpty()); + QVERIFY(m_fallPkg.filePath("ui", "otherfile.qml").isEmpty()); +} + +void FallbackPackageTest::afterFallback() +{ + m_fallPkg.setFallbackPackage(m_pkg); + + QVERIFY(!m_fallPkg.filePath("ui", "otherfile.qml").isEmpty()); + QCOMPARE(m_pkg.filePath("ui", "otherfile.qml"), m_fallPkg.filePath("ui", "otherfile.qml")); + QVERIFY(m_pkg.filePath("mainscript") != m_fallPkg.filePath("mainscript")); +} + +void FallbackPackageTest::cycle() +{ + m_pkg.setFallbackPackage(m_fallPkg); + m_fallPkg.setFallbackPackage(m_pkg); + + //The cycle should have been detected and filePath should take a not infinite tiume + QCOMPARE(m_pkg.filePath("ui", "otherfile.qml"), m_fallPkg.filePath("ui", "otherfile.qml")); +} + +QTEST_MAIN(FallbackPackageTest) + diff --git a/autotests/fallbackpackagetest.h b/autotests/fallbackpackagetest.h new file mode 100644 index 000000000..66e777f7f --- /dev/null +++ b/autotests/fallbackpackagetest.h @@ -0,0 +1,46 @@ +/****************************************************************************** +* Copyright 2007 by Aaron Seigo * +* Copyright 2014 Marco Martin * +* * +* This library is free software; you can redistribute it and/or * +* modify it under the terms of the GNU Library General Public * +* License as published by the Free Software Foundation; either * +* version 2 of the License, or (at your option) any later version. * +* * +* This library is distributed in the hope that it will be useful, * +* but WITHOUT ANY WARRANTY; without even the implied warranty of * +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * +* Library General Public License for more details. * +* * +* You should have received a copy of the GNU Library General Public License * +* along with this library; see the file COPYING.LIB. If not, write to * +* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * +* Boston, MA 02110-1301, USA. * +*******************************************************************************/ + +#ifndef FALLBACKPACKAGETEST_H + +#include + +#include "plasma/package.h" + +class FallbackPackageTest : public QObject +{ + Q_OBJECT + +private Q_SLOTS: + void initTestCase(); + void beforeFallback(); + void afterFallback(); + void cycle(); + + +private: + Plasma::Package m_pkg; + Plasma::Package m_fallPkg; + QString m_packagePath; + QString m_fallPackagePath; +}; + +#endif + diff --git a/src/plasma/package.cpp b/src/plasma/package.cpp index 4fa5150ca..c65eda30b 100644 --- a/src/plasma/package.cpp +++ b/src/plasma/package.cpp @@ -198,7 +198,7 @@ void Package::setFallbackPackage(const Plasma::Package &package) return; } - (*d->fallbackPackage) = package; + d->fallbackPackage = new Package(package); } Plasma::Package Package::fallbackPackage() const @@ -819,7 +819,9 @@ PackagePrivate &PackagePrivate::operator=(const PackagePrivate &rhs) } structure = rhs.structure; - (*fallbackPackage) = (*rhs.fallbackPackage); + if (rhs.fallbackPackage) { + (*fallbackPackage) = (*rhs.fallbackPackage); + } path = rhs.path; contentsPrefixPaths = rhs.contentsPrefixPaths; servicePrefix = rhs.servicePrefix; @@ -923,7 +925,7 @@ bool PackagePrivate::hasCycle(const Plasma::Package &package) while (fastPackage && fastPackage->d->fallbackPackage) { //consider two packages the same if they have the same metadata if ((fastPackage->d->fallbackPackage->metadata().isValid() && fastPackage->d->fallbackPackage->metadata() == slowPackage->metadata()) || - (fastPackage->d->fallbackPackage->d->fallbackPackage->metadata().isValid() && fastPackage->d->fallbackPackage->d->fallbackPackage->metadata() == slowPackage->metadata())) { + (fastPackage->d->fallbackPackage->d->fallbackPackage && fastPackage->d->fallbackPackage->d->fallbackPackage->metadata().isValid() && fastPackage->d->fallbackPackage->d->fallbackPackage->metadata() == slowPackage->metadata())) { return true; } fastPackage = fastPackage->d->fallbackPackage->d->fallbackPackage; From 36e585d7e7ddb689a870d0a43ac676e6495a8fb2 Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Mon, 1 Sep 2014 15:53:58 +0200 Subject: [PATCH 09/14] comments++ --- autotests/fallbackpackagetest.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/autotests/fallbackpackagetest.cpp b/autotests/fallbackpackagetest.cpp index f44a0eaba..8d41ad158 100644 --- a/autotests/fallbackpackagetest.cpp +++ b/autotests/fallbackpackagetest.cpp @@ -42,6 +42,7 @@ void FallbackPackageTest::beforeFallback() QVERIFY(m_pkg.hasValidStructure()); QVERIFY(m_fallPkg.hasValidStructure()); + //m_pkg should have otherfile.qml, m_fallPkg shouldn't QVERIFY(!m_pkg.filePath("ui", "otherfile.qml").isEmpty()); QVERIFY(m_fallPkg.filePath("ui", "otherfile.qml").isEmpty()); } @@ -50,6 +51,8 @@ void FallbackPackageTest::afterFallback() { m_fallPkg.setFallbackPackage(m_pkg); + //afetr setting the fallback, m_fallPkg should resolve the exact same file as m_pkg + // for otherfile.qml QVERIFY(!m_fallPkg.filePath("ui", "otherfile.qml").isEmpty()); QCOMPARE(m_pkg.filePath("ui", "otherfile.qml"), m_fallPkg.filePath("ui", "otherfile.qml")); QVERIFY(m_pkg.filePath("mainscript") != m_fallPkg.filePath("mainscript")); From 325ea71a2e5d88a24629ef0176bc566ae4f0010b Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Mon, 1 Sep 2014 16:01:10 +0200 Subject: [PATCH 10/14] remove the fallback from the metadata --- src/plasma/data/servicetypes/plasma-shell.desktop | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/plasma/data/servicetypes/plasma-shell.desktop b/src/plasma/data/servicetypes/plasma-shell.desktop index b3b395d8e..ab7ac686c 100644 --- a/src/plasma/data/servicetypes/plasma-shell.desktop +++ b/src/plasma/data/servicetypes/plasma-shell.desktop @@ -56,6 +56,3 @@ Comment[sv]=Plasma skalkomponenter Comment[uk]=Компоненти оболонки Плазми Comment[x-test]=xxPlasma Shell Componentsxx Comment[zh_TW]=Plasma Shell 組件 - -[PropertyDef::X-KDE-fallbackPackage] -Type=QString From 5db7db4ae2fde2838a43b2ac8b55705c5b39ee8e Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Mon, 1 Sep 2014 16:26:34 +0200 Subject: [PATCH 11/14] crash-- --- src/plasma/package.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/plasma/package.cpp b/src/plasma/package.cpp index c65eda30b..1e80bbdd8 100644 --- a/src/plasma/package.cpp +++ b/src/plasma/package.cpp @@ -820,7 +820,9 @@ PackagePrivate &PackagePrivate::operator=(const PackagePrivate &rhs) structure = rhs.structure; if (rhs.fallbackPackage) { - (*fallbackPackage) = (*rhs.fallbackPackage); + fallbackPackage = new Package(*rhs.fallbackPackage); + } else { + fallbackPackage = 0; } path = rhs.path; contentsPrefixPaths = rhs.contentsPrefixPaths; @@ -904,7 +906,7 @@ void PackagePrivate::createPackageMetadata(const QString &path) QString PackagePrivate::fallbackFilePath(const char *key, const QString &filename) const { //don't fallback if the package isn't valid and never fallback the metadata file - if (fallbackPackage && fallbackPackage->isValid() && strcmp(key, "metadata") != 0) { + if (qstrcmp(key, "metadata") != 0 && fallbackPackage && fallbackPackage->isValid()) { return fallbackPackage->filePath(key, filename); } else { return QString(); From 7e73be169c741f8159772f95d0e8025873120f74 Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Mon, 1 Sep 2014 16:40:38 +0200 Subject: [PATCH 12/14] add a timeout, in case the cycle was infinite --- autotests/fallbackpackagetest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autotests/fallbackpackagetest.cpp b/autotests/fallbackpackagetest.cpp index 8d41ad158..293798e88 100644 --- a/autotests/fallbackpackagetest.cpp +++ b/autotests/fallbackpackagetest.cpp @@ -64,7 +64,7 @@ void FallbackPackageTest::cycle() m_fallPkg.setFallbackPackage(m_pkg); //The cycle should have been detected and filePath should take a not infinite tiume - QCOMPARE(m_pkg.filePath("ui", "otherfile.qml"), m_fallPkg.filePath("ui", "otherfile.qml")); + QTRY_COMPARE_WITH_TIMEOUT(m_pkg.filePath("ui", "otherfile.qml"), m_fallPkg.filePath("ui", "otherfile.qml"), 1000); } QTEST_MAIN(FallbackPackageTest) From 6be2e9d46dca5d037f6b64332016170b6b4d3352 Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Mon, 1 Sep 2014 19:23:18 +0200 Subject: [PATCH 13/14] use non const pointers --- autotests/fallbackpackagetest.cpp | 34 +++++++++++++++---------------- src/plasma/package.cpp | 5 +++-- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/autotests/fallbackpackagetest.cpp b/autotests/fallbackpackagetest.cpp index 293798e88..ae2fa24ad 100644 --- a/autotests/fallbackpackagetest.cpp +++ b/autotests/fallbackpackagetest.cpp @@ -28,43 +28,43 @@ void FallbackPackageTest::initTestCase() { - m_packagePath = QFINDTESTDATA("data/testpackage"); - m_pkg = Plasma::PluginLoader::self()->loadPackage("Plasma/Generic"); - m_pkg.setPath(m_packagePath); - - m_fallPackagePath = QFINDTESTDATA("data/testfallbackpackage"); + m_fallPackagePath = QFINDTESTDATA("data/testpackage"); m_fallPkg = Plasma::PluginLoader::self()->loadPackage("Plasma/Generic"); m_fallPkg.setPath(m_fallPackagePath); + + m_packagePath = QFINDTESTDATA("data/testfallbackpackage"); + m_pkg = Plasma::PluginLoader::self()->loadPackage("Plasma/Generic"); + m_pkg.setPath(m_packagePath); } void FallbackPackageTest::beforeFallback() { - QVERIFY(m_pkg.hasValidStructure()); QVERIFY(m_fallPkg.hasValidStructure()); + QVERIFY(m_pkg.hasValidStructure()); - //m_pkg should have otherfile.qml, m_fallPkg shouldn't - QVERIFY(!m_pkg.filePath("ui", "otherfile.qml").isEmpty()); - QVERIFY(m_fallPkg.filePath("ui", "otherfile.qml").isEmpty()); + //m_fallPkg should have otherfile.qml, m_pkg shouldn't + QVERIFY(!m_fallPkg.filePath("ui", "otherfile.qml").isEmpty()); + QVERIFY(m_pkg.filePath("ui", "otherfile.qml").isEmpty()); } void FallbackPackageTest::afterFallback() { - m_fallPkg.setFallbackPackage(m_pkg); + m_pkg.setFallbackPackage(m_fallPkg); - //afetr setting the fallback, m_fallPkg should resolve the exact same file as m_pkg + //after setting the fallback, m_pkg should resolve the exact same file as m_fallPkg // for otherfile.qml - QVERIFY(!m_fallPkg.filePath("ui", "otherfile.qml").isEmpty()); - QCOMPARE(m_pkg.filePath("ui", "otherfile.qml"), m_fallPkg.filePath("ui", "otherfile.qml")); - QVERIFY(m_pkg.filePath("mainscript") != m_fallPkg.filePath("mainscript")); + QVERIFY(!m_pkg.filePath("ui", "otherfile.qml").isEmpty()); + QCOMPARE(m_fallPkg.filePath("ui", "otherfile.qml"), m_pkg.filePath("ui", "otherfile.qml")); + QVERIFY(m_fallPkg.filePath("mainscript") != m_pkg.filePath("mainscript")); } void FallbackPackageTest::cycle() { - m_pkg.setFallbackPackage(m_fallPkg); m_fallPkg.setFallbackPackage(m_pkg); + m_pkg.setFallbackPackage(m_fallPkg); - //The cycle should have been detected and filePath should take a not infinite tiume - QTRY_COMPARE_WITH_TIMEOUT(m_pkg.filePath("ui", "otherfile.qml"), m_fallPkg.filePath("ui", "otherfile.qml"), 1000); + //The cycle should have been detected and filePath should take a not infinite time + QTRY_COMPARE_WITH_TIMEOUT(m_fallPkg.filePath("ui", "otherfile.qml"), m_pkg.filePath("ui", "otherfile.qml"), 1000); } QTEST_MAIN(FallbackPackageTest) diff --git a/src/plasma/package.cpp b/src/plasma/package.cpp index 1e80bbdd8..1b4c90cb7 100644 --- a/src/plasma/package.cpp +++ b/src/plasma/package.cpp @@ -921,13 +921,14 @@ bool PackagePrivate::hasCycle(const Plasma::Package &package) //This is the Floyd cycle detection algorithm //http://en.wikipedia.org/wiki/Cycle_detection#Tortoise_and_hare - const Plasma::Package *slowPackage = &package; - const Plasma::Package *fastPackage = &package; + Plasma::Package *slowPackage = const_cast(&package); + Plasma::Package *fastPackage = const_cast(&package); while (fastPackage && fastPackage->d->fallbackPackage) { //consider two packages the same if they have the same metadata if ((fastPackage->d->fallbackPackage->metadata().isValid() && fastPackage->d->fallbackPackage->metadata() == slowPackage->metadata()) || (fastPackage->d->fallbackPackage->d->fallbackPackage && fastPackage->d->fallbackPackage->d->fallbackPackage->metadata().isValid() && fastPackage->d->fallbackPackage->d->fallbackPackage->metadata() == slowPackage->metadata())) { + qWarning() << "Warning: the fallback chain of " << package.metadata().pluginName() << "contains a cyclical dependency."; return true; } fastPackage = fastPackage->d->fallbackPackage->d->fallbackPackage; From 04593a3f1bdc3eedeb52f24fa6ac1fc4dfbe8090 Mon Sep 17 00:00:00 2001 From: Marco Martin Date: Mon, 1 Sep 2014 20:36:06 +0200 Subject: [PATCH 14/14] more verbose name --- autotests/fallbackpackagetest.cpp | 24 ++++++++++++------------ autotests/fallbackpackagetest.h | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/autotests/fallbackpackagetest.cpp b/autotests/fallbackpackagetest.cpp index ae2fa24ad..91bc6e93d 100644 --- a/autotests/fallbackpackagetest.cpp +++ b/autotests/fallbackpackagetest.cpp @@ -29,8 +29,8 @@ void FallbackPackageTest::initTestCase() { m_fallPackagePath = QFINDTESTDATA("data/testpackage"); - m_fallPkg = Plasma::PluginLoader::self()->loadPackage("Plasma/Generic"); - m_fallPkg.setPath(m_fallPackagePath); + m_fallbackPkg = Plasma::PluginLoader::self()->loadPackage("Plasma/Generic"); + m_fallbackPkg.setPath(m_fallPackagePath); m_packagePath = QFINDTESTDATA("data/testfallbackpackage"); m_pkg = Plasma::PluginLoader::self()->loadPackage("Plasma/Generic"); @@ -39,32 +39,32 @@ void FallbackPackageTest::initTestCase() void FallbackPackageTest::beforeFallback() { - QVERIFY(m_fallPkg.hasValidStructure()); + QVERIFY(m_fallbackPkg.hasValidStructure()); QVERIFY(m_pkg.hasValidStructure()); - //m_fallPkg should have otherfile.qml, m_pkg shouldn't - QVERIFY(!m_fallPkg.filePath("ui", "otherfile.qml").isEmpty()); + //m_fallbackPkg should have otherfile.qml, m_pkg shouldn't + QVERIFY(!m_fallbackPkg.filePath("ui", "otherfile.qml").isEmpty()); QVERIFY(m_pkg.filePath("ui", "otherfile.qml").isEmpty()); } void FallbackPackageTest::afterFallback() { - m_pkg.setFallbackPackage(m_fallPkg); + m_pkg.setFallbackPackage(m_fallbackPkg); - //after setting the fallback, m_pkg should resolve the exact same file as m_fallPkg + //after setting the fallback, m_pkg should resolve the exact same file as m_fallbackPkg // for otherfile.qml QVERIFY(!m_pkg.filePath("ui", "otherfile.qml").isEmpty()); - QCOMPARE(m_fallPkg.filePath("ui", "otherfile.qml"), m_pkg.filePath("ui", "otherfile.qml")); - QVERIFY(m_fallPkg.filePath("mainscript") != m_pkg.filePath("mainscript")); + QCOMPARE(m_fallbackPkg.filePath("ui", "otherfile.qml"), m_pkg.filePath("ui", "otherfile.qml")); + QVERIFY(m_fallbackPkg.filePath("mainscript") != m_pkg.filePath("mainscript")); } void FallbackPackageTest::cycle() { - m_fallPkg.setFallbackPackage(m_pkg); - m_pkg.setFallbackPackage(m_fallPkg); + m_fallbackPkg.setFallbackPackage(m_pkg); + m_pkg.setFallbackPackage(m_fallbackPkg); //The cycle should have been detected and filePath should take a not infinite time - QTRY_COMPARE_WITH_TIMEOUT(m_fallPkg.filePath("ui", "otherfile.qml"), m_pkg.filePath("ui", "otherfile.qml"), 1000); + QTRY_COMPARE_WITH_TIMEOUT(m_fallbackPkg.filePath("ui", "otherfile.qml"), m_pkg.filePath("ui", "otherfile.qml"), 1000); } QTEST_MAIN(FallbackPackageTest) diff --git a/autotests/fallbackpackagetest.h b/autotests/fallbackpackagetest.h index 66e777f7f..a1bdb4a3c 100644 --- a/autotests/fallbackpackagetest.h +++ b/autotests/fallbackpackagetest.h @@ -37,7 +37,7 @@ private Q_SLOTS: private: Plasma::Package m_pkg; - Plasma::Package m_fallPkg; + Plasma::Package m_fallbackPkg; QString m_packagePath; QString m_fallPackagePath; };