Commit e2580375dc76f46dce9963225449fcc872e86b0b

nulltoken 2011-12-28T11:36:18

transport: make local transport accept a file Uri containing percent-encoded characters This makes libgit2 compliant with the following scenario $ git ls-remote file:///d:/temp/dwm%20tinou 732d790b702db4b8985f5104fc44642654f6a6b6 HEAD 732d790b702db4b8985f5104fc44642654f6a6b6 refs/heads/master 732d790b702db4b8985f5104fc44642654f6a6b6 refs/remotes/origin/HEAD 732d790b702db4b8985f5104fc44642654f6a6b6 refs/remotes/origin/master $ mv "/d/temp/dwm tinou" /d/temp/dwm+tinou $ git ls-remote file:///d:/temp/dwm%20tinou fatal: 'd:/temp/dwm tinou' does not appear to be a git repository fatal: The remote end hung up unexpectedly $ git ls-remote file:///d:/temp/dwm+tinou 732d790b702db4b8985f5104fc44642654f6a6b6 HEAD 732d790b702db4b8985f5104fc44642654f6a6b6 refs/heads/master 732d790b702db4b8985f5104fc44642654f6a6b6 refs/remotes/origin/HEAD 732d790b702db4b8985f5104fc44642654f6a6b6 refs/remotes/origin/master

diff --git a/src/transports/local.c b/src/transports/local.c
index 2937da0..a2135e7 100644
--- a/src/transports/local.c
+++ b/src/transports/local.c
@@ -13,6 +13,8 @@
 #include "refs.h"
 #include "transport.h"
 #include "posix.h"
+#include "path.h"
+#include "buffer.h"
 
 typedef struct {
 	git_transport parent;
@@ -148,7 +150,6 @@ static int local_ls(git_transport *transport, git_headlist_cb list_cb, void *pay
 	return GIT_SUCCESS;
 }
 
-
 /*
  * Try to open the url as a git directory. The direction doesn't
  * matter in this case because we're calulating the heads ourselves.
@@ -159,24 +160,26 @@ static int local_connect(git_transport *transport, int GIT_UNUSED(direction))
 	int error;
 	transport_local *t = (transport_local *) transport;
 	const char *path;
+	git_buf buf = GIT_BUF_INIT;
+
 	GIT_UNUSED_ARG(direction);
 
 	/* The repo layer doesn't want the prefix */
 	if (!git__prefixcmp(transport->url, "file://")) {
-		path = transport->url + strlen("file://");
-
-#ifdef _MSC_VER
-		/* skip the leading slash on windows before the drive letter */
-		if (*path != '/')
-			return git__throw(GIT_EINVALIDPATH, "Invalid local uri '%s'.", transport->url);
-
-		path++;
-#endif
-
-	} else
+		error = git_path_fromurl(&buf, transport->url);
+		if (error < GIT_SUCCESS) {
+			git_buf_free(&buf);
+			return git__rethrow(error, "Failed to parse remote path");
+		}
+		path = git_buf_cstr(&buf);
+
+	} else /* We assume transport->url is already a path */
 		path = transport->url;
 
 	error = git_repository_open(&repo, path);
+
+	git_buf_free(&buf);
+
 	if (error < GIT_SUCCESS)
 		return git__rethrow(error, "Failed to open remote");
 
diff --git a/tests-clay/clay.h b/tests-clay/clay.h
index 8cbd8dd..1f40f32 100644
--- a/tests-clay/clay.h
+++ b/tests-clay/clay.h
@@ -132,6 +132,7 @@ extern void test_index_rename__single_file(void);
 extern void test_network_remotelocal__cleanup(void);
 extern void test_network_remotelocal__initialize(void);
 extern void test_network_remotelocal__retrieve_advertised_references(void);
+extern void test_network_remotelocal__retrieve_advertised_references_from_spaced_repository(void);
 extern void test_network_remotes__cleanup(void);
 extern void test_network_remotes__fnmatch(void);
 extern void test_network_remotes__initialize(void);
diff --git a/tests-clay/clay_main.c b/tests-clay/clay_main.c
index ce2ffaf..c824704 100644
--- a/tests-clay/clay_main.c
+++ b/tests-clay/clay_main.c
@@ -205,7 +205,8 @@ static const struct clay_func _clay_cb_index_rename[] = {
     {"single_file", &test_index_rename__single_file}
 };
 static const struct clay_func _clay_cb_network_remotelocal[] = {
-    {"retrieve_advertised_references", &test_network_remotelocal__retrieve_advertised_references}
+    {"retrieve_advertised_references", &test_network_remotelocal__retrieve_advertised_references},
+	{"retrieve_advertised_references_from_spaced_repository", &test_network_remotelocal__retrieve_advertised_references_from_spaced_repository}
 };
 static const struct clay_func _clay_cb_network_remotes[] = {
     {"fnmatch", &test_network_remotes__fnmatch},
@@ -419,7 +420,7 @@ static const struct clay_suite _clay_suites[] = {
         "network::remotelocal",
         {"initialize", &test_network_remotelocal__initialize},
         {"cleanup", &test_network_remotelocal__cleanup},
-        _clay_cb_network_remotelocal, 1
+        _clay_cb_network_remotelocal, 2
     },
 	{
         "network::remotes",
@@ -550,7 +551,7 @@ static const struct clay_suite _clay_suites[] = {
 };
 
 static size_t _clay_suite_count = 39;
-static size_t _clay_callback_count = 125;
+static size_t _clay_callback_count = 126;
 
 /* Core test functions */
 static void
diff --git a/tests-clay/network/remotelocal.c b/tests-clay/network/remotelocal.c
index b9003e7..961c623 100644
--- a/tests-clay/network/remotelocal.c
+++ b/tests-clay/network/remotelocal.c
@@ -2,6 +2,7 @@
 #include "transport.h"
 #include "buffer.h"
 #include "path.h"
+#include "posix.h"
 
 static git_repository *repo;
 static git_buf file_path_buf = GIT_BUF_INIT;
@@ -9,9 +10,11 @@ static git_remote *remote;
 
 static void build_local_file_url(git_buf *out, const char *fixture)
 {
+	const char *in_buf;
+
 	git_buf path_buf = GIT_BUF_INIT;
 
-	cl_git_pass(git_path_prettify_dir(&path_buf, cl_fixture(fixture), NULL));
+	cl_git_pass(git_path_prettify_dir(&path_buf, fixture, NULL));
 	cl_git_pass(git_buf_puts(out, "file://"));
 
 #ifdef _MSC_VER
@@ -27,21 +30,27 @@ static void build_local_file_url(git_buf *out, const char *fixture)
 	cl_git_pass(git_buf_putc(out, '/'));
 #endif
 
-	cl_git_pass(git_buf_puts(out, git_buf_cstr(&path_buf)));
+	in_buf = git_buf_cstr(&path_buf);
+
+	/*
+	 * A very hacky Url encoding that only takes care of escaping the spaces
+	 */
+	while (*in_buf) {
+		if (*in_buf == ' ')
+			cl_git_pass(git_buf_puts(out, "%20"));
+		else
+			cl_git_pass(git_buf_putc(out, *in_buf));
+
+		in_buf++;
+	}
 
 	git_buf_free(&path_buf);
 }
 
 void test_network_remotelocal__initialize(void)
 {
-	cl_fixture("remotelocal");
 	cl_git_pass(git_repository_init(&repo, "remotelocal/", 0));
 	cl_assert(repo != NULL);
-
-	build_local_file_url(&file_path_buf, "testrepo.git");
-
-	cl_git_pass(git_remote_new(&remote, repo, git_buf_cstr(&file_path_buf), NULL));
-	cl_git_pass(git_remote_connect(remote, GIT_DIR_FETCH));
 }
 
 void test_network_remotelocal__cleanup(void)
@@ -62,11 +71,38 @@ static int count_ref__cb(git_remote_head *head, void *payload)
 	return GIT_SUCCESS;
 }
 
+static void connect_to_local_repository(const char *local_repository)
+{
+	build_local_file_url(&file_path_buf, local_repository);
+
+	cl_git_pass(git_remote_new(&remote, repo, git_buf_cstr(&file_path_buf), NULL));
+	cl_git_pass(git_remote_connect(remote, GIT_DIR_FETCH));
+
+}
+
 void test_network_remotelocal__retrieve_advertised_references(void)
 {
 	int how_many_refs = 0;
 
+	connect_to_local_repository(cl_fixture("testrepo.git"));
+
 	cl_git_pass(git_remote_ls(remote, &count_ref__cb, &how_many_refs));
 
 	cl_assert(how_many_refs == 12); /* 1 HEAD + 9 refs + 2 peeled tags */
 }
+
+void test_network_remotelocal__retrieve_advertised_references_from_spaced_repository(void)
+{
+	int how_many_refs = 0;
+
+	cl_fixture_sandbox("testrepo.git");
+	cl_git_pass(p_rename("testrepo.git", "spaced testrepo.git"));
+
+	connect_to_local_repository("spaced testrepo.git");
+
+	cl_git_pass(git_remote_ls(remote, &count_ref__cb, &how_many_refs));
+
+	cl_assert(how_many_refs == 12); /* 1 HEAD */
+
+	cl_fixture_cleanup("spaced testrepo.git");
+}