diff options
| author | Josh Triplett <josh@joshtriplett.org> | 2016-04-03 17:22:07 -0700 |
|---|---|---|
| committer | Josh Triplett <josh@joshtriplett.org> | 2016-06-24 12:26:51 -0700 |
| commit | 0dd98b6905a8a0f5f88ea89fa55d663c02c5aeb2 (patch) | |
| tree | 22379ea9a70d5e855e339e0574726aa13019fe77 /src | |
| parent | 39c6fca33aa38ad26c7c5f36734c6434593daae1 (diff) | |
| download | libgit2-0dd98b6905a8a0f5f88ea89fa55d663c02c5aeb2.tar.gz | |
Add GIT_REPOSITORY_OPEN_FROM_ENV flag to respect $GIT_* environment vars
git_repository_open_ext provides parameters for the start path, whether
to search across filesystems, and what ceiling directories to stop at.
git commands have standard environment variables and defaults for each
of those, as well as various other parameters of the repository. To
avoid duplicate environment variable handling in users of libgit2, add a
GIT_REPOSITORY_OPEN_FROM_ENV flag, which makes git_repository_open_ext
automatically handle the appropriate environment variables. Commands
that intend to act just like those built into git itself can use this
flag to get the expected default behavior.
git_repository_open_ext with the GIT_REPOSITORY_OPEN_FROM_ENV flag
respects $GIT_DIR, $GIT_DISCOVERY_ACROSS_FILESYSTEM,
$GIT_CEILING_DIRECTORIES, $GIT_INDEX_FILE, $GIT_NAMESPACE,
$GIT_OBJECT_DIRECTORY, and $GIT_ALTERNATE_OBJECT_DIRECTORIES. In the
future, when libgit2 gets worktree support, git_repository_open_env will
also respect $GIT_WORK_TREE and $GIT_COMMON_DIR; until then,
git_repository_open_ext with this flag will error out if either
$GIT_WORK_TREE or $GIT_COMMON_DIR is set.
Diffstat (limited to 'src')
| -rw-r--r-- | src/repository.c | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/src/repository.c b/src/repository.c index 5b4346793..635b13b84 100644 --- a/src/repository.c +++ b/src/repository.c @@ -491,6 +491,172 @@ 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, @@ -503,6 +669,9 @@ 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; |
