Unverified Commit aaa48d06 by Edward Thomson Committed by GitHub

Merge pull request #5196 from pks-t/pks/config-include-onbranch

config: implement "onbranch" conditional
parents 4e20c7b1 722ba93f
......@@ -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)
......
#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"));
}
#include "clar_libgit2.h"
void test_config_snapshot__create_snapshot(void)
{
int32_t tmp;
git_config *cfg, *snapshot, *new_snapshot;
const char *filename = "config-ext-change";
static git_config *cfg;
static git_config *snapshot;
cl_git_mkfile(filename, "[old]\nvalue = 5\n");
void test_config_snapshot__cleanup(void)
{
git_config_free(cfg);
cfg = NULL;
git_config_free(snapshot);
snapshot = NULL;
}
cl_git_pass(git_config_open_ondisk(&cfg, filename));
void test_config_snapshot__create_snapshot(void)
{
int32_t i;
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_mkfile("config", "[old]\nvalue = 999\n");
cl_git_pass(git_config_snapshot(&new_snapshot, cfg));
/* Old snapshot should still have the old value */
cl_git_pass(git_config_get_int32(&i, snapshot, "old.value"));
cl_assert_equal_i(5, i);
/* New snapshot should see new value */
cl_git_pass(git_config_get_int32(&tmp, new_snapshot, "old.value"));
cl_assert_equal_i(999, tmp);
/* 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);
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");
int count;
cl_git_pass(git_config_open_ondisk(&cfg, filename));
count = 0;
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);
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));
git_config_free(cfg);
count = 0;
cl_git_pass(git_config_get_multivar_foreach(snapshot, "old.value", NULL, count_me, &count));
cl_git_pass(git_config_get_int32(&i, snapshot, "section.key"));
cl_assert_equal_i(i, 1);
cl_assert_equal_i(2, count);
/* Rewrite "included" config */
cl_git_mkfile("included", "[section]\nkey = 11\n");
git_config_free(snapshot);
/* 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"));
}
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