diff --git a/app/flatpak-builtins-add-remote.c b/app/flatpak-builtins-add-remote.c index 9f687304..3d823818 100644 --- a/app/flatpak-builtins-add-remote.c +++ b/app/flatpak-builtins-add-remote.c @@ -47,6 +47,7 @@ static gboolean opt_do_enumerate; static gboolean opt_no_enumerate; static gboolean opt_if_not_exists; static gboolean opt_enable; +static gboolean opt_update_metadata; static gboolean opt_disable; static int opt_prio = -1; static char *opt_title; @@ -67,6 +68,7 @@ static GOptionEntry modify_options[] = { { "enumerate", 0, 0, G_OPTION_ARG_NONE, &opt_do_enumerate, N_("Mark the remote as enumerate"), NULL }, { "url", 0, 0, G_OPTION_ARG_STRING, &opt_url, N_("Set a new url"), N_("URL") }, { "enable", 0, 0, G_OPTION_ARG_NONE, &opt_enable, N_("Enable the remote"), NULL }, + { "update-metadata", 0, 0, G_OPTION_ARG_NONE, &opt_update_metadata, N_("Update extra metadata from the summary file"), NULL }, { NULL } }; @@ -259,6 +261,46 @@ load_options (char *filename, } } +static gboolean +update_remote_with_extra_metadata (FlatpakDir* dir, + const char *remote, + GBytes *gpg_data, + GCancellable *cancellable, + GError **error) +{ + g_autofree char *title = NULL; + g_autofree char *default_branch = NULL; + g_autoptr(GKeyFile) config = NULL; + + if (opt_title == NULL) + { + title = flatpak_dir_fetch_remote_title (dir, + remote, + NULL, + NULL); + if (title) + opt_title = title; + } + + if (opt_default_branch == NULL) + { + default_branch = flatpak_dir_fetch_remote_default_branch (dir, + remote, + NULL, + NULL); + if (default_branch) + opt_default_branch = default_branch; + } + + if (title != NULL || default_branch != NULL) + { + config = get_config_from_opts (dir, remote); + return flatpak_dir_modify_remote (dir, remote, config, gpg_data, cancellable, error); + } + + return TRUE; +} + gboolean flatpak_builtin_add_remote (int argc, char **argv, GCancellable *cancellable, GError **error) @@ -267,7 +309,6 @@ flatpak_builtin_add_remote (int argc, char **argv, g_autoptr(FlatpakDir) dir = NULL; g_autoptr(GFile) file = NULL; g_auto(GStrv) remotes = NULL; - g_autofree char *title = NULL; g_autofree char *remote_url = NULL; const char *remote_name; const char *url_or_path = NULL; @@ -323,17 +364,6 @@ flatpak_builtin_add_remote (int argc, char **argv, if (!opt_no_gpg_verify) opt_do_gpg_verify = TRUE; - - if (opt_title == NULL) - { - title = flatpak_dir_fetch_remote_title (dir, - remote_name, - NULL, - NULL); - if (title) - opt_title = title; - } - config = get_config_from_opts (dir, remote_name); if (opt_gpg_import != NULL) @@ -343,7 +373,12 @@ flatpak_builtin_add_remote (int argc, char **argv, return FALSE; } - return flatpak_dir_modify_remote (dir, remote_name, config, gpg_data, cancellable, error); + if (!flatpak_dir_modify_remote (dir, remote_name, config, gpg_data, cancellable, error)) + return FALSE; + + /* We can't retrieve the extra metadata until the remote has been added locally, since + ostree_repo_remote_fetch_summary() works with the repository's name, not its URL. */ + return update_remote_with_extra_metadata (dir, remote_name, gpg_data, cancellable, error); } gboolean @@ -397,6 +432,18 @@ flatpak_builtin_modify_remote (int argc, char **argv, GCancellable *cancellable, if (!ostree_repo_remote_get_url (flatpak_dir_get_repo (dir), remote_name, NULL, NULL)) return flatpak_fail (error, _("No remote %s"), remote_name); + if (opt_update_metadata) + { + g_autoptr(GError) local_error = NULL; + + g_print (_("Updating extra metadata from remote summary for %s\n"), remote_name); + if (!flatpak_dir_update_remote_configuration (dir, remote_name, cancellable, &local_error)) + { + g_printerr (_("Error updating extra metadata for '%s': %s\n"), remote_name, local_error->message); + return flatpak_fail (error, _("Could not update extra metadata for %s"), remote_name); + } + } + config = get_config_from_opts (dir, remote_name); if (opt_gpg_import != NULL) diff --git a/app/flatpak-builtins-install.c b/app/flatpak-builtins-install.c index 89a0bd26..ce559bca 100644 --- a/app/flatpak-builtins-install.c +++ b/app/flatpak-builtins-install.c @@ -293,7 +293,7 @@ flatpak_builtin_install (int argc, char **argv, GCancellable *cancellable, GErro const char *repository; char **prefs = NULL; int i, n_prefs; - const char *default_branch = NULL; + g_autofree char *default_branch = NULL; FlatpakKinds kinds; g_autoptr(GPtrArray) refs = NULL; @@ -322,7 +322,7 @@ flatpak_builtin_install (int argc, char **argv, GCancellable *cancellable, GErro /* Backwards compat for old "REPOSITORY NAME [BRANCH]" argument version */ if (argc == 4 && looks_like_branch (argv[3])) { - default_branch = argv[3]; + default_branch = g_strdup (argv[3]); n_prefs = 1; } @@ -343,7 +343,8 @@ flatpak_builtin_install (int argc, char **argv, GCancellable *cancellable, GErro &matched_kinds, &id, &arch, &branch, error)) return FALSE; - ref = flatpak_dir_find_remote_ref (dir, repository, id, branch, arch, + default_branch = flatpak_dir_get_remote_default_branch (dir, repository); + ref = flatpak_dir_find_remote_ref (dir, repository, id, branch, default_branch, arch, matched_kinds, &kind, cancellable, error); if (ref == NULL) return FALSE; diff --git a/app/flatpak-builtins-repo-update.c b/app/flatpak-builtins-repo-update.c index 25c7886e..e5656326 100644 --- a/app/flatpak-builtins-repo-update.c +++ b/app/flatpak-builtins-repo-update.c @@ -33,6 +33,7 @@ #include "flatpak-utils.h" static char *opt_title; +static char *opt_default_branch; static char *opt_gpg_homedir; static char **opt_gpg_key_ids; static gboolean opt_prune; @@ -41,6 +42,7 @@ static gint opt_prune_depth = -1; static GOptionEntry options[] = { { "title", 0, 0, G_OPTION_ARG_STRING, &opt_title, N_("A nice name to use for this repository"), N_("TITLE") }, + { "default-branch", 0, 0, G_OPTION_ARG_STRING, &opt_default_branch, N_("Default branch to use for this repository"), N_("BRANCH") }, { "gpg-sign", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_gpg_key_ids, N_("GPG Key ID to sign the summary with"), N_("KEY-ID") }, { "gpg-homedir", 0, 0, G_OPTION_ARG_STRING, &opt_gpg_homedir, N_("GPG Homedir to use when looking for keyrings"), N_("HOMEDIR") }, { "generate-static-deltas", 0, 0, G_OPTION_ARG_NONE, &opt_generate_deltas, N_("Generate delta files"), NULL }, @@ -376,6 +378,10 @@ flatpak_builtin_build_update_repo (int argc, char **argv, !flatpak_repo_set_title (repo, opt_title, error)) return FALSE; + if (opt_default_branch && + !flatpak_repo_set_default_branch (repo, opt_default_branch, error)) + return FALSE; + g_print (_("Updating appstream branch\n")); if (!flatpak_repo_generate_appstream (repo, (const char **) opt_gpg_key_ids, opt_gpg_homedir, cancellable, error)) return FALSE; diff --git a/common/flatpak-dir.c b/common/flatpak-dir.c index a1e3cadc..24f7bd46 100644 --- a/common/flatpak-dir.c +++ b/common/flatpak-dir.c @@ -4362,6 +4362,7 @@ static char * find_matching_ref (GHashTable *refs, const char *name, const char *opt_branch, + const char *opt_default_branch, const char *opt_arch, FlatpakKinds kinds, GError **error) @@ -4377,6 +4378,7 @@ find_matching_ref (GHashTable *refs, for (i = 0; arches[i] != NULL; i++) { g_autoptr(GPtrArray) matched_refs = NULL; + int j; matched_refs = find_matching_refs (refs, name, opt_branch, arches[i], kinds, error); @@ -4386,25 +4388,36 @@ find_matching_ref (GHashTable *refs, if (matched_refs->len == 0) continue; - if (matched_refs->len > 1) + if (matched_refs->len == 1) + return g_strdup (g_ptr_array_index (matched_refs, 0)); + + /* Multiple refs found, see if some belongs to the default branch, if passed */ + if (opt_default_branch != NULL) { - int i; - g_autoptr(GString) err = g_string_new (""); - g_string_printf (err, "Multiple branches available for %s, you must specify one of: ", name); - for (i = 0; i < matched_refs->len; i++) + for (j = 0; j < matched_refs->len; j++) { - g_auto(GStrv) parts = flatpak_decompose_ref (g_ptr_array_index (matched_refs, i), NULL); - if (i != 0) - g_string_append (err, ", "); + char *current_ref = g_ptr_array_index (matched_refs, j); + g_auto(GStrv) parts = flatpak_decompose_ref (current_ref, NULL); - g_string_append (err, parts[3]); + if (g_strcmp0 (opt_default_branch, parts[3]) == 0) + return g_strdup (current_ref); } - - flatpak_fail (error, err->str); - return NULL; } - return g_strdup (g_ptr_array_index (matched_refs, 0)); + /* Nothing to do other than reporting the different choices */ + g_autoptr(GString) err = g_string_new (""); + g_string_printf (err, "Multiple branches available for %s, you must specify one of: ", name); + for (j = 0; j < matched_refs->len; j++) + { + g_auto(GStrv) parts = flatpak_decompose_ref (g_ptr_array_index (matched_refs, j), NULL); + if (j != 0) + g_string_append (err, ", "); + + g_string_append (err, parts[3]); + } + + flatpak_fail (error, err->str); + return NULL; } g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, @@ -4446,6 +4459,7 @@ flatpak_dir_find_remote_ref (FlatpakDir *self, const char *remote, const char *name, const char *opt_branch, + const char *opt_default_branch, const char *opt_arch, FlatpakKinds kinds, FlatpakKinds *out_kind, @@ -4463,7 +4477,7 @@ flatpak_dir_find_remote_ref (FlatpakDir *self, &remote_refs, cancellable, error)) return NULL; - remote_ref = find_matching_ref (remote_refs, name, opt_branch, + remote_ref = find_matching_ref (remote_refs, name, opt_branch, opt_default_branch, opt_arch, kinds, &my_error); if (remote_ref == NULL) { @@ -4580,7 +4594,7 @@ flatpak_dir_find_installed_ref (FlatpakDir *self, if (local_refs == NULL) return NULL; - local_ref = find_matching_ref (local_refs, opt_name, opt_branch, + local_ref = find_matching_ref (local_refs, opt_name, opt_branch, NULL, opt_arch, kinds, &my_error); if (local_ref == NULL) { @@ -5211,18 +5225,14 @@ flatpak_dir_list_remote_refs (FlatpakDir *self, return TRUE; } -char * -flatpak_dir_fetch_remote_title (FlatpakDir *self, - const char *remote, - GCancellable *cancellable, - GError **error) +static GVariant * +fetch_remote_summary_file (FlatpakDir *self, + const char *remote, + GCancellable *cancellable, + GError **error) { g_autoptr(GError) my_error = NULL; g_autoptr(GBytes) summary_bytes = NULL; - g_autoptr(GVariant) summary = NULL; - g_autoptr(GVariant) extensions = NULL; - GVariantDict dict; - g_autofree char *title = NULL; if (error == NULL) error = &my_error; @@ -5233,17 +5243,35 @@ flatpak_dir_fetch_remote_title (FlatpakDir *self, if (!flatpak_dir_remote_fetch_summary (self, remote, &summary_bytes, cancellable, error)) - return FALSE; + return NULL; if (summary_bytes == NULL) { g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - _("Remote title not available; server has no summary file")); - return FALSE; + _("Remote extra metadata not available; server has no summary file")); + return NULL; } - summary = g_variant_ref_sink (g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT, - summary_bytes, FALSE)); + return g_variant_ref_sink (g_variant_new_from_bytes (OSTREE_SUMMARY_GVARIANT_FORMAT, + summary_bytes, FALSE)); +} + + +char * +flatpak_dir_fetch_remote_title (FlatpakDir *self, + const char *remote, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GVariant) summary = NULL; + g_autoptr(GVariant) extensions = NULL; + GVariantDict dict; + g_autofree char *title = NULL; + + summary = fetch_remote_summary_file (self, remote, cancellable, error); + if (summary == NULL) + return NULL; + extensions = g_variant_get_child_value (summary, 1); g_variant_dict_init (&dict, extensions); @@ -5260,6 +5288,115 @@ flatpak_dir_fetch_remote_title (FlatpakDir *self, return g_steal_pointer (&title); } +char * +flatpak_dir_fetch_remote_default_branch (FlatpakDir *self, + const char *remote, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(GVariant) summary = NULL; + g_autoptr(GVariant) extensions = NULL; + GVariantDict dict; + g_autofree char *default_branch = NULL; + + summary = fetch_remote_summary_file (self, remote, cancellable, error); + if (summary == NULL) + return NULL; + + extensions = g_variant_get_child_value (summary, 1); + + g_variant_dict_init (&dict, extensions); + g_variant_dict_lookup (&dict, "xa.default-branch", "s", &default_branch); + g_variant_dict_end (&dict); + + if (default_branch == NULL) + { + g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + _("Remote default-branch not set")); + return FALSE; + } + + return g_steal_pointer (&default_branch); +} + +gboolean +flatpak_dir_update_remote_configuration (FlatpakDir *self, + const char *remote, + GCancellable *cancellable, + GError **error) +{ + /* We only support those configuration parameters that can + be set in the server when building the repo (see the + flatpak_repo_set_* () family of functions) */ + static const char *const supported_params[] = { + "xa.title", + "xa.default-branch", NULL + }; + + g_autoptr(GVariant) summary = NULL; + g_autoptr(GVariant) extensions = NULL; + g_autoptr(GPtrArray) updated_params = g_ptr_array_new_with_free_func (g_free); + GVariantIter iter; + + summary = fetch_remote_summary_file (self, remote, cancellable, error); + if (summary == NULL) + return FALSE; + + extensions = g_variant_get_child_value (summary, 1); + + g_variant_iter_init (&iter, extensions); + if (g_variant_iter_n_children (&iter) > 0) + { + GVariant *value_var = NULL; + char *key = NULL; + + while (g_variant_iter_next (&iter, "{sv}", &key, &value_var)) + { + /* At the moment, every supported parameter are strings */ + if (g_strv_contains (supported_params, key) && + g_variant_get_type_string (value_var)) + { + const char *value = g_variant_get_string(value_var, NULL); + if (value != NULL && *value != 0) + { + g_ptr_array_add (updated_params, g_strdup (key)); + g_ptr_array_add (updated_params, g_strdup (value)); + } + } + + g_variant_unref (value_var); + g_free (key); + } + } + + if (updated_params->len > 0) + { + g_autoptr(GKeyFile) config = NULL; + g_autofree char *group = NULL; + int i; + + config = ostree_repo_copy_config (flatpak_dir_get_repo (self)); + group = g_strdup_printf ("remote \"%s\"", remote); + + i = 0; + while (i < (updated_params->len - 1)) + { + /* This array should have an even number of elements with + keys in the odd positions and values on even ones. */ + g_key_file_set_string (config, group, + g_ptr_array_index (updated_params, i), + g_ptr_array_index (updated_params, i+1)); + i += 2; + } + + /* Update the local remote configuration with the updated info. */ + if (!flatpak_dir_modify_remote (self, remote, config, NULL, cancellable, error)) + return FALSE; + } + + return TRUE; +} + static gboolean flatpak_dir_parse_summary_for_ref (FlatpakDir *self, GVariant *summary, diff --git a/common/flatpak-dir.h b/common/flatpak-dir.h index 9d74fcf4..273c0dd4 100644 --- a/common/flatpak-dir.h +++ b/common/flatpak-dir.h @@ -157,6 +157,7 @@ char * flatpak_dir_find_remote_ref (FlatpakDir *self, const char *remote, const char *name, const char *opt_branch, + const char *opt_default_branch, const char *opt_arch, FlatpakKinds kinds, FlatpakKinds *out_kind, @@ -424,6 +425,14 @@ char * flatpak_dir_fetch_remote_title (FlatpakDir *self, const char *remote, GCancellable *cancellable, GError **error); +char * flatpak_dir_fetch_remote_default_branch (FlatpakDir *self, + const char *remote, + GCancellable *cancellable, + GError **error); +gboolean flatpak_dir_update_remote_configuration (FlatpakDir *self, + const char *remote, + GCancellable *cancellable, + GError **error); gboolean flatpak_dir_fetch_ref_cache (FlatpakDir *self, const char *remote_name, const char *ref, diff --git a/common/flatpak-utils.c b/common/flatpak-utils.c index 5ef07e6f..30ed6b1c 100644 --- a/common/flatpak-utils.c +++ b/common/flatpak-utils.c @@ -2179,6 +2179,27 @@ flatpak_repo_set_title (OstreeRepo *repo, return TRUE; } + +gboolean +flatpak_repo_set_default_branch (OstreeRepo *repo, + const char *branch, + GError **error) +{ + g_autoptr(GKeyFile) config = NULL; + + config = ostree_repo_copy_config (repo); + + if (branch) + g_key_file_set_string (config, "flatpak", "default-branch", branch); + else + g_key_file_remove_key (config, "flatpak", "default-branch", NULL); + + if (!ostree_repo_write_config (repo, config, error)) + return FALSE; + + return TRUE; +} + #define OSTREE_GIO_FAST_QUERYINFO ("standard::name,standard::type,standard::size,standard::is-symlink,standard::symlink-target," \ "unix::device,unix::inode,unix::mode,unix::uid,unix::gid,unix::rdev") @@ -2299,6 +2320,7 @@ flatpak_repo_update (OstreeRepo *repo, GVariantBuilder ref_data_builder; GKeyFile *config; g_autofree char *title = NULL; + g_autofree char *default_branch = NULL; g_autoptr(GVariant) old_summary = NULL; g_autoptr(GHashTable) refs = NULL; const char *prefixes[] = { "appstream", "app", "runtime", NULL }; @@ -2312,12 +2334,18 @@ flatpak_repo_update (OstreeRepo *repo, config = ostree_repo_get_config (repo); if (config) - title = g_key_file_get_string (config, "flatpak", "title", NULL); + { + title = g_key_file_get_string (config, "flatpak", "title", NULL); + default_branch = g_key_file_get_string (config, "flatpak", "default-branch", NULL); + } if (title) g_variant_builder_add (&builder, "{sv}", "xa.title", g_variant_new_string (title)); + if (default_branch) + g_variant_builder_add (&builder, "{sv}", "xa.default-branch", + g_variant_new_string (default_branch)); g_variant_builder_init (&ref_data_builder, G_VARIANT_TYPE ("a{s(tts)}")); diff --git a/common/flatpak-utils.h b/common/flatpak-utils.h index 71006f0d..3b9bebe7 100644 --- a/common/flatpak-utils.h +++ b/common/flatpak-utils.h @@ -229,6 +229,9 @@ void flatpak_table_printer_print (FlatpakTablePrinter *printer); gboolean flatpak_repo_set_title (OstreeRepo *repo, const char *title, GError **error); +gboolean flatpak_repo_set_default_branch (OstreeRepo *repo, + const char *branch, + GError **error); gboolean flatpak_repo_update (OstreeRepo *repo, const char **gpg_key_ids, const char *gpg_homedir, diff --git a/doc/flatpak-remote-modify.xml b/doc/flatpak-remote-modify.xml index a2743389..92c162af 100644 --- a/doc/flatpak-remote-modify.xml +++ b/doc/flatpak-remote-modify.xml @@ -158,6 +158,18 @@ + + + + + A default branch to for the remote, mainly for use in a UI. + + + Update the remote's extra metadata from the OSTree repository's summary + file. Only xa.title and xa.default-branch are supported at the moment. + + + diff --git a/doc/reference/flatpak-sections.txt b/doc/reference/flatpak-sections.txt index 0f117e35..7c32306e 100644 --- a/doc/reference/flatpak-sections.txt +++ b/doc/reference/flatpak-sections.txt @@ -29,6 +29,7 @@ flatpak_installation_install_bundle flatpak_installation_drop_caches flatpak_installation_modify_remote flatpak_installation_remove_remote +flatpak_installation_update_remote_sync flatpak_get_default_arch FlatpakProgressCallback FlatpakUpdateFlags diff --git a/lib/flatpak-installation.c b/lib/flatpak-installation.c index 4ab6e6b5..0e473ced 100644 --- a/lib/flatpak-installation.c +++ b/lib/flatpak-installation.c @@ -798,6 +798,45 @@ flatpak_installation_remove_remote (FlatpakInstallation *self, return TRUE; } +/** + * flatpak_installation_update_remote_sync: + * @self: a #FlatpakInstallation + * @name: the name of the remote to update + * @cancellable: (nullable): a #GCancellable + * @error: return location for a #GError + * + * Updates the local configuration of a remote repository by fetching + * the related information from the summary file in the remote OSTree + * repository and committing the changes to the local installation. + * + * Returns: %TRUE if the remote has been updated successfully + * + * Since: 0.6.13 + */ +gboolean +flatpak_installation_update_remote_sync (FlatpakInstallation *self, + const char *name, + GCancellable *cancellable, + GError **error) +{ + g_autoptr(FlatpakDir) dir = flatpak_installation_get_dir (self); + g_autoptr(FlatpakDir) dir_clone = NULL; + + /* We clone the dir here to make sure we re-read the latest ostree repo config, in case + it has local changes */ + dir_clone = flatpak_dir_clone (dir); + if (!flatpak_dir_ensure_repo (dir_clone, cancellable, error)) + return FALSE; + + if (!flatpak_dir_update_remote_configuration (dir, name, cancellable, error)) + return FALSE; + + /* Make sure we pick up the new config */ + flatpak_installation_drop_caches (self, NULL, NULL); + + return TRUE; +} + /** * flatpak_installation_get_remote_by_name: * @self: a #FlatpakInstallation diff --git a/lib/flatpak-installation.h b/lib/flatpak-installation.h index bdaeb52d..1b059e41 100644 --- a/lib/flatpak-installation.h +++ b/lib/flatpak-installation.h @@ -158,6 +158,10 @@ FLATPAK_EXTERN gboolean flatpak_installation_remove_remote (Flatpak const char *name, GCancellable *cancellable, GError **error); +FLATPAK_EXTERN gboolean flatpak_installation_update_remote_sync (FlatpakInstallation *self, + const char *name, + GCancellable *cancellable, + GError **error); FLATPAK_EXTERN char * flatpak_installation_load_app_overrides (FlatpakInstallation *self, const char *app_id, GCancellable *cancellable, diff --git a/lib/test-lib.c b/lib/test-lib.c index 6df516c1..206fc0c1 100644 --- a/lib/test-lib.c +++ b/lib/test-lib.c @@ -357,11 +357,12 @@ main (int argc, char *argv[]) { FlatpakRemote *remote = g_ptr_array_index (remotes, i); g_autoptr(GPtrArray) refs = NULL; - g_print ("\nRemote: %s %d %s %s %d %d %s\n", + g_print ("\nRemote: %s %d %s %s %s %d %d %s\n", flatpak_remote_get_name (remote), flatpak_remote_get_prio (remote), flatpak_remote_get_url (remote), flatpak_remote_get_title (remote), + flatpak_remote_get_default_branch (remote), flatpak_remote_get_gpg_verify (remote), flatpak_remote_get_noenumerate (remote), g_file_get_path (flatpak_remote_get_appstream_dir (remote, NULL)));