From 516b628b71a8d0521d67ad5b454cfbacd6b886b2 Mon Sep 17 00:00:00 2001 From: Kevin Kofler Date: Sun, 21 Aug 2011 04:10:16 +0200 Subject: [PATCH] * Sun Aug 21 2011 Kevin Kofler 4.7.0-3 - backport my GSoC 2011 patches for libplasma PackageKit integration (F17+) (The main reason this is F17+ only is because F16 and F15 don't have the required Provides at this time.) --- ...ntly-private-for-installing-missing-.patch | 312 ++++++++++++++++ ...tion-of-missing-components-when-inst.patch | 166 +++++++++ ...tic-scanning-of-source-code-for-requ.patch | 333 ++++++++++++++++++ kdelibs.spec | 23 +- 4 files changed, 833 insertions(+), 1 deletion(-) create mode 100644 0001-Add-an-API-currently-private-for-installing-missing-.patch create mode 100644 0002-Trigger-installation-of-missing-components-when-inst.patch create mode 100644 0003-Implement-automatic-scanning-of-source-code-for-requ.patch diff --git a/0001-Add-an-API-currently-private-for-installing-missing-.patch b/0001-Add-an-API-currently-private-for-installing-missing-.patch new file mode 100644 index 0000000..29aa786 --- /dev/null +++ b/0001-Add-an-API-currently-private-for-installing-missing-.patch @@ -0,0 +1,312 @@ +From 5bf9e0aa14f849726f3573b04eb51acfff635fc6 Mon Sep 17 00:00:00 2001 +Message-Id: <5bf9e0aa14f849726f3573b04eb51acfff635fc6.1312359834.git.kevin.kofler@chello.at> +From: Kevin Kofler +Date: Mon, 1 Aug 2011 21:53:32 +0200 +Subject: [PATCH] Add an API (currently private) for installing missing Plasma + engines. + +Use it when a requested data or script engine is not found. + +REVIEW: 102175 +--- + plasma/CMakeLists.txt | 11 ++++ + plasma/dataenginemanager.cpp | 4 + + plasma/private/componentinstaller.cpp | 103 +++++++++++++++++++++++++++++++++ + plasma/private/componentinstaller_p.h | 94 ++++++++++++++++++++++++++++++ + plasma/scripting/scriptengine.cpp | 4 + + 5 files changed, 216 insertions(+), 0 deletions(-) + +diff --git a/plasma/CMakeLists.txt b/plasma/CMakeLists.txt +index ef411df..f929967 100644 +--- a/plasma/CMakeLists.txt ++++ b/plasma/CMakeLists.txt +@@ -6,8 +6,13 @@ if(KDE_PLATFORM_FEATURE_BINARY_COMPATIBLE_FEATURE_REDUCTION) + set(PLASMA_NO_KNEWSTUFF TRUE) + set(PLASMA_NO_SOLID TRUE) + set(PLASMA_NO_KIO TRUE) ++ set(PLASMA_NO_PACKAGEKIT TRUE) + endif(KDE_PLATFORM_FEATURE_BINARY_COMPATIBLE_FEATURE_REDUCTION) + ++if(NOT Q_WS_X11) ++ set(PLASMA_NO_PACKAGEKIT TRUE) ++endif(NOT Q_WS_X11) ++ + include_directories(${CMAKE_CURRENT_SOURCE_DIR} + ${KDE4_KDECORE_INCLUDES} + ${KDE4_KDEUI_INCLUDES} +@@ -42,6 +47,11 @@ if(NOT PLASMA_NO_SOLID) + set(PLASMA_EXTRA_LIBS ${PLASMA_EXTRA_LIBS} ${KDE4_SOLID_LIBS}) + endif(NOT PLASMA_NO_SOLID) + ++if(NOT PLASMA_NO_PACKAGEKIT) ++ add_definitions(-DPLASMA_ENABLE_PACKAGEKIT_SUPPORT=1) ++ set(PLASMA_EXTRA_LIBS ${PLASMA_EXTRA_LIBS} ${QT_QTDBUS_LIBRARY}) ++endif(NOT PLASMA_NO_PACKAGEKIT) ++ + if(QCA2_FOUND) + include_directories(${QCA2_INCLUDE_DIR}) + set(ENABLE_REMOTE_WIDGETS TRUE) +@@ -110,6 +120,7 @@ set(plasma_LIB_SRCS + private/animablegraphicswebview.cpp + private/applethandle.cpp + private/associatedapplicationmanager.cpp ++ private/componentinstaller.cpp + private/datacontainer_p.cpp + private/dataenginebindings.cpp + private/dataengineconsumer.cpp +diff --git a/plasma/dataenginemanager.cpp b/plasma/dataenginemanager.cpp +index 988fe76..c98ac40 100644 +--- a/plasma/dataenginemanager.cpp ++++ b/plasma/dataenginemanager.cpp +@@ -29,6 +29,7 @@ + + #include "datacontainer.h" + #include "pluginloader.h" ++#include "private/componentinstaller_p.h" + #include "private/dataengine_p.h" + #include "private/datacontainer_p.h" + #include "scripting/scriptengine.h" +@@ -130,6 +131,9 @@ Plasma::DataEngine *DataEngineManager::loadEngine(const QString &name) + + DataEngine *engine = PluginLoader::pluginLoader()->loadDataEngine(name); + if (!engine) { ++ // Try installing the engine. However, it's too late for this request. ++ ComponentInstaller::self()->installMissingComponent("dataengine", name); ++ + return d->nullEngine(); + } + +diff --git a/plasma/private/componentinstaller.cpp b/plasma/private/componentinstaller.cpp +new file mode 100644 +index 0000000..870667f +--- /dev/null ++++ b/plasma/private/componentinstaller.cpp +@@ -0,0 +1,103 @@ ++/* ++ * Copyright 2011 Kevin Kofler ++ * ++ * This program 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, or ++ * (at your option) any later version. ++ * ++ * This program 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 General Public License for more details ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this program; if not, write to the ++ * Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#include "private/componentinstaller_p.h" ++ ++#include ++ ++#ifdef PLASMA_ENABLE_PACKAGEKIT_SUPPORT ++#include ++#include ++#include ++#include ++#include ++#include ++#endif ++ ++namespace Plasma ++{ ++ ++class ComponentInstallerPrivate ++{ ++ public: ++#ifdef PLASMA_ENABLE_PACKAGEKIT_SUPPORT ++ QSet alreadyPrompted; ++#endif ++}; ++ ++class ComponentInstallerSingleton ++{ ++ public: ++ ComponentInstaller self; ++}; ++ ++K_GLOBAL_STATIC(ComponentInstallerSingleton, privateComponentInstallerSelf) ++ ++ComponentInstaller *ComponentInstaller::self() ++{ ++ return &privateComponentInstallerSelf->self; ++} ++ ++ComponentInstaller::ComponentInstaller() ++ : d(new ComponentInstallerPrivate) ++{ ++} ++ ++ComponentInstaller::~ComponentInstaller() ++{ ++ delete d; ++} ++ ++void ComponentInstaller::installMissingComponent(const QString &type, ++ const QString &name, ++ QWidget *parent, bool force) ++{ ++#ifdef PLASMA_ENABLE_PACKAGEKIT_SUPPORT ++ QString searchString = type + '-' + name; ++ ++ if (!force) { ++ if (d->alreadyPrompted.contains(searchString)) { ++ return; ++ } ++ } ++ ++ d->alreadyPrompted.insert(searchString); ++ ++ QDBusInterface packageKit(QLatin1String("org.freedesktop.PackageKit"), ++ QLatin1String("/org/freedesktop/PackageKit"), ++ QLatin1String("org.freedesktop.PackageKit.Modify")); ++ // We don't check packageKit.isValid() because the service is activated on ++ // demand, so it will show up as "not valid". ++ WId wid = 0; ++ if (parent) { ++ wid = parent->winId(); ++ } ++ QStringList resources; ++ resources.append(searchString); ++ packageKit.asyncCall(QLatin1String("InstallResources"), (unsigned int) wid, ++ QLatin1String("plasma-service"), resources, QString()); ++#else ++ Q_UNUSED(type); ++ Q_UNUSED(name); ++ Q_UNUSED(parent); ++ Q_UNUSED(force); ++#endif ++} ++ ++} // namespace Plasma +diff --git a/plasma/private/componentinstaller_p.h b/plasma/private/componentinstaller_p.h +new file mode 100644 +index 0000000..f85cbb6 +--- /dev/null ++++ b/plasma/private/componentinstaller_p.h +@@ -0,0 +1,94 @@ ++/* ++ * Copyright 2011 Kevin Kofler ++ * ++ * This program 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, or ++ * (at your option) any later version. ++ * ++ * This program 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 General Public License for more details ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this program; if not, write to the ++ * Free Software Foundation, Inc., ++ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef PLASMA_COMPONENTINSTALLER_H ++#define PLASMA_COMPONENTINSTALLER_H ++ ++class QString; ++class QWidget; ++ ++namespace Plasma ++{ ++ ++class ComponentInstallerPrivate; ++ ++/** ++ * @class ComponentInstaller plasma/private/componentinstaller_p.h ++ * ++ * @short This class provides a generic API for installation of components. ++ * ++ * @internal ++ * ++ * Plasma::ComponentInstaller allows searching for a missing data or script ++ * engine by name, and allowing the user to install the missing service. ++ * Currently, PackageKit is supported as the mechanism to install components, ++ * but more mechanisms could be supported in the future through the same API. ++ * ++ * @since 4.8 ++ */ ++class ComponentInstaller ++{ ++ public: ++ /** ++ * Singleton pattern accessor. ++ */ ++ static ComponentInstaller *self(); ++ ++ /** ++ * Installs a missing component asynchronously. ++ * ++ * By default, this method will cache requested components and not ++ * prompt again for the same engine in the same session. The force ++ * parameter can be used to disable this mechanism, e.g. when the user ++ * just installed a new widget written in a scripting language, and so ++ * is likely to want the script engine installed after all. ++ * ++ * In the case of on-demand installation, this will unfortunately not ++ * allow the call which triggered the missing component lookup to ++ * succeed, but we cannot afford to block all of Plasma until the ++ * mechanism is done installing the service. ++ * ++ * This function does nothing if PackageKit integration was disabled at ++ * compile time. ++ * ++ * @param type the type of the component, should be "scriptengine" or ++ * "dataengine" ++ * @param name the name of the component ++ * @param parent a parent widget, used to set the wid for PackageKit ++ * @param force whether to always prompt, even if recently prompted ++ */ ++ void installMissingComponent(const QString &type, const QString &name, ++ QWidget *parent = 0, bool force = false); ++ ++ private: ++ /** ++ * Default constructor. The singleton method self() is the ++ * preferred access mechanism. ++ */ ++ ComponentInstaller(); ++ ~ComponentInstaller(); ++ ++ ComponentInstallerPrivate *const d; ++ ++ friend class ComponentInstallerSingleton; ++}; ++ ++} // namespace Plasma ++ ++#endif // multiple inclusion guard +diff --git a/plasma/scripting/scriptengine.cpp b/plasma/scripting/scriptengine.cpp +index fb8cd1a..21f8a9a 100644 +--- a/plasma/scripting/scriptengine.cpp ++++ b/plasma/scripting/scriptengine.cpp +@@ -27,6 +27,7 @@ + #include "applet.h" + #include "dataengine.h" + #include "package.h" ++#include "private/componentinstaller_p.h" + #include "scripting/appletscript.h" + #include "scripting/dataenginescript.h" + #include "scripting/runnerscript.h" +@@ -196,6 +197,9 @@ ScriptEngine *loadEngine(const QString &language, ComponentType type, QObject *p + << "! error reported: " << error; + } + ++ // Try installing the engine. However, it's too late for this request. ++ ComponentInstaller::self()->installMissingComponent("scriptengine", language); ++ + return 0; + } + +-- +1.7.4.4 + diff --git a/0002-Trigger-installation-of-missing-components-when-inst.patch b/0002-Trigger-installation-of-missing-components-when-inst.patch new file mode 100644 index 0000000..b786bbf --- /dev/null +++ b/0002-Trigger-installation-of-missing-components-when-inst.patch @@ -0,0 +1,166 @@ +From 00a8b22ad6dbb03eea18090f6d9f578101632752 Mon Sep 17 00:00:00 2001 +Message-Id: <00a8b22ad6dbb03eea18090f6d9f578101632752.1313007841.git.kevin.kofler@chello.at> +From: Kevin Kofler +Date: Wed, 10 Aug 2011 21:48:19 +0200 +Subject: [PATCH] Trigger installation of missing components when installing a + package. + +For script engines, the existing metadata (X-Plasma-API) is sufficient. + +For data engines, we introduce a new metadata entry: +X-Plasma-RequiredDataEngines. Third-party packages will have to add this entry +to benefit from this feature at this time. Automatic support for scanning +package source code on installation (at least for some languages) is planned, +but the metadata entry is definitely the most efficient method. +--- + plasma/package.cpp | 39 +++++++++++++++++++++++++++++++++++++++ + plasma/packagemetadata.cpp | 13 +++++++++++++ + plasma/packagemetadata.h | 7 +++++++ + 3 files changed, 59 insertions(+), 0 deletions(-) + +diff --git a/plasma/package.cpp b/plasma/package.cpp +index 4c00d36..0a45c87 100644 +--- a/plasma/package.cpp ++++ b/plasma/package.cpp +@@ -49,8 +49,11 @@ + #include + + #include "authorizationmanager.h" ++#include "dataenginemanager.h" + #include "packagemetadata.h" ++#include "scripting/scriptengine.h" + #include "private/authorizationmanager_p.h" ++#include "private/componentinstaller_p.h" + #include "private/package_p.h" + #include "private/plasmoidservice_p.h" + #include "private/service_p.h" +@@ -603,6 +606,42 @@ bool Package::installPackage(const QString &package, + tempdir.setAutoRemove(false); + } + ++ // check for missing dependencies ++ QString requiredScriptEngine = meta.implementationApi(); ++ if (!requiredScriptEngine.isEmpty()) { ++ // figure out the component type to query for ++ ComponentTypes componentTypes = static_cast(0); ++ QStringList serviceTypes = meta.serviceType().split(','); ++ if (serviceTypes.contains("Plasma/Applet")) { ++ componentTypes |= AppletComponent; ++ } ++ if (serviceTypes.contains("Plasma/DataEngine")) { ++ componentTypes |= DataEngineComponent; ++ } ++ if (serviceTypes.contains("Plasma/Runner")) { ++ componentTypes |= RunnerComponent; ++ } ++ if (serviceTypes.contains("Plasma/Wallpaper")) { ++ componentTypes |= WallpaperComponent; ++ } ++ if (!knownLanguages(componentTypes).contains(requiredScriptEngine)) { ++ // install the missing script engine ++ // force prompting because the user has just explicitly installed a widget ++ ComponentInstaller::self()->installMissingComponent("scriptengine", requiredScriptEngine, 0, true); ++ } ++ } ++ QStringList requiredDataEngines = meta.requiredDataEngines(); ++ if (!requiredDataEngines.isEmpty()) { ++ QStringList knownDataEngines = DataEngineManager::self()->listAllEngines(meta.application()); ++ foreach (const QString &requiredDataEngine, requiredDataEngines) { ++ if (!knownDataEngines.contains(requiredDataEngine)) { ++ // install the missing data engine ++ // force prompting because the user has just explicitly installed a widget ++ ComponentInstaller::self()->installMissingComponent("dataengine", requiredDataEngine, 0, true); ++ } ++ } ++ } ++ + if (!servicePrefix.isEmpty()) { + // and now we register it as a service =) + QString metaPath = targetName + "/metadata.desktop"; +diff --git a/plasma/packagemetadata.cpp b/plasma/packagemetadata.cpp +index 59163b2..8cfaf64 100644 +--- a/plasma/packagemetadata.cpp ++++ b/plasma/packagemetadata.cpp +@@ -52,6 +52,7 @@ class PackageMetadataPrivate + QString serviceType; + QString api; + KUrl location; ++ QStringList requiredDataEngines; + }; + + PackageMetadata::PackageMetadata(const PackageMetadata &other) +@@ -106,6 +107,7 @@ void PackageMetadata::write(const QString &filename) const + config.writeEntry("X-KDE-ParentApp", d->app); + config.writeEntry("Type", d->type); + config.writeEntry("X-Plasma-RemoteLocation", d->location); ++ config.writeEntry("X-Plasma-RequiredDataEngines", d->requiredDataEngines); + } + + void PackageMetadata::read(const QString &filename) +@@ -133,6 +135,7 @@ void PackageMetadata::read(const QString &filename) + d->app = config.readEntry("X-KDE-ParentApp", d->app); + d->type = config.readEntry("Type", d->type); + d->location = config.readEntry("X-Plasma-RemoteLocation", d->location); ++ d->requiredDataEngines = config.readEntry("X-Plasma-RequiredDataEngines", d->requiredDataEngines); + } + + QString PackageMetadata::name() const +@@ -225,6 +228,11 @@ QString PackageMetadata::implementationApi() const + return d->api; + } + ++QStringList PackageMetadata::requiredDataEngines() const ++{ ++ return d->requiredDataEngines; ++} ++ + void PackageMetadata::setImplementationApi(const QString &api) + { + d->api = api; +@@ -300,6 +308,11 @@ void PackageMetadata::setRemoteLocation(const KUrl &location) + d->location = location; + } + ++void PackageMetadata::setRequiredDataEngines(const QStringList &requiredDataEngines) ++{ ++ d->requiredDataEngines = requiredDataEngines; ++} ++ + void PackageMetadata::setType(const QString &type) + { + d->type = type; +diff --git a/plasma/packagemetadata.h b/plasma/packagemetadata.h +index b10f0e4..ec396a6 100644 +--- a/plasma/packagemetadata.h ++++ b/plasma/packagemetadata.h +@@ -21,6 +21,7 @@ + #define PLASMA_PACKAGEMETADATA_H + + #include ++#include + + #include + +@@ -92,6 +93,7 @@ public: + QString pluginName() const; + QString implementationApi() const; + KUrl remoteLocation() const; ++ QStringList requiredDataEngines() const; + + QString type() const; + +@@ -205,6 +207,11 @@ public: + */ + void setImplementationApi(const QString &api); + ++ /** ++ * Set the required data engines for this package. ++ */ ++ void setRequiredDataEngines(const QStringList &); ++ + private: + PackageMetadataPrivate * const d; + }; +-- +1.7.4.4 + diff --git a/0003-Implement-automatic-scanning-of-source-code-for-requ.patch b/0003-Implement-automatic-scanning-of-source-code-for-requ.patch new file mode 100644 index 0000000..250e5ea --- /dev/null +++ b/0003-Implement-automatic-scanning-of-source-code-for-requ.patch @@ -0,0 +1,333 @@ +From 1ce984bda1bb6a06f237240069a9f3a554cbbf37 Mon Sep 17 00:00:00 2001 +Message-Id: <1ce984bda1bb6a06f237240069a9f3a554cbbf37.1313890335.git.kevin.kofler@chello.at> +From: Kevin Kofler +Date: Wed, 17 Aug 2011 04:54:37 +0200 +Subject: [PATCH] Implement automatic scanning of source code for required + data engines. + +For packages in scripting languages and distributed through OCS, this is fully +automatic and triggered from Package::installPackage. If an +X-Plasma-RequiredDataEngines entry is present in the .desktop file (even if +empty), the dependency extraction is not run and the explicitly provided +information is trusted instead. + +For native distribution packages, we ship a tool called +plasma-dataengine-depextractor which can be run at any time during the build +process and which adds the dependency information to the relevant .desktop file. + +Authors of plasmoids are encouraged to run plasma-dataengine-depextractor and/or +fill in X-Plasma-RequiredDataEngines manually. (Please note that the list is +expected to be comma-separated.) +--- + plasma/CMakeLists.txt | 15 ++++ + plasma/depextractor/depextractor.cpp | 115 +++++++++++++++++++++++++++++++++ + plasma/package.cpp | 11 +++ + plasma/private/componentinstaller.cpp | 68 +++++++++++++++++++ + plasma/private/componentinstaller_p.h | 17 +++++- + 5 files changed, 225 insertions(+), 1 deletions(-) + +diff --git a/plasma/CMakeLists.txt b/plasma/CMakeLists.txt +index f929967..9a760ef 100644 +--- a/plasma/CMakeLists.txt ++++ b/plasma/CMakeLists.txt +@@ -304,6 +304,18 @@ set_target_properties(plasma PROPERTIES + + install(TARGETS plasma EXPORT kdelibsLibraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) + ++if(NOT PLASMA_NO_PACKAGEKIT) ++ # we need a copy of the component installer because libplasma does not export it ++ # plus, this avoids depending on GUI stuff in this command-line utility ++ set(plasma_dataengine_depextractor_SRCS depextractor/depextractor.cpp ++ private/componentinstaller.cpp) ++ kde4_add_executable(plasma-dataengine-depextractor ++ ${plasma_dataengine_depextractor_SRCS}) ++ set_target_properties(plasma-dataengine-depextractor PROPERTIES ++ COMPILE_FLAGS -DPLASMA_COMPONENTINSTALLER_NO_QWIDGET=1) ++ target_link_libraries(plasma-dataengine-depextractor ${KDE4_KDECORE_LIBS}) ++endif(NOT PLASMA_NO_PACKAGEKIT) ++ + + ########### install files ############### + +@@ -460,3 +472,6 @@ install(FILES data/operations/dataengineservice.operations DESTINATION ${DATA_IN + install(FILES data/operations/plasmoidservice.operations DESTINATION ${DATA_INSTALL_DIR}/plasma/services) + install(FILES data/operations/storage.operations DESTINATION ${DATA_INSTALL_DIR}/plasma/services) + ++if(NOT PLASMA_NO_PACKAGEKIT) ++ install(TARGETS plasma-dataengine-depextractor DESTINATION ${BIN_INSTALL_DIR}) ++endif(NOT PLASMA_NO_PACKAGEKIT) +diff --git a/plasma/depextractor/depextractor.cpp b/plasma/depextractor/depextractor.cpp +new file mode 100644 +index 0000000..221b88b +--- /dev/null ++++ b/plasma/depextractor/depextractor.cpp +@@ -0,0 +1,115 @@ ++/* Plasma Data Engine dependency extractor ++ Copyright (C) 2011 Kevin Kofler ++ ++ This program is free software: you can redistribute it and/or modify ++ it under the terms of the GNU General Public License as published by ++ the Free Software Foundation, either version 2 of the License, or ++ (at your option) any later version. ++ ++ This program 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 General Public License for more details. ++ ++ You should have received a copy of the GNU General Public License ++ along with this program. If not, see . */ ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "private/componentinstaller_p.h" ++ ++static void writeDataEngineDependencies(const QStringList &deps, ++ const QString &desktopFile) ++{ ++ if (!deps.isEmpty()) { ++ KDesktopFile desktop(desktopFile); ++ desktop.desktopGroup().writeEntry("X-Plasma-RequiredDataEngines", deps); ++ } ++} ++ ++int main(int argc, char **argv) ++{ ++ KAboutData aboutData("plasma-dataengine-depextractor", QByteArray(), ++ ki18n("Plasma Data Engine dependency extractor"), ++ "1", ++ ki18n("Plasma Data Engine dependency extractor")); ++ aboutData.addAuthor(ki18n("Kevin Kofler"), ki18n("Author"), ++ "kevin.kofler@chello.at"); ++ ++ KCmdLineArgs::init(argc, argv, &aboutData); ++ KCmdLineOptions options; ++ options.add("a") ++ .add("api ", ++ ki18n("Sets the name of the scripting API/language")); ++ options.add("+[path]", ++ ki18n("Source path (default: .)")); ++ options.add("+[file]", ++ ki18n(".desktop rel. to path (default: metadata.desktop)") ++ ); ++ KCmdLineArgs::addCmdLineOptions(options); ++ ++ QCoreApplication *app = new QCoreApplication(KCmdLineArgs::qtArgc(), ++ KCmdLineArgs::qtArgv()); ++ ++ KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); ++ ++ int exitCode = 0; ++ ++ QString api, path, desktopFile; ++ if (args->isSet("api")) { ++ api = args->getOption("api"); ++ } ++ int argCount = args->count(); ++ switch (argCount) { ++ case 0: ++ path = "."; ++ desktopFile = "metadata.desktop"; ++ break; ++ case 1: ++ path = args->arg(0); ++ desktopFile = "metadata.desktop"; ++ break; ++ case 2: ++ path = args->arg(0); ++ desktopFile = args->arg(1); ++ break; ++ default: ++ { ++ QTextStream err(stderr, QIODevice::WriteOnly | QIODevice::Text); ++ err << i18n("Expected at most 2 arguments, but %1 given", argCount) ++ << endl; ++ exitCode = 1; ++ break; ++ } ++ } ++ ++ if (!exitCode) { ++ if (QFileInfo(desktopFile).isRelative()) ++ desktopFile = QDir(path).filePath(desktopFile); ++ ++ if (QFileInfo(desktopFile).exists()) { ++ writeDataEngineDependencies(Plasma::ComponentInstaller::self() ++ ->extractDataEngineDependencies(path, ++ api), ++ desktopFile); ++ } else { ++ QTextStream err(stderr, QIODevice::WriteOnly | QIODevice::Text); ++ err << i18n("Desktop file \"%1\" not found", desktopFile) << endl; ++ exitCode = 1; ++ } ++ } ++ ++ args->clear(); ++ delete app; ++ return exitCode; ++} +diff --git a/plasma/package.cpp b/plasma/package.cpp +index 0a45c87..131f204 100644 +--- a/plasma/package.cpp ++++ b/plasma/package.cpp +@@ -631,6 +631,17 @@ bool Package::installPackage(const QString &package, + } + } + QStringList requiredDataEngines = meta.requiredDataEngines(); ++ if (requiredDataEngines.isEmpty()) { ++ // check whether this was explicitly specified as empty ++ QString metaPath = targetName + "/metadata.desktop"; ++ KDesktopFile df(metaPath); ++ KConfigGroup cg = df.desktopGroup(); ++ if (!cg.hasKey("X-Plasma-RequiredDataEngines")) { ++ // not specified at all, try running the dependency extraction ++ requiredDataEngines = ComponentInstaller::self()->extractDataEngineDependencies(targetName, ++ requiredScriptEngine); ++ } ++ } + if (!requiredDataEngines.isEmpty()) { + QStringList knownDataEngines = DataEngineManager::self()->listAllEngines(meta.application()); + foreach (const QString &requiredDataEngine, requiredDataEngines) { +diff --git a/plasma/private/componentinstaller.cpp b/plasma/private/componentinstaller.cpp +index 870667f..2c8c2dd 100644 +--- a/plasma/private/componentinstaller.cpp ++++ b/plasma/private/componentinstaller.cpp +@@ -28,6 +28,10 @@ + #include + #include + #include ++#include ++#include ++#include ++#include + #endif + + namespace Plasma +@@ -85,9 +89,13 @@ void ComponentInstaller::installMissingComponent(const QString &type, + // We don't check packageKit.isValid() because the service is activated on + // demand, so it will show up as "not valid". + WId wid = 0; ++#ifndef PLASMA_COMPONENTINSTALLER_NO_QWIDGET + if (parent) { + wid = parent->winId(); + } ++#else ++ Q_UNUSED(parent); ++#endif + QStringList resources; + resources.append(searchString); + packageKit.asyncCall(QLatin1String("InstallResources"), (unsigned int) wid, +@@ -100,4 +108,64 @@ void ComponentInstaller::installMissingComponent(const QString &type, + #endif + } + ++QStringList ComponentInstaller::extractDataEngineDependencies(const QString &path, ++ const QString &api) ++{ ++ QStringList deps; ++ ++#ifdef PLASMA_ENABLE_PACKAGEKIT_SUPPORT ++ QStringList nameFilters; ++ QRegExp searchRegExp("dataEngine *\\( *\"([^\"]+)\" *\\)"); ++ if (api.isEmpty()) { ++ // no script engine API, this is native C++ code ++ nameFilters.append("*.cpp"); ++ nameFilters.append("*.cxx"); ++ nameFilters.append("*.cc"); ++ nameFilters.append("*.C"); ++ nameFilters.append("*.h"); ++ nameFilters.append("*.hpp"); ++ nameFilters.append("*.hxx"); ++ nameFilters.append("*.hh"); ++ nameFilters.append("*.H"); ++ } else if (api == "javascript") { ++ nameFilters.append("*.js"); ++ } else if (api == "python") { ++ nameFilters.append("*.py"); ++ searchRegExp = QRegExp("dataEngine *\\( *[\'\"]([^\'\"]+)[\'\"] *\\)"); ++ } else if (api == "ruby-script") { ++ nameFilters.append("*.rb"); ++ searchRegExp = QRegExp("dataEngine *\\( *[\'\"]([^\'\"]+)[\'\"] *\\)"); ++ } else { ++ // dependency extraction not supported for this API ++ return deps; ++ } ++ ++ QDirIterator it(path, nameFilters, QDir::Files | QDir::CaseSensitive, ++ QDirIterator::Subdirectories ++ | QDirIterator::FollowSymlinks); ++ while (it.hasNext()) { ++ QFile file(it.next()); ++ file.open(QIODevice::ReadOnly | QIODevice::Text); ++ QTextStream stream(&file); ++ QString line; ++ while (!(line = stream.readLine()).isNull()) { ++ int column = 0; ++ while ((column = searchRegExp.indexIn(line, column)) != -1) { ++ QString dep = searchRegExp.cap(1); ++ if (!deps.contains(dep)) { ++ deps.append(dep); ++ } ++ column += searchRegExp.matchedLength(); ++ } ++ } ++ file.close(); ++ } ++#else ++ Q_UNUSED(path); ++ Q_UNUSED(api); ++#endif ++ ++ return deps; ++} ++ + } // namespace Plasma +diff --git a/plasma/private/componentinstaller_p.h b/plasma/private/componentinstaller_p.h +index f85cbb6..d0d9c75 100644 +--- a/plasma/private/componentinstaller_p.h ++++ b/plasma/private/componentinstaller_p.h +@@ -20,7 +20,7 @@ + #ifndef PLASMA_COMPONENTINSTALLER_H + #define PLASMA_COMPONENTINSTALLER_H + +-class QString; ++#include + class QWidget; + + namespace Plasma +@@ -76,6 +76,21 @@ class ComponentInstaller + void installMissingComponent(const QString &type, const QString &name, + QWidget *parent = 0, bool force = false); + ++ /** ++ * Extracts the list of required data engines from source code. ++ * ++ * If the scripting API is not supported for dependency extraction or ++ * if Plasma was compiled without support for missing component ++ * installation, an empty list of dependencies is returned. ++ * ++ * @param path the path containing the source code ++ * @param api the scripting API used; ++ * if empty (the default), assumes the native C++ API ++ */ ++ QStringList extractDataEngineDependencies(const QString &path, ++ const QString &api ++ = QString()); ++ + private: + /** + * Default constructor. The singleton method self() is the +-- +1.7.4.4 + diff --git a/kdelibs.spec b/kdelibs.spec index 0e89883..9f76991 100644 --- a/kdelibs.spec +++ b/kdelibs.spec @@ -13,7 +13,7 @@ Summary: KDE Libraries Version: 4.7.0 -Release: 2%{?dist} +Release: 3%{?dist} Name: kdelibs Epoch: 6 @@ -96,6 +96,17 @@ Patch24: kdelibs-4.3.1-drkonq.patch # -DCMAKE_SKIP_RPATH:BOOL=ON (finally) Patch27: kdelibs-4.5.80-no_rpath.patch +## libplasma PackageKit integration +# Add an API (currently private) for installing missing Plasma engines. +# https://git.reviewboard.kde.org/r/102175/ +Patch40: 0001-Add-an-API-currently-private-for-installing-missing-.patch +# Trigger installation of missing components when installing a package. +# https://git.reviewboard.kde.org/r/102291/ +Patch41: 0002-Trigger-installation-of-missing-components-when-inst.patch +# Implement automatic scanning of source code for required data engines. +# https://git.reviewboard.kde.org/r/102350/ +Patch42: 0003-Implement-automatic-scanning-of-source-code-for-requ.patch + ## upstreamable # add gpg2 support to knewstuff, rough first try s/gpg/gpg2/ # reverting to our past gnupg2-only setup. @@ -290,6 +301,13 @@ sed -i -e "s|@@VERSION_RELEASE@@|%{version}-%{release}|" kio/kio/kprotocolmanage %endif %patch27 -p1 -b .no_rpath +# libplasma PackageKit integration +%if 0%{?fedora} > 16 +%patch40 -p1 -b .libplasma-pk-0001 +%patch41 -p1 -b .libplasma-pk-0002 +%patch42 -p1 -b .libplasma-pk-0003 +%endif + # upstreamable patches %patch50 -p1 -b .knewstuff_gpg2 %patch51 -p1 -b .uri_mimetypes @@ -542,6 +560,9 @@ rm -rf %{buildroot} %changelog +* Sun Aug 21 2011 Kevin Kofler 4.7.0-3 +- backport my GSoC 2011 patches for libplasma PackageKit integration (F17+) + * Sun Aug 21 2011 Kevin Kofler 4.7.0-2 - rebuild for the RPM dependency generators for Plasma (GSoC 2011) - add BuildRequires: kde-settings to pick up the above