From e2580375dc76f46dce9963225449fcc872e86b0b Mon Sep 17 00:00:00 2001 From: nulltoken Date: Wed, 28 Dec 2011 11:36:18 +0100 Subject: [PATCH] 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 --- src/transports/local.c | 25 ++++++++------- tests-clay/clay.h | 1 + tests-clay/clay_main.c | 7 +++-- tests-clay/network/remotelocal.c | 52 +++++++++++++++++++++++++++----- 4 files changed, 63 insertions(+), 22 deletions(-) diff --git a/src/transports/local.c b/src/transports/local.c index 2937da06d..a2135e73e 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://"); + 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); -#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 + } 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 8cbd8ddf8..1f40f3267 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 ce2ffaff4..c8247041d 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 b9003e7ca..961c623a1 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"); +}