diff --git a/app/flatpak-builtins-install.c b/app/flatpak-builtins-install.c index 0fb8f201..fcc18244 100644 --- a/app/flatpak-builtins-install.c +++ b/app/flatpak-builtins-install.c @@ -155,6 +155,8 @@ handle_runtime_repo_deps (FlatpakDir *dir, const char *dep_url, GError **error) 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; @@ -168,6 +170,12 @@ handle_runtime_repo_deps (FlatpakDir *dir, const char *dep_url, GError **error) 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 */ @@ -190,7 +198,7 @@ handle_runtime_repo_deps (FlatpakDir *dir, const char *dep_url, GError **error) } while (remotes != NULL && g_strv_contains ((const char * const*)remotes, new_remote)); - config = flatpak_dir_parse_repofile (dir, new_remote, FALSE, dep_data, &gpg_key, NULL, error); + 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); @@ -305,81 +313,6 @@ install_bundle (FlatpakDir *dir, return TRUE; } -static gboolean -handle_suggested_remote_name (FlatpakDir *dir, GBytes *data, GError **error) -{ - g_autoptr(GKeyFile) keyfile = g_key_file_new (); - g_autofree char *suggested_name = NULL; - g_autofree char *url = NULL; - g_autofree char *collection_id = NULL; - g_autoptr(GKeyFile) config = NULL; - g_autoptr(GBytes) gpg_key = NULL; - - if (!g_key_file_load_from_data (keyfile, g_bytes_get_data (data, NULL), g_bytes_get_size (data), - 0, error)) - return FALSE; - - suggested_name = g_key_file_get_string (keyfile, FLATPAK_REF_GROUP, - FLATPAK_REF_SUGGEST_REMOTE_NAME_KEY, NULL); - if (suggested_name == NULL) - return TRUE; - - url = g_key_file_get_string (keyfile, FLATPAK_REF_GROUP, - FLATPAK_REF_URL_KEY, NULL); - if (url == NULL) - return TRUE; - - collection_id = g_key_file_get_string (keyfile, FLATPAK_REF_GROUP, FLATPAK_REF_COLLECTION_ID_KEY, NULL); - - if (remote_is_already_configured (dir, url, collection_id)) - return TRUE; - - /* The name is already used, ignore */ - if (ostree_repo_remote_get_url (flatpak_dir_get_repo (dir), suggested_name, NULL, NULL)) - return TRUE; - - if (opt_yes || - flatpak_yes_no_prompt (_("The remote '%s', at location %s contains additional applications.\nShould the remote be kept for future installations?"), - suggested_name, url)) - { - if (opt_yes) - g_print (_("Configuring %s as new remote '%s'"), url, suggested_name); - - config = flatpak_dir_parse_repofile (dir, suggested_name, TRUE, data, &gpg_key, NULL, error); - if (config == NULL) - return FALSE; - - if (!flatpak_dir_modify_remote (dir, suggested_name, 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_keyfile (FlatpakDir *dir, GBytes *data, GError **error) -{ - g_autoptr(GKeyFile) keyfile = g_key_file_new (); - g_autofree char *dep_url = NULL; - - if (opt_no_deps) - return TRUE; - - if (!g_key_file_load_from_data (keyfile, g_bytes_get_data (data, NULL), g_bytes_get_size (data), - 0, error)) - return FALSE; - - dep_url = g_key_file_get_string (keyfile, FLATPAK_REF_GROUP, - FLATPAK_REF_RUNTIME_REPO_KEY, NULL); - if (dep_url == NULL) - return TRUE; - - return handle_runtime_repo_deps (dir, dep_url, error); -} - static gboolean install_from (FlatpakDir *dir, GOptionContext *context, @@ -392,10 +325,6 @@ install_from (FlatpakDir *dir, g_autofree char *data = NULL; gsize data_len; const char *filename; - g_autofree char *remote = NULL; - g_autofree char *ref = NULL; - const char *slash; - FlatpakDir *clone; g_autoptr(FlatpakTransaction) transaction = NULL; if (argc < 2) @@ -427,25 +356,7 @@ install_from (FlatpakDir *dir, file_data = g_bytes_new_take (g_steal_pointer (&data), data_len); } - /* Handle this before the runtime deps, because they might be the same */ - if (!handle_suggested_remote_name (dir, file_data, error)) - return FALSE; - - if (!handle_runtime_repo_deps_from_keyfile (dir, file_data, error)) - return FALSE; - - if (!flatpak_dir_create_remote_for_ref_file (dir, file_data, opt_arch, &remote, NULL, &ref, error)) - return FALSE; - - /* Need to pick up the new config, in case it was applied in the system helper. */ - clone = flatpak_dir_clone (dir); - if (!flatpak_dir_ensure_repo (clone, cancellable, error)) - return FALSE; - - slash = strchr (ref, '/'); - g_print (_("Installing: %s\n"), slash + 1); - - transaction = flatpak_cli_transaction_new (clone, opt_yes, TRUE, error); + transaction = flatpak_cli_transaction_new (dir, opt_yes, TRUE, error); if (transaction == NULL) return FALSE; @@ -455,8 +366,9 @@ install_from (FlatpakDir *dir, flatpak_transaction_set_disable_dependencies (transaction, opt_no_deps); flatpak_transaction_set_disable_related (transaction, opt_no_related); flatpak_transaction_set_reinstall (transaction, opt_reinstall); + flatpak_transaction_set_default_arch (transaction, opt_arch); - if (!flatpak_cli_transaction_add_install (transaction, remote, ref, (const char **)opt_subpaths, error)) + if (!flatpak_transaction_add_install_flatpakref (transaction, file_data, error)) return FALSE; if (!flatpak_cli_transaction_run (transaction, cancellable, error)) diff --git a/app/flatpak-cli-transaction.c b/app/flatpak-cli-transaction.c index 9e233c80..811665bb 100644 --- a/app/flatpak-cli-transaction.c +++ b/app/flatpak-cli-transaction.c @@ -94,6 +94,39 @@ choose_remote_for_ref (FlatpakTransaction *transaction, return chosen; } +static gboolean +add_new_remote (FlatpakTransaction *transaction, + FlatpakTransactionRemoteReason reason, + const char *from_id, + const char *remote_name, + const char *url) +{ + FlatpakCliTransaction *self = FLATPAK_CLI_TRANSACTION (transaction); + + if (self->disable_interaction) + { + g_print (_("Configuring %s as new remote '%s'"), url, remote_name); + return TRUE; + } + + if (reason == FLATPAK_TRANSACTION_REMOTE_GENERIC_REPO) + { + if (flatpak_yes_no_prompt (_("The remote '%s', refered to by '%s' at location %s contains additional applications.\n" + "Should the remote be kept for future installations?"), + remote_name, from_id, url)) + return TRUE; + } + else if (reason == FLATPAK_TRANSACTION_REMOTE_RUNTIME_DEPS) + { + if (flatpak_yes_no_prompt (_("The application %s depends on runtimes from:\n %s\n" + "Configure this as new remote '%s'"), + from_id, url, remote_name)) + return TRUE; + } + + return FALSE; +} + static char * op_type_to_string (FlatpakTransactionOperationType operation_type) { @@ -602,6 +635,7 @@ flatpak_cli_transaction_class_init (FlatpakCliTransactionClass *klass) FlatpakTransactionClass *transaction_class = FLATPAK_TRANSACTION_CLASS (klass); object_class->finalize = flatpak_cli_transaction_finalize; + transaction_class->add_new_remote = add_new_remote; transaction_class->ready = transaction_ready; transaction_class->new_operation = new_operation; transaction_class->operation_done = operation_done; diff --git a/common/flatpak-dir-private.h b/common/flatpak-dir-private.h index b096329e..cd82305a 100644 --- a/common/flatpak-dir-private.h +++ b/common/flatpak-dir-private.h @@ -615,7 +615,7 @@ char *flatpak_dir_create_origin_remote (FlatpakDir *self, void flatpak_dir_prune_origin_remote (FlatpakDir *self, const char *remote); gboolean flatpak_dir_create_remote_for_ref_file (FlatpakDir *self, - GBytes *data, + GKeyFile *keyfile, const char *default_arch, char **remote_name_out, char **collection_id_out, @@ -627,7 +627,7 @@ gboolean flatpak_dir_create_suggested_remote_for_ref_file (FlatpakDir *self, GKeyFile * flatpak_dir_parse_repofile (FlatpakDir *self, const char *remote_name, gboolean from_ref, - GBytes *data, + GKeyFile *keyfile, GBytes **gpg_data_out, GCancellable *cancellable, GError **error); diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c index 78ff663f..59ff8e7a 100644 --- a/common/flatpak-dir.c +++ b/common/flatpak-dir.c @@ -10072,13 +10072,11 @@ GKeyFile * flatpak_dir_parse_repofile (FlatpakDir *self, const char *remote_name, gboolean from_ref, - GBytes *data, + GKeyFile *keyfile, GBytes **gpg_data_out, GCancellable *cancellable, GError **error) { - g_autoptr(GKeyFile) keyfile = g_key_file_new (); - g_autoptr(GError) local_error = NULL; g_autoptr(GBytes) gpg_data = NULL; g_autofree char *uri = NULL; g_autofree char *title = NULL; @@ -10096,15 +10094,6 @@ flatpak_dir_parse_repofile (FlatpakDir *self, GKeyFile *config = g_key_file_new (); g_autofree char *group = g_strdup_printf ("remote \"%s\"", remote_name); - if (!g_key_file_load_from_data (keyfile, - g_bytes_get_data (data, NULL), - g_bytes_get_size (data), - 0, &local_error)) - { - flatpak_fail (error, "Invalid .flatpakref: %s", local_error->message); - return NULL; - } - if (!g_key_file_has_group (keyfile, source_group)) { flatpak_fail (error, "Invalid .flatpakref"); @@ -10179,7 +10168,7 @@ flatpak_dir_parse_repofile (FlatpakDir *self, } static gboolean -parse_ref_file (GBytes *data, +parse_ref_file (GKeyFile *keyfile, char **name_out, char **branch_out, char **url_out, @@ -10189,7 +10178,6 @@ parse_ref_file (GBytes *data, char **collection_id_out, GError **error) { - g_autoptr(GKeyFile) keyfile = g_key_file_new (); g_autofree char *url = NULL; g_autofree char *title = NULL; g_autofree char *name = NULL; @@ -10207,10 +10195,6 @@ parse_ref_file (GBytes *data, *gpg_data_out = NULL; *is_runtime_out = FALSE; - if (!g_key_file_load_from_data (keyfile, g_bytes_get_data (data, NULL), g_bytes_get_size (data), - 0, error)) - return FALSE; - if (!g_key_file_has_group (keyfile, FLATPAK_REF_GROUP)) return flatpak_fail (error, "Invalid file format, no %s group", FLATPAK_REF_GROUP); @@ -10273,7 +10257,7 @@ parse_ref_file (GBytes *data, gboolean flatpak_dir_create_remote_for_ref_file (FlatpakDir *self, - GBytes *data, + GKeyFile *keyfile, const char *default_arch, char **remote_name_out, char **collection_id_out, @@ -10291,7 +10275,7 @@ flatpak_dir_create_remote_for_ref_file (FlatpakDir *self, g_autofree char *collection_id = NULL; g_autoptr(GFile) deploy_dir = NULL; - if (!parse_ref_file (data, &name, &branch, &url, &title, &gpg_data, &is_runtime, &collection_id, error)) + if (!parse_ref_file (keyfile, &name, &branch, &url, &title, &gpg_data, &is_runtime, &collection_id, error)) return FALSE; ref = flatpak_compose_ref (!is_runtime, name, branch, default_arch, error); diff --git a/common/flatpak-installation.c b/common/flatpak-installation.c index cb750338..7c545893 100644 --- a/common/flatpak-installation.c +++ b/common/flatpak-installation.c @@ -1638,12 +1638,19 @@ flatpak_installation_install_ref_file (FlatpakInstallation *self, g_autofree char *ref = NULL; g_autofree char *collection_id = NULL; g_autoptr(FlatpakCollectionRef) coll_ref = NULL; + g_autoptr(GKeyFile) keyfile = g_key_file_new (); dir = flatpak_installation_get_dir (self, error); if (dir == NULL) return NULL; - if (!flatpak_dir_create_remote_for_ref_file (dir, ref_file_data, NULL, &remote, &collection_id, &ref, error)) + if (!g_key_file_load_from_data (keyfile, g_bytes_get_data (ref_file_data, NULL), + g_bytes_get_size (ref_file_data), + 0, error)) + return FALSE; + + + if (!flatpak_dir_create_remote_for_ref_file (dir, keyfile, NULL, &remote, &collection_id, &ref, error)) return NULL; if (!flatpak_installation_drop_caches (self, cancellable, error)) diff --git a/common/flatpak-transaction.c b/common/flatpak-transaction.c index 803cae77..abd72712 100644 --- a/common/flatpak-transaction.c +++ b/common/flatpak-transaction.c @@ -22,6 +22,7 @@ #include #include +#include #include "flatpak-transaction-private.h" #include "flatpak-installation-private.h" @@ -88,6 +89,8 @@ struct _FlatpakTransactionPrivate { GList *ops; GPtrArray *added_origin_remotes; + GList *flatpakrefs; /* GKeyFiles */ + FlatpakTransactionOperation *current_op; gboolean no_pull; @@ -108,6 +111,7 @@ enum { CHOOSE_REMOTE_FOR_REF, END_OF_LIFED, READY, + ADD_NEW_REMOTE, LAST_SIGNAL }; @@ -487,6 +491,7 @@ flatpak_transaction_finalize (GObject *object) g_clear_object (&priv->installation); + g_list_free_full (priv->flatpakrefs, (GDestroyNotify)g_key_file_unref); g_free (priv->default_arch); g_hash_table_unref (priv->last_op_for_ref); g_hash_table_unref (priv->remote_states); @@ -565,12 +570,23 @@ flatpak_transaction_ready (FlatpakTransaction *transaction) return TRUE; } +static gboolean +flatpak_transaction_add_new_remote (FlatpakTransaction *transaction, + FlatpakTransactionRemoteReason reason, + const char *from_id, + const char *suggested_remote_name, + const char *url) +{ + return FALSE; +} + static void flatpak_transaction_class_init (FlatpakTransactionClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); klass->ready = flatpak_transaction_ready; + klass->add_new_remote = flatpak_transaction_add_new_remote; object_class->finalize = flatpak_transaction_finalize; object_class->get_property = flatpak_transaction_get_property; object_class->set_property = flatpak_transaction_set_property; @@ -689,6 +705,26 @@ flatpak_transaction_class_init (FlatpakTransactionClass *klass) signal_accumulator_false_abort, NULL, NULL, G_TYPE_BOOLEAN, 0); + /** + * FlatpakTransaction::add-new-remote: + * @object: A #FlatpakTransaction + * @reason: The reason for the new remote is needed + * @from_id: The id of the app/runtime + * @suggested_remote_name: The suggested remote name + * @url: The repo url + * + * As part of the transaction, it is required or recommended + * that a new remote is added, for the reason described in @reason. + * Return %TRUE to add it. + */ + signals[ADD_NEW_REMOTE] = + g_signal_new ("add-new-remote", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (FlatpakTransactionClass, add_new_remote), + g_signal_accumulator_first_wins, NULL, + NULL, + G_TYPE_BOOLEAN, 4, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); } static void @@ -1324,6 +1360,25 @@ flatpak_transaction_add_install_bundle (FlatpakTransaction *self, return flatpak_transaction_add_ref (self, remote, ref, NULL, commit, FLATPAK_TRANSACTION_OPERATION_INSTALL_BUNDLE, file, metadata, error); } +gboolean +flatpak_transaction_add_install_flatpakref (FlatpakTransaction *self, + GBytes *flatpakref_data, + GError **error) +{ + FlatpakTransactionPrivate *priv = flatpak_transaction_get_instance_private (self); + g_autoptr(GKeyFile) keyfile = g_key_file_new (); + g_autoptr(GError) local_error = NULL; + + if (!g_key_file_load_from_data (keyfile, g_bytes_get_data (flatpakref_data, NULL), + g_bytes_get_size (flatpakref_data), + 0, error)) + return flatpak_fail (error, "Invalid .flatpakref: %s", local_error->message); + + priv->flatpakrefs = g_list_append (priv->flatpakrefs, g_steal_pointer (&keyfile)); + + return TRUE; +} + gboolean flatpak_transaction_add_update (FlatpakTransaction *self, const char *ref, @@ -1760,6 +1815,262 @@ flatpak_transaction_get_installation (FlatpakTransaction *self) return g_object_ref (priv->installation); } + +static GBytes * +download_uri (const char *url, + GError **error) +{ + g_autoptr(SoupSession) session = NULL; + g_autoptr(SoupRequest) req = NULL; + g_autoptr(GInputStream) input = NULL; + g_autoptr(GOutputStream) out = NULL; + + session = flatpak_create_soup_session (PACKAGE_STRING); + + req = soup_session_request (session, url, error); + if (req == NULL) + return NULL; + + input = soup_request_send (req, NULL, error); + if (input == NULL) + return NULL; + + out = g_memory_output_stream_new_resizable (); + if (!g_output_stream_splice (out, + input, + G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET | G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE, + NULL, + error)) + return NULL; + + return g_memory_output_stream_steal_as_bytes (G_MEMORY_OUTPUT_STREAM (out)); +} + +static gboolean +remote_is_already_configured (FlatpakTransaction *self, + const char *url, + const char *collection_id) +{ + FlatpakTransactionPrivate *priv = flatpak_transaction_get_instance_private (self); + g_autofree char *old_remote = NULL; + int i; + + old_remote = flatpak_dir_find_remote_by_uri (priv->dir, url, collection_id); + if (old_remote == NULL) + { + for (i = 0; i < priv->extra_dependency_dirs->len; i++) + { + FlatpakDir *dependency_dir = g_ptr_array_index (priv->extra_dependency_dirs, i); + + old_remote = flatpak_dir_find_remote_by_uri (dependency_dir, url, collection_id); + if (old_remote != NULL) + break; + } + } + + return old_remote != NULL; +} + +static gboolean +handle_suggested_remote_name (FlatpakTransaction *self, GKeyFile *keyfile, GError **error) +{ + FlatpakTransactionPrivate *priv = flatpak_transaction_get_instance_private (self); + g_autofree char *suggested_name = NULL; + g_autofree char *name = NULL; + g_autofree char *url = NULL; + g_autofree char *collection_id = NULL; + g_autoptr(GKeyFile) config = NULL; + g_autoptr(GBytes) gpg_key = NULL; + gboolean res; + + suggested_name = g_key_file_get_string (keyfile, FLATPAK_REF_GROUP, + FLATPAK_REF_SUGGEST_REMOTE_NAME_KEY, NULL); + if (suggested_name == NULL) + return TRUE; + + name = g_key_file_get_string (keyfile, FLATPAK_REF_GROUP, FLATPAK_REF_NAME_KEY, NULL); + if (name == NULL) + return TRUE; + + url = g_key_file_get_string (keyfile, FLATPAK_REF_GROUP, FLATPAK_REF_URL_KEY, NULL); + if (url == NULL) + return TRUE; + + collection_id = g_key_file_get_string (keyfile, FLATPAK_REF_GROUP, FLATPAK_REF_COLLECTION_ID_KEY, NULL); + + if (remote_is_already_configured (self, url, collection_id)) + return TRUE; + + /* The name is already used, ignore */ + if (ostree_repo_remote_get_url (flatpak_dir_get_repo (priv->dir), suggested_name, NULL, NULL)) + return TRUE; + + res = FALSE; + g_signal_emit (self, signals[ADD_NEW_REMOTE], 0, FLATPAK_TRANSACTION_REMOTE_GENERIC_REPO, + name, suggested_name, url, &res); + if (res) + { + config = flatpak_dir_parse_repofile (priv->dir, suggested_name, TRUE, keyfile, &gpg_key, NULL, error); + if (config == NULL) + return FALSE; + + if (!flatpak_dir_modify_remote (priv->dir, suggested_name, config, gpg_key, NULL, error)) + return FALSE; + + if (!flatpak_dir_recreate_repo (priv->dir, NULL, error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +handle_runtime_repo_deps (FlatpakTransaction *self, const char *id, const char *dep_url, GError **error) +{ + FlatpakTransactionPrivate *priv = flatpak_transaction_get_instance_private (self); + 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(GKeyFile) dep_keyfile = g_key_file_new (); + g_autoptr(GBytes) gpg_key = NULL; + g_autofree char *group = NULL; + g_autoptr(GError) local_error = NULL; + g_autofree char *runtime_collection_id = NULL; + char *t; + int i; + gboolean res; + + if (priv->disable_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 (priv->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 (priv->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 (self, runtime_url, runtime_collection_id)) + return TRUE; + + res = FALSE; + g_signal_emit (self, signals[ADD_NEW_REMOTE], 0, FLATPAK_TRANSACTION_REMOTE_RUNTIME_DEPS, + id, new_remote, runtime_url, &res); + if (res) + { + if (!flatpak_dir_modify_remote (priv->dir, new_remote, config, gpg_key, NULL, error)) + return FALSE; + + if (!flatpak_dir_recreate_repo (priv->dir, NULL, error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +handle_runtime_repo_deps_from_keyfile (FlatpakTransaction *self, GKeyFile *keyfile, GError **error) +{ + FlatpakTransactionPrivate *priv = flatpak_transaction_get_instance_private (self); + g_autofree char *dep_url = NULL; + g_autofree char *name = NULL; + + if (priv->disable_deps) + return TRUE; + + dep_url = g_key_file_get_string (keyfile, FLATPAK_REF_GROUP, + FLATPAK_REF_RUNTIME_REPO_KEY, NULL); + if (dep_url == NULL) + return TRUE; + + name = g_key_file_get_string (keyfile, FLATPAK_REF_GROUP, FLATPAK_REF_NAME_KEY, NULL); + if (name == NULL) + return TRUE; + + return handle_runtime_repo_deps (self, name, dep_url, error); +} + +static gboolean +flatpak_transaction_resolve_flatpakrefs (FlatpakTransaction *self, + GCancellable *cancellable, + GError **error) +{ + FlatpakTransactionPrivate *priv = flatpak_transaction_get_instance_private (self); + GList *l; + + for (l = priv->flatpakrefs; l != NULL; l = l->next) + { + GKeyFile *flatpakref = l->data; + g_autofree char *remote = NULL; + g_autofree char *ref = NULL; + + /* Handle this before the runtime deps, because they might be the same */ + if (!handle_suggested_remote_name (self, flatpakref, error)) + return FALSE; + + if (!handle_runtime_repo_deps_from_keyfile (self, flatpakref, error)) + return FALSE; + + if (!flatpak_dir_create_remote_for_ref_file (priv->dir, flatpakref, priv->default_arch, + &remote, NULL, &ref, error)) + return FALSE; + + /* Need to pick up the new config, in case it was applied in the system helper. */ + if (!flatpak_dir_recreate_repo (priv->dir, NULL, error)) + return FALSE; + + if (!flatpak_transaction_add_install (self, remote, ref, NULL, error)) + return FALSE; + } + + return TRUE; +} + gboolean flatpak_transaction_run (FlatpakTransaction *self, GCancellable *cancellable, @@ -1783,6 +2094,9 @@ flatpak_transaction_run (FlatpakTransaction *self, /* Work around ostree-pull spinning the default main context for the sync calls */ main_context = flatpak_main_context_new_default (); + if (!flatpak_transaction_resolve_flatpakrefs (self, cancellable, error)) + return FALSE; + /* Resolve initial ops */ if (!resolve_ops (self, cancellable, error)) return FALSE; diff --git a/common/flatpak-transaction.h b/common/flatpak-transaction.h index 45a59784..f2185b38 100644 --- a/common/flatpak-transaction.h +++ b/common/flatpak-transaction.h @@ -68,6 +68,16 @@ typedef enum { FLATPAK_TRANSACTION_RESULT_NO_CHANGE = 1 << 0, } FlatpakTransactionResult; +/** + * FlatpakTransactionRemoteReason + * @FLATPAK_TRANSACTION_REMOTE_GENERIC_REPO: The remote specified in the flatpakref has other apps too + * @FLATPAK_TRANSACTION_REMOTE_RUNTIME_DEPS: The remote has runtimes needed for the app + */ +typedef enum { + FLATPAK_TRANSACTION_REMOTE_GENERIC_REPO, + FLATPAK_TRANSACTION_REMOTE_RUNTIME_DEPS, +} FlatpakTransactionRemoteReason; + FLATPAK_EXTERN G_DECLARE_FINAL_TYPE (FlatpakTransactionProgress, flatpak_transaction_progress, FLATPAK, TRANSACTION_PROGRESS, GObject) @@ -101,7 +111,12 @@ struct _FlatpakTransactionClass const char *rebase); gboolean (*ready) (FlatpakTransaction *transaction); - gpointer padding[11]; + gboolean (*add_new_remote) (FlatpakTransaction *transaction, + FlatpakTransactionRemoteReason reason, + const char *from_id, + const char *remote_name, + const char *url); + gpointer padding[10]; }; FLATPAK_EXTERN @@ -190,6 +205,10 @@ gboolean flatpak_transaction_add_install_bundle (FlatpakTransa GBytes *gpg_data, GError **error); FLATPAK_EXTERN +gboolean flatpak_transaction_add_install_flatpakref (FlatpakTransaction *self, + GBytes *flatpakref_data, + GError **error); +FLATPAK_EXTERN gboolean flatpak_transaction_add_update (FlatpakTransaction *self, const char *ref, const char **subpaths, diff --git a/doc/reference/flatpak-sections.txt b/doc/reference/flatpak-sections.txt index cae4050e..2c848d73 100644 --- a/doc/reference/flatpak-sections.txt +++ b/doc/reference/flatpak-sections.txt @@ -238,6 +238,7 @@ flatpak_transaction_set_no_pull flatpak_transaction_set_reinstall flatpak_transaction_set_force_uninstall flatpak_transaction_set_default_arch +flatpak_transaction_add_install_flatpakref FlatpakTransactionClass FLATPAK_IS_TRANSACTION