refs: Add a --collections argument to the built-in refs command

Rather than change the output format used by the existing refs command
to output collection IDs in addition to ref names, this functionality has
been hidden behind an --collections argument. If it’s not specified `ostree
refs` will output the same content as before for a given repository. If
it is specified, the collection ID for each ref will be included in the
output as (collection ID, ref name).

Signed-off-by: Philip Withnall <withnall@endlessm.com>

Closes: #924
Approved by: cgwalters
This commit is contained in:
Philip Withnall 2017-06-07 14:51:58 +01:00 committed by Atomic Bot
parent 205a84b36e
commit b7b79fa78d
2 changed files with 117 additions and 0 deletions

View File

@ -83,6 +83,26 @@ Boston, MA 02111-1307, USA.
you will then need to <command>ostree prune</command> or <command>ostree admin cleanup</command>.
</para></listitem>
</varlistentry>
<varlistentry>
<term><option>--collections</option></term>
<listitem><para>
Enable interactions with refs using the combination of their
collection IDs and ref names. When listing refs, this changes
the output format to include collection IDs, and enables
listing remote mirrored refs.</para>
<para>When creating refs, the refspec value passed to the
<option>--create</option> option is treated as
<literal>COLLECTION-ID:REF-NAME</literal> and a mirrored ref
is created. (This is an abuse of the refspec syntax.)</para>
<para>When deleting refs, all refs whose collection ID equals
the value of the <option>--delete</option> argument are
deleted.
</para></listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@ -29,14 +29,106 @@
static gboolean opt_delete;
static gboolean opt_list;
static char *opt_create;
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
static gboolean opt_collections;
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */
static GOptionEntry options[] = {
{ "delete", 0, 0, G_OPTION_ARG_NONE, &opt_delete, "Delete refs which match PREFIX, rather than listing them", NULL },
{ "list", 0, 0, G_OPTION_ARG_NONE, &opt_list, "Do not remove the prefix from the refs", NULL },
{ "create", 0, 0, G_OPTION_ARG_STRING, &opt_create, "Create a new ref for an existing commit", "NEWREF" },
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
{ "collections", 'c', 0, G_OPTION_ARG_NONE, &opt_collections, "Enable listing collection IDs for refs", NULL },
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */
{ NULL }
};
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
static gboolean
do_ref_with_collections (OstreeRepo *repo,
const char *refspec_prefix,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GHashTable) refs = NULL; /* (element-type OstreeCollectionRef utf8) */
GHashTableIter hashiter;
gpointer hashkey, hashvalue;
gboolean ret = FALSE;
if (!ostree_repo_list_collection_refs (repo,
(!opt_create) ? refspec_prefix : NULL,
&refs, cancellable, error))
goto out;
if (!opt_delete && !opt_create)
{
g_hash_table_iter_init (&hashiter, refs);
while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue))
{
const OstreeCollectionRef *ref = hashkey;
g_print ("(%s, %s)\n", ref->collection_id, ref->ref_name);
}
}
else if (opt_create)
{
g_autofree char *checksum = NULL;
g_autofree char *checksum_existing = NULL;
if (!ostree_repo_resolve_rev_ext (repo, opt_create, TRUE, OSTREE_REPO_RESOLVE_REV_EXT_NONE, &checksum_existing, error))
{
if (g_error_matches (*error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY))
{
/* A folder exists with the specified ref name,
* which is handled by _ostree_repo_write_ref */
g_clear_error (error);
}
else goto out;
}
if (checksum_existing != NULL)
{
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
"--create specified but ref %s already exists", opt_create);
goto out;
}
if (!ostree_repo_resolve_rev (repo, refspec_prefix, FALSE, &checksum, error))
goto out;
/* This is technically an abuse of the refspec syntax: collection IDs
* should not be treated like remote names. */
g_auto(GStrv) parts = g_strsplit (opt_create, ":", 2);
const char *collection_id = parts[0];
const char *ref_name = parts[1];
if (!ostree_validate_collection_id (collection_id, error))
goto out;
if (!ostree_validate_rev (ref_name, error))
goto out;
const OstreeCollectionRef ref = { (gchar *) collection_id, (gchar *) ref_name };
if (!ostree_repo_set_collection_ref_immediate (repo, &ref, checksum,
cancellable, error))
goto out;
}
else
/* delete */
{
g_hash_table_iter_init (&hashiter, refs);
while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue))
{
const OstreeCollectionRef *ref = hashkey;
if (!ostree_repo_set_collection_ref_immediate (repo, ref, NULL,
cancellable, error))
goto out;
}
}
ret = TRUE;
out:
return ret;
}
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */
static gboolean do_ref (OstreeRepo *repo, const char *refspec_prefix, GCancellable *cancellable, GError **error)
{
g_autoptr(GHashTable) refs = NULL;
@ -44,6 +136,11 @@ static gboolean do_ref (OstreeRepo *repo, const char *refspec_prefix, GCancellab
gpointer hashkey, hashvalue;
gboolean ret = FALSE;
#ifdef OSTREE_ENABLE_EXPERIMENTAL_API
if (opt_collections)
return do_ref_with_collections (repo, refspec_prefix, cancellable, error);
#endif /* OSTREE_ENABLE_EXPERIMENTAL_API */
if (opt_delete || opt_list)
{
if (!ostree_repo_list_refs_ext (repo, refspec_prefix, &refs, OSTREE_REPO_LIST_REFS_EXT_NONE,