* Sun Aug 21 2011 Kevin Kofler <Kevin@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.)
This commit is contained in:
Kevin Kofler 2011-08-21 04:10:16 +02:00
parent 6620216a96
commit 516b628b71
4 changed files with 833 additions and 1 deletions

View File

@ -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 <kevin.kofler@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@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@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

View File

@ -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 <kevin.kofler@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

View File

@ -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 <kevin.kofler@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@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@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

View File

@ -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@tigcc.ticalc.org> 4.7.0-3
- backport my GSoC 2011 patches for libplasma PackageKit integration (F17+)
* Sun Aug 21 2011 Kevin Kofler <Kevin@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