diff --git a/Makefile-ostree.am b/Makefile-ostree.am index 4e33c4eb..76cd0479 100644 --- a/Makefile-ostree.am +++ b/Makefile-ostree.am @@ -40,6 +40,7 @@ ostree_SOURCES = src/ostree/main.c \ src/ostree/ot-builtin-log.c \ src/ostree/ot-builtin-ls.c \ src/ostree/ot-builtin-prune.c \ + src/ostree/ot-builtin-refs.c \ src/ostree/ot-builtin-remote.c \ src/ostree/ot-builtin-rev-parse.c \ src/ostree/ot-builtin-show.c \ diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index 31d25fb7..5ef94bfd 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -1759,6 +1759,7 @@ create_empty_gvariant_dict (void) static gboolean enumerate_refs_recurse (OstreeRepo *repo, + const char *remote, GFile *base, GFile *dir, GHashTable *refs, @@ -1787,20 +1788,32 @@ enumerate_refs_recurse (OstreeRepo *repo, if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY) { - if (!enumerate_refs_recurse (repo, base, child, refs, cancellable, error)) + if (!enumerate_refs_recurse (repo, remote, base, child, refs, cancellable, error)) goto out; } else if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR) { char *contents; + char *relpath; gsize len; + GString *refname; if (!g_file_load_contents (child, cancellable, &contents, &len, NULL, error)) goto out; g_strchomp (contents); - g_hash_table_insert (refs, g_file_get_relative_path (base, child), contents); + refname = g_string_new (""); + if (remote) + { + g_string_append (refname, remote); + g_string_append_c (refname, ':'); + } + relpath = g_file_get_relative_path (base, child); + g_string_append (refname, relpath); + g_free (relpath); + + g_hash_table_insert (refs, g_string_free (refname, FALSE), contents); } } @@ -1810,25 +1823,71 @@ enumerate_refs_recurse (OstreeRepo *repo, } gboolean -ostree_repo_list_all_refs (OstreeRepo *repo, - GHashTable **out_all_refs, - GCancellable *cancellable, - GError **error) +ostree_repo_list_refs (OstreeRepo *repo, + const char *refspec_prefix, + GHashTable **out_all_refs, + GCancellable *cancellable, + GError **error) { gboolean ret = FALSE; - ot_lhash GHashTable *ret_all_refs = NULL; - ot_lobj GFile *dir = NULL; + gs_unref_hashtable GHashTable *ret_all_refs = NULL; + gs_free char *remote = NULL; + gs_free char *ref_prefix = NULL; ret_all_refs = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); - dir = g_file_resolve_relative_path (ostree_repo_get_path (repo), "refs/heads"); - if (!enumerate_refs_recurse (repo, dir, dir, ret_all_refs, cancellable, error)) - goto out; + if (refspec_prefix) + { + gs_unref_object GFile *dir = NULL; + gs_unref_object GFile *child = NULL; - g_clear_object (&dir); - dir = g_file_resolve_relative_path (ostree_repo_get_path (repo), "refs/remotes"); - if (!enumerate_refs_recurse (repo, dir, dir, ret_all_refs, cancellable, error)) - goto out; + if (!ostree_parse_refspec (refspec_prefix, &remote, &ref_prefix, error)) + goto out; + + if (remote) + dir = g_file_get_child (repo->remote_heads_dir, remote); + else + dir = g_object_ref (repo->local_heads_dir); + + child = g_file_resolve_relative_path (dir, ref_prefix); + + if (!enumerate_refs_recurse (repo, remote, child, child, + ret_all_refs, + cancellable, error)) + goto out; + } + else + { + gs_unref_object GFileEnumerator *remote_enumerator = NULL; + + if (!enumerate_refs_recurse (repo, NULL, repo->local_heads_dir, repo->local_heads_dir, + ret_all_refs, + cancellable, error)) + goto out; + + remote_enumerator = g_file_enumerate_children (repo->remote_heads_dir, OSTREE_GIO_FAST_QUERYINFO, + 0, + cancellable, error); + + while (TRUE) + { + GFileInfo *info; + GFile *child; + const char *name; + + if (!gs_file_enumerator_iterate (remote_enumerator, &info, &child, + cancellable, error)) + goto out; + if (!info) + break; + + name = g_file_info_get_name (info); + if (!enumerate_refs_recurse (repo, name, child, child, + ret_all_refs, + cancellable, error)) + goto out; + } + } ret = TRUE; ot_transfer_out_value (out_all_refs, &ret_all_refs); @@ -1850,7 +1909,7 @@ write_ref_summary (OstreeRepo *self, ot_lobj GOutputStream *out = NULL; ot_lfree char *buf = NULL; - if (!ostree_repo_list_all_refs (self, &all_refs, cancellable, error)) + if (!ostree_repo_list_refs (self, NULL, &all_refs, cancellable, error)) goto out; summary_path = g_file_resolve_relative_path (ostree_repo_get_path (self), diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h index e10c78f3..69b4dff7 100644 --- a/src/libostree/ostree-repo.h +++ b/src/libostree/ostree-repo.h @@ -169,10 +169,11 @@ gboolean ostree_repo_write_refspec (OstreeRepo *self, const char *rev, GError **error); -gboolean ostree_repo_list_all_refs (OstreeRepo *repo, - GHashTable **out_all_refs, - GCancellable *cancellable, - GError **error); +gboolean ostree_repo_list_refs (OstreeRepo *repo, + const char *refspec_prefix, + GHashTable **out_all_refs, + GCancellable *cancellable, + GError **error); gboolean ostree_repo_load_variant_c (OstreeRepo *self, OstreeObjectType expected_type, diff --git a/src/ostree/main.c b/src/ostree/main.c index ff716d0d..2648ff49 100644 --- a/src/ostree/main.c +++ b/src/ostree/main.c @@ -42,6 +42,7 @@ static OstreeCommand commands[] = { { "init", ostree_builtin_init, 0 }, { "log", ostree_builtin_log, 0 }, { "ls", ostree_builtin_ls, 0 }, + { "refs", ostree_builtin_refs, 0 }, { "prune", ostree_builtin_prune, 0 }, { "pull", ostree_builtin_pull, 0 }, { "pull-local", ostree_builtin_pull_local, 0 }, diff --git a/src/ostree/ostree-prune.c b/src/ostree/ostree-prune.c index e4bcb8fd..fb0c485f 100644 --- a/src/ostree/ostree-prune.c +++ b/src/ostree/ostree-prune.c @@ -110,7 +110,8 @@ ostree_prune (OstreeRepo *repo, if (refs_only) { - if (!ostree_repo_list_all_refs (repo, &all_refs, cancellable, error)) + if (!ostree_repo_list_refs (repo, NULL, &all_refs, + cancellable, error)) goto out; g_hash_table_iter_init (&hash_iter, all_refs); diff --git a/src/ostree/ot-builtin-pull-local.c b/src/ostree/ot-builtin-pull-local.c index 1f760db3..ed1b6629 100644 --- a/src/ostree/ot-builtin-pull-local.c +++ b/src/ostree/ot-builtin-pull-local.c @@ -219,7 +219,8 @@ ostree_builtin_pull_local (int argc, char **argv, GFile *repo_path, GError **err if (argc == 2) { - if (!ostree_repo_list_all_refs (data->src_repo, &refs_to_clone, cancellable, error)) + if (!ostree_repo_list_refs (data->src_repo, NULL, &refs_to_clone, + cancellable, error)) goto out; } else diff --git a/src/ostree/ot-builtin-refs.c b/src/ostree/ot-builtin-refs.c new file mode 100644 index 00000000..541d959b --- /dev/null +++ b/src/ostree/ot-builtin-refs.c @@ -0,0 +1,75 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2013 Colin Walters + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Author: Colin Walters + */ + +#include "config.h" + +#include "ot-builtins.h" +#include "ostree.h" +#include "ostree-repo-file.h" + +static GOptionEntry options[] = { + { NULL } +}; + +gboolean +ostree_builtin_refs (int argc, char **argv, GFile *repo_path, GError **error) +{ + gboolean ret = FALSE; + GCancellable *cancellable = NULL; + GOptionContext *context; + const char *refspec_prefix = NULL; + gs_unref_object OstreeRepo *repo = NULL; + gs_unref_hashtable GHashTable *refs = NULL; + GHashTableIter hashiter; + gpointer hashkey, hashvalue; + guint i; + + context = g_option_context_new ("[PREFIX...] - List refs"); + g_option_context_add_main_entries (context, options, NULL); + + if (!g_option_context_parse (context, &argc, &argv, error)) + goto out; + + repo = ostree_repo_new (repo_path); + if (!ostree_repo_check (repo, error)) + goto out; + + if (argc >= 2) + refspec_prefix = argv[1]; + + if (!ostree_repo_list_refs (repo, refspec_prefix, &refs, + cancellable, error)) + goto out; + + g_hash_table_iter_init (&hashiter, refs); + while (g_hash_table_iter_next (&hashiter, &hashkey, &hashvalue)) + { + const char *ref = hashkey; + g_print ("%s\n", ref); + } + + ret = TRUE; + out: + if (context) + g_option_context_free (context); + return ret; +} diff --git a/src/ostree/ot-builtins.h b/src/ostree/ot-builtins.h index 0562e82d..e8748640 100644 --- a/src/ostree/ot-builtins.h +++ b/src/ostree/ot-builtins.h @@ -40,6 +40,7 @@ gboolean ostree_builtin_pull_local (int argc, char **argv, GFile *repo_path, GEr gboolean ostree_builtin_log (int argc, char **argv, GFile *repo_path, GError **error); gboolean ostree_builtin_ls (int argc, char **argv, GFile *repo_path, GError **error); gboolean ostree_builtin_prune (int argc, char **argv, GFile *repo_path, GError **error); +gboolean ostree_builtin_refs (int argc, char **argv, GFile *repo_path, GError **error); gboolean ostree_builtin_fsck (int argc, char **argv, GFile *repo_path, GError **error); gboolean ostree_builtin_show (int argc, char **argv, GFile *repo_path, GError **error); gboolean ostree_builtin_rev_parse (int argc, char **argv, GFile *repo_path, GError **error); diff --git a/tests/t0000-basic.sh b/tests/t0000-basic.sh index 11da6a58..97bd7ed3 100755 --- a/tests/t0000-basic.sh +++ b/tests/t0000-basic.sh @@ -19,7 +19,7 @@ set -e -echo "1..32" +echo "1..33" . $(dirname $0)/libtest.sh @@ -34,6 +34,12 @@ $OSTREE rev-parse 'test2^' $OSTREE rev-parse 'test2^^' 2>/dev/null && (echo 1>&2 "rev-parse test2^^ unexpectedly succeeded!"; exit 1) echo "ok rev-parse" +$OSTREE refs > reflist +assert_file_has_content reflist '^test2$' +rm reflist + +echo "ok refs" + cd checkout-test2 assert_has_file firstfile assert_has_file baz/cow