From 98fd052695d6e026ff91e87b8778f6fe44b8cbab Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Sat, 7 Jul 2018 15:27:26 +0200 Subject: [PATCH] transaction: Move the handling of bundle runtime remote from cli code This allows libflatpak users to also add runtime remotes as needed by bundles. Closes: #1868 Approved by: alexlarsson --- app/flatpak-builtins-install.c | 147 --------------------------------- common/flatpak-transaction.c | 121 +++++++++++++++++++++++---- 2 files changed, 107 insertions(+), 161 deletions(-) diff --git a/app/flatpak-builtins-install.c b/app/flatpak-builtins-install.c index fcc18244..7f632c0d 100644 --- a/app/flatpak-builtins-install.c +++ b/app/flatpak-builtins-install.c @@ -113,147 +113,6 @@ read_gpg_data (GCancellable *cancellable, return flatpak_read_stream (source_stream, FALSE, error); } -static gboolean -remote_is_already_configured (FlatpakDir *dir, - const char *url, - const char *collection_id) -{ - g_autofree char *old_remote = NULL; - - old_remote = flatpak_dir_find_remote_by_uri (dir, url, collection_id); - if (old_remote == NULL && flatpak_dir_is_user (dir)) - { - g_autoptr(GPtrArray) system_dirs = NULL; - int i; - - system_dirs = flatpak_dir_get_system_list (NULL, NULL); - if (system_dirs == NULL) - return FALSE; - - for (i = 0; i < system_dirs->len; i++) - { - FlatpakDir *system_dir = g_ptr_array_index (system_dirs, i); - old_remote = flatpak_dir_find_remote_by_uri (system_dir, url, collection_id); - if (old_remote != NULL) - break; - } - } - - return old_remote != NULL; -} - -static gboolean -handle_runtime_repo_deps (FlatpakDir *dir, const char *dep_url, GError **error) -{ - g_autoptr(GBytes) dep_data = NULL; - g_autofree char *runtime_url = NULL; - g_autofree char *new_remote = NULL; - g_autofree char *basename = NULL; - g_autoptr(SoupURI) uri = NULL; - g_auto(GStrv) remotes = NULL; - g_autoptr(GKeyFile) config = NULL; - g_autoptr(GBytes) gpg_key = NULL; - g_autofree char *group = NULL; - g_autofree char *runtime_collection_id = NULL; - g_autoptr(GKeyFile) dep_keyfile = g_key_file_new (); - g_autoptr(GError) local_error = NULL; - char *t; - int i; - - if (opt_no_deps) - return TRUE; - - dep_data = download_uri (dep_url, error); - if (dep_data == NULL) - { - g_prefix_error (error, "Can't load dependent file %s", dep_url); - return FALSE; - } - - if (!g_key_file_load_from_data (dep_keyfile, - g_bytes_get_data (dep_data, NULL), - g_bytes_get_size (dep_data), - 0, error)) - return flatpak_fail (error, "Invalid .flatpakrepo: %s", local_error->message); - - uri = soup_uri_new (dep_url); - basename = g_path_get_basename (soup_uri_get_path (uri)); - /* Strip suffix */ - t = strchr (basename, '.'); - if (t != NULL) - *t = 0; - - /* Find a free remote name */ - remotes = flatpak_dir_list_remotes (dir, NULL, NULL); - i = 0; - do - { - g_clear_pointer (&new_remote, g_free); - - if (i == 0) - new_remote = g_strdup (basename); - else - new_remote = g_strdup_printf ("%s-%d", basename, i); - i++; - } - while (remotes != NULL && g_strv_contains ((const char * const*)remotes, new_remote)); - - config = flatpak_dir_parse_repofile (dir, new_remote, FALSE, dep_keyfile, &gpg_key, NULL, error); - if (config == NULL) - { - g_prefix_error (error, "Can't parse dependent file %s: ", dep_url); - return FALSE; - } - - /* See if it already exists */ - group = g_strdup_printf ("remote \"%s\"", new_remote); - runtime_url = g_key_file_get_string (config, group, "url", NULL); - g_assert (runtime_url != NULL); - runtime_collection_id = g_key_file_get_string (config, group, "collection-id", NULL); - - if (remote_is_already_configured (dir, runtime_url, runtime_collection_id)) - return TRUE; - - if (opt_yes || - flatpak_yes_no_prompt (_("This application depends on runtimes from:\n %s\nConfigure this as new remote '%s'"), - runtime_url, new_remote)) - { - if (opt_yes) - g_print (_("Configuring %s as new remote '%s'"), runtime_url, new_remote); - - if (!flatpak_dir_modify_remote (dir, new_remote, config, gpg_key, NULL, error)) - return FALSE; - if (!flatpak_dir_recreate_repo (dir, NULL, error)) - return FALSE; - } - - return TRUE; -} - -static gboolean -handle_runtime_repo_deps_from_bundle (FlatpakDir *dir, GFile *file, GError **error) -{ - g_autofree char *dep_url = NULL; - g_autoptr(GVariant) metadata = NULL; - - if (opt_no_deps) - return TRUE; - - metadata = flatpak_bundle_load (file, NULL, - NULL, - NULL, - &dep_url, - NULL, - NULL, - NULL, - NULL, - NULL); - if (metadata == NULL || dep_url == NULL) - return TRUE; - - return handle_runtime_repo_deps (dir, dep_url, error); -} - static gboolean install_bundle (FlatpakDir *dir, GOptionContext *context, @@ -287,12 +146,6 @@ install_bundle (FlatpakDir *dir, return FALSE; } - if (!handle_runtime_repo_deps_from_bundle (dir, file, error)) - return FALSE; - - if (!flatpak_dir_ensure_repo (dir, cancellable, error)) - return FALSE; - transaction = flatpak_cli_transaction_new (dir, opt_yes, TRUE, error); if (transaction == NULL) return FALSE; diff --git a/common/flatpak-transaction.c b/common/flatpak-transaction.c index abd72712..aed83910 100644 --- a/common/flatpak-transaction.c +++ b/common/flatpak-transaction.c @@ -78,6 +78,13 @@ struct _FlatpakTransactionOperation { typedef struct _FlatpakTransactionPrivate FlatpakTransactionPrivate; +typedef struct _BundleData BundleData; + +struct _BundleData { + GFile *file; + GBytes *gpg_data; +}; + struct _FlatpakTransactionPrivate { GObject parent; @@ -90,6 +97,7 @@ struct _FlatpakTransactionPrivate { GPtrArray *added_origin_remotes; GList *flatpakrefs; /* GKeyFiles */ + GList *bundles; /* BundleData */ FlatpakTransactionOperation *current_op; @@ -136,6 +144,27 @@ enum { LAST_PROGRESS_SIGNAL }; +static BundleData * +bundle_data_new (GFile *file, + GBytes *gpg_data) +{ + BundleData *data = g_new0 (BundleData, 1); + + data->file = g_object_ref (file); + if (gpg_data) + data->gpg_data = g_object_ref (gpg_data); + + return data; +} + +static void +bundle_data_free (BundleData *data) +{ + g_clear_object (&data->file); + g_clear_object (&data->gpg_data); + g_free (data); +} + static guint progress_signals[LAST_SIGNAL] = { 0 }; G_DEFINE_TYPE (FlatpakTransactionProgress, flatpak_transaction_progress, G_TYPE_OBJECT) @@ -492,6 +521,7 @@ flatpak_transaction_finalize (GObject *object) g_clear_object (&priv->installation); g_list_free_full (priv->flatpakrefs, (GDestroyNotify)g_key_file_unref); + g_list_free_full (priv->bundles, (GDestroyNotify)bundle_data_free); g_free (priv->default_arch); g_hash_table_unref (priv->last_op_for_ref); g_hash_table_unref (priv->remote_states); @@ -1342,22 +1372,10 @@ flatpak_transaction_add_install_bundle (FlatpakTransaction *self, GError **error) { FlatpakTransactionPrivate *priv = flatpak_transaction_get_instance_private (self); - g_autofree char *remote = NULL; - g_autofree char *ref = NULL; - g_autofree char *commit = NULL; - g_autofree char *metadata = NULL; - gboolean created_remote; - remote = flatpak_dir_ensure_bundle_remote (priv->dir, file, gpg_data, - &ref, &commit, &metadata, &created_remote, - NULL, error); - if (remote == NULL) - return FALSE; + priv->bundles = g_list_append (priv->flatpakrefs, bundle_data_new (file, gpg_data)); - if (!flatpak_dir_recreate_repo (priv->dir, NULL, error)) - return FALSE; - - return flatpak_transaction_add_ref (self, remote, ref, NULL, commit, FLATPAK_TRANSACTION_OPERATION_INSTALL_BUNDLE, file, metadata, error); + return TRUE; } gboolean @@ -2071,6 +2089,78 @@ flatpak_transaction_resolve_flatpakrefs (FlatpakTransaction *self, return TRUE; } +static gboolean +handle_runtime_repo_deps_from_bundle (FlatpakTransaction *self, + GFile *file, + GError **error) +{ + FlatpakTransactionPrivate *priv = flatpak_transaction_get_instance_private (self); + g_autofree char *dep_url = NULL; + g_autofree char *ref = NULL; + g_auto(GStrv) ref_parts = NULL; + g_autoptr(GVariant) metadata = NULL; + + if (priv->disable_deps) + return TRUE; + + metadata = flatpak_bundle_load (file, NULL, + NULL, + &ref, + &dep_url, + NULL, + NULL, + NULL, + NULL, + NULL); + + if (metadata == NULL || dep_url == NULL || ref == NULL) + return TRUE; + + ref_parts = g_strsplit (ref, "/", -1); + + return handle_runtime_repo_deps (self, ref_parts[1], dep_url, error); +} + +static gboolean +flatpak_transaction_resolve_bundles (FlatpakTransaction *self, + GCancellable *cancellable, + GError **error) +{ + FlatpakTransactionPrivate *priv = flatpak_transaction_get_instance_private (self); + GList *l; + + for (l = priv->bundles; l != NULL; l = l->next) + { + BundleData *data = l->data; + g_autofree char *remote = NULL; + g_autofree char *ref = NULL; + g_autofree char *commit = NULL; + g_autofree char *metadata = NULL; + gboolean created_remote; + + if (!handle_runtime_repo_deps_from_bundle (self, data->file, error)) + return FALSE; + + if (!flatpak_dir_ensure_repo (priv->dir, cancellable, error)) + return FALSE; + + remote = flatpak_dir_ensure_bundle_remote (priv->dir, data->file, data->gpg_data, + &ref, &commit, &metadata, &created_remote, + NULL, error); + if (remote == NULL) + return FALSE; + + if (!flatpak_dir_recreate_repo (priv->dir, NULL, error)) + return FALSE; + + if (!flatpak_transaction_add_ref (self, remote, ref, NULL, commit, + FLATPAK_TRANSACTION_OPERATION_INSTALL_BUNDLE, data->file, metadata, error)) + return FALSE; + } + + return TRUE; +} + gboolean flatpak_transaction_run (FlatpakTransaction *self, GCancellable *cancellable, @@ -2097,6 +2187,9 @@ flatpak_transaction_run (FlatpakTransaction *self, if (!flatpak_transaction_resolve_flatpakrefs (self, cancellable, error)) return FALSE; + if (!flatpak_transaction_resolve_bundles (self, cancellable, error)) + return FALSE; + /* Resolve initial ops */ if (!resolve_ops (self, cancellable, error)) return FALSE;