Commit 04de614b by Edward Thomson Committed by GitHub

Merge pull request #4243 from pks-t/pks/submodule-workdir

Submodule working directory
parents a1023a43 2696c5c3
...@@ -422,10 +422,10 @@ static int read_gitfile(git_buf *path_out, const char *file_path) ...@@ -422,10 +422,10 @@ static int read_gitfile(git_buf *path_out, const char *file_path)
} }
static int find_repo( static int find_repo(
git_buf *repo_path, git_buf *gitdir_path,
git_buf *parent_path, git_buf *workdir_path,
git_buf *link_path, git_buf *gitlink_path,
git_buf *common_path, git_buf *commondir_path,
const char *start_path, const char *start_path,
uint32_t flags, uint32_t flags,
const char *ceiling_dirs) const char *ceiling_dirs)
...@@ -440,7 +440,7 @@ static int find_repo( ...@@ -440,7 +440,7 @@ static int find_repo(
bool in_dot_git; bool in_dot_git;
size_t ceiling_offset = 0; size_t ceiling_offset = 0;
git_buf_free(repo_path); git_buf_clear(gitdir_path);
error = git_path_prettify(&path, start_path, NULL); error = git_path_prettify(&path, start_path, NULL);
if (error < 0) if (error < 0)
...@@ -482,13 +482,13 @@ static int find_repo( ...@@ -482,13 +482,13 @@ static int find_repo(
if (S_ISDIR(st.st_mode)) { if (S_ISDIR(st.st_mode)) {
if (valid_repository_path(&path, &common_link)) { if (valid_repository_path(&path, &common_link)) {
git_path_to_dir(&path); git_path_to_dir(&path);
git_buf_set(repo_path, path.ptr, path.size); git_buf_set(gitdir_path, path.ptr, path.size);
if (link_path) if (gitlink_path)
git_buf_attach(link_path, git_buf_attach(gitlink_path,
git_worktree__read_link(path.ptr, GIT_GITDIR_FILE), 0); git_worktree__read_link(path.ptr, GIT_GITDIR_FILE), 0);
if (common_path) if (commondir_path)
git_buf_swap(&common_link, common_path); git_buf_swap(&common_link, commondir_path);
break; break;
} }
...@@ -498,12 +498,12 @@ static int find_repo( ...@@ -498,12 +498,12 @@ static int find_repo(
if (error < 0) if (error < 0)
break; break;
if (valid_repository_path(&repo_link, &common_link)) { if (valid_repository_path(&repo_link, &common_link)) {
git_buf_swap(repo_path, &repo_link); git_buf_swap(gitdir_path, &repo_link);
if (link_path) if (gitlink_path)
error = git_buf_put(link_path, path.ptr, path.size); error = git_buf_put(gitlink_path, path.ptr, path.size);
if (common_path) if (commondir_path)
git_buf_swap(&common_link, common_path); git_buf_swap(&common_link, commondir_path);
} }
break; break;
} }
...@@ -529,20 +529,20 @@ static int find_repo( ...@@ -529,20 +529,20 @@ static int find_repo(
break; break;
} }
if (!error && parent_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) { if (!error && workdir_path && !(flags & GIT_REPOSITORY_OPEN_BARE)) {
if (!git_buf_len(repo_path)) if (!git_buf_len(gitdir_path))
git_buf_clear(parent_path); git_buf_clear(workdir_path);
else { else {
git_path_dirname_r(parent_path, path.ptr); git_path_dirname_r(workdir_path, path.ptr);
git_path_to_dir(parent_path); git_path_to_dir(workdir_path);
} }
if (git_buf_oom(parent_path)) if (git_buf_oom(workdir_path))
return -1; return -1;
} }
/* If we didn't find the repository, and we don't have any other error /* If we didn't find the repository, and we don't have any other error
* to report, report that. */ * to report, report that. */
if (!git_buf_len(repo_path) && !error) { if (!git_buf_len(gitdir_path) && !error) {
giterr_set(GITERR_REPOSITORY, giterr_set(GITERR_REPOSITORY,
"could not find repository from '%s'", start_path); "could not find repository from '%s'", start_path);
error = GIT_ENOTFOUND; error = GIT_ENOTFOUND;
...@@ -758,6 +758,29 @@ success: ...@@ -758,6 +758,29 @@ success:
return error; return error;
} }
static int repo_is_worktree(unsigned *out, const git_repository *repo)
{
git_buf gitdir_link = GIT_BUF_INIT;
int error;
/* Worktrees cannot have the same commondir and gitdir */
if (repo->commondir && repo->gitdir
&& !strcmp(repo->commondir, repo->gitdir)) {
*out = 0;
return 0;
}
if ((error = git_buf_joinpath(&gitdir_link, repo->gitdir, "gitdir")) < 0)
return -1;
/* A 'gitdir' file inside a git directory is currently
* only used when the repository is a working tree. */
*out = !!git_path_exists(gitdir_link.ptr);
git_buf_free(&gitdir_link);
return error;
}
int git_repository_open_ext( int git_repository_open_ext(
git_repository **repo_ptr, git_repository **repo_ptr,
const char *start_path, const char *start_path,
...@@ -765,8 +788,9 @@ int git_repository_open_ext( ...@@ -765,8 +788,9 @@ int git_repository_open_ext(
const char *ceiling_dirs) const char *ceiling_dirs)
{ {
int error; int error;
git_buf path = GIT_BUF_INIT, parent = GIT_BUF_INIT, unsigned is_worktree;
link_path = GIT_BUF_INIT, common_path = GIT_BUF_INIT; git_buf gitdir = GIT_BUF_INIT, workdir = GIT_BUF_INIT,
gitlink = GIT_BUF_INIT, commondir = GIT_BUF_INIT;
git_repository *repo; git_repository *repo;
git_config *config = NULL; git_config *config = NULL;
...@@ -777,7 +801,7 @@ int git_repository_open_ext( ...@@ -777,7 +801,7 @@ int git_repository_open_ext(
*repo_ptr = NULL; *repo_ptr = NULL;
error = find_repo( error = find_repo(
&path, &parent, &link_path, &common_path, start_path, flags, ceiling_dirs); &gitdir, &workdir, &gitlink, &commondir, start_path, flags, ceiling_dirs);
if (error < 0 || !repo_ptr) if (error < 0 || !repo_ptr)
return error; return error;
...@@ -785,24 +809,21 @@ int git_repository_open_ext( ...@@ -785,24 +809,21 @@ int git_repository_open_ext(
repo = repository_alloc(); repo = repository_alloc();
GITERR_CHECK_ALLOC(repo); GITERR_CHECK_ALLOC(repo);
repo->gitdir = git_buf_detach(&path); repo->gitdir = git_buf_detach(&gitdir);
GITERR_CHECK_ALLOC(repo->gitdir); GITERR_CHECK_ALLOC(repo->gitdir);
if (link_path.size) { if (gitlink.size) {
repo->gitlink = git_buf_detach(&link_path); repo->gitlink = git_buf_detach(&gitlink);
GITERR_CHECK_ALLOC(repo->gitlink); GITERR_CHECK_ALLOC(repo->gitlink);
} }
if (common_path.size) { if (commondir.size) {
repo->commondir = git_buf_detach(&common_path); repo->commondir = git_buf_detach(&commondir);
GITERR_CHECK_ALLOC(repo->commondir); GITERR_CHECK_ALLOC(repo->commondir);
} }
if ((error = git_buf_joinpath(&path, repo->gitdir, "gitdir")) < 0) if ((error = repo_is_worktree(&is_worktree, repo)) < 0)
goto cleanup; goto cleanup;
/* A 'gitdir' file inside a git directory is currently repo->is_worktree = is_worktree;
* only used when the repository is a working tree. */
if (git_path_exists(path.ptr))
repo->is_worktree = 1;
/* /*
* We'd like to have the config, but git doesn't particularly * We'd like to have the config, but git doesn't particularly
...@@ -822,13 +843,13 @@ int git_repository_open_ext( ...@@ -822,13 +843,13 @@ int git_repository_open_ext(
if (config && if (config &&
((error = load_config_data(repo, config)) < 0 || ((error = load_config_data(repo, config)) < 0 ||
(error = load_workdir(repo, config, &parent)) < 0)) (error = load_workdir(repo, config, &workdir)) < 0))
goto cleanup; goto cleanup;
} }
cleanup: cleanup:
git_buf_free(&path); git_buf_free(&gitdir);
git_buf_free(&parent); git_buf_free(&workdir);
git_config_free(config); git_config_free(config);
if (error < 0) if (error < 0)
......
#include "clar_libgit2.h"
#include "submodule_helpers.h"
#include "path.h"
static git_repository *g_parent;
static git_repository *g_child;
static git_submodule *g_module;
void test_submodule_open__initialize(void)
{
g_parent = setup_fixture_submod2();
}
void test_submodule_open__cleanup(void)
{
git_submodule_free(g_module);
git_repository_free(g_child);
cl_git_sandbox_cleanup();
g_parent = NULL;
g_child = NULL;
g_module = NULL;
}
static void assert_sm_valid(git_repository *parent, git_repository *child, const char *sm_name)
{
git_buf expected = GIT_BUF_INIT, actual = GIT_BUF_INIT;
/* assert working directory */
cl_git_pass(git_buf_joinpath(&expected, git_repository_workdir(parent), sm_name));
cl_git_pass(git_path_prettify_dir(&expected, expected.ptr, NULL));
cl_git_pass(git_buf_sets(&actual, git_repository_workdir(child)));
cl_git_pass(git_path_prettify_dir(&actual, actual.ptr, NULL));
cl_assert_equal_s(expected.ptr, actual.ptr);
git_buf_clear(&expected);
git_buf_clear(&actual);
/* assert common directory */
cl_git_pass(git_buf_joinpath(&expected, git_repository_commondir(parent), "modules"));
cl_git_pass(git_buf_joinpath(&expected, expected.ptr, sm_name));
cl_git_pass(git_path_prettify_dir(&expected, expected.ptr, NULL));
cl_git_pass(git_buf_sets(&actual, git_repository_commondir(child)));
cl_git_pass(git_path_prettify_dir(&actual, actual.ptr, NULL));
cl_assert_equal_s(expected.ptr, actual.ptr);
/* assert git directory */
cl_git_pass(git_buf_sets(&actual, git_repository_path(child)));
cl_git_pass(git_path_prettify_dir(&actual, actual.ptr, NULL));
cl_assert_equal_s(expected.ptr, actual.ptr);
git_buf_free(&expected);
git_buf_free(&actual);
}
void test_submodule_open__opening_via_lookup_succeeds(void)
{
cl_git_pass(git_submodule_lookup(&g_module, g_parent, "sm_unchanged"));
cl_git_pass(git_submodule_open(&g_child, g_module));
assert_sm_valid(g_parent, g_child, "sm_unchanged");
}
void test_submodule_open__direct_open_succeeds(void)
{
git_buf path = GIT_BUF_INIT;
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_parent), "sm_unchanged"));
cl_git_pass(git_repository_open(&g_child, path.ptr));
assert_sm_valid(g_parent, g_child, "sm_unchanged");
git_buf_free(&path);
}
void test_submodule_open__direct_open_succeeds_for_broken_sm_with_gitdir(void)
{
git_buf path = GIT_BUF_INIT;
/*
* This is actually not a valid submodule, but we
* encountered at least one occasion where the gitdir
* file existed inside of a submodule's gitdir. As we are
* now able to open these submodules correctly, we still
* add a test for this.
*/
cl_git_mkfile("submod2/.git/modules/sm_unchanged/gitdir", ".git");
cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_parent), "sm_unchanged"));
cl_git_pass(git_repository_open(&g_child, path.ptr));
assert_sm_valid(g_parent, g_child, "sm_unchanged");
git_buf_free(&path);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment