[kdelibs] * Sun Aug 21 2011 Kevin Kofler <Kevin at tigcc.ticalc.org> 4.7.0-3 - backport my GSoC 2011 patches for

Kevin Kofler kkofler at fedoraproject.org
Sun Aug 21 02:10:47 UTC 2011


commit 516b628b71a8d0521d67ad5b454cfbacd6b886b2
Author: Kevin Kofler <Kevin at tigcc.ticalc.org>
Date:   Sun Aug 21 04:10:16 2011 +0200

    * Sun Aug 21 2011 Kevin Kofler <Kevin at tigcc.ticalc.org> 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.)

 ...currently-private-for-installing-missing-.patch |  312 ++++++++++++++++++
 ...tallation-of-missing-components-when-inst.patch |  166 ++++++++++
 ...utomatic-scanning-of-source-code-for-requ.patch |  333 ++++++++++++++++++++
 kdelibs.spec                                       |   23 ++-
 4 files changed, 833 insertions(+), 1 deletions(-)
---
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 at chello.at>
+From: Kevin Kofler <kevin.kofler at chello.at>
+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 <kevin.kofler at chello.at>
++ *
++ *   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 <kglobal.h>
++
++#ifdef PLASMA_ENABLE_PACKAGEKIT_SUPPORT
++#include <QSet>
++#include <QDBusInterface>
++#include <QDBusPendingCall>
++#include <QWidget>
++#include <QLatin1String>
++#include <QStringList>
++#endif
++
++namespace Plasma
++{
++
++class ComponentInstallerPrivate
++{
++    public:
++#ifdef PLASMA_ENABLE_PACKAGEKIT_SUPPORT
++        QSet<QString> 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 <kevin.kofler at chello.at>
++ *
++ *   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 at chello.at>
+From: Kevin Kofler <kevin.kofler at chello.at>
+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 <kdebug.h>
+ 
+ #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<ComponentTypes>(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 <QtCore/QString>
++#include <QtCore/QStringList>
+ 
+ #include <plasma/plasma_export.h>
+ 
+@@ -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 at chello.at>
+From: Kevin Kofler <kevin.kofler at chello.at>
+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 <kevin.kofler at chello.at>
++
++   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 <http://www.gnu.org/licenses/>. */
++
++#include <QCoreApplication>
++#include <QTextStream>
++#include <QFileInfo>
++#include <QDir>
++
++#include <cstdio>
++
++#include <kaboutdata.h>
++#include <kcmdlineargs.h>
++#include <kdesktopfile.h>
++#include <kconfiggroup.h>
++
++#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 at chello.at");
++
++    KCmdLineArgs::init(argc, argv, &aboutData);
++    KCmdLineOptions options;
++    options.add("a")
++           .add("api <name>",
++                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 <QWidget>
+ #include <QLatin1String>
+ #include <QStringList>
++#include <QTextStream>
++#include <QFile>
++#include <QDirIterator>
++#include <QRegExp>
+ #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 <QStringList>
+ 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 <Kevin at tigcc.ticalc.org> 4.7.0-3
+- backport my GSoC 2011 patches for libplasma PackageKit integration (F17+)
+
 * Sun Aug 21 2011 Kevin Kofler <Kevin at tigcc.ticalc.org> 4.7.0-2
 - rebuild for the RPM dependency generators for Plasma (GSoC 2011)
 - add BuildRequires: kde-settings to pick up the above


More information about the scm-commits mailing list