Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support namespaced references again #4154

Merged
merged 2 commits into from Mar 6, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
61 changes: 35 additions & 26 deletions src/refdb_fs.c
Expand Up @@ -1433,48 +1433,50 @@ static void refdb_fs_backend__free(git_refdb_backend *_backend)
git__free(backend);
}

static int setup_namespace(git_buf *gitpath, git_repository *repo)
static char *setup_namespace(git_repository *repo, const char *in)
{
char *parts, *start, *end;
git_buf path = GIT_BUF_INIT;
char *parts, *start, *end, *out = NULL;

/* Not all repositories have a gitpath */
if (repo->gitdir == NULL)
return 0;
if (repo->commondir == NULL)
return 0;
if (!in)
goto done;

/* Load the path to the repo first */
git_buf_puts(gitpath, repo->gitdir);
git_buf_puts(&path, in);

/* if the repo is not namespaced, nothing else to do */
if (repo->namespace == NULL)
return 0;
if (repo->namespace == NULL) {
out = git_buf_detach(&path);
goto done;
}

parts = end = git__strdup(repo->namespace);
if (parts == NULL)
return -1;
goto done;

/*
* From `man gitnamespaces`:
* namespaces which include a / will expand to a hierarchy
* of namespaces; for example, GIT_NAMESPACE=foo/bar will store
* refs under refs/namespaces/foo/refs/namespaces/bar/
*/
while ((start = git__strsep(&end, "/")) != NULL) {
git_buf_printf(gitpath, "refs/namespaces/%s/", start);
}
while ((start = git__strsep(&end, "/")) != NULL)
git_buf_printf(&path, "refs/namespaces/%s/", start);

git_buf_printf(gitpath, "refs/namespaces/%s/refs", end);
git_buf_printf(&path, "refs/namespaces/%s/refs", end);
git__free(parts);

/* Make sure that the folder with the namespace exists */
if (git_futils_mkdir_relative(git_buf_cstr(gitpath), repo->commondir,
0777, GIT_MKDIR_PATH, NULL) < 0)
return -1;
if (git_futils_mkdir_relative(git_buf_cstr(&path), in, 0777,
GIT_MKDIR_PATH, NULL) < 0)
goto done;

/* Return root of the namespaced gitpath, i.e. without the trailing '/refs' */
git_buf_rtruncate_at_char(gitpath, '/');
return 0;
git_buf_rtruncate_at_char(&path, '/');
out = git_buf_detach(&path);

done:
git_buf_free(&path);
return out;
}

static int reflog_alloc(git_reflog **reflog, const char *name)
Expand Down Expand Up @@ -1979,12 +1981,19 @@ int git_refdb_backend_fs(

backend->repo = repository;

if (setup_namespace(&gitpath, repository) < 0)
goto fail;
if (repository->gitdir) {
backend->gitpath = setup_namespace(repository, repository->gitdir);

backend->gitpath = backend->commonpath = git_buf_detach(&gitpath);
if (repository->commondir)
backend->commonpath = git__strdup(repository->commondir);
if (backend->gitpath == NULL)
goto fail;
}

if (repository->commondir) {
backend->commonpath = setup_namespace(repository, repository->commondir);

if (backend->commonpath == NULL)
goto fail;
}

if (git_buf_joinpath(&gitpath, backend->commonpath, GIT_PACKEDREFS_FILE) < 0 ||
git_sortedcache_new(
Expand Down
36 changes: 36 additions & 0 deletions tests/refs/namespaces.c
@@ -0,0 +1,36 @@
#include "clar_libgit2.h"

#include "repository.h"

static git_repository *g_repo;

void test_refs_namespaces__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo");
}

void test_refs_namespaces__cleanup(void)
{
cl_git_sandbox_cleanup();
}

void test_refs_namespaces__get_and_set(void)
{
cl_assert_equal_s(NULL, git_repository_get_namespace(g_repo));

cl_git_pass(git_repository_set_namespace(g_repo, "namespace"));
cl_assert_equal_s("namespace", git_repository_get_namespace(g_repo));

cl_git_pass(git_repository_set_namespace(g_repo, NULL));
cl_assert_equal_s(NULL, git_repository_get_namespace(g_repo));
}

void test_refs_namespaces__namespace_doesnt_show_normal_refs(void)
{
static git_strarray ref_list;

cl_git_pass(git_repository_set_namespace(g_repo, "namespace"));
cl_git_pass(git_reference_list(&ref_list, g_repo));
cl_assert_equal_i(0, ref_list.count);
git_strarray_free(&ref_list);
}