summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJosh Triplett <josh@joshtriplett.org>2016-04-03 17:22:07 -0700
committerJosh Triplett <josh@joshtriplett.org>2016-06-24 12:26:51 -0700
commit0dd98b6905a8a0f5f88ea89fa55d663c02c5aeb2 (patch)
tree22379ea9a70d5e855e339e0574726aa13019fe77 /src
parent39c6fca33aa38ad26c7c5f36734c6434593daae1 (diff)
downloadlibgit2-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.c169
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;