vendor/libgit2/src/clone.c in rugged-0.21.4 vs vendor/libgit2/src/clone.c in rugged-0.22.0b1

- old
+ new

@@ -22,10 +22,12 @@ #include "refs.h" #include "path.h" #include "repository.h" #include "odb.h" +static int clone_local_into(git_repository *repo, git_remote *remote, const git_checkout_options *co_opts, const char *branch, int link, const git_signature *signature); + static int create_branch( git_reference **branch, git_repository *repo, const git_oid *target, const char *name, @@ -140,65 +142,64 @@ git_repository *repo, git_remote *remote, const git_signature *signature, const char *reflog_message) { - int error = 0, found_branch = 0; + int error = 0; size_t refs_len; - git_refspec dummy_spec, *refspec; + git_refspec *refspec; const git_remote_head *remote_head, **refs; const git_oid *remote_head_id; git_buf remote_master_name = GIT_BUF_INIT; git_buf branch = GIT_BUF_INIT; if ((error = git_remote_ls(&refs, &refs_len, remote)) < 0) return error; - /* Did we just clone an empty repository? */ - if (refs_len == 0) + /* We cloned an empty repository or one with an unborn HEAD */ + if (refs_len == 0 || strcmp(refs[0]->name, GIT_HEAD_FILE)) return setup_tracking_config( repo, "master", GIT_REMOTE_ORIGIN, GIT_REFS_HEADS_MASTER_FILE); - error = git_remote_default_branch(&branch, remote); - if (error == GIT_ENOTFOUND) { - git_buf_puts(&branch, GIT_REFS_HEADS_MASTER_FILE); - } else { - found_branch = 1; - } - - /* Get the remote's HEAD. This is always the first ref in the list. */ + /* We know we have HEAD, let's see where it points */ remote_head = refs[0]; assert(remote_head); remote_head_id = &remote_head->oid; + + error = git_remote_default_branch(&branch, remote); + if (error == GIT_ENOTFOUND) { + error = git_repository_set_head_detached( + repo, remote_head_id, signature, reflog_message); + goto cleanup; + } + refspec = git_remote__matching_refspec(remote, git_buf_cstr(&branch)); if (refspec == NULL) { - memset(&dummy_spec, 0, sizeof(git_refspec)); - refspec = &dummy_spec; + giterr_set(GITERR_NET, "the remote's default branch does not fit the refspec configuration"); + error = GIT_EINVALIDSPEC; + goto cleanup; } /* Determine the remote tracking reference name from the local master */ if ((error = git_refspec_transform( &remote_master_name, refspec, git_buf_cstr(&branch))) < 0) - return error; + goto cleanup; - if (found_branch) { - error = update_head_to_new_branch( - repo, - remote_head_id, - git_buf_cstr(&branch), - signature, reflog_message); - } else { - error = git_repository_set_head_detached( - repo, remote_head_id, signature, reflog_message); - } + error = update_head_to_new_branch( + repo, + remote_head_id, + git_buf_cstr(&branch), + signature, reflog_message); +cleanup: git_buf_free(&remote_master_name); git_buf_free(&branch); + return error; } static int update_head_to_branch( git_repository *repo, @@ -227,10 +228,33 @@ git_reference_free(remote_ref); git_buf_free(&remote_branch_name); return retcode; } +static int default_repository_create(git_repository **out, const char *path, int bare, void *payload) +{ + GIT_UNUSED(payload); + + return git_repository_init(out, path, bare); +} + +static int default_remote_create( + git_remote **out, + git_repository *repo, + const char *name, + const char *url, + void *payload) +{ + int error; + git_remote_callbacks *callbacks = payload; + + if ((error = git_remote_create(out, repo, name, url)) < 0) + return error; + + return git_remote_set_callbacks(*out, callbacks); +} + /* * submodules? */ static int create_and_configure_origin( @@ -239,29 +263,28 @@ const char *url, const git_clone_options *options) { int error; git_remote *origin = NULL; - const char *name; char buf[GIT_PATH_MAX]; + git_remote_create_cb remote_create = options->remote_cb; + void *payload = options->remote_cb_payload; /* If the path exists and is a dir, the url should be the absolute path */ if (git_path_root(url) < 0 && git_path_exists(url) && git_path_isdir(url)) { if (p_realpath(url, buf) == NULL) return -1; url = buf; } - name = options->remote_name ? options->remote_name : "origin"; - if ((error = git_remote_create(&origin, repo, name, url)) < 0) - goto on_error; + if (!remote_create) { + remote_create = default_remote_create; + payload = (void *)&options->remote_callbacks; + } - if (options->ignore_cert_errors) - git_remote_check_cert(origin, 0); - - if ((error = git_remote_set_callbacks(origin, &options->remote_callbacks)) < 0) + if ((error = remote_create(&origin, repo, "origin", url, payload)) < 0) goto on_error; if ((error = git_remote_save(origin)) < 0) goto on_error; @@ -305,11 +328,11 @@ error = git_checkout_head(repo, co_opts); return error; } -int git_clone_into(git_repository *repo, git_remote *_remote, const git_checkout_options *co_opts, const char *branch, const git_signature *signature) +static int clone_into(git_repository *repo, git_remote *_remote, const git_checkout_options *co_opts, const char *branch, const git_signature *signature) { int error; git_buf reflog_message = GIT_BUF_INIT; git_remote *remote; const git_remote_callbacks *callbacks; @@ -333,11 +356,11 @@ goto cleanup; git_remote_set_update_fetchhead(remote, 0); git_buf_printf(&reflog_message, "clone: from %s", git_remote_url(remote)); - if ((error = git_remote_fetch(remote, signature, git_buf_cstr(&reflog_message))) != 0) + if ((error = git_remote_fetch(remote, NULL, signature, git_buf_cstr(&reflog_message))) != 0) goto cleanup; error = checkout_branch(repo, remote, co_opts, branch, signature, git_buf_cstr(&reflog_message)); cleanup: @@ -345,31 +368,34 @@ git_buf_free(&reflog_message); return error; } -int git_clone__should_clone_local(const char *url, git_clone_local_t local) +int git_clone__should_clone_local(const char *url_or_path, git_clone_local_t local) { - const char *path; - int is_url; + git_buf fromurl = GIT_BUF_INIT; + const char *path = url_or_path; + bool is_url, is_local; if (local == GIT_CLONE_NO_LOCAL) - return false; + return 0; - is_url = !git__prefixcmp(url, "file://"); + if ((is_url = git_path_is_local_file_url(url_or_path)) != 0) { + if (git_path_fromurl(&fromurl, url_or_path) < 0) { + is_local = -1; + goto done; + } - if (is_url && local != GIT_CLONE_LOCAL && local != GIT_CLONE_LOCAL_NO_LINKS ) - return false; + path = fromurl.ptr; + } - path = url; - if (is_url) - path = url + strlen("file://"); + is_local = (!is_url || local != GIT_CLONE_LOCAL_AUTO) && + git_path_isdir(path); - if ((git_path_exists(path) && git_path_isdir(path)) && local != GIT_CLONE_NO_LOCAL) - return true; - - return false; +done: + git_buf_free(&fromurl); + return is_local; } int git_clone( git_repository **out, const char *url, @@ -379,10 +405,11 @@ int error = 0; git_repository *repo = NULL; git_remote *origin; git_clone_options options = GIT_CLONE_OPTIONS_INIT; uint32_t rmdir_flags = GIT_RMDIR_REMOVE_FILES; + git_repository_create_cb repository_cb; assert(out && url && local_path); if (_options) memcpy(&options, _options, sizeof(git_clone_options)); @@ -398,24 +425,32 @@ /* Only remove the root directory on failure if we create it */ if (git_path_exists(local_path)) rmdir_flags |= GIT_RMDIR_SKIP_ROOT; - if ((error = git_repository_init(&repo, local_path, options.bare)) < 0) + if (options.repository_cb) + repository_cb = options.repository_cb; + else + repository_cb = default_repository_create; + + if ((error = repository_cb(&repo, local_path, options.bare, options.repository_cb_payload)) < 0) return error; if (!(error = create_and_configure_origin(&origin, repo, url, &options))) { - if (git_clone__should_clone_local(url, options.local)) { - int link = options.local != GIT_CLONE_LOCAL_NO_LINKS; - error = git_clone_local_into( + int clone_local = git_clone__should_clone_local(url, options.local); + int link = options.local != GIT_CLONE_LOCAL_NO_LINKS; + + if (clone_local == 1) + error = clone_local_into( repo, origin, &options.checkout_opts, options.checkout_branch, link, options.signature); - } else { - error = git_clone_into( + else if (clone_local == 0) + error = clone_into( repo, origin, &options.checkout_opts, options.checkout_branch, options.signature); - } + else + error = -1; git_remote_free(origin); } if (error != 0) { @@ -450,10 +485,13 @@ } static bool can_link(const char *src, const char *dst, int link) { #ifdef GIT_WIN32 + GIT_UNUSED(src); + GIT_UNUSED(dst); + GIT_UNUSED(link); return false; #else struct stat st_src, st_dst; @@ -468,11 +506,11 @@ return st_src.st_dev == st_dst.st_dev; #endif } -int git_clone_local_into(git_repository *repo, git_remote *remote, const git_checkout_options *co_opts, const char *branch, int link, const git_signature *signature) +static int clone_local_into(git_repository *repo, git_remote *remote, const git_checkout_options *co_opts, const char *branch, int link, const git_signature *signature) { int error, flags; git_repository *src; git_buf src_odb = GIT_BUF_INIT, dst_odb = GIT_BUF_INIT, src_path = GIT_BUF_INIT; git_buf reflog_message = GIT_BUF_INIT; @@ -513,10 +551,10 @@ flags, GIT_OBJECT_DIR_MODE)) < 0) goto cleanup; git_buf_printf(&reflog_message, "clone: from %s", git_remote_url(remote)); - if ((error = git_remote_fetch(remote, signature, git_buf_cstr(&reflog_message))) != 0) + if ((error = git_remote_fetch(remote, NULL, signature, git_buf_cstr(&reflog_message))) != 0) goto cleanup; error = checkout_branch(repo, remote, co_opts, branch, signature, git_buf_cstr(&reflog_message)); cleanup: