mirror of
https://git.proxmox.com/git/libgit2
synced 2025-08-03 03:44:21 +00:00
Merge pull request #3711 from joshtriplett/git_repository_discover_default
Add GIT_REPOSITORY_OPEN_FROM_ENV flag to respect $GIT_* environment vars
This commit is contained in:
commit
ebeb56f0f5
26
CHANGELOG.md
26
CHANGELOG.md
@ -3,6 +3,13 @@ v0.24 + 1
|
||||
|
||||
### Changes or improvements
|
||||
|
||||
* Fix repository discovery with `git_repository_discover` and
|
||||
`git_repository_open_ext` to match git's handling of a ceiling
|
||||
directory at the current directory. git only checks ceiling
|
||||
directories when its search ascends to a parent directory. A ceiling
|
||||
directory matching the starting directory will not prevent git from
|
||||
finding a repository in the starting directory or a parent directory.
|
||||
|
||||
### API additions
|
||||
|
||||
* `git_commit_create_buffer()` creates a commit and writes it into a
|
||||
@ -13,6 +20,25 @@ v0.24 + 1
|
||||
writing into a stream. Useful when you do not know the final size or
|
||||
want to copy the contents from another stream.
|
||||
|
||||
* New flags for `git_repository_open_ext`:
|
||||
|
||||
* `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.
|
||||
|
||||
### API removals
|
||||
|
||||
* `git_blob_create_fromchunks()` has been removed in favour of
|
||||
|
@ -95,11 +95,29 @@ 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;
|
||||
|
||||
/**
|
||||
@ -110,7 +128,8 @@ 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.
|
||||
* inside the working directory of the repository. May be NULL if
|
||||
* flags is GIT_REPOSITORY_OPEN_FROM_ENV.
|
||||
* @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
|
||||
|
214
src/repository.c
214
src/repository.c
@ -359,7 +359,8 @@ static int find_repo(
|
||||
git_buf path = GIT_BUF_INIT;
|
||||
struct stat st;
|
||||
dev_t initial_device = 0;
|
||||
bool try_with_dot_git = ((flags & GIT_REPOSITORY_OPEN_BARE) != 0);
|
||||
int min_iterations;
|
||||
bool in_dot_git;
|
||||
int ceiling_offset;
|
||||
|
||||
git_buf_free(repo_path);
|
||||
@ -367,13 +368,30 @@ static int find_repo(
|
||||
if ((error = git_path_prettify(&path, start_path, NULL)) < 0)
|
||||
return error;
|
||||
|
||||
ceiling_offset = find_ceiling_dir_offset(path.ptr, ceiling_dirs);
|
||||
/* 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;
|
||||
}
|
||||
|
||||
if (!try_with_dot_git &&
|
||||
(error = git_buf_joinpath(&path, path.ptr, DOT_GIT)) < 0)
|
||||
return error;
|
||||
while (!error && (min_iterations || !(path.ptr[ceiling_offset] == 0 ||
|
||||
(flags & GIT_REPOSITORY_OPEN_NO_SEARCH)))) {
|
||||
if (!(flags & GIT_REPOSITORY_OPEN_NO_DOTGIT)) {
|
||||
if (!in_dot_git)
|
||||
if ((error = git_buf_joinpath(&path, path.ptr, DOT_GIT)) < 0)
|
||||
break;
|
||||
in_dot_git = !in_dot_git;
|
||||
}
|
||||
|
||||
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)
|
||||
@ -414,17 +432,10 @@ static int find_repo(
|
||||
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;
|
||||
/* 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);
|
||||
}
|
||||
|
||||
if (!error && parent_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) {
|
||||
@ -480,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,
|
||||
@ -492,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;
|
||||
|
||||
|
@ -118,12 +118,22 @@ void test_repo_discover__0(void)
|
||||
cl_git_fail(git_repository_discover(&found_path, ALTERNATE_MALFORMED_FOLDER3, 0, ceiling_dirs));
|
||||
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, ALTERNATE_NOT_FOUND_FOLDER, 0, ceiling_dirs));
|
||||
|
||||
append_ceiling_dir(&ceiling_dirs_buf, SUB_REPOSITORY_FOLDER_SUB);
|
||||
ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf);
|
||||
|
||||
/* this must pass as ceiling_directories cannot prevent the current
|
||||
* working directory to be checked */
|
||||
ensure_repository_discover(SUB_REPOSITORY_FOLDER, ceiling_dirs, &sub_repository_path);
|
||||
ensure_repository_discover(SUB_REPOSITORY_FOLDER_SUB, ceiling_dirs, &sub_repository_path);
|
||||
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs));
|
||||
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs));
|
||||
|
||||
append_ceiling_dir(&ceiling_dirs_buf, SUB_REPOSITORY_FOLDER);
|
||||
ceiling_dirs = git_buf_cstr(&ceiling_dirs_buf);
|
||||
|
||||
//this must pass as ceiling_directories cannot predent the current
|
||||
//working directory to be checked
|
||||
cl_git_pass(git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER, 0, ceiling_dirs));
|
||||
ensure_repository_discover(SUB_REPOSITORY_FOLDER, ceiling_dirs, &sub_repository_path);
|
||||
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB, 0, ceiling_dirs));
|
||||
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB_SUB, 0, ceiling_dirs));
|
||||
cl_assert_equal_i(GIT_ENOTFOUND, git_repository_discover(&found_path, SUB_REPOSITORY_FOLDER_SUB_SUB_SUB, 0, ceiling_dirs));
|
||||
|
@ -3,12 +3,42 @@
|
||||
#include "sysdir.h"
|
||||
#include <ctype.h>
|
||||
|
||||
static void clear_git_env(void)
|
||||
{
|
||||
cl_setenv("GIT_DIR", NULL);
|
||||
cl_setenv("GIT_CEILING_DIRECTORIES", NULL);
|
||||
cl_setenv("GIT_INDEX_FILE", NULL);
|
||||
cl_setenv("GIT_NAMESPACE", NULL);
|
||||
cl_setenv("GIT_OBJECT_DIRECTORY", NULL);
|
||||
cl_setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", NULL);
|
||||
cl_setenv("GIT_WORK_TREE", NULL);
|
||||
cl_setenv("GIT_COMMON_DIR", NULL);
|
||||
}
|
||||
|
||||
static git_buf cwd_backup_buf = GIT_BUF_INIT;
|
||||
|
||||
void test_repo_open__initialize(void)
|
||||
{
|
||||
if (!git_buf_is_allocated(&cwd_backup_buf))
|
||||
cl_git_pass(git_path_prettify_dir(&cwd_backup_buf, ".", NULL));
|
||||
clear_git_env();
|
||||
}
|
||||
|
||||
void test_repo_open__cleanup(void)
|
||||
{
|
||||
cl_git_sandbox_cleanup();
|
||||
|
||||
if (git_path_isdir("alternate"))
|
||||
git_futils_rmdir_r("alternate", NULL, GIT_RMDIR_REMOVE_FILES);
|
||||
if (git_path_isdir("attr"))
|
||||
git_futils_rmdir_r("attr", NULL, GIT_RMDIR_REMOVE_FILES);
|
||||
if (git_path_isdir("testrepo.git"))
|
||||
git_futils_rmdir_r("testrepo.git", NULL, GIT_RMDIR_REMOVE_FILES);
|
||||
if (git_path_isdir("peeled.git"))
|
||||
git_futils_rmdir_r("peeled.git", NULL, GIT_RMDIR_REMOVE_FILES);
|
||||
|
||||
cl_must_pass(p_chdir(git_buf_cstr(&cwd_backup_buf)));
|
||||
clear_git_env();
|
||||
}
|
||||
|
||||
void test_repo_open__bare_empty_repo(void)
|
||||
@ -196,8 +226,9 @@ void test_repo_open__failures(void)
|
||||
&repo, "attr/sub", GIT_REPOSITORY_OPEN_NO_SEARCH, NULL));
|
||||
|
||||
/* fail with ceiling too low */
|
||||
cl_git_pass(git_buf_joinpath(&ceiling, ceiling.ptr, "sub"));
|
||||
cl_git_fail(git_repository_open_ext(&repo, "attr/sub", 0, ceiling.ptr));
|
||||
cl_git_pass(git_buf_joinpath(&ceiling, ceiling.ptr, "sub"));
|
||||
cl_git_fail(git_repository_open_ext(&repo, "attr/sub/sub", 0, ceiling.ptr));
|
||||
|
||||
/* fail with no repo */
|
||||
cl_git_pass(p_mkdir("alternate", 0777));
|
||||
@ -205,6 +236,12 @@ void test_repo_open__failures(void)
|
||||
cl_git_fail(git_repository_open_ext(&repo, "alternate", 0, NULL));
|
||||
cl_git_fail(git_repository_open_ext(&repo, "alternate/.git", 0, NULL));
|
||||
|
||||
/* fail with no searching and no appending .git */
|
||||
cl_git_fail(git_repository_open_ext(
|
||||
&repo, "attr",
|
||||
GIT_REPOSITORY_OPEN_NO_SEARCH | GIT_REPOSITORY_OPEN_NO_DOTGIT,
|
||||
NULL));
|
||||
|
||||
git_buf_free(&ceiling);
|
||||
}
|
||||
|
||||
@ -394,3 +431,231 @@ void test_repo_open__force_bare(void)
|
||||
cl_assert(git_repository_is_bare(barerepo));
|
||||
git_repository_free(barerepo);
|
||||
}
|
||||
|
||||
static int GIT_FORMAT_PRINTF(2, 3) cl_setenv_printf(const char *name, const char *fmt, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list args;
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
|
||||
va_start(args, fmt);
|
||||
cl_git_pass(git_buf_vprintf(&buf, fmt, args));
|
||||
va_end(args);
|
||||
|
||||
ret = cl_setenv(name, git_buf_cstr(&buf));
|
||||
git_buf_free(&buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Helper functions for test_repo_open__env, passing through the file and line
|
||||
* from the caller rather than those of the helper. The expression strings
|
||||
* distinguish between the possible failures within the helper. */
|
||||
|
||||
static void env_pass_(const char *path, const char *file, int line)
|
||||
{
|
||||
git_repository *repo;
|
||||
cl_git_pass_(git_repository_open_ext(NULL, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), file, line);
|
||||
cl_git_pass_(git_repository_open_ext(&repo, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), file, line);
|
||||
cl_assert_at_line(git__suffixcmp(git_repository_path(repo), "attr/.git/") == 0, file, line);
|
||||
cl_assert_at_line(git__suffixcmp(git_repository_workdir(repo), "attr/") == 0, file, line);
|
||||
cl_assert_at_line(!git_repository_is_bare(repo), file, line);
|
||||
git_repository_free(repo);
|
||||
}
|
||||
#define env_pass(path) env_pass_((path), __FILE__, __LINE__)
|
||||
|
||||
#define cl_git_fail_at_line(expr, file, line) clar__assert((expr) < 0, file, line, "Expected function call to fail: " #expr, NULL, 1)
|
||||
|
||||
static void env_fail_(const char *path, const char *file, int line)
|
||||
{
|
||||
git_repository *repo;
|
||||
cl_git_fail_at_line(git_repository_open_ext(NULL, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), file, line);
|
||||
cl_git_fail_at_line(git_repository_open_ext(&repo, path, GIT_REPOSITORY_OPEN_FROM_ENV, NULL), file, line);
|
||||
}
|
||||
#define env_fail(path) env_fail_((path), __FILE__, __LINE__)
|
||||
|
||||
static void env_cd_(
|
||||
const char *path,
|
||||
void (*passfail_)(const char *, const char *, int),
|
||||
const char *file, int line)
|
||||
{
|
||||
git_buf cwd_buf = GIT_BUF_INIT;
|
||||
cl_git_pass(git_path_prettify_dir(&cwd_buf, ".", NULL));
|
||||
cl_must_pass(p_chdir(path));
|
||||
passfail_(NULL, file, line);
|
||||
cl_must_pass(p_chdir(git_buf_cstr(&cwd_buf)));
|
||||
}
|
||||
#define env_cd_pass(path) env_cd_((path), env_pass_, __FILE__, __LINE__)
|
||||
#define env_cd_fail(path) env_cd_((path), env_fail_, __FILE__, __LINE__)
|
||||
|
||||
static void env_check_objects_(bool a, bool t, bool p, const char *file, int line)
|
||||
{
|
||||
git_repository *repo;
|
||||
git_oid oid_a, oid_t, oid_p;
|
||||
git_object *object;
|
||||
cl_git_pass(git_oid_fromstr(&oid_a, "45141a79a77842c59a63229403220a4e4be74e3d"));
|
||||
cl_git_pass(git_oid_fromstr(&oid_t, "1385f264afb75a56a5bec74243be9b367ba4ca08"));
|
||||
cl_git_pass(git_oid_fromstr(&oid_p, "0df1a5865c8abfc09f1f2182e6a31be550e99f07"));
|
||||
cl_git_pass_(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL), file, line);
|
||||
if (a) {
|
||||
cl_git_pass_(git_object_lookup(&object, repo, &oid_a, GIT_OBJ_BLOB), file, line);
|
||||
git_object_free(object);
|
||||
} else
|
||||
cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_a, GIT_OBJ_BLOB), file, line);
|
||||
if (t) {
|
||||
cl_git_pass_(git_object_lookup(&object, repo, &oid_t, GIT_OBJ_BLOB), file, line);
|
||||
git_object_free(object);
|
||||
} else
|
||||
cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_t, GIT_OBJ_BLOB), file, line);
|
||||
if (p) {
|
||||
cl_git_pass_(git_object_lookup(&object, repo, &oid_p, GIT_OBJ_COMMIT), file, line);
|
||||
git_object_free(object);
|
||||
} else
|
||||
cl_git_fail_at_line(git_object_lookup(&object, repo, &oid_p, GIT_OBJ_COMMIT), file, line);
|
||||
git_repository_free(repo);
|
||||
}
|
||||
#define env_check_objects(a, t, t2) env_check_objects_((a), (t), (t2), __FILE__, __LINE__)
|
||||
|
||||
void test_repo_open__env(void)
|
||||
{
|
||||
git_repository *repo = NULL;
|
||||
git_buf repo_dir_buf = GIT_BUF_INIT;
|
||||
const char *repo_dir = NULL;
|
||||
git_index *index = NULL;
|
||||
const char *t_obj = "testrepo.git/objects";
|
||||
const char *p_obj = "peeled.git/objects";
|
||||
|
||||
cl_fixture_sandbox("attr");
|
||||
cl_fixture_sandbox("testrepo.git");
|
||||
cl_fixture_sandbox("peeled.git");
|
||||
cl_git_pass(p_rename("attr/.gitted", "attr/.git"));
|
||||
|
||||
cl_git_pass(git_path_prettify_dir(&repo_dir_buf, "attr", NULL));
|
||||
repo_dir = git_buf_cstr(&repo_dir_buf);
|
||||
|
||||
/* GIT_DIR that doesn't exist */
|
||||
cl_setenv("GIT_DIR", "does-not-exist");
|
||||
env_fail(NULL);
|
||||
/* Explicit start_path overrides GIT_DIR */
|
||||
env_pass("attr");
|
||||
env_pass("attr/.git");
|
||||
env_pass("attr/sub");
|
||||
env_pass("attr/sub/sub");
|
||||
|
||||
/* GIT_DIR with relative paths */
|
||||
cl_setenv("GIT_DIR", "attr/.git");
|
||||
env_pass(NULL);
|
||||
cl_setenv("GIT_DIR", "attr");
|
||||
env_fail(NULL);
|
||||
cl_setenv("GIT_DIR", "attr/sub");
|
||||
env_fail(NULL);
|
||||
cl_setenv("GIT_DIR", "attr/sub/sub");
|
||||
env_fail(NULL);
|
||||
|
||||
/* GIT_DIR with absolute paths */
|
||||
cl_setenv_printf("GIT_DIR", "%s/.git", repo_dir);
|
||||
env_pass(NULL);
|
||||
cl_setenv("GIT_DIR", repo_dir);
|
||||
env_fail(NULL);
|
||||
cl_setenv_printf("GIT_DIR", "%s/sub", repo_dir);
|
||||
env_fail(NULL);
|
||||
cl_setenv_printf("GIT_DIR", "%s/sub/sub", repo_dir);
|
||||
env_fail(NULL);
|
||||
cl_setenv("GIT_DIR", NULL);
|
||||
|
||||
/* Searching from the current directory */
|
||||
env_cd_pass("attr");
|
||||
env_cd_pass("attr/.git");
|
||||
env_cd_pass("attr/sub");
|
||||
env_cd_pass("attr/sub/sub");
|
||||
|
||||
/* A ceiling directory blocks searches from ascending into that
|
||||
* directory, but doesn't block the start_path itself. */
|
||||
cl_setenv("GIT_CEILING_DIRECTORIES", repo_dir);
|
||||
env_cd_pass("attr");
|
||||
env_cd_fail("attr/sub");
|
||||
env_cd_fail("attr/sub/sub");
|
||||
|
||||
cl_setenv_printf("GIT_CEILING_DIRECTORIES", "%s/sub", repo_dir);
|
||||
env_cd_pass("attr");
|
||||
env_cd_pass("attr/sub");
|
||||
env_cd_fail("attr/sub/sub");
|
||||
|
||||
/* Multiple ceiling directories */
|
||||
cl_setenv_printf("GIT_CEILING_DIRECTORIES", "123%c%s/sub%cabc",
|
||||
GIT_PATH_LIST_SEPARATOR, repo_dir, GIT_PATH_LIST_SEPARATOR);
|
||||
env_cd_pass("attr");
|
||||
env_cd_pass("attr/sub");
|
||||
env_cd_fail("attr/sub/sub");
|
||||
|
||||
cl_setenv_printf("GIT_CEILING_DIRECTORIES", "%s%c%s/sub",
|
||||
repo_dir, GIT_PATH_LIST_SEPARATOR, repo_dir);
|
||||
env_cd_pass("attr");
|
||||
env_cd_fail("attr/sub");
|
||||
env_cd_fail("attr/sub/sub");
|
||||
|
||||
cl_setenv_printf("GIT_CEILING_DIRECTORIES", "%s/sub%c%s",
|
||||
repo_dir, GIT_PATH_LIST_SEPARATOR, repo_dir);
|
||||
env_cd_pass("attr");
|
||||
env_cd_fail("attr/sub");
|
||||
env_cd_fail("attr/sub/sub");
|
||||
|
||||
cl_setenv_printf("GIT_CEILING_DIRECTORIES", "%s%c%s/sub/sub",
|
||||
repo_dir, GIT_PATH_LIST_SEPARATOR, repo_dir);
|
||||
env_cd_pass("attr");
|
||||
env_cd_fail("attr/sub");
|
||||
env_cd_fail("attr/sub/sub");
|
||||
|
||||
cl_setenv("GIT_CEILING_DIRECTORIES", NULL);
|
||||
|
||||
/* Index files */
|
||||
cl_setenv("GIT_INDEX_FILE", cl_fixture("gitgit.index"));
|
||||
cl_git_pass(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL));
|
||||
cl_git_pass(git_repository_index(&index, repo));
|
||||
cl_assert_equal_s(git_index_path(index), cl_fixture("gitgit.index"));
|
||||
cl_assert_equal_i(git_index_entrycount(index), 1437);
|
||||
git_index_free(index);
|
||||
git_repository_free(repo);
|
||||
cl_setenv("GIT_INDEX_FILE", NULL);
|
||||
|
||||
/* Namespaces */
|
||||
cl_setenv("GIT_NAMESPACE", "some-namespace");
|
||||
cl_git_pass(git_repository_open_ext(&repo, "attr", GIT_REPOSITORY_OPEN_FROM_ENV, NULL));
|
||||
cl_assert_equal_s(git_repository_get_namespace(repo), "some-namespace");
|
||||
git_repository_free(repo);
|
||||
cl_setenv("GIT_NAMESPACE", NULL);
|
||||
|
||||
/* Object directories and alternates */
|
||||
env_check_objects(true, false, false);
|
||||
|
||||
cl_setenv("GIT_OBJECT_DIRECTORY", t_obj);
|
||||
env_check_objects(false, true, false);
|
||||
cl_setenv("GIT_OBJECT_DIRECTORY", NULL);
|
||||
|
||||
cl_setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", t_obj);
|
||||
env_check_objects(true, true, false);
|
||||
cl_setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", NULL);
|
||||
|
||||
cl_setenv("GIT_OBJECT_DIRECTORY", p_obj);
|
||||
env_check_objects(false, false, true);
|
||||
cl_setenv("GIT_OBJECT_DIRECTORY", NULL);
|
||||
|
||||
cl_setenv("GIT_OBJECT_DIRECTORY", t_obj);
|
||||
cl_setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", p_obj);
|
||||
env_check_objects(false, true, true);
|
||||
cl_setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", NULL);
|
||||
cl_setenv("GIT_OBJECT_DIRECTORY", NULL);
|
||||
|
||||
cl_setenv_printf("GIT_ALTERNATE_OBJECT_DIRECTORIES",
|
||||
"%s%c%s", t_obj, GIT_PATH_LIST_SEPARATOR, p_obj);
|
||||
env_check_objects(true, true, true);
|
||||
cl_setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", NULL);
|
||||
|
||||
cl_setenv_printf("GIT_ALTERNATE_OBJECT_DIRECTORIES",
|
||||
"%s%c%s", p_obj, GIT_PATH_LIST_SEPARATOR, t_obj);
|
||||
env_check_objects(true, true, true);
|
||||
cl_setenv("GIT_ALTERNATE_OBJECT_DIRECTORIES", NULL);
|
||||
|
||||
cl_fixture_cleanup("peeled.git");
|
||||
cl_fixture_cleanup("testrepo.git");
|
||||
cl_fixture_cleanup("attr");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user