diff --git a/R/libgit2.r b/R/libgit2.r index 3d1cf45d8..d3e79092a 100644 --- a/R/libgit2.r +++ b/R/libgit2.r @@ -47,7 +47,7 @@ libgit2_version <- function() { ##' @export ##' @examples ##' libgit2_sha() -libgit2_sha <- function() "d8243465be6ae4c3d0482ec262da58276f3a4e58" +libgit2_sha <- function() "e4218450338cf6757077f63bac570ea77f655eff" ##' Set the SSL certificate-authority locations ##' diff --git a/src/libgit2/include/git2/repository.h b/src/libgit2/include/git2/repository.h index 3d70d1b89..85b7e6861 100644 --- a/src/libgit2/include/git2/repository.h +++ b/src/libgit2/include/git2/repository.h @@ -95,29 +95,11 @@ GIT_EXTERN(int) git_repository_discover( * * GIT_REPOSITORY_OPEN_BARE - Open repository as a bare repo regardless * of core.bare config, and defer loading config file for faster setup. * Unlike `git_repository_open_bare`, this can follow gitlinks. - * * GIT_REPOSITORY_OPEN_NO_DOTGIT - Do not check for a repository by - * appending /.git to the start_path; only open the repository if - * start_path itself points to the git directory. - * * GIT_REPOSITORY_OPEN_FROM_ENV - Find and open a git repository, - * respecting the environment variables used by the git command-line - * tools. If set, `git_repository_open_ext` will ignore the other - * flags and the `ceiling_dirs` argument, and will allow a NULL `path` - * to use `GIT_DIR` or search from the current directory. The search - * for a repository will respect $GIT_CEILING_DIRECTORIES and - * $GIT_DISCOVERY_ACROSS_FILESYSTEM. The opened repository will - * respect $GIT_INDEX_FILE, $GIT_NAMESPACE, $GIT_OBJECT_DIRECTORY, and - * $GIT_ALTERNATE_OBJECT_DIRECTORIES. In the future, this flag will - * also cause `git_repository_open_ext` to respect $GIT_WORK_TREE and - * $GIT_COMMON_DIR; currently, `git_repository_open_ext` with this - * flag will error out if either $GIT_WORK_TREE or $GIT_COMMON_DIR is - * set. */ typedef enum { GIT_REPOSITORY_OPEN_NO_SEARCH = (1 << 0), GIT_REPOSITORY_OPEN_CROSS_FS = (1 << 1), GIT_REPOSITORY_OPEN_BARE = (1 << 2), - GIT_REPOSITORY_OPEN_NO_DOTGIT = (1 << 3), - GIT_REPOSITORY_OPEN_FROM_ENV = (1 << 4), } git_repository_open_flag_t; /** @@ -128,8 +110,7 @@ typedef enum { * see if a repo at this path could be opened. * @param path Path to open as git repository. If the flags * permit "searching", then this can be a path to a subdirectory - * inside the working directory of the repository. May be NULL if - * flags is GIT_REPOSITORY_OPEN_FROM_ENV. + * inside the working directory of the repository. * @param flags A combination of the GIT_REPOSITORY_OPEN flags above. * @param ceiling_dirs A GIT_PATH_LIST_SEPARATOR delimited list of path * prefixes at which the search for a containing repository should diff --git a/src/libgit2/src/repository.c b/src/libgit2/src/repository.c index ecc07806e..d39a9015d 100644 --- a/src/libgit2/src/repository.c +++ b/src/libgit2/src/repository.c @@ -357,50 +357,29 @@ static int find_repo( { int error; git_buf path = GIT_BUF_INIT; - git_buf repo_link = GIT_BUF_INIT; struct stat st; dev_t initial_device = 0; - int min_iterations; - bool in_dot_git; + bool try_with_dot_git = ((flags & GIT_REPOSITORY_OPEN_BARE) != 0); int ceiling_offset; git_buf_free(repo_path); - error = git_path_prettify(&path, start_path, NULL); - if (error < 0) + if ((error = git_path_prettify(&path, start_path, NULL)) < 0) return error; - /* in_dot_git toggles each loop: - * /a/b/c/.git, /a/b/c, /a/b/.git, /a/b, /a/.git, /a - * With GIT_REPOSITORY_OPEN_BARE or GIT_REPOSITORY_OPEN_NO_DOTGIT, we - * assume we started with /a/b/c.git and don't append .git the first - * time through. - * min_iterations indicates the number of iterations left before going - * further counts as a search. */ - if (flags & (GIT_REPOSITORY_OPEN_BARE | GIT_REPOSITORY_OPEN_NO_DOTGIT)) { - in_dot_git = true; - min_iterations = 1; - } else { - in_dot_git = false; - min_iterations = 2; - } + ceiling_offset = find_ceiling_dir_offset(path.ptr, ceiling_dirs); - for (;;) { - if (!(flags & GIT_REPOSITORY_OPEN_NO_DOTGIT)) { - if (!in_dot_git) { - error = git_buf_joinpath(&path, path.ptr, DOT_GIT); - if (error < 0) - break; - } - in_dot_git = !in_dot_git; - } + if (!try_with_dot_git && + (error = git_buf_joinpath(&path, path.ptr, DOT_GIT)) < 0) + return error; + while (!error && !git_buf_len(repo_path)) { if (p_stat(path.ptr, &st) == 0) { /* check that we have not crossed device boundaries */ if (initial_device == 0) initial_device = st.st_dev; else if (st.st_dev != initial_device && - !(flags & GIT_REPOSITORY_OPEN_CROSS_FS)) + (flags & GIT_REPOSITORY_OPEN_CROSS_FS) == 0) break; if (S_ISDIR(st.st_mode)) { @@ -411,37 +390,41 @@ static int find_repo( } } else if (S_ISREG(st.st_mode)) { - error = read_gitfile(&repo_link, path.ptr); - if (error < 0) - break; - if (valid_repository_path(&repo_link)) { - git_buf_swap(repo_path, &repo_link); + git_buf repo_link = GIT_BUF_INIT; + + if (!(error = read_gitfile(&repo_link, path.ptr))) { + if (valid_repository_path(&repo_link)) { + git_buf_swap(repo_path, &repo_link); + + if (link_path) + error = git_buf_put(link_path, + path.ptr, path.size); + } - if (link_path) - error = git_buf_put(link_path, path.ptr, path.size); + git_buf_free(&repo_link); + break; } - break; + git_buf_free(&repo_link); } } - /* Move up one directory. If we're in_dot_git, we'll search the - * parent itself next. If we're !in_dot_git, we'll search .git - * in the parent directory next (added at the top of the loop). */ + /* move up one directory level */ if (git_path_dirname_r(&path, path.ptr) < 0) { error = -1; break; } - /* Once we've checked the directory (and .git if applicable), - * find the ceiling for a search. */ - if (min_iterations && (--min_iterations == 0)) - ceiling_offset = find_ceiling_dir_offset(path.ptr, ceiling_dirs); - - /* Check if we should stop searching here. */ - if (min_iterations == 0 - && (path.ptr[ceiling_offset] == 0 - || (flags & GIT_REPOSITORY_OPEN_NO_SEARCH))) - break; + if (try_with_dot_git) { + /* if we tried original dir with and without .git AND either hit + * directory ceiling or NO_SEARCH was requested, then be done. + */ + if (path.ptr[ceiling_offset] == '\0' || + (flags & GIT_REPOSITORY_OPEN_NO_SEARCH) != 0) + break; + /* otherwise look first for .git item */ + error = git_buf_joinpath(&path, path.ptr, DOT_GIT); + } + try_with_dot_git = !try_with_dot_git; } if (!error && parent_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) { @@ -455,16 +438,14 @@ static int find_repo( return -1; } - /* If we didn't find the repository, and we don't have any other error - * to report, report that. */ + git_buf_free(&path); + if (!git_buf_len(repo_path) && !error) { giterr_set(GITERR_REPOSITORY, "Could not find repository from '%s'", start_path); error = GIT_ENOTFOUND; } - git_buf_free(&path); - git_buf_free(&repo_link); return error; } @@ -499,172 +480,6 @@ int git_repository_open_bare( return 0; } -static int _git_repository_open_ext_from_env( - git_repository **out, - const char *start_path) -{ - git_repository *repo = NULL; - git_index *index = NULL; - git_odb *odb = NULL; - git_buf dir_buf = GIT_BUF_INIT; - git_buf ceiling_dirs_buf = GIT_BUF_INIT; - git_buf across_fs_buf = GIT_BUF_INIT; - git_buf index_file_buf = GIT_BUF_INIT; - git_buf namespace_buf = GIT_BUF_INIT; - git_buf object_dir_buf = GIT_BUF_INIT; - git_buf alts_buf = GIT_BUF_INIT; - git_buf work_tree_buf = GIT_BUF_INIT; - git_buf common_dir_buf = GIT_BUF_INIT; - const char *ceiling_dirs = NULL; - unsigned flags = 0; - int error; - - if (!start_path) { - error = git__getenv(&dir_buf, "GIT_DIR"); - if (error == GIT_ENOTFOUND) { - giterr_clear(); - start_path = "."; - } else if (error < 0) - goto error; - else { - start_path = git_buf_cstr(&dir_buf); - flags |= GIT_REPOSITORY_OPEN_NO_SEARCH; - flags |= GIT_REPOSITORY_OPEN_NO_DOTGIT; - } - } - - error = git__getenv(&ceiling_dirs_buf, "GIT_CEILING_DIRECTORIES"); - if (error == GIT_ENOTFOUND) - giterr_clear(); - else if (error < 0) - goto error; - else - ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf); - - error = git__getenv(&across_fs_buf, "GIT_DISCOVERY_ACROSS_FILESYSTEM"); - if (error == GIT_ENOTFOUND) - giterr_clear(); - else if (error < 0) - goto error; - else { - int across_fs = 0; - error = git_config_parse_bool(&across_fs, git_buf_cstr(&across_fs_buf)); - if (error < 0) - goto error; - if (across_fs) - flags |= GIT_REPOSITORY_OPEN_CROSS_FS; - } - - error = git__getenv(&index_file_buf, "GIT_INDEX_FILE"); - if (error == GIT_ENOTFOUND) - giterr_clear(); - else if (error < 0) - goto error; - else { - error = git_index_open(&index, git_buf_cstr(&index_file_buf)); - if (error < 0) - goto error; - } - - error = git__getenv(&namespace_buf, "GIT_NAMESPACE"); - if (error == GIT_ENOTFOUND) - giterr_clear(); - else if (error < 0) - goto error; - - error = git__getenv(&object_dir_buf, "GIT_OBJECT_DIRECTORY"); - if (error == GIT_ENOTFOUND) - giterr_clear(); - else if (error < 0) - goto error; - else { - error = git_odb_open(&odb, git_buf_cstr(&object_dir_buf)); - if (error < 0) - goto error; - } - - error = git__getenv(&work_tree_buf, "GIT_WORK_TREE"); - if (error == GIT_ENOTFOUND) - giterr_clear(); - else if (error < 0) - goto error; - else { - giterr_set(GITERR_INVALID, "GIT_WORK_TREE unimplemented"); - error = GIT_ERROR; - goto error; - } - - error = git__getenv(&work_tree_buf, "GIT_COMMON_DIR"); - if (error == GIT_ENOTFOUND) - giterr_clear(); - else if (error < 0) - goto error; - else { - giterr_set(GITERR_INVALID, "GIT_COMMON_DIR unimplemented"); - error = GIT_ERROR; - goto error; - } - - error = git_repository_open_ext(&repo, start_path, flags, ceiling_dirs); - if (error < 0) - goto error; - - if (odb) - git_repository_set_odb(repo, odb); - - error = git__getenv(&alts_buf, "GIT_ALTERNATE_OBJECT_DIRECTORIES"); - if (error == GIT_ENOTFOUND) - giterr_clear(); - else if (error < 0) - goto error; - else { - const char *end; - char *alt, *sep; - if (!odb) { - error = git_repository_odb(&odb, repo); - if (error < 0) - goto error; - } - - end = git_buf_cstr(&alts_buf) + git_buf_len(&alts_buf); - for (sep = alt = alts_buf.ptr; sep != end; alt = sep+1) { - for (sep = alt; *sep && *sep != GIT_PATH_LIST_SEPARATOR; sep++) - ; - if (*sep) - *sep = '\0'; - error = git_odb_add_disk_alternate(odb, alt); - if (error < 0) - goto error; - } - } - - error = git_repository_set_namespace(repo, git_buf_cstr(&namespace_buf)); - if (error < 0) - goto error; - - git_repository_set_index(repo, index); - - if (out) { - *out = repo; - goto success; - } -error: - git_repository_free(repo); -success: - git_odb_free(odb); - git_index_free(index); - git_buf_free(&common_dir_buf); - git_buf_free(&work_tree_buf); - git_buf_free(&alts_buf); - git_buf_free(&object_dir_buf); - git_buf_free(&namespace_buf); - git_buf_free(&index_file_buf); - git_buf_free(&across_fs_buf); - git_buf_free(&ceiling_dirs_buf); - git_buf_free(&dir_buf); - return error; -} - int git_repository_open_ext( git_repository **repo_ptr, const char *start_path, @@ -677,9 +492,6 @@ int git_repository_open_ext( git_repository *repo; git_config *config = NULL; - if (flags & GIT_REPOSITORY_OPEN_FROM_ENV) - return _git_repository_open_ext_from_env(repo_ptr, start_path); - if (repo_ptr) *repo_ptr = NULL;