Merge branch 'mart/packageFallback'
REVIEW:120029
This commit is contained in:
commit
8c8bd49130
@ -37,6 +37,7 @@ MACRO(PLASMA_UNIT_TESTS)
|
|||||||
ENDMACRO(PLASMA_UNIT_TESTS)
|
ENDMACRO(PLASMA_UNIT_TESTS)
|
||||||
|
|
||||||
PLASMA_UNIT_TESTS(
|
PLASMA_UNIT_TESTS(
|
||||||
|
fallbackpackagetest
|
||||||
packagestructuretest
|
packagestructuretest
|
||||||
packageurlinterceptortest
|
packageurlinterceptortest
|
||||||
pluginloadertest
|
pluginloadertest
|
||||||
|
7
autotests/data/testfallbackpackage/contents/ui/main.qml
Normal file
7
autotests/data/testfallbackpackage/contents/ui/main.qml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import QtQuick 2.0
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
color: "darkblue"
|
||||||
|
}
|
||||||
|
|
15
autotests/data/testfallbackpackage/metadata.desktop
Normal file
15
autotests/data/testfallbackpackage/metadata.desktop
Normal file
@ -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
|
7
autotests/data/testpackage/contents/ui/otherfile.qml
Normal file
7
autotests/data/testpackage/contents/ui/otherfile.qml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
import QtQuick 2.0
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
color: "darkblue"
|
||||||
|
}
|
||||||
|
|
71
autotests/fallbackpackagetest.cpp
Normal file
71
autotests/fallbackpackagetest.cpp
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Copyright 2007 by Aaron Seigo <aseigo@kde.org> *
|
||||||
|
* Copyright 2014 Marco Martin <mart@kde.org> *
|
||||||
|
* *
|
||||||
|
* 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 <QDebug>
|
||||||
|
|
||||||
|
#include "packagestructure.h"
|
||||||
|
#include "pluginloader.h"
|
||||||
|
|
||||||
|
void FallbackPackageTest::initTestCase()
|
||||||
|
{
|
||||||
|
m_fallPackagePath = QFINDTESTDATA("data/testpackage");
|
||||||
|
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");
|
||||||
|
m_pkg.setPath(m_packagePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FallbackPackageTest::beforeFallback()
|
||||||
|
{
|
||||||
|
QVERIFY(m_fallbackPkg.hasValidStructure());
|
||||||
|
QVERIFY(m_pkg.hasValidStructure());
|
||||||
|
|
||||||
|
//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_fallbackPkg);
|
||||||
|
|
||||||
|
//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_fallbackPkg.filePath("ui", "otherfile.qml"), m_pkg.filePath("ui", "otherfile.qml"));
|
||||||
|
QVERIFY(m_fallbackPkg.filePath("mainscript") != m_pkg.filePath("mainscript"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FallbackPackageTest::cycle()
|
||||||
|
{
|
||||||
|
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_fallbackPkg.filePath("ui", "otherfile.qml"), m_pkg.filePath("ui", "otherfile.qml"), 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
QTEST_MAIN(FallbackPackageTest)
|
||||||
|
|
46
autotests/fallbackpackagetest.h
Normal file
46
autotests/fallbackpackagetest.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Copyright 2007 by Aaron Seigo <aseigo@kde.org> *
|
||||||
|
* Copyright 2014 Marco Martin <mart@kde.org> *
|
||||||
|
* *
|
||||||
|
* 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 <QtTest/QtTest>
|
||||||
|
|
||||||
|
#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_fallbackPkg;
|
||||||
|
QString m_packagePath;
|
||||||
|
QString m_fallPackagePath;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -56,4 +56,3 @@ Comment[sv]=Plasma skalkomponenter
|
|||||||
Comment[uk]=Компоненти оболонки Плазми
|
Comment[uk]=Компоненти оболонки Плазми
|
||||||
Comment[x-test]=xxPlasma Shell Componentsxx
|
Comment[x-test]=xxPlasma Shell Componentsxx
|
||||||
Comment[zh_TW]=Plasma Shell 組件
|
Comment[zh_TW]=Plasma Shell 組件
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@ Package::Package(PackageStructure *structure)
|
|||||||
: d(new PackagePrivate())
|
: d(new PackagePrivate())
|
||||||
{
|
{
|
||||||
d->structure = structure;
|
d->structure = structure;
|
||||||
|
|
||||||
if (d->structure) {
|
if (d->structure) {
|
||||||
d->structure.data()->initPackage(this);
|
d->structure.data()->initPackage(this);
|
||||||
}
|
}
|
||||||
@ -188,6 +189,27 @@ void Package::setDefaultPackageRoot(const QString &packageRoot)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()) ||
|
||||||
|
d->hasCycle(package)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
d->fallbackPackage = new Package(package);
|
||||||
|
}
|
||||||
|
|
||||||
|
Plasma::Package Package::fallbackPackage() const
|
||||||
|
{
|
||||||
|
if (d->fallbackPackage) {
|
||||||
|
return (*d->fallbackPackage);
|
||||||
|
} else {
|
||||||
|
return Package();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString Package::servicePrefix() const
|
QString Package::servicePrefix() const
|
||||||
{
|
{
|
||||||
return d->servicePrefix;
|
return d->servicePrefix;
|
||||||
@ -290,7 +312,7 @@ QString Package::filePath(const char *fileType, const QString &filename) const
|
|||||||
{
|
{
|
||||||
if (!d->valid) {
|
if (!d->valid) {
|
||||||
//qDebug() << "package is not valid";
|
//qDebug() << "package is not valid";
|
||||||
return QString();
|
return d->fallbackFilePath(fileType, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString discoveryKey(fileType + filename);
|
const QString discoveryKey(fileType + filename);
|
||||||
@ -305,7 +327,7 @@ QString Package::filePath(const char *fileType, const QString &filename) const
|
|||||||
//qDebug()<<d->contents.keys();
|
//qDebug()<<d->contents.keys();
|
||||||
if (!d->contents.contains(fileType)) {
|
if (!d->contents.contains(fileType)) {
|
||||||
//qDebug() << "package does not contain" << fileType << filename;
|
//qDebug() << "package does not contain" << fileType << filename;
|
||||||
return QString();
|
return d->fallbackFilePath(fileType, filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
paths = d->contents[fileType].paths;
|
paths = d->contents[fileType].paths;
|
||||||
@ -313,7 +335,7 @@ QString Package::filePath(const char *fileType, const QString &filename) const
|
|||||||
if (paths.isEmpty()) {
|
if (paths.isEmpty()) {
|
||||||
//qDebug() << "no matching path came of it, while looking for" << fileType << filename;
|
//qDebug() << "no matching path came of it, while looking for" << fileType << filename;
|
||||||
d->discoveries.insert(discoveryKey, QString());
|
d->discoveries.insert(discoveryKey, QString());
|
||||||
return QString();
|
return d->fallbackFilePath(fileType, filename);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//when filetype is empty paths is always empty, so try with an empty string
|
//when filetype is empty paths is always empty, so try with an empty string
|
||||||
@ -356,7 +378,7 @@ QString Package::filePath(const char *fileType, const QString &filename) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
//qDebug() << fileType << filename << "does not exist in" << prefixes << "at root" << d->path;
|
//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
|
QStringList Package::entryList(const char *key) const
|
||||||
@ -500,6 +522,7 @@ void Package::setPath(const QString &path)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// if nothing did change, then we go back to the old dptr
|
// if nothing did change, then we go back to the old dptr
|
||||||
if (d->path == previousPath) {
|
if (d->path == previousPath) {
|
||||||
d = oldD;
|
d = oldD;
|
||||||
@ -511,6 +534,8 @@ void Package::setPath(const QString &path)
|
|||||||
delete d->metadata;
|
delete d->metadata;
|
||||||
d->metadata = 0;
|
d->metadata = 0;
|
||||||
|
|
||||||
|
QString fallback;
|
||||||
|
|
||||||
// uh-oh, but we didn't end up with anything valid, so we sadly reset ourselves
|
// uh-oh, but we didn't end up with anything valid, so we sadly reset ourselves
|
||||||
// to futility.
|
// to futility.
|
||||||
if (!d->valid) {
|
if (!d->valid) {
|
||||||
@ -764,6 +789,7 @@ KJob *Package::uninstall(const QString &packageName, const QString &packageRoot)
|
|||||||
PackagePrivate::PackagePrivate()
|
PackagePrivate::PackagePrivate()
|
||||||
: QSharedData(),
|
: QSharedData(),
|
||||||
servicePrefix("plasma-applet-"),
|
servicePrefix("plasma-applet-"),
|
||||||
|
fallbackPackage(0),
|
||||||
metadata(0),
|
metadata(0),
|
||||||
externalPaths(false),
|
externalPaths(false),
|
||||||
valid(false),
|
valid(false),
|
||||||
@ -786,6 +812,7 @@ PackagePrivate::~PackagePrivate()
|
|||||||
dir.removeRecursively();
|
dir.removeRecursively();
|
||||||
}
|
}
|
||||||
delete metadata;
|
delete metadata;
|
||||||
|
delete fallbackPackage;
|
||||||
}
|
}
|
||||||
|
|
||||||
PackagePrivate &PackagePrivate::operator=(const PackagePrivate &rhs)
|
PackagePrivate &PackagePrivate::operator=(const PackagePrivate &rhs)
|
||||||
@ -795,6 +822,11 @@ PackagePrivate &PackagePrivate::operator=(const PackagePrivate &rhs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
structure = rhs.structure;
|
structure = rhs.structure;
|
||||||
|
if (rhs.fallbackPackage) {
|
||||||
|
fallbackPackage = new Package(*rhs.fallbackPackage);
|
||||||
|
} else {
|
||||||
|
fallbackPackage = 0;
|
||||||
|
}
|
||||||
path = rhs.path;
|
path = rhs.path;
|
||||||
contentsPrefixPaths = rhs.contentsPrefixPaths;
|
contentsPrefixPaths = rhs.contentsPrefixPaths;
|
||||||
servicePrefix = rhs.servicePrefix;
|
servicePrefix = rhs.servicePrefix;
|
||||||
@ -874,4 +906,38 @@ void PackagePrivate::createPackageMetadata(const QString &path)
|
|||||||
metadata = new KPluginInfo(metadataPath);
|
metadata = new KPluginInfo(metadataPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 (qstrcmp(key, "metadata") != 0 && fallbackPackage && fallbackPackage->isValid()) {
|
||||||
|
return fallbackPackage->filePath(key, filename);
|
||||||
|
} else {
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
Plasma::Package *slowPackage = const_cast<Plasma::Package *>(&package);
|
||||||
|
Plasma::Package *fastPackage = const_cast<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 && 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;
|
||||||
|
slowPackage = slowPackage->d->fallbackPackage;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
} // Namespace
|
} // Namespace
|
||||||
|
@ -290,6 +290,20 @@ public:
|
|||||||
*/
|
*/
|
||||||
void setDefaultPackageRoot(const QString &packageRoot);
|
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 setFallbackPackage(const Plasma::Package &package);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The fallback package root path
|
||||||
|
*/
|
||||||
|
Plasma::Package fallbackPackage() const;
|
||||||
|
|
||||||
// Content structure description methods
|
// Content structure description methods
|
||||||
/**
|
/**
|
||||||
* @return all directories registered as part of this Package's structure
|
* @return all directories registered as part of this Package's structure
|
||||||
@ -328,6 +342,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
QExplicitlySharedDataPointer<PackagePrivate> d;
|
QExplicitlySharedDataPointer<PackagePrivate> d;
|
||||||
|
friend class PackagePrivate;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -73,6 +73,8 @@ public:
|
|||||||
void createPackageMetadata(const QString &path);
|
void createPackageMetadata(const QString &path);
|
||||||
QString unpack(const QString &filePath);
|
QString unpack(const QString &filePath);
|
||||||
void updateHash(const QString &basePath, const QString &subPath, const QDir &dir, QCryptographicHash &hash);
|
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<PackageStructure> structure;
|
QWeakPointer<PackageStructure> structure;
|
||||||
QString path;
|
QString path;
|
||||||
@ -82,6 +84,7 @@ public:
|
|||||||
QString servicePrefix;
|
QString servicePrefix;
|
||||||
QHash<QString, QString> discoveries;
|
QHash<QString, QString> discoveries;
|
||||||
QHash<QByteArray, ContentStructure> contents;
|
QHash<QByteArray, ContentStructure> contents;
|
||||||
|
Package *fallbackPackage;
|
||||||
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
|
#ifndef PLASMA_NO_PACKAGE_EXTRADATA
|
||||||
QStringList mimeTypes;
|
QStringList mimeTypes;
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user