summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVicent Marti <tanoku@gmail.com>2011-03-12 16:04:46 +0200
committerVicent Marti <tanoku@gmail.com>2011-03-14 23:52:32 +0200
commit005718280712634486a097427212e652b0e29f36 (patch)
tree00aba58f1f723bee77a251382cc3e407e2840fa5
parent58d06cf120eb9bb9247bb807bb105981bb3482a8 (diff)
downloadlibgit2-005718280712634486a097427212e652b0e29f36.tar.gz
Add new method `git_reference_listall`
Lists all the references in a repository. Listing may be filtered by reference type. This should applease Lord Clem.
-rw-r--r--include/git2/common.h16
-rw-r--r--include/git2/refs.h23
-rw-r--r--include/git2/types.h1
-rw-r--r--src/refs.c82
-rw-r--r--tests/t10-refs.c13
5 files changed, 135 insertions, 0 deletions
diff --git a/include/git2/common.h b/include/git2/common.h
index 34efe808b..11a08f897 100644
--- a/include/git2/common.h
+++ b/include/git2/common.h
@@ -27,6 +27,7 @@
#include "thread-utils.h"
#include <time.h>
+#include <stdlib.h>
#ifdef __cplusplus
# define GIT_BEGIN_DECL extern "C" {
@@ -158,6 +159,21 @@
#define GIT_EINVALIDREFSTATE (GIT_ERROR - 21)
GIT_BEGIN_DECL
+
+typedef struct {
+ char **strings;
+ size_t count;
+} git_strarray;
+
+GIT_INLINE(void) git_strarray_free(git_strarray *array)
+{
+ size_t i;
+ for (i = 0; i < array->count; ++i)
+ free(array->strings[i]);
+
+ free(array->strings);
+}
+
/** @} */
GIT_END_DECL
#endif
diff --git a/include/git2/refs.h b/include/git2/refs.h
index 1702d7ee1..4ffc5ce5b 100644
--- a/include/git2/refs.h
+++ b/include/git2/refs.h
@@ -218,6 +218,29 @@ GIT_EXTERN(int) git_reference_delete(git_reference *ref);
*/
GIT_EXTERN(int) git_reference_packall(git_repository *repo);
+/**
+ * Fill a list with all the references that can be found
+ * in a repository.
+ *
+ * The listed references may be filtered by type, or using
+ * a bitwise OR of several types. Use the magic value
+ * `GIT_REF_LISTALL` to obtain all references, including
+ * packed ones.
+ *
+ * The string array will be filled with the names of all
+ * references; these values are owned by the user and
+ * should be free'd manually when no longer needed, using
+ * `git_strarray_free`.
+ *
+ * @param array Pointer to a git_strarray structure where
+ * the reference names will be stored
+ * @param repo Repository where to find the refs
+ * @param list_flags Filtering flags for the reference
+ * listing.
+ * @return 0 on success; error code otherwise
+ */
+GIT_EXTERN(int) git_reference_listall(git_strarray *array, git_repository *repo, unsigned int list_flags);
+
/** @} */
GIT_END_DECL
#endif
diff --git a/include/git2/types.h b/include/git2/types.h
index 62467ec45..b5a8d7b2d 100644
--- a/include/git2/types.h
+++ b/include/git2/types.h
@@ -145,6 +145,7 @@ typedef enum {
GIT_REF_SYMBOLIC = 2, /** A reference which points at another reference */
GIT_REF_PACKED = 4,
GIT_REF_HAS_PEEL = 8,
+ GIT_REF_LISTALL = GIT_REF_OID|GIT_REF_SYMBOLIC|GIT_REF_PACKED,
} git_rtype;
/** @} */
diff --git a/src/refs.c b/src/refs.c
index 2fc383e22..93897a7f9 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -235,6 +235,24 @@ static int loose_read(gitfo_buf *file_content, const char *name, const char *rep
return error;
}
+static git_rtype loose_guess_rtype(const char *full_path)
+{
+ gitfo_buf ref_file = GITFO_BUF_INIT;
+ git_rtype type;
+
+ type = GIT_REF_INVALID;
+
+ if (gitfo_read_file(&ref_file, full_path) == GIT_SUCCESS) {
+ if (git__prefixcmp((const char *)(ref_file.data), GIT_SYMREF) == 0)
+ type = GIT_REF_SYMBOLIC;
+ else
+ type = GIT_REF_OID;
+ }
+
+ gitfo_free_buf(&ref_file);
+ return type;
+}
+
static int loose_lookup(
git_reference **ref_out,
git_repository *repo,
@@ -531,6 +549,31 @@ cleanup:
return error;
}
+
+
+
+struct dirent_list_data {
+ git_vector ref_list;
+ size_t repo_path_len;
+ unsigned int list_flags;
+};
+
+static int _dirent_loose_listall(void *_data, char *full_path)
+{
+ struct dirent_list_data *data = (struct dirent_list_data *)_data;
+ char *file_path;
+
+ if (gitfo_isdir(full_path) == GIT_SUCCESS)
+ return gitfo_dirent(full_path, GIT_PATH_MAX, _dirent_loose_listall, _data);
+
+ if ((data->list_flags & loose_guess_rtype(full_path)) == 0)
+ return GIT_SUCCESS; /* we are filtering out this reference */
+
+ file_path = full_path + data->repo_path_len;
+
+ return git_vector_insert(&data->ref_list, git__strdup(file_path));
+}
+
static int _dirent_loose_load(void *data, char *full_path)
{
git_repository *repository = (git_repository *)data;
@@ -1292,6 +1335,45 @@ int git_reference_packall(git_repository *repo)
return packed_write(repo);
}
+int git_reference_listall(git_strarray *array, git_repository *repo, unsigned int list_flags)
+{
+ int error;
+ struct dirent_list_data data;
+ char refs_path[GIT_PATH_MAX];
+
+ array->strings = NULL;
+ array->count = 0;
+
+ git_vector_init(&data.ref_list, 8, NULL);
+ data.repo_path_len = strlen(repo->path_repository);
+ data.list_flags = list_flags;
+
+ git__joinpath(refs_path, repo->path_repository, GIT_REFS_DIR);
+ error = gitfo_dirent(refs_path, GIT_PATH_MAX, _dirent_loose_listall, &data);
+
+ if (error < GIT_SUCCESS) {
+ git_vector_free(&data.ref_list);
+ return error;
+ }
+
+ if (list_flags & GIT_REF_PACKED) {
+ const char *ref_name;
+ void *_unused;
+
+ if ((error = packed_load(repo)) < GIT_SUCCESS) {
+ git_vector_free(&data.ref_list);
+ return error;
+ }
+
+ GIT_HASHTABLE_FOREACH(repo->references.packfile, ref_name, _unused,
+ git_vector_insert(&data.ref_list, git__strdup(ref_name));
+ );
+ }
+
+ array->strings = (char **)data.ref_list.contents;
+ array->count = data.ref_list.length;
+ return GIT_SUCCESS;
+}
diff --git a/tests/t10-refs.c b/tests/t10-refs.c
index abe364133..c70fb69ce 100644
--- a/tests/t10-refs.c
+++ b/tests/t10-refs.c
@@ -710,6 +710,18 @@ BEGIN_TEST(normalize2, "tests borrowed from JGit")
must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/master@{1.hour.ago}", NULL));
END_TEST
+BEGIN_TEST(list0, "try to list all the references in our test repo")
+ git_repository *repo;
+ git_strarray ref_list;
+
+ must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
+ must_pass(git_reference_listall(&ref_list, repo, GIT_REF_LISTALL));
+ must_be_true(ref_list.count == 8); /* 8 refs in total if we include the packed ones */
+
+ git_strarray_free(&ref_list);
+ git_repository_free(repo);
+END_TEST
+
BEGIN_SUITE(refs)
ADD_TEST(readtag0);
@@ -741,4 +753,5 @@ BEGIN_SUITE(refs)
ADD_TEST(rename4);
ADD_TEST(delete0);
+ ADD_TEST(list0);
END_SUITE