summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2014-06-20 04:58:31 -0400
committerColin Walters <walters@verbum.org>2014-06-20 15:36:46 -0400
commit2265ccdeb310eb9055f4e1dd110d53e150f8576e (patch)
treea453ea8cb744c8eefebdba8cd915df455603ad49
parentb2329cf87536482c03c1babbc183c098bd8a53ba (diff)
downloadostree-2265ccdeb310eb9055f4e1dd110d53e150f8576e.tar.gz
libostree: Add ostree_repo_remote_add() API, port "ostree remote add"
At least one external tool is using the API, and wants to add a remote, but all of the logic right now is in the tool. Move it to the library. https://bugzilla.gnome.org/show_bug.cgi?id=731984
-rw-r--r--src/libostree/ostree-repo.c129
-rw-r--r--src/libostree/ostree-repo.h7
-rw-r--r--src/ostree/ot-builtin-remote.c117
3 files changed, 163 insertions, 90 deletions
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index aa2bd2df..45d0fbcb 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -342,6 +342,132 @@ ostree_repo_write_config (OstreeRepo *self,
return ret;
}
+/* Bind a subset of an a{sv} to options in a given GKeyfile section */
+static void
+keyfile_set_from_vardict (GKeyFile *keyfile,
+ const char *section,
+ GVariant *vardict)
+{
+ GVariantIter viter;
+ const char *key;
+ GVariant *val;
+
+ g_variant_iter_init (&viter, vardict);
+ while (g_variant_iter_loop (&viter, "{&s@v}", &key, &val))
+ {
+ gs_unref_variant GVariant *child = g_variant_get_variant (val);
+ if (g_variant_is_of_type (child, G_VARIANT_TYPE_STRING))
+ g_key_file_set_string (keyfile, section, key, g_variant_get_string (child, NULL));
+ else if (g_variant_is_of_type (child, G_VARIANT_TYPE_BOOLEAN))
+ g_key_file_set_boolean (keyfile, section, key, g_variant_get_boolean (child));
+ else if (g_variant_is_of_type (child, G_VARIANT_TYPE_STRING_ARRAY))
+ {
+ gsize len;
+ const char *const*strv_child = g_variant_get_strv (child, &len);
+ g_key_file_set_string_list (keyfile, section, key, strv_child, len);
+ }
+ else
+ g_critical ("Unhandled type '%s' in " G_GNUC_FUNCTION,
+ (char*)g_variant_get_type (child));
+ }
+}
+
+GS_DEFINE_CLEANUP_FUNCTION0(GKeyFile*, local_keyfile_unref, g_key_file_unref)
+#define local_cleanup_keyfile __attribute__ ((cleanup(local_keyfile_unref)))
+
+/**
+ * ostree_repo_remote_add:
+ * @self: Repo
+ * @name: Name of remote
+ * @url: URL for remote
+ * @options: (allow-none): GVariant of type a{sv}
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * Create a new remote named @name pointing to @url. If @options is
+ * provided, then it will be mapped to #GKeyFile entries, where the
+ * GVariant dictionary key is an option string, and the value is
+ * mapped as follows:
+ * * s: g_key_file_set_string()
+ * * b: g_key_file_set_boolean()
+ * * as: g_key_file_set_string_list()
+ *
+ */
+gboolean
+ostree_repo_remote_add (OstreeRepo *self,
+ const char *name,
+ const char *url,
+ GVariant *options,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ gboolean is_system;
+ gs_free char *section = NULL;
+ gs_unref_object GFile *etc_ostree_remotes_d = g_file_new_for_path (SYSCONFDIR "/ostree/remotes.d");
+ local_cleanup_keyfile GKeyFile *target_keyfile = NULL;
+ gs_free char *target_name = NULL;
+ gs_unref_object GFile *target_conf = NULL;
+
+ g_return_val_if_fail (name != NULL, FALSE);
+ g_return_val_if_fail (url != NULL, FALSE);
+ g_return_val_if_fail (g_variant_is_of_type (options, G_VARIANT_TYPE ("a{sv}")), FALSE);
+
+ if (strchr (name, '/') != NULL)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Invalid character '/' in remote name: %s",
+ name);
+ goto out;
+ }
+
+ section = g_strdup_printf ("remote \"%s\"", name);
+
+ is_system = ostree_repo_is_system (self);
+ if (is_system)
+ {
+ target_keyfile = g_key_file_new ();
+
+ target_name = g_strconcat (name, ".conf", NULL);
+ target_conf = g_file_get_child (etc_ostree_remotes_d, target_name);
+
+ if (g_file_query_exists (target_conf, NULL))
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ "Remote configuration already exists: %s",
+ gs_file_get_path_cached (target_conf));
+ goto out;
+ }
+ }
+ else
+ {
+ target_keyfile = ostree_repo_copy_config (self);
+ }
+
+ g_key_file_set_string (target_keyfile, section, "url", url);
+ if (options)
+ keyfile_set_from_vardict (target_keyfile, section, options);
+
+ if (is_system)
+ {
+ gsize len;
+ gs_free char *data = g_key_file_to_data (target_keyfile, &len, error);
+ if (!g_file_replace_contents (target_conf, data, len,
+ NULL, FALSE, 0, NULL,
+ cancellable, error))
+ goto out;
+ }
+ else
+ {
+ if (!ostree_repo_write_config (self, target_keyfile, error))
+ goto out;
+ }
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
static gboolean
ostree_repo_mode_to_string (OstreeRepoMode mode,
const char **out_mode,
@@ -504,9 +630,6 @@ enumerate_directory_allow_noent (GFile *dirpath,
return ret;
}
-GS_DEFINE_CLEANUP_FUNCTION0(GKeyFile*, local_keyfile_unref, g_key_file_unref)
-#define local_cleanup_keyfile __attribute__ ((cleanup(local_keyfile_unref)))
-
static gboolean
append_one_remote_config (OstreeRepo *self,
GFile *path,
diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h
index ccd9f407..7a57d335 100644
--- a/src/libostree/ostree-repo.h
+++ b/src/libostree/ostree-repo.h
@@ -67,6 +67,13 @@ GKeyFile * ostree_repo_get_config (OstreeRepo *self);
GKeyFile * ostree_repo_copy_config (OstreeRepo *self);
+gboolean ostree_repo_remote_add (OstreeRepo *self,
+ const char *name,
+ const char *url,
+ GVariant *options,
+ GCancellable *cancellable,
+ GError **error);
+
OstreeRepo * ostree_repo_get_parent (OstreeRepo *self);
gboolean ostree_repo_write_config (OstreeRepo *self,
diff --git a/src/ostree/ot-builtin-remote.c b/src/ostree/ot-builtin-remote.c
index 442e118c..43750309 100644
--- a/src/ostree/ot-builtin-remote.c
+++ b/src/ostree/ot-builtin-remote.c
@@ -63,47 +63,6 @@ parse_keyvalue (const char *keyvalue,
return TRUE;
}
-GS_DEFINE_CLEANUP_FUNCTION0(GKeyFile*, local_keyfile_unref, g_key_file_unref)
-#define local_cleanup_keyfile __attribute__ ((cleanup(local_keyfile_unref)))
-
-static gboolean
-add_remote_to_keyfile (GKeyFile *new_keyfile,
- const char *key,
- const char *url,
- GPtrArray *branches,
- GError **error)
-{
- gboolean ret = FALSE;
- char **iter;
-
- g_key_file_set_string (new_keyfile, key, "url", url);
-
- for (iter = opt_set; iter && *iter; iter++)
- {
- const char *keyvalue = *iter;
- gs_free char *subkey = NULL;
- gs_free char *subvalue = NULL;
-
- if (!parse_keyvalue (keyvalue, &subkey, &subvalue, error))
- goto out;
-
- g_key_file_set_string (new_keyfile, key, subkey, subvalue);
- }
-
- if (branches->len > 0)
- g_key_file_set_string_list (new_keyfile, key, "branches",
- (const char *const *)branches->pdata,
- branches->len);
-
- if (opt_no_gpg_verify)
- g_key_file_set_boolean (new_keyfile, key, "gpg-verify", FALSE);
-
- ret = TRUE;
- out:
- return ret;
-}
-
-
gboolean
ostree_builtin_remote (int argc, char **argv, OstreeRepo *repo, GCancellable *cancellable, GError **error)
{
@@ -140,71 +99,55 @@ ostree_builtin_remote (int argc, char **argv, OstreeRepo *repo, GCancellable *ca
if (!strcmp (op, "add"))
{
const char *url = argv[3];
- gs_unref_object GFile *etc_ostree_remotes_d = g_file_new_for_path (SYSCONFDIR "/ostree/remotes.d");
+ char **iter;
gs_free char *target_name = NULL;
gs_unref_object GFile *target_conf = NULL;
- local_cleanup_keyfile GKeyFile *new_keyfile = NULL;
- GKeyFile *target_keyfile = NULL;
gs_unref_ptrarray GPtrArray *branches = NULL;
+ gs_unref_variant_builder GVariantBuilder *optbuilder = NULL;
- if (strchr (remote_name, '/') != NULL)
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Invalid character '/' in remote name: %s",
- remote_name);
- goto out;
- }
-
if (argc < 4)
{
usage_error (context, "URL must be specified", error);
goto out;
}
- branches = g_ptr_array_new ();
- for (i = 4; i < argc; i++)
- g_ptr_array_add (branches, argv[i]);
+ optbuilder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
- if (ostree_repo_is_system (repo))
+ if (branches)
{
- new_keyfile = g_key_file_new ();
+ gs_unref_ptrarray GPtrArray *branchesp = g_ptr_array_new ();
- target_keyfile = new_keyfile;
+ for (i = 4; i < argc; i++)
+ g_ptr_array_add (branchesp, argv[i]);
+ g_ptr_array_add (branchesp, NULL);
- target_name = g_strconcat (remote_name, ".conf", NULL);
- target_conf = g_file_get_child (etc_ostree_remotes_d, target_name);
-
- if (g_file_query_exists (target_conf, NULL))
- {
- g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- "Remote configuration already exists: %s",
- gs_file_get_path_cached (target_conf));
- goto out;
- }
- }
- else
- {
- target_keyfile = config;
+ g_variant_builder_add (optbuilder, "{s@v}",
+ "branches",
+ g_variant_new_variant (g_variant_new_strv ((const char*const*)branchesp->pdata, -1)));
}
- if (!add_remote_to_keyfile (target_keyfile, key, url, branches, error))
- goto out;
-
- /* For the system repository, write to /etc/ostree/remotes.d */
- if (ostree_repo_is_system (repo))
- {
- gsize len;
- gs_free char *data = g_key_file_to_data (target_keyfile, &len, error);
- if (!g_file_replace_contents (target_conf, data, len,
- NULL, FALSE, 0, NULL,
- cancellable, error))
- goto out;
- }
- else
+ for (iter = opt_set; iter && *iter; iter++)
{
- if (!ostree_repo_write_config (repo, config, error))
+ const char *keyvalue = *iter;
+ gs_free char *subkey = NULL;
+ gs_free char *subvalue = NULL;
+
+ if (!parse_keyvalue (keyvalue, &subkey, &subvalue, error))
goto out;
+
+ g_variant_builder_add (optbuilder, "{s@v}",
+ subkey, g_variant_new_variant (g_variant_new_string (subvalue)));
}
+
+ if (opt_no_gpg_verify)
+ g_variant_builder_add (optbuilder, "{s@v}",
+ "gpg-verify",
+ g_variant_new_variant (g_variant_new_boolean (FALSE)));
+
+ if (!ostree_repo_remote_add (repo, remote_name, url,
+ g_variant_builder_end (optbuilder),
+ cancellable, error))
+ goto out;
}
else if (!strcmp (op, "show-url"))
{