diff --git a/src/libostree/ostree-repo-private.h b/src/libostree/ostree-repo-private.h index f3f1cfe4..fa963d18 100644 --- a/src/libostree/ostree-repo-private.h +++ b/src/libostree/ostree-repo-private.h @@ -162,6 +162,9 @@ _ostree_repo_commit_modifier_apply (OstreeRepo *self, GFileInfo *file_info, GFileInfo **out_modified_info); +gboolean +_ostree_repo_remote_name_is_file (const char *remote_name); + gboolean _ostree_repo_get_remote_option (OstreeRepo *self, const char *remote_name, diff --git a/src/libostree/ostree-repo-pull.c b/src/libostree/ostree-repo-pull.c index f79c46cf..c4249143 100644 --- a/src/libostree/ostree-repo-pull.c +++ b/src/libostree/ostree-repo-pull.c @@ -1603,7 +1603,7 @@ ostree_repo_pull_one_dir (OstreeRepo *self, /* Documented in ostree-repo.c */ gboolean ostree_repo_pull_with_options (OstreeRepo *self, - const char *remote_name, + const char *remote_name_or_baseurl, GVariant *options, OstreeAsyncProgress *progress, GCancellable *cancellable, @@ -1642,6 +1642,7 @@ ostree_repo_pull_with_options (OstreeRepo *self, /* Reduce risk of issues if enum happens to be 64 bit for some reason */ flags = flags_i; (void) g_variant_lookup (options, "subdir", "&s", &dir_to_pull); + (void) g_variant_lookup (options, "override-remote-name", "s", &pull_data->remote_name); (void) g_variant_lookup (options, "depth", "i", &pull_data->maxdepth); } @@ -1676,21 +1677,32 @@ ostree_repo_pull_with_options (OstreeRepo *self, pull_data->start_time = g_get_monotonic_time (); - pull_data->remote_name = g_strdup (remote_name); + if (_ostree_repo_remote_name_is_file (remote_name_or_baseurl)) + { + baseurl = g_strdup (remote_name_or_baseurl); + /* For compatibility with pull-local, don't gpg verify local + * pulls. + */ + pull_data->gpg_verify = FALSE; + } + else + { + pull_data->remote_name = g_strdup (remote_name_or_baseurl); #ifdef HAVE_GPGME - if (!_ostree_repo_get_remote_boolean_option (self, - pull_data->remote_name, "gpg-verify", - TRUE, &pull_data->gpg_verify, error)) - goto out; + if (!_ostree_repo_get_remote_boolean_option (self, + remote_name_or_baseurl, "gpg-verify", + TRUE, &pull_data->gpg_verify, error)) + goto out; #else - pull_data->gpg_verify = FALSE; + pull_data->gpg_verify = FALSE; #endif + } pull_data->phase = OSTREE_PULL_PHASE_FETCHING_REFS; if (!_ostree_repo_get_remote_boolean_option (self, - pull_data->remote_name, "tls-permissive", + remote_name_or_baseurl, "tls-permissive", FALSE, &tls_permissive, error)) goto out; if (tls_permissive) @@ -1706,11 +1718,11 @@ ostree_repo_pull_with_options (OstreeRepo *self, gs_free char *tls_client_key_path = NULL; if (!_ostree_repo_get_remote_option (self, - pull_data->remote_name, "tls-client-cert-path", + remote_name_or_baseurl, "tls-client-cert-path", NULL, &tls_client_cert_path, error)) goto out; if (!_ostree_repo_get_remote_option (self, - pull_data->remote_name, "tls-client-key-path", + remote_name_or_baseurl, "tls-client-key-path", NULL, &tls_client_key_path, error)) goto out; @@ -1718,7 +1730,7 @@ ostree_repo_pull_with_options (OstreeRepo *self, { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "remote \"%s\" must specify both \"tls-client-cert-path\" and \"tls-client-key-path\"", - pull_data->remote_name); + remote_name_or_baseurl); goto out; } else if (tls_client_cert_path) @@ -1742,7 +1754,7 @@ ostree_repo_pull_with_options (OstreeRepo *self, gs_unref_object GTlsDatabase *db = NULL; if (!_ostree_repo_get_remote_option (self, - pull_data->remote_name, "tls-ca-path", + remote_name_or_baseurl, "tls-ca-path", NULL, &tls_ca_path, error)) goto out; @@ -1760,7 +1772,7 @@ ostree_repo_pull_with_options (OstreeRepo *self, gs_free char *http_proxy = NULL; if (!_ostree_repo_get_remote_option (self, - pull_data->remote_name, "proxy", + remote_name_or_baseurl, "proxy", NULL, &http_proxy, error)) goto out; @@ -1769,20 +1781,23 @@ ostree_repo_pull_with_options (OstreeRepo *self, } if (!_ostree_repo_get_remote_option (self, - pull_data->remote_name, "metalink", + remote_name_or_baseurl, "metalink", NULL, &metalink_url_str, error)) goto out; if (!metalink_url_str) { - if (!repo_get_remote_option_inherit (self, pull_data->remote_name, "url", &baseurl, error)) - goto out; + if (baseurl == NULL) + { + if (!repo_get_remote_option_inherit (self, remote_name_or_baseurl, "url", &baseurl, error)) + goto out; + } if (baseurl == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, "No \"url\" option in remote \"%s\"", - pull_data->remote_name); + remote_name_or_baseurl); goto out; } @@ -1841,7 +1856,7 @@ ostree_repo_pull_with_options (OstreeRepo *self, } if (!_ostree_repo_get_remote_list_option (self, - pull_data->remote_name, "branches", + remote_name_or_baseurl, "branches", &configured_branches, error)) goto out; @@ -1944,7 +1959,7 @@ ostree_repo_pull_with_options (OstreeRepo *self, if (!(branches_iter && *branches_iter)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No configured branches for remote %s", pull_data->remote_name); + "No configured branches for remote %s", remote_name_or_baseurl); goto out; } for (;branches_iter && *branches_iter; branches_iter++) @@ -2077,7 +2092,10 @@ ostree_repo_pull_with_options (OstreeRepo *self, gs_free char *remote_ref = NULL; gs_free char *original_rev = NULL; - remote_ref = g_strdup_printf ("%s/%s", pull_data->remote_name, ref); + if (pull_data->remote_name) + remote_ref = g_strdup_printf ("%s/%s", pull_data->remote_name, ref); + else + remote_ref = g_strdup (ref); if (!ostree_repo_resolve_rev (pull_data->repo, remote_ref, TRUE, &original_rev, error)) goto out; @@ -2087,7 +2105,8 @@ ostree_repo_pull_with_options (OstreeRepo *self, } else { - ostree_repo_transaction_set_ref (pull_data->repo, pull_data->is_mirror ? NULL : pull_data->remote_name, ref, checksum); + ostree_repo_transaction_set_ref (pull_data->repo, pull_data->is_mirror ? NULL : pull_data->remote_name, + ref, checksum); } } diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index accb011b..49ccbd87 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -231,6 +231,12 @@ ost_repo_remove_remote (OstreeRepo *self, return removed; } +gboolean +_ostree_repo_remote_name_is_file (const char *remote_name) +{ + return g_str_has_prefix (remote_name, "file://"); +} + gboolean _ostree_repo_get_remote_option (OstreeRepo *self, const char *remote_name, @@ -242,6 +248,12 @@ _ostree_repo_get_remote_option (OstreeRepo *self, local_cleanup_remote OstreeRemote *remote = NULL; gboolean ret = FALSE; + if (_ostree_repo_remote_name_is_file (remote_name)) + { + *out_value = g_strdup (default_value); + return TRUE; + } + remote = ost_repo_get_remote (self, remote_name, error); if (remote != NULL) @@ -267,6 +279,12 @@ _ostree_repo_get_remote_list_option (OstreeRepo *self, local_cleanup_remote OstreeRemote *remote = NULL; gboolean ret = FALSE; + if (_ostree_repo_remote_name_is_file (remote_name)) + { + *out_value = NULL; + return TRUE; + } + remote = ost_repo_get_remote (self, remote_name, error); if (remote != NULL) @@ -304,6 +322,12 @@ _ostree_repo_get_remote_boolean_option (OstreeRepo *self, local_cleanup_remote OstreeRemote *remote = NULL; gboolean ret = FALSE; + if (_ostree_repo_remote_name_is_file (remote_name)) + { + *out_value = default_value; + return TRUE; + } + remote = ost_repo_get_remote (self, remote_name, error); if (remote != NULL) diff --git a/src/ostree/ot-builtin-pull-local.c b/src/ostree/ot-builtin-pull-local.c index c49ad0f6..acad43bc 100644 --- a/src/ostree/ot-builtin-pull-local.c +++ b/src/ostree/ot-builtin-pull-local.c @@ -39,99 +39,25 @@ static GOptionEntry options[] = { { NULL } }; -typedef struct { - OstreeRepo *src_repo; - OstreeRepo *dest_repo; - GThreadPool *threadpool; - GMainLoop *loop; - int n_objects_to_check; - volatile int n_objects_checked; - volatile int n_objects_copied; - GSConsole *console; -} OtLocalCloneData; - -static gboolean -termination_condition (OtLocalCloneData *self) -{ - return g_atomic_int_get (&self->n_objects_checked) == self->n_objects_to_check; -} - -static void -import_one_object_thread (gpointer object, - gpointer user_data) -{ - OtLocalCloneData *data = user_data; - gs_unref_variant GVariant *serialized_key = object; - GError *local_error = NULL; - GError **error = &local_error; - const char *checksum; - OstreeObjectType objtype; - GCancellable *cancellable = NULL; - - ostree_object_name_deserialize (serialized_key, &checksum, &objtype); - - if (!ostree_repo_import_object_from (data->dest_repo, data->src_repo, - objtype, checksum, cancellable, error)) - goto out; - - g_atomic_int_inc (&data->n_objects_copied); - - out: - g_atomic_int_add (&data->n_objects_checked, 1); - if (termination_condition (data)) - g_main_context_wakeup (NULL); - if (local_error != NULL) - { - g_printerr ("%s\n", local_error->message); - exit (EXIT_FAILURE); - } -} - -static gboolean -idle_print_status (gpointer user_data) -{ - OtLocalCloneData *data = user_data; - gs_free char *str = NULL; - - str = g_strdup_printf ("pull: %d/%d scanned, %d objects copied", - g_atomic_int_get (&data->n_objects_checked), - data->n_objects_to_check, - g_atomic_int_get (&data->n_objects_copied)); - if (data->console) - gs_console_begin_status_line (data->console, str, NULL, NULL); - else - g_print ("%s\n", str); - - return TRUE; -} - gboolean ostree_builtin_pull_local (int argc, char **argv, GCancellable *cancellable, GError **error) { gboolean ret = FALSE; GOptionContext *context; gs_unref_object OstreeRepo *repo = NULL; - const char *src_repo_path; int i; - GHashTableIter hash_iter; - gpointer key, value; - gboolean transaction_resuming = FALSE; - gs_unref_object GFile *src_f = NULL; - gs_unref_object GFile *src_repo_dir = NULL; - gs_unref_object GFile *dest_repo_dir = NULL; - gs_unref_hashtable GHashTable *refs_to_clone = NULL; - gs_unref_hashtable GHashTable *commits_to_clone = NULL; + const char *src_repo_arg; + GSConsole *console = NULL; + gs_free char *src_repo_uri = NULL; + gs_unref_object OstreeAsyncProgress *progress = NULL; + gs_unref_ptrarray GPtrArray *refs_to_fetch = NULL; gs_unref_hashtable GHashTable *source_objects = NULL; - OtLocalCloneData datav = { 0, }; - OtLocalCloneData *data = &datav; context = g_option_context_new ("SRC_REPO [REFS...] - Copy data from SRC_REPO"); if (!ostree_option_context_parse (context, options, &argc, &argv, OSTREE_BUILTIN_FLAG_NONE, &repo, cancellable, error)) goto out; - data->dest_repo = g_object_ref (repo); - if (argc < 2) { gchar *help = g_option_context_get_help (context, TRUE, NULL); @@ -142,133 +68,80 @@ ostree_builtin_pull_local (int argc, char **argv, GCancellable *cancellable, GEr goto out; } - src_repo_path = argv[1]; - src_f = g_file_new_for_path (src_repo_path); + src_repo_arg = argv[1]; - data->src_repo = ostree_repo_new (src_f); - if (!ostree_repo_open (data->src_repo, cancellable, error)) - goto out; + { gs_free char *cwd = g_get_current_dir (); + src_repo_uri = g_strconcat ("file://", cwd, "/", src_repo_arg, NULL); + } if (opt_disable_fsync) - ostree_repo_set_disable_fsync (data->dest_repo, TRUE); - - data->threadpool = ot_thread_pool_new_nproc (import_one_object_thread, data); - - src_repo_dir = g_object_ref (ostree_repo_get_path (data->src_repo)); - dest_repo_dir = g_object_ref (ostree_repo_get_path (data->dest_repo)); + ostree_repo_set_disable_fsync (repo, TRUE); if (argc == 2) { - if (!ostree_repo_list_refs (data->src_repo, NULL, &refs_to_clone, + gs_unref_object GFile *src_repo_path = g_file_new_for_path (src_repo_arg); + gs_unref_object OstreeRepo *src_repo = ostree_repo_new (src_repo_path); + gs_unref_hashtable GHashTable *refs_to_clone = NULL; + + refs_to_fetch = g_ptr_array_new_with_free_func (g_free); + + if (!ostree_repo_open (src_repo, cancellable, error)) + goto out; + + if (!ostree_repo_list_refs (src_repo, NULL, &refs_to_clone, cancellable, error)) goto out; + + { GHashTableIter hashiter; + gpointer hkey, hvalue; + + g_hash_table_iter_init (&hashiter, refs_to_clone); + while (g_hash_table_iter_next (&hashiter, &hkey, &hvalue)) + g_ptr_array_add (refs_to_fetch, g_strdup (hkey)); + } + g_ptr_array_add (refs_to_fetch, NULL); } else { - refs_to_clone = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - commits_to_clone = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); + refs_to_fetch = g_ptr_array_new (); for (i = 2; i < argc; i++) { const char *ref = argv[i]; - char *rev; - if (ostree_validate_checksum_string (ref, NULL)) - { - g_hash_table_insert (commits_to_clone, (char*)ref, (char*) ref); - } - else - { - if (!ostree_repo_resolve_rev (data->src_repo, ref, FALSE, &rev, error)) - goto out; - - /* Transfer ownership of rev */ - g_hash_table_insert (refs_to_clone, g_strdup (ref), rev); - } + g_ptr_array_add (refs_to_fetch, (char*)ref); } + g_ptr_array_add (refs_to_fetch, NULL); } - if (!ostree_repo_prepare_transaction (data->dest_repo, &transaction_resuming, + console = gs_console_get (); + if (console) + { + gs_console_begin_status_line (console, "", NULL, NULL); + progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, console); + } + + { GVariantBuilder builder; + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + + g_variant_builder_add (&builder, "{s@v}", "flags", + g_variant_new_variant (g_variant_new_int32 (OSTREE_REPO_PULL_FLAGS_NONE))); + g_variant_builder_add (&builder, "{s@v}", "refs", + g_variant_new_variant (g_variant_new_strv ((const char *const*) refs_to_fetch->pdata, -1))); + if (opt_remote) + g_variant_builder_add (&builder, "{s@v}", "override-remote-name", + g_variant_new_variant (g_variant_new_string (opt_remote))); + + if (!ostree_repo_pull_with_options (repo, src_repo_uri, + g_variant_builder_end (&builder), + progress, cancellable, error)) - goto out; - - g_print ("Enumerating objects...\n"); - - source_objects = ostree_repo_traverse_new_reachable (); - - if (refs_to_clone) - { - g_hash_table_iter_init (&hash_iter, refs_to_clone); - while (g_hash_table_iter_next (&hash_iter, &key, &value)) - { - const char *checksum = value; - - if (!ostree_repo_traverse_commit_union (data->src_repo, checksum, 0, source_objects, - cancellable, error)) - goto out; - } - } - - if (commits_to_clone) - { - g_hash_table_iter_init (&hash_iter, commits_to_clone); - while (g_hash_table_iter_next (&hash_iter, &key, &value)) - { - const char *checksum = key; - gs_unref_hashtable GHashTable *tmp_source_objects = NULL; - - if (!ostree_repo_traverse_commit_union (data->src_repo, checksum, 0, source_objects, - cancellable, error)) - goto out; - } - } - - data->n_objects_to_check = g_hash_table_size (source_objects); - g_hash_table_iter_init (&hash_iter, source_objects); - while (g_hash_table_iter_next (&hash_iter, &key, &value)) - { - GVariant *serialized_key = key; - g_thread_pool_push (data->threadpool, g_variant_ref (serialized_key), NULL); - } - - if (data->n_objects_to_check > 0) - { - data->console = gs_console_get (); - - if (data->console) - gs_console_begin_status_line (data->console, "", NULL, NULL); - - g_timeout_add_seconds (1, idle_print_status, data); - idle_print_status (data); - - while (!termination_condition (data)) - g_main_context_iteration (NULL, TRUE); - - idle_print_status (data); - if (data->console) - gs_console_end_status_line (data->console, NULL, NULL); - } - - g_print ("Writing %u refs\n", g_hash_table_size (refs_to_clone)); - - g_hash_table_iter_init (&hash_iter, refs_to_clone); - while (g_hash_table_iter_next (&hash_iter, &key, &value)) - { - const char *name = key; - const char *checksum = value; - - ostree_repo_transaction_set_ref (data->dest_repo, opt_remote, name, checksum); - } - - if (!ostree_repo_commit_transaction (data->dest_repo, NULL, NULL, error)) - goto out; + goto out; + } ret = TRUE; out: - g_clear_pointer (&data->threadpool, (GDestroyNotify) g_thread_pool_free); - if (data->src_repo) - g_object_unref (data->src_repo); - if (data->dest_repo) - g_object_unref (data->dest_repo); + if (progress) + ostree_async_progress_finish (progress); if (context) g_option_context_free (context); if (repo)