[gnome-software/1476-add-a-way-for-app-developers-to-test-their-metainfo-appdata-files] application: Add '--show-appdata' command line argument
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software/1476-add-a-way-for-app-developers-to-test-their-metainfo-appdata-files] application: Add '--show-appdata' command line argument
- Date: Thu, 14 Oct 2021 10:30:55 +0000 (UTC)
commit d8d5b0b7e526fe337f0b7a115bb8a6213c641dfe
Author: Milan Crha <mcrha redhat com>
Date: Thu Oct 14 12:27:05 2021 +0200
application: Add '--show-appdata' command line argument
This can be used to view an appstream data file how it'll be shown
in the Software, without a need to install it and search for it.
Closes https://gitlab.gnome.org/GNOME/gnome-software/-/issues/1476
src/gs-application.c | 30 ++++++++++++
src/gs-details-page.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++--
src/gs-details-page.h | 2 +
src/gs-shell.c | 17 ++++++-
src/gs-shell.h | 2 +
5 files changed, 172 insertions(+), 5 deletions(-)
---
diff --git a/src/gs-application.c b/src/gs-application.c
index b62931bc1..0969428c8 100644
--- a/src/gs-application.c
+++ b/src/gs-application.c
@@ -143,6 +143,8 @@ gs_application_init (GsApplication *application)
{ "interaction", '\0', 0, G_OPTION_ARG_STRING, NULL,
_("The kind of interaction expected for this action: either "
"‘none’, ‘notify’, or ‘full’"), NULL },
+ { "show-appdata", '\0', 0, G_OPTION_ARG_FILENAME, NULL,
+ _("Show a local appdata file"), _("FILENAME") },
{ "verbose", '\0', 0, G_OPTION_ARG_NONE, NULL,
_("Show verbose debugging information"), NULL },
{ "autoupdate", 0, 0, G_OPTION_ARG_NONE, NULL,
@@ -786,6 +788,23 @@ filename_activated (GSimpleAction *action,
gs_shell_show_local_file (app->shell, file);
}
+static void
+show_appdata_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer data)
+{
+ GsApplication *app = GS_APPLICATION (data);
+ const gchar *filename;
+ g_autoptr(GFile) file = NULL;
+
+ g_variant_get (parameter, "(&s)", &filename);
+
+ file = g_file_new_for_path (filename);
+
+ gs_shell_reset_state (app->shell);
+ gs_shell_show_appdata (app->shell, file);
+}
+
static void
launch_activated (GSimpleAction *action,
GVariant *parameter,
@@ -903,6 +922,7 @@ static GActionEntry actions_after_loading[] = {
{ "install", install_activated, "(su)", NULL, NULL },
{ "filename", filename_activated, "(s)", NULL, NULL },
{ "install-resources", install_resources_activated, "(sassss)", NULL, NULL },
+ { "show-appdata", show_appdata_activated, "(s)", NULL, NULL },
{ "nop", NULL, NULL, NULL }
};
@@ -1221,6 +1241,16 @@ gs_application_handle_local_options (GApplication *app, GVariantDict *options)
"filename",
g_variant_new ("(s)", absolute_filename));
rc = 0;
+ } else if (g_variant_dict_lookup (options, "show-appdata", "^&ay", &local_filename)) {
+ g_autoptr(GFile) file = NULL;
+ g_autofree gchar *absolute_filename = NULL;
+
+ file = g_file_new_for_path (local_filename);
+ absolute_filename = g_file_get_path (file);
+ g_action_group_activate_action (G_ACTION_GROUP (app),
+ "show-appdata",
+ g_variant_new ("(s)", absolute_filename));
+ rc = 0;
}
return rc;
diff --git a/src/gs-details-page.c b/src/gs-details-page.c
index e0a7ad2b5..ccbef2898 100644
--- a/src/gs-details-page.c
+++ b/src/gs-details-page.c
@@ -14,6 +14,8 @@
#include <string.h>
#include <glib/gi18n.h>
+#include "lib/gs-appstream.h"
+
#include "gs-common.h"
#include "gs-utils.h"
@@ -1482,7 +1484,8 @@ _set_app (GsDetailsPage *self, GsApp *app)
/* show the UI and do operations that should not block page load */
static void
-gs_details_page_load_stage2 (GsDetailsPage *self)
+gs_details_page_load_stage2 (GsDetailsPage *self,
+ gboolean continue_loading)
{
g_autofree gchar *tmp = NULL;
g_autoptr(GsPluginJob) plugin_job1 = NULL;
@@ -1504,6 +1507,9 @@ gs_details_page_load_stage2 (GsDetailsPage *self)
gs_details_page_refresh_all (self);
gs_details_page_update_origin_button (self, FALSE);
+ if (!continue_loading)
+ return;
+
/* if these tasks fail (e.g. because we have no networking) then it's
* of no huge importance if we don't get the required data */
plugin_job1 = gs_plugin_job_newv (GS_PLUGIN_ACTION_REFINE,
@@ -1570,7 +1576,7 @@ gs_details_page_load_stage1_cb (GObject *source,
}
/* do 2nd stage refine */
- gs_details_page_load_stage2 (self);
+ gs_details_page_load_stage2 (self, TRUE);
}
static void
@@ -1594,7 +1600,7 @@ gs_details_page_file_to_app_cb (GObject *source,
GsApp *app = gs_app_list_index (list, 0);
g_set_object (&self->app_local_file, app);
_set_app (self, app);
- gs_details_page_load_stage2 (self);
+ gs_details_page_load_stage2 (self, TRUE);
}
}
@@ -1618,7 +1624,7 @@ gs_details_page_url_to_app_cb (GObject *source,
} else {
GsApp *app = gs_app_list_index (list, 0);
_set_app (self, app);
- gs_details_page_load_stage2 (self);
+ gs_details_page_load_stage2 (self, TRUE);
}
}
@@ -2475,3 +2481,115 @@ gs_details_page_set_is_narrow (GsDetailsPage *self, gboolean is_narrow)
self->is_narrow = is_narrow;
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_IS_NARROW]);
}
+
+static void
+gs_details_page_appdata_ready_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GsDetailsPage *self = GS_DETAILS_PAGE (source_object);
+ g_autoptr(GsApp) app = NULL;
+ g_autoptr(GError) error = NULL;
+
+ app = g_task_propagate_pointer (G_TASK (result), &error);
+ if (error) {
+ gtk_label_set_text (GTK_LABEL (self->label_failed), error->message);
+ gs_details_page_set_state (self, GS_DETAILS_PAGE_STATE_FAILED);
+ return;
+ }
+
+ g_set_object (&self->app_local_file, app);
+ _set_app (self, app);
+ gs_details_page_load_stage2 (self, FALSE);
+}
+
+static void
+gs_details_page_appdata_thread (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ const gchar *const *locales;
+ g_autofree gchar *xml = NULL;
+ g_autofree gchar *path = NULL;
+ g_autoptr(XbBuilder) builder = NULL;
+ g_autoptr(XbBuilderSource) builder_source = NULL;
+ g_autoptr(XbSilo) silo = NULL;
+ g_autoptr(GPtrArray) nodes = NULL;
+ g_autoptr(GError) error = NULL;
+ g_autoptr(GsApp) app = NULL;
+ GFile *file = task_data;
+ XbNode *component;
+
+ builder_source = xb_builder_source_new ();
+ if (!xb_builder_source_load_file (builder_source, file, XB_BUILDER_SOURCE_FLAG_NONE, cancellable,
&error)) {
+ g_task_return_error (task, g_steal_pointer (&error));
+ return;
+ }
+
+ builder = xb_builder_new ();
+ locales = g_get_language_names ();
+
+ /* add current locales */
+ for (guint i = 0; locales[i] != NULL; i++) {
+ xb_builder_add_locale (builder, locales[i]);
+ }
+
+ xb_builder_import_source (builder, builder_source);
+
+ silo = xb_builder_compile (builder, XB_BUILDER_COMPILE_FLAG_IGNORE_INVALID |
XB_BUILDER_COMPILE_FLAG_SINGLE_LANG, cancellable, &error);
+ if (silo == NULL) {
+ g_task_return_error (task, g_steal_pointer (&error));
+ return;
+ }
+
+ nodes = xb_silo_query (silo, "component", 0, NULL);
+ if (nodes == NULL)
+ nodes = xb_silo_query (silo, "application", 0, NULL);
+ if (nodes == NULL) {
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "%s",
+ "Passed-in file doesn't have a 'component' (nor 'application') top-level element");
+ return;
+ }
+
+ if (nodes->len != 1) {
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Only one top-level element expected, received %u instead", nodes->len);
+ return;
+ }
+
+ component = g_ptr_array_index (nodes, 0);
+
+ app = gs_appstream_create_app (NULL, silo, component, &error);
+ if (app == NULL) {
+ g_task_return_error (task, g_steal_pointer (&error));
+ return;
+ }
+
+ if (!gs_appstream_refine_app (NULL, app, silo, component, GS_DETAILS_PAGE_REFINE_FLAGS, &error)) {
+ g_task_return_error (task, g_steal_pointer (&error));
+ return;
+ }
+
+ path = g_file_get_path (file);
+ gs_app_set_origin (app, path);
+
+ gs_app_set_state (app, GS_APP_STATE_UNKNOWN);
+
+ g_task_return_pointer (task, g_steal_pointer (&app), g_object_unref);
+}
+
+void
+gs_details_page_set_appdata (GsDetailsPage *self,
+ GFile *file)
+{
+ g_autoptr(GTask) task = NULL;
+ gs_details_page_set_state (self, GS_DETAILS_PAGE_STATE_LOADING);
+ g_clear_object (&self->app_local_file);
+ g_clear_object (&self->app);
+ self->origin_by_packaging_format = FALSE;
+ task = g_task_new (self, self->cancellable, gs_details_page_appdata_ready_cb, NULL);
+ g_task_set_source_tag (task, gs_details_page_set_appdata);
+ g_task_set_task_data (task, g_object_ref (file), g_object_unref);
+ g_task_run_in_thread (task, gs_details_page_appdata_thread);
+}
diff --git a/src/gs-details-page.h b/src/gs-details-page.h
index 1ec5059d1..bf1a697f1 100644
--- a/src/gs-details-page.h
+++ b/src/gs-details-page.h
@@ -33,5 +33,7 @@ void gs_details_page_set_odrs_provider (GsDetailsPage *self,
gboolean gs_details_page_get_is_narrow (GsDetailsPage *self);
void gs_details_page_set_is_narrow (GsDetailsPage *self,
gboolean is_narrow);
+void gs_details_page_set_appdata (GsDetailsPage *self,
+ GFile *file);
G_END_DECLS
diff --git a/src/gs-shell.c b/src/gs-shell.c
index 9e2cde8c8..710c34bfe 100644
--- a/src/gs-shell.c
+++ b/src/gs-shell.c
@@ -620,7 +620,10 @@ gs_shell_change_mode (GsShell *shell,
gtk_editable_set_position (GTK_EDITABLE (shell->entry_search), -1);
} else if (mode == GS_SHELL_MODE_DETAILS) {
app = GS_APP (data);
- if (gs_app_get_local_file (app) != NULL) {
+ if (gs_app_get_metadata_item (app, "GnomeSoftware::show-appdata") != NULL) {
+ gs_details_page_set_appdata (GS_DETAILS_PAGE (page),
+ gs_app_get_local_file (app));
+ } else if (gs_app_get_local_file (app) != NULL) {
gs_details_page_set_local_file (GS_DETAILS_PAGE (page),
gs_app_get_local_file (app));
} else if (gs_app_get_metadata_item (app, "GnomeSoftware::from-url") != NULL) {
@@ -2359,6 +2362,18 @@ gs_shell_show_local_file (GsShell *shell, GFile *file)
gs_shell_activate (shell);
}
+void
+gs_shell_show_appdata (GsShell *shell, GFile *file)
+{
+ g_autoptr(GsApp) app = gs_app_new (NULL);
+ save_back_entry (shell);
+ gs_app_set_metadata (app, "GnomeSoftware::show-appdata", "1");
+ gs_app_set_local_file (app, file);
+ gs_shell_change_mode (shell, GS_SHELL_MODE_DETAILS,
+ (gpointer) app, TRUE);
+ gs_shell_activate (shell);
+}
+
void
gs_shell_show_search_result (GsShell *shell, const gchar *id, const gchar *search)
{
diff --git a/src/gs-shell.h b/src/gs-shell.h
index d11345b46..73e4c072c 100644
--- a/src/gs-shell.h
+++ b/src/gs-shell.h
@@ -86,5 +86,7 @@ void gs_shell_setup (GsShell *shell,
void gs_shell_show_notification (GsShell *shell,
const gchar *title);
gboolean gs_shell_get_is_narrow (GsShell *shell);
+void gs_shell_show_appdata (GsShell *shell,
+ GFile *file);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]