[gnome-software] rpm-ostree: Implement locally downloaded rpm install



commit c16a317d2b5e0c6e24f6369696746378c35bce23
Author: Kalev Lember <klember redhat com>
Date:   Fri Jan 25 13:02:08 2019 +0100

    rpm-ostree: Implement locally downloaded rpm install

 plugins/rpm-ostree/gs-plugin-rpm-ostree.c | 233 ++++++++++++++++++++++++++++++
 1 file changed, 233 insertions(+)
---
diff --git a/plugins/rpm-ostree/gs-plugin-rpm-ostree.c b/plugins/rpm-ostree/gs-plugin-rpm-ostree.c
index 90ce335a..f57de5fe 100644
--- a/plugins/rpm-ostree/gs-plugin-rpm-ostree.c
+++ b/plugins/rpm-ostree/gs-plugin-rpm-ostree.c
@@ -40,6 +40,7 @@
  */
 #define GS_RPMOSTREE_CLIENT_ID PACKAGE_NAME
 
+G_DEFINE_AUTO_CLEANUP_FREE_FUNC(Header, headerFree, NULL)
 G_DEFINE_AUTO_CLEANUP_FREE_FUNC(rpmts, rpmtsFree, NULL);
 G_DEFINE_AUTO_CLEANUP_FREE_FUNC(rpmdbMatchIterator, rpmdbFreeIterator, NULL);
 
@@ -462,6 +463,32 @@ make_rpmostree_modifiers_variant (const char *install_package,
 
        }
 
+       if (install_local_package != NULL) {
+               g_auto(GVariantBuilder) builder;
+               int fd;
+               int idx;
+
+               g_variant_builder_init (&builder, G_VARIANT_TYPE ("ah"));
+
+               fd = openat (AT_FDCWD, install_local_package, O_RDONLY | O_CLOEXEC | O_NOCTTY);
+               if (fd == -1) {
+                       g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED,
+                                    "Failed to open %s", install_local_package);
+                       return FALSE;
+               }
+
+               idx = g_unix_fd_list_append (fd_list, fd, error);
+               if (idx < 0) {
+                       close (fd);
+                       return FALSE;
+               }
+
+               g_variant_builder_add (&builder, "h", idx);
+               g_variant_dict_insert_value (&dict, "install-local-packages",
+                                            g_variant_new ("ah", &builder));
+               close (fd);
+       }
+
        *out_fd_list = g_steal_pointer (&fd_list);
        *out_modifiers = g_variant_ref_sink (g_variant_dict_end (&dict));
        return TRUE;
@@ -762,6 +789,89 @@ gs_plugin_update_app (GsPlugin *plugin,
        return TRUE;
 }
 
+gboolean
+gs_plugin_app_install (GsPlugin *plugin,
+                       GsApp *app,
+                       GCancellable *cancellable,
+                       GError **error)
+{
+       GsPluginData *priv = gs_plugin_get_data (plugin);
+       g_autofree gchar *local_filename = NULL;
+       g_autofree gchar *transaction_address = NULL;
+       g_autoptr(GVariant) options = NULL;
+
+       /* only process this app if was created by this plugin */
+       if (g_strcmp0 (gs_app_get_management_plugin (app), gs_plugin_get_name (plugin)) != 0)
+               return TRUE;
+
+       switch (gs_app_get_state (app)) {
+       case AS_APP_STATE_AVAILABLE_LOCAL:
+               if (gs_app_get_local_file (app) == NULL) {
+                       g_set_error_literal (error,
+                                            GS_PLUGIN_ERROR,
+                                            GS_PLUGIN_ERROR_NOT_SUPPORTED,
+                                            "local package, but no filename");
+                       return FALSE;
+               }
+
+               local_filename = g_file_get_path (gs_app_get_local_file (app));
+               break;
+       default:
+               g_set_error (error,
+                            GS_PLUGIN_ERROR,
+                            GS_PLUGIN_ERROR_NOT_SUPPORTED,
+                            "do not know how to install app in state %s",
+                            as_app_state_to_string (gs_app_get_state (app)));
+               return FALSE;
+       }
+
+       gs_app_set_state (app, AS_APP_STATE_INSTALLING);
+
+       options = make_rpmostree_options_variant (FALSE,  /* reboot */
+                                                 FALSE,  /* allow-downgrade */
+                                                 FALSE,   /* cache-only */
+                                                 FALSE,  /* download-only */
+                                                 FALSE,  /* skip-purge */
+                                                 TRUE,  /* no-pull-base */
+                                                 FALSE,  /* dry-run */
+                                                 FALSE); /* no-overrides */
+
+       if (!rpmostree_update_deployment (priv->os_proxy,
+                                         NULL /* install package */,
+                                         NULL /* remove package */,
+                                         local_filename,
+                                         options,
+                                         &transaction_address,
+                                         cancellable,
+                                         error)) {
+               gs_utils_error_convert_gio (error);
+               gs_app_set_state_recover (app);
+               return FALSE;
+       }
+
+       if (!gs_rpmostree_transaction_get_response_sync (priv->sysroot_proxy,
+                                                        transaction_address,
+                                                        cancellable,
+                                                        error)) {
+               gs_utils_error_convert_gio (error);
+               gs_app_set_state_recover (app);
+               return FALSE;
+       }
+
+       /* state is known */
+       gs_app_set_state (app, AS_APP_STATE_INSTALLED);
+
+       /* get the new icon from the package */
+       gs_app_set_local_file (app, NULL);
+       gs_app_add_icon (app, NULL);
+       gs_app_set_pixbuf (app, NULL);
+
+       /* no longer valid */
+       gs_app_clear_source_ids (app);
+
+       return TRUE;
+}
+
 gboolean
 gs_plugin_app_remove (GsPlugin *plugin,
                       GsApp *app,
@@ -1029,3 +1139,126 @@ gs_plugin_launch (GsPlugin *plugin,
 
        return gs_plugin_app_launch (plugin, app, error);
 }
+
+static void
+add_quirks_from_package_name (GsApp *app, const gchar *package_name)
+{
+       /* these packages don't have a .repo file in their file lists, but
+        * instead install one through rpm scripts / cron job */
+       const gchar *packages_with_repos[] = {
+               "google-chrome-stable",
+               "google-earth-pro-stable",
+               "google-talkplugin",
+               NULL };
+
+       if (g_strv_contains (packages_with_repos, package_name))
+               gs_app_add_quirk (app, GS_APP_QUIRK_HAS_SOURCE);
+}
+
+gboolean
+gs_plugin_file_to_app (GsPlugin *plugin,
+                      GsAppList *list,
+                      GFile *file,
+                      GCancellable *cancellable,
+                      GError **error)
+{
+       gboolean ret = FALSE;
+       FD_t rpmfd;
+       int r;
+       guint64 epoch;
+       guint64 size;
+       const gchar *name;
+       const gchar *version;
+       const gchar *release;
+       const gchar *license;
+       g_auto(Header) h = NULL;
+       g_auto(rpmts) ts = NULL;
+       g_autofree gchar *evr = NULL;
+       g_autofree gchar *filename = NULL;
+       g_autoptr(GsApp) app = NULL;
+
+       filename = g_file_get_path (file);
+       if (!g_str_has_suffix (filename, ".rpm")) {
+               ret = TRUE;
+               goto out;
+       }
+
+       ts = rpmtsCreate ();
+       rpmtsSetVSFlags (ts, _RPMVSF_NOSIGNATURES);
+
+       /* librpm needs Fopenfd */
+       rpmfd = Fopen (filename, "r.fdio");
+       if (rpmfd == NULL) {
+               g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED,
+                            "Opening %s failed", filename);
+               goto out;
+       }
+       if (Ferror (rpmfd)) {
+               g_set_error (error,
+                            GS_PLUGIN_ERROR,
+                            GS_PLUGIN_ERROR_FAILED,
+                            "Opening %s failed: %s",
+                            filename,
+                            Fstrerror (rpmfd));
+               goto out;
+       }
+
+       if ((r = rpmReadPackageFile (ts, rpmfd, filename, &h)) != RPMRC_OK) {
+               g_set_error (error,
+                            GS_PLUGIN_ERROR,
+                            GS_PLUGIN_ERROR_FAILED,
+                            "Verification of %s failed",
+                            filename);
+               goto out;
+       }
+
+       app = gs_app_new (NULL);
+       gs_app_set_metadata (app, "GnomeSoftware::Creator", gs_plugin_get_name (plugin));
+       gs_app_set_management_plugin (app, gs_plugin_get_name (plugin));
+       gs_app_set_kind (app, AS_APP_KIND_GENERIC);
+       gs_app_set_bundle_kind (app, AS_BUNDLE_KIND_PACKAGE);
+       gs_app_set_scope (app, AS_APP_SCOPE_SYSTEM);
+       gs_app_set_state (app, AS_APP_STATE_AVAILABLE_LOCAL);
+
+       /* add default source */
+       name = headerGetString (h, RPMTAG_NAME);
+       g_debug ("rpm: setting source to %s", name);
+       gs_app_add_source (app, name);
+
+       /* add version */
+       epoch = headerGetNumber (h, RPMTAG_EPOCH);
+       version = headerGetString (h, RPMTAG_VERSION);
+       release = headerGetString (h, RPMTAG_RELEASE);
+       if (epoch > 0) {
+               evr = g_strdup_printf ("%" G_GUINT64_FORMAT ":%s-%s",
+                                      epoch, version, release);
+       } else {
+               evr = g_strdup_printf ("%s-%s",
+                                      version, release);
+       }
+       g_debug ("rpm: setting version to %s", evr);
+       gs_app_set_version (app, evr);
+
+       /* set size */
+       size = headerGetNumber (h, RPMTAG_SIZE);
+       gs_app_set_size_installed (app, size);
+
+       /* set license */
+       license = headerGetString (h, RPMTAG_LICENSE);
+       if (license != NULL) {
+               g_autofree gchar *license_spdx = NULL;
+               license_spdx = as_utils_license_to_spdx (license);
+               gs_app_set_license (app, GS_APP_QUALITY_NORMAL, license_spdx);
+               g_debug ("rpm: setting license to %s", license_spdx);
+       }
+
+       add_quirks_from_package_name (app, name);
+
+       gs_app_list_add (list, app);
+       ret = TRUE;
+
+out:
+       if (rpmfd)
+               (void) Fclose (rpmfd);
+       return ret;
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]