tag: add pattern based retrieval of list of tag names
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
diff --git a/include/git2/tag.h b/include/git2/tag.h
index 15635cc..71b27bb 100644
--- a/include/git2/tag.h
+++ b/include/git2/tag.h
@@ -235,6 +235,29 @@ GIT_EXTERN(int) git_tag_list(
git_strarray *tag_names,
git_repository *repo);
+/**
+ * Fill a list with all the tags in the Repository
+ * which name match a defined pattern
+ *
+ * If an empty pattern is provided, all the tags
+ * will be returned.
+ *
+ * The string array will be filled with the names of the
+ * matching tags; these values are owned by the user and
+ * should be free'd manually when no longer needed, using
+ * `git_strarray_free`.
+ *
+ * @param tag_names Pointer to a git_strarray structure where
+ * the tag names will be stored
+ * @param pattern Standard fnmatch pattern
+ * @param repo Repository where to find the tags
+ * @return 0 on success; error code otherwise
+ */
+GIT_EXTERN(int) git_tag_list_match(
+ git_strarray *tag_names,
+ const char *pattern,
+ git_repository *repo);
+
/** @} */
GIT_END_DECL
#endif
diff --git a/src/tag.c b/src/tag.c
index de70c50..f508fb7 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -364,23 +364,42 @@ int git_tag__parse(git_tag *tag, git_odb_object *obj)
return parse_tag_buffer(tag, obj->raw.data, (char *)obj->raw.data + obj->raw.len);
}
+typedef struct {
+ git_vector *taglist;
+ const char *pattern;
+} tag_filter_data;
+
+#define GIT_REFS_TAGS_DIR_LEN STRLEN(GIT_REFS_TAGS_DIR)
+
static int tag_list_cb(const char *tag_name, void *payload)
{
- if (git__prefixcmp(tag_name, GIT_REFS_TAGS_DIR) == 0)
- return git_vector_insert((git_vector *)payload, git__strdup(tag_name));
+ tag_filter_data *filter;
+
+ if (git__prefixcmp(tag_name, GIT_REFS_TAGS_DIR) != 0)
+ return GIT_SUCCESS;
+
+ filter = (tag_filter_data *)payload;
+ if (!*filter->pattern || p_fnmatch(filter->pattern, tag_name + GIT_REFS_TAGS_DIR_LEN, 0) == GIT_SUCCESS)
+ return git_vector_insert(filter->taglist, git__strdup(tag_name));
return GIT_SUCCESS;
}
-int git_tag_list(git_strarray *tag_names, git_repository *repo)
+int git_tag_list_match(git_strarray *tag_names, const char *pattern, git_repository *repo)
{
int error;
+ tag_filter_data filter;
git_vector taglist;
+ assert(tag_names && repo && pattern);
+
if (git_vector_init(&taglist, 8, NULL) < GIT_SUCCESS)
return GIT_ENOMEM;
- error = git_reference_foreach(repo, GIT_REF_OID|GIT_REF_PACKED, &tag_list_cb, (void *)&taglist);
+ filter.taglist = &taglist;
+ filter.pattern = pattern;
+
+ error = git_reference_foreach(repo, GIT_REF_OID|GIT_REF_PACKED, &tag_list_cb, (void *)&filter);
if (error < GIT_SUCCESS) {
git_vector_free(&taglist);
return git__rethrow(error, "Failed to list tags");
@@ -390,3 +409,8 @@ int git_tag_list(git_strarray *tag_names, git_repository *repo)
tag_names->count = taglist.length;
return GIT_SUCCESS;
}
+
+int git_tag_list(git_strarray *tag_names, git_repository *repo)
+{
+ return git_tag_list_match(tag_names, "", repo);
+}
\ No newline at end of file
diff --git a/tests/t08-tag.c b/tests/t08-tag.c
index 64a939f..aeff8b3 100644
--- a/tests/t08-tag.c
+++ b/tests/t08-tag.c
@@ -77,6 +77,35 @@ BEGIN_TEST(read1, "list all tag names from the repository")
git_repository_free(repo);
END_TEST
+static int ensure_tag_pattern_match(git_repository *repo, const char *pattern, const size_t expected_matches)
+{
+ git_strarray tag_list;
+ int error = GIT_SUCCESS;
+
+ if ((error = git_tag_list_match(&tag_list, pattern, repo)) < GIT_SUCCESS)
+ goto exit;
+
+ if (tag_list.count != expected_matches)
+ error = GIT_ERROR;
+
+exit:
+ git_strarray_free(&tag_list);
+ return error;
+}
+
+BEGIN_TEST(read2, "list all tag names from the repository matching a specified pattern")
+ git_repository *repo;
+ must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
+ must_pass(ensure_tag_pattern_match(repo, "", 3));
+ must_pass(ensure_tag_pattern_match(repo, "*", 3));
+ must_pass(ensure_tag_pattern_match(repo, "t*", 1));
+ must_pass(ensure_tag_pattern_match(repo, "*b", 2));
+ must_pass(ensure_tag_pattern_match(repo, "e", 0));
+ must_pass(ensure_tag_pattern_match(repo, "e90810b", 1));
+ must_pass(ensure_tag_pattern_match(repo, "e90810[ab]", 1));
+ git_repository_free(repo);
+END_TEST
+
#define TAGGER_NAME "Vicent Marti"
#define TAGGER_EMAIL "vicent@github.com"
@@ -222,6 +251,8 @@ END_TEST
BEGIN_SUITE(tag)
ADD_TEST(read0);
ADD_TEST(read1);
+ ADD_TEST(read2);
+
ADD_TEST(write0);
ADD_TEST(write2);
ADD_TEST(write3);