summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2019-08-01 15:14:06 +0200
committerPatrick Steinhardt <ps@pks.im>2019-08-01 15:57:16 +0200
commit722ba93f6f813669ff9ea2359d3dfbbd662283fc (patch)
tree9058ff55a0226b87032b90b860186045c47c0795
parente208b1953853f27f2de23f429e9518480a2d51e2 (diff)
downloadlibgit2-722ba93f6f813669ff9ea2359d3dfbbd662283fc.tar.gz
config: implement "onbranch" conditional
With Git v2.23.0, the conditional include mechanism gained another new conditional "onbranch". As the name says, it will cause a file to be included if the "onbranch" pattern matches the currently checked out branch. Implement this new condition and add a bunch of tests.
-rw-r--r--src/config_file.c54
-rw-r--r--tests/config/conditionals.c40
2 files changed, 93 insertions, 1 deletions
diff --git a/src/config_file.c b/src/config_file.c
index 3e8e30cbd..849096d0f 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -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)
diff --git a/tests/config/conditionals.c b/tests/config/conditionals.c
index e2c74c1f5..5858782c1 100644
--- a/tests/config/conditionals.c
+++ b/tests/config/conditionals.c
@@ -1,6 +1,7 @@
#include "clar_libgit2.h"
#include "buffer.h"
#include "futils.h"
+#include "repository.h"
#ifdef GIT_WIN32
# define ROOT_PREFIX "C:"
@@ -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);
+}