Commit bc6374eac485ab9ad9cfd7165b6d071c3dcb673a

Carlos Martín Nieto 2013-04-20T18:49:11

remote: allow querying for refspecs Introduce git_remote_{fetch,push}_refspecs() to get a list of refspecs from the remote and rename the refspec-adding functions to a less silly name. Use this instead of the vector index hacks in the tests.

diff --git a/include/git2/remote.h b/include/git2/remote.h
index 7a16179..5dcd930 100644
--- a/include/git2/remote.h
+++ b/include/git2/remote.h
@@ -148,7 +148,18 @@ GIT_EXTERN(int) git_remote_set_pushurl(git_remote *remote, const char* url);
  * @apram refspec the new fetch refspec
  * @return 0 or an error value
  */
-GIT_EXTERN(int) git_remote_add_fetchspec(git_remote *remote, const char *refspec);
+GIT_EXTERN(int) git_remote_add_fetch(git_remote *remote, const char *refspec);
+
+/**
+ * Get the remote's list of fetch refspecs
+ *
+ * The memory is owned by the user and should be freed with
+ * `git_strarray_free`.
+ *
+ * @param array pointer to the array in which to store the strings
+ * @param remote the remote to query
+ */
+GIT_EXTERN(int) git_remote_get_fetch_refspecs(git_strarray *array, git_remote *remote);
 
 /**
  * Add a push refspec to the remote
@@ -157,7 +168,18 @@ GIT_EXTERN(int) git_remote_add_fetchspec(git_remote *remote, const char *refspec
  * @param refspec the new push refspec
  * @return 0 or an error value
  */
-GIT_EXTERN(int) git_remote_add_pushspec(git_remote *remote, const char *refspec);
+GIT_EXTERN(int) git_remote_add_push(git_remote *remote, const char *refspec);
+
+/**
+ * Get the remote's list of push refspecs
+ *
+ * The memory is owned by the user and should be freed with
+ * `git_strarray_free`.
+ *
+ * @param array pointer to the array in which to store the strings
+ * @param remote the remote to query
+ */
+GIT_EXTERN(int) git_remote_get_push_refspecs(git_strarray *array, git_remote *remote);
 
 /**
  * Get the push refspec
diff --git a/src/clone.c b/src/clone.c
index cb40537..8f10ca8 100644
--- a/src/clone.c
+++ b/src/clone.c
@@ -324,11 +324,11 @@ static int create_and_configure_origin(
 		goto on_error;
 
 	if (options->fetch_spec &&
-	    (error = git_remote_add_fetchspec(origin, options->fetch_spec)) < 0)
+	    (error = git_remote_add_fetch(origin, options->fetch_spec)) < 0)
 		goto on_error;
 
 	if (options->push_spec &&
-	    (error = git_remote_add_pushspec(origin, options->push_spec)) < 0)
+	    (error = git_remote_add_push(origin, options->push_spec)) < 0)
 		goto on_error;
 
 	if (options->pushurl &&
diff --git a/src/remote.c b/src/remote.c
index 1c4b22b..8b7e66e 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -1467,12 +1467,60 @@ void git_remote_clear_refspecs(git_remote *remote)
 	git_vector_clear(&remote->refspec_strings);
 }
 
-int git_remote_add_fetchspec(git_remote *remote, const char *refspec)
+int git_remote_add_fetch(git_remote *remote, const char *refspec)
 {
 	return add_refspec(remote, refspec, true);
 }
 
-int git_remote_add_pushspec(git_remote *remote, const char *refspec)
+int git_remote_add_push(git_remote *remote, const char *refspec)
 {
 	return add_refspec(remote, refspec, false);
 }
+
+static int copy_refspecs(git_strarray *array, git_remote *remote, int push)
+{
+	size_t i;
+	git_vector refspecs;
+	git_refspec *spec;
+	char *dup;
+
+	if (git_vector_init(&refspecs, remote->refspecs.length, NULL) < 0)
+		return -1;
+
+	git_vector_foreach(&remote->refspecs, i, spec) {
+		if (spec->push != push)
+			continue;
+
+		dup = git__strdup(git_vector_get(&remote->refspec_strings, i));
+		if (!dup) {
+			goto on_error;
+		}
+
+		if (git_vector_insert(&refspecs, dup) < 0) {
+			git__free(dup);
+			goto on_error;
+		}
+	}
+
+	array->strings = (char **)refspecs.contents;
+	array->count = refspecs.length;
+
+	return 0;
+
+on_error:
+	git_vector_foreach(&refspecs, i, dup)
+		git__free(dup);
+	git_vector_free(&refspecs);
+
+	return -1;
+}
+
+int git_remote_get_fetch_refspecs(git_strarray *array, git_remote *remote)
+{
+	return copy_refspecs(array, remote, false);
+}
+
+int git_remote_get_push_refspecs(git_strarray *array, git_remote *remote)
+{
+	return copy_refspecs(array, remote, true);
+}
diff --git a/tests-clar/network/remote/remotes.c b/tests-clar/network/remote/remotes.c
index 92c9d8a..7b6e6aa 100644
--- a/tests-clar/network/remote/remotes.c
+++ b/tests-clar/network/remote/remotes.c
@@ -116,7 +116,7 @@ void test_network_remote_remotes__add_fetchspec(void)
 	size = _remote->refspecs.length;
 	cl_assert_equal_i(size, _remote->refspec_strings.length);
 
-	cl_git_pass(git_remote_add_fetchspec(_remote, "refs/*:refs/*"));
+	cl_git_pass(git_remote_add_fetch(_remote, "refs/*:refs/*"));
 
 	size++;
 	cl_assert_equal_i(size, _remote->refspec_strings.length);
@@ -134,7 +134,7 @@ void test_network_remote_remotes__add_pushspec(void)
 
 	size = _remote->refspecs.length;
 
-	cl_git_pass(git_remote_add_pushspec(_remote, "refs/*:refs/*"));
+	cl_git_pass(git_remote_add_push(_remote, "refs/*:refs/*"));
 	size++;
 	cl_assert_equal_i(size, _remote->refspec_strings.length);
 	cl_assert_equal_i(size, _remote->refspecs.length);
@@ -148,23 +148,19 @@ void test_network_remote_remotes__add_pushspec(void)
 
 void test_network_remote_remotes__save(void)
 {
+	git_strarray array;
+	const char *fetch_refspec = "refs/heads/*:refs/remotes/upstream/*";
+	const char *push_refspec = "refs/heads/*:refs/heads/*";
+
 	git_remote_free(_remote);
 	_remote = NULL;
 
 	/* Set up the remote and save it to config */
 	cl_git_pass(git_remote_create(&_remote, _repo, "upstream", "git://github.com/libgit2/libgit2"));
 	git_remote_clear_refspecs(_remote);
-	cl_assert_equal_i(0, _remote->refspecs.length);
-	cl_assert_equal_i(0, _remote->refspec_strings.length);
-
-	cl_git_pass(git_remote_add_fetchspec(_remote, "refs/heads/*:refs/remotes/upstream/*"));
-	cl_assert_equal_i(1, _remote->refspecs.length);
-	cl_assert_equal_i(1, _remote->refspec_strings.length);
-
-	cl_git_pass(git_remote_add_pushspec(_remote, "refs/heads/*:refs/heads/*"));
-	cl_assert_equal_i(2, _remote->refspecs.length);
-	cl_assert_equal_i(2, _remote->refspec_strings.length);
 
+	cl_git_pass(git_remote_add_fetch(_remote, fetch_refspec));
+	cl_git_pass(git_remote_add_push(_remote, push_refspec));
 	cl_git_pass(git_remote_set_pushurl(_remote, "git://github.com/libgit2/libgit2_push"));
 	cl_git_pass(git_remote_save(_remote));
 	git_remote_free(_remote);
@@ -173,20 +169,17 @@ void test_network_remote_remotes__save(void)
 	/* Load it from config and make sure everything matches */
 	cl_git_pass(git_remote_load(&_remote, _repo, "upstream"));
 
-	_refspec = git_vector_get(&_remote->refspecs, 0);
-	cl_assert(_refspec != NULL);
-	cl_assert_equal_s(git_refspec_src(_refspec), "refs/heads/*");
-	cl_assert_equal_s(git_refspec_dst(_refspec), "refs/remotes/upstream/*");
-	cl_assert_equal_i(0, git_refspec_force(_refspec));
-
-	cl_assert(_refspec != git_vector_get(&_remote->refspecs, 1));
-	_refspec = git_vector_get(&_remote->refspecs, 1);
-	cl_assert(_refspec != NULL);
-	cl_assert_equal_s(git_refspec_src(_refspec), "refs/heads/*");
-	cl_assert_equal_s(git_refspec_dst(_refspec), "refs/heads/*");
+	cl_git_pass(git_remote_get_fetch_refspecs(&array, _remote));
+	cl_assert_equal_i(1, array.count);
+	cl_assert_equal_s(fetch_refspec, array.strings[0]);
+	git_strarray_free(&array);
 
+	cl_git_pass(git_remote_get_push_refspecs(&array, _remote));
+	cl_assert_equal_i(1, array.count);
+	cl_assert_equal_s(push_refspec, array.strings[0]);
 	cl_assert_equal_s(git_remote_url(_remote), "git://github.com/libgit2/libgit2");
 	cl_assert_equal_s(git_remote_pushurl(_remote), "git://github.com/libgit2/libgit2_push");
+	git_strarray_free(&array);
 
 	/* remove the pushurl again and see if we can save that too */
 	cl_git_pass(git_remote_set_pushurl(_remote, NULL));
@@ -418,3 +411,43 @@ void test_network_remote_remotes__cannot_create_a_remote_which_name_is_invalid(v
 	assert_cannot_create_remote(".lock", GIT_EINVALIDSPEC);
 	assert_cannot_create_remote("a.lock", GIT_EINVALIDSPEC);
 }
+
+static const char *fetch_refspecs[] = {
+	"+refs/heads/*:refs/remotes/origin/*",
+	"refs/tags/*:refs/tags/*",
+	"+refs/pull/*:refs/pull/*",
+};
+
+static const char *push_refspecs[] = {
+	"refs/heads/*:refs/heads/*",
+	"refs/tags/*:refs/tags/*",
+	"refs/notes/*:refs/notes/*",
+};
+
+void test_network_remote_remotes__query_refspecs(void)
+{
+	git_remote *remote;
+	git_strarray array;
+	int i;
+
+	cl_git_pass(git_remote_create_inmemory(&remote, _repo, NULL, "git://github.com/libgit2/libgit2"));
+
+	for (i = 0; i < 3; i++) {
+		cl_git_pass(git_remote_add_fetch(remote, fetch_refspecs[i]));
+		cl_git_pass(git_remote_add_push(remote, push_refspecs[i]));
+	}
+
+	cl_git_pass(git_remote_get_fetch_refspecs(&array, remote));
+	for (i = 0; i < 3; i++) {
+		cl_assert_equal_s(fetch_refspecs[i], array.strings[i]);
+	}
+	git_strarray_free(&array);
+
+	cl_git_pass(git_remote_get_push_refspecs(&array, remote));
+	for (i = 0; i < 3; i++) {
+		cl_assert_equal_s(push_refspecs[i], array.strings[i]);
+	}
+	git_strarray_free(&array);
+
+	git_remote_free(remote);
+}
diff --git a/tests-clar/online/fetchhead.c b/tests-clar/online/fetchhead.c
index 3cbdc7e..e14ae09 100644
--- a/tests-clar/online/fetchhead.c
+++ b/tests-clar/online/fetchhead.c
@@ -44,7 +44,7 @@ static void fetchhead_test_fetch(const char *fetchspec, const char *expected_fet
 
 	if(fetchspec != NULL) {
 		git_remote_clear_refspecs(remote);
-		git_remote_add_fetchspec(remote, fetchspec);
+		git_remote_add_fetch(remote, fetchspec);
 	}
 
 	cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH));
diff --git a/tests-clar/refs/branches/remote.c b/tests-clar/refs/branches/remote.c
index 475fa54..6043828 100644
--- a/tests-clar/refs/branches/remote.c
+++ b/tests-clar/refs/branches/remote.c
@@ -70,7 +70,7 @@ void test_refs_branches_remote__ambiguous_remote_returns_error(void)
 
 	/* Update the remote fetch spec */
 	git_remote_clear_refspecs(remote);
-	cl_git_pass(git_remote_add_fetchspec(remote, "refs/heads/*:refs/remotes/test/*"));
+	cl_git_pass(git_remote_add_fetch(remote, "refs/heads/*:refs/remotes/test/*"));
 	cl_git_pass(git_remote_save(remote));
 
 	git_remote_free(remote);