Commit acdd3d95 by Ben Straub

Clone: allow empty dirs.

parent 5a20196f
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
*/ */
#include <assert.h> #include <assert.h>
#include <dirent.h>
#include "git2/clone.h" #include "git2/clone.h"
#include "git2/remote.h" #include "git2/remote.h"
...@@ -85,7 +86,7 @@ static int update_head_to_new_branch(git_repository *repo, git_oid *target, cons ...@@ -85,7 +86,7 @@ static int update_head_to_new_branch(git_repository *repo, git_oid *target, cons
if (!create_tracking_branch(repo, target, name)) { if (!create_tracking_branch(repo, target, name)) {
git_reference *head; git_reference *head;
if (!git_repository_head(&head, repo)) { if (!git_reference_lookup(&head, repo, GIT_HEAD_FILE)) {
git_buf target = GIT_BUF_INIT; git_buf target = GIT_BUF_INIT;
if (!git_buf_printf(&target, "refs/heads/%s", name) && if (!git_buf_printf(&target, "refs/heads/%s", name) &&
!git_reference_set_target(head, git_buf_cstr(&target))) { !git_reference_set_target(head, git_buf_cstr(&target))) {
...@@ -101,7 +102,7 @@ static int update_head_to_new_branch(git_repository *repo, git_oid *target, cons ...@@ -101,7 +102,7 @@ static int update_head_to_new_branch(git_repository *repo, git_oid *target, cons
static int update_head_to_remote(git_repository *repo, git_remote *remote) static int update_head_to_remote(git_repository *repo, git_remote *remote)
{ {
int retcode = 0; int retcode = GIT_ERROR;
git_remote_head *remote_head; git_remote_head *remote_head;
git_oid oid; git_oid oid;
struct HeadInfo head_info; struct HeadInfo head_info;
...@@ -115,16 +116,15 @@ static int update_head_to_remote(git_repository *repo, git_remote *remote) ...@@ -115,16 +116,15 @@ static int update_head_to_remote(git_repository *repo, git_remote *remote)
/* Check to see if "master" matches the remote head */ /* Check to see if "master" matches the remote head */
if (!git_reference_name_to_oid(&oid, repo, "refs/remotes/origin/master") && if (!git_reference_name_to_oid(&oid, repo, "refs/remotes/origin/master") &&
!git_oid_cmp(&remote_head->oid, &oid)) { !git_oid_cmp(&remote_head->oid, &oid)) {
update_head_to_new_branch(repo, &oid, "master"); retcode = update_head_to_new_branch(repo, &oid, "master");
} }
/* Not master. Check all the other refs. */ /* Not master. Check all the other refs. */
else if (!git_reference_foreach(repo, GIT_REF_LISTALL, else if (!git_reference_foreach(repo, GIT_REF_LISTALL,
reference_matches_remote_head, reference_matches_remote_head,
&head_info) && &head_info) &&
git_buf_len(&head_info.branchname) > 0 && git_buf_len(&head_info.branchname) > 0) {
update_head_to_new_branch(repo, &head_info.remote_head_oid, retcode = update_head_to_new_branch(repo, &head_info.remote_head_oid,
git_buf_cstr(&head_info.branchname))) { git_buf_cstr(&head_info.branchname));
retcode = 0;
} }
git_buf_free(&head_info.branchname); git_buf_free(&head_info.branchname);
...@@ -173,6 +173,50 @@ static int setup_remotes_and_fetch(git_repository *repo, ...@@ -173,6 +173,50 @@ static int setup_remotes_and_fetch(git_repository *repo,
return retcode; return retcode;
} }
static bool is_dot_or_dotdot(const char *name)
{
return (name[0] == '.' &&
(name[1] == '\0' ||
(name[1] == '.' && name[2] == '\0')));
}
/* TODO: p_opendir, p_closedir */
static bool path_is_okay(const char *path)
{
DIR *dir;
struct dirent *e;
bool retval = true;
/* The path must either not exist, or be an empty directory */
if (!git_path_exists(path)) return true;
if (!git_path_isdir(path)) {
giterr_set(GITERR_INVALID,
"'%s' exists and is not an empty directory", path);
return false;
}
dir = opendir(path);
if (!dir) {
giterr_set(GITERR_OS, "Couldn't open '%s'", path);
return false;
}
while ((e = readdir(dir)) != NULL) {
if (!is_dot_or_dotdot(e->d_name)) {
giterr_set(GITERR_INVALID,
"'%s' exists and is not an empty directory", path);
retval = false;
break;
}
}
closedir(dir);
return retval;
}
static int clone_internal(git_repository **out, static int clone_internal(git_repository **out,
const char *origin_url, const char *origin_url,
const char *path, const char *path,
...@@ -182,8 +226,7 @@ static int clone_internal(git_repository **out, ...@@ -182,8 +226,7 @@ static int clone_internal(git_repository **out,
int retcode = GIT_ERROR; int retcode = GIT_ERROR;
git_repository *repo = NULL; git_repository *repo = NULL;
if (git_path_exists(path)) { if (!path_is_okay(path)) {
giterr_set(GITERR_INVALID, "Path '%s' already exists.", path);
return GIT_ERROR; return GIT_ERROR;
} }
......
...@@ -117,7 +117,28 @@ void test_clone_clone__network_bare(void) ...@@ -117,7 +117,28 @@ void test_clone_clone__network_bare(void)
void test_clone_clone__already_exists(void) void test_clone_clone__already_exists(void)
{ {
#if 0
int bar;
/* Should pass with existing-but-empty dir */
p_mkdir("./foo", GIT_DIR_MODE);
cl_git_pass(git_clone(&g_repo,
"http://github.com/libgit2/libgit2.git",
"./foo", NULL));
git_repository_free(g_repo); g_repo = NULL;
git_futils_rmdir_r("./foo", GIT_DIRREMOVAL_FILES_AND_DIRS);
#endif
/* Should fail with a file */
cl_git_mkfile("./foo", "Bar!");
cl_git_fail(git_clone(&g_repo,
"http://github.com/libgit2/libgit2.git",
"./foo", NULL));
git_futils_rmdir_r("./foo", GIT_DIRREMOVAL_FILES_AND_DIRS);
/* Should fail with existing-and-nonempty dir */
p_mkdir("./foo", GIT_DIR_MODE); p_mkdir("./foo", GIT_DIR_MODE);
cl_git_mkfile("./foo/bar", "Baz!");
cl_git_fail(git_clone(&g_repo, cl_git_fail(git_clone(&g_repo,
"https://github.com/libgit2/libgit2.git", "https://github.com/libgit2/libgit2.git",
"./foo", NULL)); "./foo", NULL));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment