Commit e07c2d225deec42e592133df49ad8c564d4d66c7

Vicent Martí 2012-02-26T10:45:23

Merge pull request #574 from carlosmn/remotes Add git_remote_list()

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);
+}