Merge pull request #574 from carlosmn/remotes Add git_remote_list()
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
diff --git a/include/git2/remote.h b/include/git2/remote.h
index 9339434..e6537ec 100644
--- a/include/git2/remote.h
+++ b/include/git2/remote.h
@@ -197,6 +197,17 @@ GIT_EXTERN(int) git_remote_update_tips(git_remote *remote);
*/
GIT_EXTERN(int) git_remote_valid_url(const char *url);
+/**
+ * Get a list of the configured remotes for a repo
+ *
+ * The string array must be freed by the user.
+ *
+ * @param remotes_list a string array with the names of the remotes
+ * @param repo the repository to query
+ * @return GIT_SUCCESS or an error code
+ */
+GIT_EXTERN(int) git_remote_list(git_strarray *remotes_list, git_repository *repo);
+
/** @} */
GIT_END_DECL
#endif
diff --git a/src/remote.c b/src/remote.c
index 3e0dbf0..5b442e9 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -15,6 +15,8 @@
#include "fetch.h"
#include "refs.h"
+#include <regex.h>
+
static int refspec_parse(git_refspec *refspec, const char *str)
{
char *delim;
@@ -423,3 +425,70 @@ void git_remote_free(git_remote *remote)
git_remote_disconnect(remote);
git__free(remote);
}
+
+struct cb_data {
+ git_vector *list;
+ regex_t *preg;
+};
+
+static int remote_list_cb(const char *name, const char *GIT_UNUSED(value), void *data_)
+{
+ struct cb_data *data = (struct cb_data *)data_;
+ size_t nmatch = 2;
+ regmatch_t pmatch[2];
+ int error;
+ GIT_UNUSED_ARG(value);
+
+ if (!regexec(data->preg, name, nmatch, pmatch, 0)) {
+ char *remote_name = git__strndup(&name[pmatch[1].rm_so], pmatch[1].rm_eo - pmatch[1].rm_so);
+ if (remote_name == NULL)
+ return GIT_ENOMEM;
+
+ error = git_vector_insert(data->list, remote_name);
+ if (error < GIT_SUCCESS)
+ return error;
+ }
+
+ return GIT_SUCCESS;
+}
+
+int git_remote_list(git_strarray *remotes_list, git_repository *repo)
+{
+ git_config *cfg;
+ git_vector list;
+ regex_t preg;
+ struct cb_data data;
+ int error;
+
+ error = git_repository_config__weakptr(&cfg, repo);
+ if (error < GIT_SUCCESS)
+ return error;
+
+ error = git_vector_init(&list, 4, NULL);
+ if (error < GIT_SUCCESS)
+ return error;
+
+ error = regcomp(&preg, "^remote\\.(.*)\\.url$", REG_EXTENDED);
+ if (error < 0)
+ return GIT_EOSERR;
+
+ data.list = &list;
+ data.preg = &preg;
+ error = git_config_foreach(cfg, remote_list_cb, &data);
+ regfree(&preg);
+ if (error < GIT_SUCCESS) {
+ size_t i;
+ char *elem;
+ git_vector_foreach(&list, i, elem) {
+ free(elem);
+ }
+
+ git_vector_free(&list);
+ return error;
+ }
+
+ remotes_list->strings = (char **)list.contents;
+ remotes_list->count = list.length;
+
+ return GIT_SUCCESS;
+}
diff --git a/tests-clar/network/remotes.c b/tests-clar/network/remotes.c
index cc453e3..36b945f 100644
--- a/tests-clar/network/remotes.c
+++ b/tests-clar/network/remotes.c
@@ -114,3 +114,21 @@ void test_network_remotes__missing_refspecs(void)
git_config_free(cfg);
}
+
+void test_network_remotes__list(void)
+{
+ git_strarray list;
+ git_config *cfg;
+
+ cl_git_pass(git_remote_list(&list, _repo));
+ cl_assert(list.count == 1);
+ git_strarray_free(&list);
+
+ cl_git_pass(git_repository_config(&cfg, _repo));
+ cl_git_pass(git_config_set_string(cfg, "remote.specless.url", "http://example.com"));
+ cl_git_pass(git_remote_list(&list, _repo));
+ cl_assert(list.count == 2);
+ git_strarray_free(&list);
+
+ git_config_free(cfg);
+}