[gnome-software] Add a plugin method to convert a local file to a GsApp
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Add a plugin method to convert a local file to a GsApp
- Date: Wed, 29 Jan 2014 11:41:32 +0000 (UTC)
commit 3a03420b9e2538353a67f5f008427f00631780de
Author: Richard Hughes <richard hughsie com>
Date: Wed Jan 29 08:42:25 2014 +0000
Add a plugin method to convert a local file to a GsApp
src/gs-cmd.c | 13 ++-
src/gs-plugin-loader-sync.c | 51 +++++++
src/gs-plugin-loader-sync.h | 5 +
src/gs-plugin-loader.c | 195 ++++++++++++++++++++++++++++
src/gs-plugin-loader.h | 9 ++
src/gs-plugin.h | 10 ++
src/plugins/gs-plugin-packagekit-refresh.c | 79 +++++++++++
7 files changed, 361 insertions(+), 1 deletions(-)
---
diff --git a/src/gs-cmd.c b/src/gs-cmd.c
index 1133259..b02aab8 100644
--- a/src/gs-cmd.c
+++ b/src/gs-cmd.c
@@ -277,6 +277,17 @@ main (int argc, char **argv)
if (!ret)
break;
}
+ } else if (argc == 3 && g_strcmp0 (argv[1], "filename-to-app") == 0) {
+ app = gs_plugin_loader_filename_to_app (plugin_loader,
+ argv[2],
+ refine_flags,
+ NULL,
+ &error);
+ if (app == NULL) {
+ ret = FALSE;
+ } else {
+ gs_plugin_add_app (&list, app);
+ }
} else if (argc == 2 && g_strcmp0 (argv[1], "updates") == 0) {
for (i = 0; i < repeat; i++) {
if (list != NULL)
@@ -358,7 +369,7 @@ main (int argc, char **argv)
GS_PLUGIN_ERROR_FAILED,
"Did not recognise option, use 'installed', "
"'updates', 'popular', 'get-categories', "
- "'get-category-apps', or 'search'");
+ "'get-category-apps', 'filename-to-app', or 'search'");
}
if (!ret) {
g_print ("Failed: %s\n", error->message);
diff --git a/src/gs-plugin-loader-sync.c b/src/gs-plugin-loader-sync.c
index efd2253..144e7ae 100644
--- a/src/gs-plugin-loader-sync.c
+++ b/src/gs-plugin-loader-sync.c
@@ -52,6 +52,7 @@ typedef struct {
GMainContext *context;
GMainLoop *loop;
gboolean ret;
+ GsApp *app;
} GsPluginLoaderHelper;
static void
@@ -523,4 +524,54 @@ gs_plugin_loader_refresh (GsPluginLoader *plugin_loader,
return helper.ret;
}
+static void
+gs_plugin_loader_filename_to_app_finish_sync (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source_object);
+ GsPluginLoaderHelper *helper = (GsPluginLoaderHelper *) user_data;
+ helper->app = gs_plugin_loader_filename_to_app_finish (plugin_loader,
+ res,
+ helper->error);
+ g_main_loop_quit (helper->loop);
+}
+
+/**
+ * gs_plugin_loader_filename_to_app:
+ **/
+GsApp *
+gs_plugin_loader_filename_to_app (GsPluginLoader *plugin_loader,
+ const gchar *filename,
+ GsPluginRefineFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GsPluginLoaderHelper helper;
+
+ /* create temp object */
+ helper.app = NULL;
+ helper.context = g_main_context_new ();
+ helper.loop = g_main_loop_new (helper.context, FALSE);
+ helper.error = error;
+
+ g_main_context_push_thread_default (helper.context);
+
+ /* run async method */
+ gs_plugin_loader_filename_to_app_async (plugin_loader,
+ filename,
+ flags,
+ cancellable,
+ gs_plugin_loader_filename_to_app_finish_sync,
+ &helper);
+ g_main_loop_run (helper.loop);
+
+ g_main_context_pop_thread_default (helper.context);
+
+ g_main_loop_unref (helper.loop);
+ g_main_context_unref (helper.context);
+
+ return helper.app;
+}
+
/* vim: set noexpandtab: */
diff --git a/src/gs-plugin-loader-sync.h b/src/gs-plugin-loader-sync.h
index 64f940c..ec509bf 100644
--- a/src/gs-plugin-loader-sync.h
+++ b/src/gs-plugin-loader-sync.h
@@ -78,6 +78,11 @@ GsApp *gs_plugin_loader_get_app_by_id (GsPluginLoader
*plugin_loader,
GsPluginRefineFlags flags,
GCancellable *cancellable,
GError **error);
+GsApp *gs_plugin_loader_filename_to_app (GsPluginLoader *plugin_loader,
+ const gchar *filename,
+ GsPluginRefineFlags flags,
+ GCancellable *cancellable,
+ GError **error);
G_END_DECLS
diff --git a/src/gs-plugin-loader.c b/src/gs-plugin-loader.c
index 9334630..796db23 100644
--- a/src/gs-plugin-loader.c
+++ b/src/gs-plugin-loader.c
@@ -644,6 +644,7 @@ typedef struct {
GsPluginLoader *plugin_loader;
GsPluginRefineFlags flags;
gchar *value;
+ gchar *filename;
guint cache_age;
GsCategory *category;
GsApp *app;
@@ -2996,4 +2997,198 @@ gs_plugin_loader_refresh_finish (GsPluginLoader *plugin_loader,
/******************************************************************************/
+/**
+ * gs_plugin_loader_filename_to_app_state_finish:
+ **/
+static void
+gs_plugin_loader_filename_to_app_state_finish (GsPluginLoaderAsyncState *state,
+ const GError *error)
+{
+ if (state->app != NULL) {
+ g_simple_async_result_set_op_res_gpointer (state->res,
+ g_object_ref (state->app),
+ (GDestroyNotify) g_object_unref);
+ } else {
+ g_simple_async_result_set_from_error (state->res, error);
+ }
+
+ if (state->cancellable != NULL)
+ g_object_unref (state->cancellable);
+ if (state->app != NULL)
+ g_object_unref (state->app);
+ g_free (state->filename);
+ gs_plugin_list_free (state->list);
+ g_object_unref (state->res);
+ g_object_unref (state->plugin_loader);
+ g_slice_free (GsPluginLoaderAsyncState, state);
+}
+
+/**
+ * gs_plugin_loader_filename_to_app_thread_cb:
+ **/
+static void
+gs_plugin_loader_filename_to_app_thread_cb (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ const gchar *function_name = "gs_plugin_filename_to_app";
+ gboolean ret = TRUE;
+ gchar *profile_id;
+ GError *error = NULL;
+ GsPluginLoaderAsyncState *state = (GsPluginLoaderAsyncState *) g_object_get_data (G_OBJECT
(cancellable), "state");
+ GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (object);
+ GsPlugin *plugin;
+ GsPluginFilenameToAppFunc plugin_func = NULL;
+ guint i;
+
+ /* run each plugin */
+ for (i = 0; i < plugin_loader->priv->plugins->len; i++) {
+ plugin = g_ptr_array_index (plugin_loader->priv->plugins, i);
+ if (!plugin->enabled)
+ continue;
+ ret = g_cancellable_set_error_if_cancelled (cancellable, &error);
+ if (ret) {
+ gs_plugin_loader_filename_to_app_state_finish (state, error);
+ g_error_free (error);
+ goto out;
+ }
+ ret = g_module_symbol (plugin->module,
+ function_name,
+ (gpointer *) &plugin_func);
+ if (!ret)
+ continue;
+ profile_id = g_strdup_printf ("GsPlugin::%s(%s)",
+ plugin->name, function_name);
+ gs_profile_start (plugin_loader->priv->profile, profile_id);
+ ret = plugin_func (plugin, &state->list, state->filename, cancellable, &error);
+ if (!ret) {
+ gs_plugin_loader_filename_to_app_state_finish (state, error);
+ g_error_free (error);
+ goto out;
+ }
+ gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_FINISHED);
+ gs_profile_stop (plugin_loader->priv->profile, profile_id);
+ g_free (profile_id);
+ }
+
+ /* dedupe applications we already know about */
+ gs_plugin_loader_list_dedupe (plugin_loader, state->list);
+
+ /* run refine() on each one */
+ ret = gs_plugin_loader_run_refine (plugin_loader,
+ function_name,
+ state->list,
+ state->flags,
+ cancellable,
+ &error);
+ if (!ret) {
+ gs_plugin_loader_filename_to_app_state_finish (state, error);
+ g_error_free (error);
+ goto out;
+ }
+
+ /* filter package list */
+ gs_plugin_list_filter_duplicates (&state->list);
+ if (state->list == NULL) {
+ g_set_error (&error,
+ GS_PLUGIN_LOADER_ERROR,
+ GS_PLUGIN_LOADER_ERROR_NO_RESULTS,
+ "no filename_to_app results to show");
+ gs_plugin_loader_filename_to_app_state_finish (state, error);
+ g_error_free (error);
+ goto out;
+ }
+
+ /* success */
+ if (g_list_length (state->list) != 1) {
+ g_set_error (&error,
+ GS_PLUGIN_LOADER_ERROR,
+ GS_PLUGIN_LOADER_ERROR_NO_RESULTS,
+ "no application was created for %s",
+ state->filename);
+ gs_plugin_loader_filename_to_app_state_finish (state, error);
+ g_error_free (error);
+ goto out;
+ }
+ state->app = g_object_ref (state->list->data);
+ gs_plugin_loader_filename_to_app_state_finish (state, NULL);
+out:
+ return;
+}
+
+/**
+ * gs_plugin_loader_filename_to_app_async:
+ *
+ * This method calls all plugins that implement the gs_plugin_add_filename_to_app()
+ * function. The plugins can either return #GsApp objects of kind
+ * %GS_APP_KIND_NORMAL for bonafide applications, or #GsApp's of kind
+ * %GS_APP_KIND_PACKAGE for packages that may or may not be applications.
+ *
+ * Once the list of updates is refined, some of the #GsApp's of kind
+ * %GS_APP_KIND_PACKAGE will have been promoted to a kind of %GS_APP_KIND_NORMAL,
+ * or if they are core applications.
+ **/
+void
+gs_plugin_loader_filename_to_app_async (GsPluginLoader *plugin_loader,
+ const gchar *filename,
+ GsPluginRefineFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GCancellable *tmp;
+ GsPluginLoaderAsyncState *state;
+
+ g_return_if_fail (GS_IS_PLUGIN_LOADER (plugin_loader));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ /* save state */
+ state = g_slice_new0 (GsPluginLoaderAsyncState);
+ state->res = g_simple_async_result_new (G_OBJECT (plugin_loader),
+ callback,
+ user_data,
+ gs_plugin_loader_filename_to_app_async);
+ state->plugin_loader = g_object_ref (plugin_loader);
+ state->flags = flags;
+ state->filename = g_strdup (filename);
+ if (cancellable != NULL)
+ state->cancellable = g_object_ref (cancellable);
+
+ /* run in a thread */
+ tmp = g_cancellable_new ();
+ g_object_set_data (G_OBJECT (tmp), "state", state);
+ g_simple_async_result_run_in_thread (G_SIMPLE_ASYNC_RESULT (state->res),
+ gs_plugin_loader_filename_to_app_thread_cb,
+ 0,
+ (GCancellable *) tmp);
+ g_object_unref (tmp);
+}
+
+/**
+ * gs_plugin_loader_filename_to_app_finish:
+ *
+ * Return value: (element-type GsApp) (transfer full): An application, or %NULL
+ **/
+GsApp *
+gs_plugin_loader_filename_to_app_finish (GsPluginLoader *plugin_loader,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (GS_IS_PLUGIN_LOADER (plugin_loader), NULL);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (res), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ /* failed */
+ simple = G_SIMPLE_ASYNC_RESULT (res);
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+
+ /* grab application */
+ return g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
+}
+
+/******************************************************************************/
+
/* vim: set noexpandtab: */
diff --git a/src/gs-plugin-loader.h b/src/gs-plugin-loader.h
index 73d7af9..302043e 100644
--- a/src/gs-plugin-loader.h
+++ b/src/gs-plugin-loader.h
@@ -136,6 +136,15 @@ void gs_plugin_loader_search_async (GsPluginLoader
*plugin_loader,
GList *gs_plugin_loader_search_finish (GsPluginLoader *plugin_loader,
GAsyncResult *res,
GError **error);
+void gs_plugin_loader_filename_to_app_async (GsPluginLoader *plugin_loader,
+ const gchar *filename,
+ GsPluginRefineFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GsApp *gs_plugin_loader_filename_to_app_finish(GsPluginLoader *plugin_loader,
+ GAsyncResult *res,
+ GError **error);
gboolean gs_plugin_loader_setup (GsPluginLoader *plugin_loader,
GError **error);
void gs_plugin_loader_dump_state (GsPluginLoader *plugin_loader);
diff --git a/src/gs-plugin.h b/src/gs-plugin.h
index 3f4240f..1350cc7 100644
--- a/src/gs-plugin.h
+++ b/src/gs-plugin.h
@@ -135,6 +135,11 @@ typedef gboolean (*GsPluginRefreshFunc ) (GsPlugin *plugin,
GsPluginRefreshFlags flags,
GCancellable *cancellable,
GError **error);
+typedef gboolean (*GsPluginFilenameToAppFunc) (GsPlugin *plugin,
+ GList **list,
+ const gchar *filename,
+ GCancellable *cancellable,
+ GError **error);
const gchar *gs_plugin_get_name (void);
void gs_plugin_initialize (GsPlugin *plugin);
@@ -216,6 +221,11 @@ gboolean gs_plugin_refresh (GsPlugin *plugin,
GsPluginRefreshFlags flags,
GCancellable *cancellable,
GError **error);
+gboolean gs_plugin_filename_to_app (GsPlugin *plugin,
+ GList **list,
+ const gchar *filename,
+ GCancellable *cancellable,
+ GError **error);
G_END_DECLS
diff --git a/src/plugins/gs-plugin-packagekit-refresh.c b/src/plugins/gs-plugin-packagekit-refresh.c
index 866387f..73f62db 100644
--- a/src/plugins/gs-plugin-packagekit-refresh.c
+++ b/src/plugins/gs-plugin-packagekit-refresh.c
@@ -169,3 +169,82 @@ out:
g_object_unref (results);
return ret;
}
+
+/**
+ * gs_plugin_refresh:
+ */
+gboolean
+gs_plugin_filename_to_app (GsPlugin *plugin,
+ GList **list,
+ const gchar *filename,
+ GCancellable *cancellable,
+ GError **error)
+{
+ const gchar *package_id;
+ gboolean ret = TRUE;
+ gchar **files;
+ gchar **split = NULL;
+ GPtrArray *array = NULL;
+ GsApp *app = NULL;
+ PkDetails *item;
+ PkResults *results;
+
+ /* get details */
+ files = g_strsplit (filename, "\t", -1);
+ pk_client_set_cache_age (PK_CLIENT (plugin->priv->task), G_MAXUINT);
+ results = pk_client_get_details_local (PK_CLIENT (plugin->priv->task),
+ files,
+ cancellable,
+ gs_plugin_packagekit_progress_cb, plugin,
+ error);
+ if (results == NULL) {
+ ret = FALSE;
+ goto out;
+ }
+
+ /* get results */
+ array = pk_results_get_details_array (results);
+ if (array->len == 0) {
+ ret = FALSE;
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "no details for %s", filename);
+ goto out;
+ }
+ if (array->len > 1) {
+ ret = FALSE;
+ g_set_error (error,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_FAILED,
+ "too many details [%i] for %s",
+ array->len, filename);
+ goto out;
+ }
+
+ /* create application */
+ item = g_ptr_array_index (array, 0);
+ app = gs_app_new (NULL);
+ package_id = pk_details_get_package_id (item);
+ split = pk_package_id_split (package_id);
+ gs_app_set_kind (app, GS_APP_KIND_PACKAGE);
+ gs_app_set_state (app, GS_APP_STATE_AVAILABLE);
+ gs_app_set_name (app, split[PK_PACKAGE_ID_NAME]);
+ gs_app_set_version (app, split[PK_PACKAGE_ID_VERSION]);
+ gs_app_set_metadata (app, "PackageKit::local-filename", filename);
+ gs_app_add_source (app, split[PK_PACKAGE_ID_NAME]);
+ gs_app_add_source_id (app, package_id);
+ gs_app_set_description (app, pk_details_get_description (item));
+ gs_app_set_url (app, GS_APP_URL_KIND_HOMEPAGE, pk_details_get_url (item));
+ gs_app_set_size (app, pk_details_get_size (item));
+ gs_app_set_licence (app, pk_details_get_license (item));
+ gs_plugin_add_app (list, app);
+out:
+ if (app != NULL)
+ g_object_unref (app);
+ if (array != NULL)
+ g_ptr_array_unref (array);
+ g_strfreev (split);
+ g_strfreev (files);
+ return ret;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]