Commit 67ba7d2031f1eef63d66db6ce3ecaceddb06a4f3

Carlos Martín Nieto 2013-04-15T22:53:57

Allow git_remote_ls after disconnecting from the remote Keep the data around until free, as expected by our own fetch example

diff --git a/src/remote.c b/src/remote.c
index 896361e..54f0a8a 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -586,11 +586,6 @@ int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload)
 {
 	assert(remote);
 
-	if (!git_remote_connected(remote)) {
-		giterr_set(GITERR_NET, "The remote is not connected");
-		return -1;
-	}
-
 	return remote->transport->ls(remote->transport, list_cb, payload);
 }
 
diff --git a/src/transports/local.c b/src/transports/local.c
index ce89bb2..8af970e 100644
--- a/src/transports/local.c
+++ b/src/transports/local.c
@@ -36,7 +36,8 @@ typedef struct {
 	git_atomic cancelled;
 	git_repository *repo;
 	git_vector refs;
-	unsigned connected : 1;
+	unsigned connected : 1,
+		have_refs : 1;
 } transport_local;
 
 static int add_ref(transport_local *t, const char *name)
@@ -139,6 +140,7 @@ static int store_refs(transport_local *t)
 			goto on_error;
 	}
 
+	t->have_refs = 1;
 	git_strarray_free(&ref_names);
 	return 0;
 
@@ -208,8 +210,8 @@ static int local_ls(git_transport *transport, git_headlist_cb list_cb, void *pay
 	unsigned int i;
 	git_remote_head *head = NULL;
 
-	if (!t->connected) {
-		giterr_set(GITERR_NET, "The transport is not connected");
+	if (!t->have_refs) {
+		giterr_set(GITERR_NET, "The transport has not yet loaded the refs");
 		return -1;
 	}
 
@@ -569,8 +571,6 @@ static void local_cancel(git_transport *transport)
 static int local_close(git_transport *transport)
 {
 	transport_local *t = (transport_local *)transport;
-	size_t i;
-	git_remote_head *head;
 
 	t->connected = 0;
 
@@ -579,13 +579,6 @@ static int local_close(git_transport *transport)
 		t->repo = NULL;
 	}
 
-	git_vector_foreach(&t->refs, i, head) {
-		git__free(head->name);
-		git__free(head);
-	}
-
-	git_vector_free(&t->refs);
-
 	if (t->url) {
 		git__free(t->url);
 		t->url = NULL;
@@ -597,10 +590,19 @@ static int local_close(git_transport *transport)
 static void local_free(git_transport *transport)
 {
 	transport_local *t = (transport_local *)transport;
+	size_t i;
+	git_remote_head *head;
 
 	/* Close the transport, if it's still open. */
 	local_close(transport);
 
+	git_vector_foreach(&t->refs, i, head) {
+		git__free(head->name);
+		git__free(head);
+	}
+
+	git_vector_free(&t->refs);
+
 	/* Free the transport */
 	git__free(t);
 }
diff --git a/src/transports/smart.c b/src/transports/smart.c
index bfcce0c..416eb22 100644
--- a/src/transports/smart.c
+++ b/src/transports/smart.c
@@ -253,7 +253,6 @@ static int git_smart__read_flags(git_transport *transport, int *flags)
 static int git_smart__close(git_transport *transport)
 {
 	transport_smart *t = (transport_smart *)transport;
-	git_vector *refs = &t->refs;
 	git_vector *common = &t->common;
 	unsigned int i;
 	git_pkt *p;
@@ -261,11 +260,6 @@ static int git_smart__close(git_transport *transport)
 
 	ret = git_smart__reset_stream(t, true);
 
-	git_vector_foreach(refs, i, p)
-		git_pkt_free(p);
-
-	git_vector_free(refs);
-
 	git_vector_foreach(common, i, p)
 		git_pkt_free(p);
 
@@ -284,6 +278,9 @@ static int git_smart__close(git_transport *transport)
 static void git_smart__free(git_transport *transport)
 {
 	transport_smart *t = (transport_smart *)transport;
+	git_vector *refs = &t->refs;
+	unsigned int i;
+	git_pkt *p;
 
 	/* Make sure that the current stream is closed, if we have one. */
 	git_smart__close(transport);
@@ -291,6 +288,11 @@ static void git_smart__free(git_transport *transport)
 	/* Free the subtransport */
 	t->wrapped->free(t->wrapped);
 
+	git_vector_foreach(refs, i, p)
+		git_pkt_free(p);
+
+	git_vector_free(refs);
+
 	git__free(t);
 }
 
diff --git a/tests-clar/online/fetch.c b/tests-clar/online/fetch.c
index a0ee7aa..bfa1eb9 100644
--- a/tests-clar/online/fetch.c
+++ b/tests-clar/online/fetch.c
@@ -134,3 +134,30 @@ void test_online_fetch__can_cancel(void)
 	git_remote_disconnect(remote);
 	git_remote_free(remote);
 }
+
+int ls_cb(git_remote_head *rhead, void *payload)
+{
+	int *nr = payload;
+	GIT_UNUSED(rhead);
+
+	(*nr)++;
+
+	return 0;
+}
+
+void test_online_fetch__ls_disconnected(void)
+{
+	git_remote *remote;
+	int nr_before = 0, nr_after = 0;
+
+	cl_git_pass(git_remote_create(&remote, _repo, "test",
+				"http://github.com/libgit2/TestGitRepository.git"));
+	cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH));
+	cl_git_pass(git_remote_ls(remote, ls_cb, &nr_before));
+	git_remote_disconnect(remote);
+	cl_git_pass(git_remote_ls(remote, ls_cb, &nr_after));
+
+	cl_assert_equal_i(nr_before, nr_after);
+
+	git_remote_free(remote);
+}