mirror of
https://github.com/libgit2/libgit2.git
synced 2026-01-25 11:06:32 +00:00
Merge pull request #5196 from pks-t/pks/config-include-onbranch
config: implement "onbranch" conditional
This commit is contained in:
@@ -651,12 +651,64 @@ static int conditional_match_gitdir_i(
|
||||
return do_match_gitdir(matches, repo, cfg_file, value, true);
|
||||
}
|
||||
|
||||
static int conditional_match_onbranch(
|
||||
int *matches,
|
||||
const git_repository *repo,
|
||||
const char *cfg_file,
|
||||
const char *condition)
|
||||
{
|
||||
git_buf reference = GIT_BUF_INIT, buf = GIT_BUF_INIT;
|
||||
int error;
|
||||
|
||||
GIT_UNUSED(cfg_file);
|
||||
|
||||
/*
|
||||
* NOTE: you cannot use `git_repository_head` here. Looking up the
|
||||
* HEAD reference will create the ODB, which causes us to read the
|
||||
* repo's config for keys like core.precomposeUnicode. As we're
|
||||
* just parsing the config right now, though, this would result in
|
||||
* an endless recursion.
|
||||
*/
|
||||
|
||||
if ((error = git_buf_joinpath(&buf, git_repository_path(repo), GIT_HEAD_FILE)) < 0 ||
|
||||
(error = git_futils_readbuffer(&reference, buf.ptr)) < 0)
|
||||
goto out;
|
||||
git_buf_rtrim(&reference);
|
||||
|
||||
if (git__strncmp(reference.ptr, GIT_SYMREF, strlen(GIT_SYMREF)))
|
||||
goto out;
|
||||
git_buf_consume(&reference, reference.ptr + strlen(GIT_SYMREF));
|
||||
|
||||
if (git__strncmp(reference.ptr, GIT_REFS_HEADS_DIR, strlen(GIT_REFS_HEADS_DIR)))
|
||||
goto out;
|
||||
git_buf_consume(&reference, reference.ptr + strlen(GIT_REFS_HEADS_DIR));
|
||||
|
||||
/*
|
||||
* If the condition ends with a '/', then we should treat it as if
|
||||
* it had '**' appended.
|
||||
*/
|
||||
if ((error = git_buf_sets(&buf, condition)) < 0)
|
||||
goto out;
|
||||
if (git_path_is_dirsep(condition[strlen(condition) - 1]) &&
|
||||
(error = git_buf_puts(&buf, "**")) < 0)
|
||||
goto out;
|
||||
|
||||
*matches = wildmatch(buf.ptr, reference.ptr, WM_PATHNAME) == WM_MATCH;
|
||||
out:
|
||||
git_buf_dispose(&reference);
|
||||
git_buf_dispose(&buf);
|
||||
|
||||
return error;
|
||||
|
||||
}
|
||||
|
||||
static const struct {
|
||||
const char *prefix;
|
||||
int (*matches)(int *matches, const git_repository *repo, const char *cfg, const char *value);
|
||||
} conditions[] = {
|
||||
{ "gitdir:", conditional_match_gitdir },
|
||||
{ "gitdir/i:", conditional_match_gitdir_i }
|
||||
{ "gitdir/i:", conditional_match_gitdir_i },
|
||||
{ "onbranch:", conditional_match_onbranch }
|
||||
};
|
||||
|
||||
static int parse_conditional_include(config_file_parse_data *parse_data, const char *section, const char *file)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "clar_libgit2.h"
|
||||
#include "buffer.h"
|
||||
#include "futils.h"
|
||||
#include "repository.h"
|
||||
|
||||
#ifdef GIT_WIN32
|
||||
# define ROOT_PREFIX "C:"
|
||||
@@ -22,11 +23,11 @@ void test_config_conditionals__cleanup(void)
|
||||
|
||||
static void assert_condition_includes(const char *keyword, const char *path, bool expected)
|
||||
{
|
||||
git_config *cfg;
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
git_config *cfg;
|
||||
|
||||
git_buf_printf(&buf, "[includeIf \"%s:%s\"]\n", keyword, path);
|
||||
git_buf_puts(&buf, "path = other\n");
|
||||
cl_git_pass(git_buf_printf(&buf, "[includeIf \"%s:%s\"]\n", keyword, path));
|
||||
cl_git_pass(git_buf_puts(&buf, "path = other\n"));
|
||||
|
||||
cl_git_mkfile("empty_standard_repo/.git/config", buf.ptr);
|
||||
cl_git_mkfile("empty_standard_repo/.git/other", "[foo]\nbar=baz\n");
|
||||
@@ -106,3 +107,42 @@ void test_config_conditionals__invalid_conditional_fails(void)
|
||||
{
|
||||
assert_condition_includes("foobar", ".git", false);
|
||||
}
|
||||
|
||||
static void set_head(git_repository *repo, const char *name)
|
||||
{
|
||||
cl_git_pass(git_repository_create_head(git_repository_path(repo), name));
|
||||
}
|
||||
|
||||
void test_config_conditionals__onbranch(void)
|
||||
{
|
||||
assert_condition_includes("onbranch", "master", true);
|
||||
assert_condition_includes("onbranch", "m*", true);
|
||||
assert_condition_includes("onbranch", "*", true);
|
||||
assert_condition_includes("onbranch", "master/", false);
|
||||
assert_condition_includes("onbranch", "foo", false);
|
||||
|
||||
set_head(_repo, "foo");
|
||||
assert_condition_includes("onbranch", "master", false);
|
||||
assert_condition_includes("onbranch", "foo", true);
|
||||
assert_condition_includes("onbranch", "f*o", true);
|
||||
|
||||
set_head(_repo, "dir/ref");
|
||||
assert_condition_includes("onbranch", "dir/ref", true);
|
||||
assert_condition_includes("onbranch", "dir/", true);
|
||||
assert_condition_includes("onbranch", "dir/*", true);
|
||||
assert_condition_includes("onbranch", "dir/**", true);
|
||||
assert_condition_includes("onbranch", "**", true);
|
||||
assert_condition_includes("onbranch", "dir", false);
|
||||
assert_condition_includes("onbranch", "dir*", false);
|
||||
|
||||
set_head(_repo, "dir/subdir/ref");
|
||||
assert_condition_includes("onbranch", "dir/subdir/", true);
|
||||
assert_condition_includes("onbranch", "dir/subdir/*", true);
|
||||
assert_condition_includes("onbranch", "dir/subdir/ref", true);
|
||||
assert_condition_includes("onbranch", "dir/", true);
|
||||
assert_condition_includes("onbranch", "dir/**", true);
|
||||
assert_condition_includes("onbranch", "**", true);
|
||||
assert_condition_includes("onbranch", "dir", false);
|
||||
assert_condition_includes("onbranch", "dir*", false);
|
||||
assert_condition_includes("onbranch", "dir/*", false);
|
||||
}
|
||||
|
||||
@@ -202,3 +202,33 @@ void test_config_include__included_variables_cannot_be_modified(void)
|
||||
cl_git_pass(p_unlink("top-level"));
|
||||
cl_git_pass(p_unlink("included"));
|
||||
}
|
||||
|
||||
void test_config_include__variables_in_included_override_including(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
cl_git_mkfile("top-level", "[foo]\nbar = 1\n[include]\npath = included");
|
||||
cl_git_mkfile("included", "[foo]\nbar = 2");
|
||||
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, "top-level"));
|
||||
cl_git_pass(git_config_get_int32(&i, cfg, "foo.bar"));
|
||||
cl_assert_equal_i(i, 2);
|
||||
|
||||
cl_git_pass(p_unlink("top-level"));
|
||||
cl_git_pass(p_unlink("included"));
|
||||
}
|
||||
|
||||
void test_config_include__variables_in_including_override_included(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
cl_git_mkfile("top-level", "[include]\npath = included\n[foo]\nbar = 1");
|
||||
cl_git_mkfile("included", "[foo]\nbar = 2");
|
||||
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, "top-level"));
|
||||
cl_git_pass(git_config_get_int32(&i, cfg, "foo.bar"));
|
||||
cl_assert_equal_i(i, 1);
|
||||
|
||||
cl_git_pass(p_unlink("top-level"));
|
||||
cl_git_pass(p_unlink("included"));
|
||||
}
|
||||
|
||||
@@ -1,45 +1,49 @@
|
||||
#include "clar_libgit2.h"
|
||||
|
||||
static git_config *cfg;
|
||||
static git_config *snapshot;
|
||||
|
||||
void test_config_snapshot__cleanup(void)
|
||||
{
|
||||
git_config_free(cfg);
|
||||
cfg = NULL;
|
||||
git_config_free(snapshot);
|
||||
snapshot = NULL;
|
||||
}
|
||||
|
||||
void test_config_snapshot__create_snapshot(void)
|
||||
{
|
||||
int32_t tmp;
|
||||
git_config *cfg, *snapshot, *new_snapshot;
|
||||
const char *filename = "config-ext-change";
|
||||
int32_t i;
|
||||
|
||||
cl_git_mkfile(filename, "[old]\nvalue = 5\n");
|
||||
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, filename));
|
||||
|
||||
cl_git_pass(git_config_get_int32(&tmp, cfg, "old.value"));
|
||||
cl_assert_equal_i(5, tmp);
|
||||
cl_git_mkfile("config", "[old]\nvalue = 5\n");
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, "config"));
|
||||
cl_git_pass(git_config_get_int32(&i, cfg, "old.value"));
|
||||
cl_assert_equal_i(5, i);
|
||||
|
||||
cl_git_pass(git_config_snapshot(&snapshot, cfg));
|
||||
|
||||
/* Change the value on the file itself (simulate external process) */
|
||||
cl_git_mkfile(filename, "[old]\nvalue = 56\n");
|
||||
cl_git_mkfile("config", "[old]\nvalue = 56\n");
|
||||
|
||||
cl_git_pass(git_config_get_int32(&tmp, cfg, "old.value"));
|
||||
cl_assert_equal_i(56, tmp);
|
||||
|
||||
cl_git_pass(git_config_get_int32(&tmp, snapshot, "old.value"));
|
||||
cl_assert_equal_i(5, tmp);
|
||||
cl_git_pass(git_config_get_int32(&i, cfg, "old.value"));
|
||||
cl_assert_equal_i(56, i);
|
||||
cl_git_pass(git_config_get_int32(&i, snapshot, "old.value"));
|
||||
cl_assert_equal_i(5, i);
|
||||
|
||||
/* Change the value on the file itself (simulate external process) */
|
||||
cl_git_mkfile(filename, "[old]\nvalue = 999\n");
|
||||
|
||||
cl_git_pass(git_config_snapshot(&new_snapshot, cfg));
|
||||
|
||||
/* New snapshot should see new value */
|
||||
cl_git_pass(git_config_get_int32(&tmp, new_snapshot, "old.value"));
|
||||
cl_assert_equal_i(999, tmp);
|
||||
cl_git_mkfile("config", "[old]\nvalue = 999\n");
|
||||
|
||||
/* Old snapshot should still have the old value */
|
||||
cl_git_pass(git_config_get_int32(&tmp, snapshot, "old.value"));
|
||||
cl_assert_equal_i(5, tmp);
|
||||
|
||||
git_config_free(new_snapshot);
|
||||
cl_git_pass(git_config_get_int32(&i, snapshot, "old.value"));
|
||||
cl_assert_equal_i(5, i);
|
||||
|
||||
/* New snapshot should see new value */
|
||||
git_config_free(snapshot);
|
||||
git_config_free(cfg);
|
||||
cl_git_pass(git_config_snapshot(&snapshot, cfg));
|
||||
cl_git_pass(git_config_get_int32(&i, snapshot, "old.value"));
|
||||
cl_assert_equal_i(999, i);
|
||||
|
||||
cl_git_pass(p_unlink("config"));
|
||||
}
|
||||
|
||||
static int count_me(const git_config_entry *entry, void *payload)
|
||||
@@ -55,24 +59,44 @@ static int count_me(const git_config_entry *entry, void *payload)
|
||||
|
||||
void test_config_snapshot__multivar(void)
|
||||
{
|
||||
int count = 0;
|
||||
git_config *cfg, *snapshot;
|
||||
const char *filename = "config-file";
|
||||
|
||||
cl_git_mkfile(filename, "[old]\nvalue = 5\nvalue = 6\n");
|
||||
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, filename));
|
||||
cl_git_pass(git_config_get_multivar_foreach(cfg, "old.value", NULL, count_me, &count));
|
||||
|
||||
cl_assert_equal_i(2, count);
|
||||
|
||||
cl_git_pass(git_config_snapshot(&snapshot, cfg));
|
||||
git_config_free(cfg);
|
||||
int count;
|
||||
|
||||
count = 0;
|
||||
cl_git_pass(git_config_get_multivar_foreach(snapshot, "old.value", NULL, count_me, &count));
|
||||
|
||||
cl_git_mkfile("config", "[old]\nvalue = 5\nvalue = 6\n");
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, "config"));
|
||||
cl_git_pass(git_config_get_multivar_foreach(cfg, "old.value", NULL, count_me, &count));
|
||||
cl_assert_equal_i(2, count);
|
||||
|
||||
git_config_free(snapshot);
|
||||
count = 0;
|
||||
cl_git_pass(git_config_snapshot(&snapshot, cfg));
|
||||
cl_git_pass(git_config_get_multivar_foreach(snapshot, "old.value", NULL, count_me, &count));
|
||||
cl_assert_equal_i(2, count);
|
||||
|
||||
cl_git_pass(p_unlink("config"));
|
||||
}
|
||||
|
||||
void test_config_snapshot__includes(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
cl_git_mkfile("including", "[include]\npath = included");
|
||||
cl_git_mkfile("included", "[section]\nkey = 1\n");
|
||||
|
||||
cl_git_pass(git_config_open_ondisk(&cfg, "including"));
|
||||
cl_git_pass(git_config_snapshot(&snapshot, cfg));
|
||||
|
||||
cl_git_pass(git_config_get_int32(&i, snapshot, "section.key"));
|
||||
cl_assert_equal_i(i, 1);
|
||||
|
||||
/* Rewrite "included" config */
|
||||
cl_git_mkfile("included", "[section]\nkey = 11\n");
|
||||
|
||||
/* Assert that the live config changed, but snapshot remained the same */
|
||||
cl_git_pass(git_config_get_int32(&i, cfg, "section.key"));
|
||||
cl_assert_equal_i(i, 11);
|
||||
cl_git_pass(git_config_get_int32(&i, snapshot, "section.key"));
|
||||
cl_assert_equal_i(i, 1);
|
||||
|
||||
cl_git_pass(p_unlink("including"));
|
||||
cl_git_pass(p_unlink("included"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user