Commit 51214b85 by Patrick Steinhardt

refs: loosen restriction on wildcard "*" refspecs

In commit cd377f45c9 (refs: loosen restriction on wildcard "*"
refspecs, 2015-07-22) in git.git, the restrictions on wildcard
"*" refspecs has been loosened. While wildcards were previously
only allowed if the component is a single "*", this was changed
to also accept other patterns as part of the component.

We never adapted to that change and still reject any wildcard
patterns that aren't a single "*" only. Update our tests to
reflect the upstream change and adjust our own code accordingly.
parent 9d651e05
......@@ -897,14 +897,13 @@ static int is_valid_ref_char(char ch)
case '\\':
case '?':
case '[':
case '*':
return 0;
default:
return 1;
}
}
static int ensure_segment_validity(const char *name)
static int ensure_segment_validity(const char *name, char may_contain_glob)
{
const char *current = name;
char prev = '\0';
......@@ -927,6 +926,12 @@ static int ensure_segment_validity(const char *name)
if (prev == '@' && *current == '{')
return -1; /* Refname contains "@{" */
if (*current == '*') {
if (!may_contain_glob)
return -1;
may_contain_glob = 0;
}
prev = *current;
}
......@@ -1005,19 +1010,20 @@ int git_reference__normalize_name(
}
while (true) {
segment_len = ensure_segment_validity(current);
if (segment_len < 0) {
if ((process_flags & GIT_REFERENCE_FORMAT_REFSPEC_PATTERN) &&
current[0] == '*' &&
(current[1] == '\0' || current[1] == '/')) {
/* Accept one wildcard as a full refname component. */
process_flags &= ~GIT_REFERENCE_FORMAT_REFSPEC_PATTERN;
segment_len = 1;
} else
goto cleanup;
}
char may_contain_glob = process_flags & GIT_REFERENCE_FORMAT_REFSPEC_PATTERN;
segment_len = ensure_segment_validity(current, may_contain_glob);
if (segment_len < 0)
goto cleanup;
if (segment_len > 0) {
/*
* There may only be one glob in a pattern, thus we reset
* the pattern-flag in case the current segment has one.
*/
if (memchr(current, '*', segment_len))
process_flags &= ~GIT_REFERENCE_FORMAT_REFSPEC_PATTERN;
if (normalize) {
size_t cur_len = git_buf_len(buf);
......
......@@ -70,15 +70,18 @@ void test_network_refspecs__parsing(void)
assert_refspec(GIT_DIRECTION_PUSH, ":refs/remotes/frotz/delete me", false);
assert_refspec(GIT_DIRECTION_FETCH, ":refs/remotes/frotz/HEAD to me", false);
assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*/for-linus:refs/remotes/mine/*-blah", false);
assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*/for-linus:refs/remotes/mine/*-blah", false);
assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*/for-linus:refs/remotes/mine/*-blah", true);
assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*/for-linus:refs/remotes/mine/*-blah", true);
assert_refspec(GIT_DIRECTION_FETCH, "refs/heads*/for-linus:refs/remotes/mine/*", false);
assert_refspec(GIT_DIRECTION_PUSH, "refs/heads*/for-linus:refs/remotes/mine/*", false);
assert_refspec(GIT_DIRECTION_FETCH, "refs/heads*/for-linus:refs/remotes/mine/*", true);
assert_refspec(GIT_DIRECTION_PUSH, "refs/heads*/for-linus:refs/remotes/mine/*", true);
assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*/*/for-linus:refs/remotes/mine/*", false);
assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*/*/for-linus:refs/remotes/mine/*", false);
assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*g*/for-linus:refs/remotes/mine/*", false);
assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*g*/for-linus:refs/remotes/mine/*", false);
assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*/for-linus:refs/remotes/mine/*", true);
assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*/for-linus:refs/remotes/mine/*", true);
......@@ -111,6 +114,12 @@ void test_network_refspecs__transform_mid_star(void)
assert_valid_transform("refs/*:refs/*", "refs/heads/master", "refs/heads/master");
}
void test_network_refspecs__transform_loosened_star(void)
{
assert_valid_transform("refs/heads/branch-*:refs/remotes/origin/branch-*", "refs/heads/branch-a", "refs/remotes/origin/branch-a");
assert_valid_transform("refs/heads/branch-*/head:refs/remotes/origin/branch-*/head", "refs/heads/branch-a/head", "refs/remotes/origin/branch-a/head");
}
void test_network_refspecs__no_dst(void)
{
assert_valid_transform("refs/heads/master:", "refs/heads/master", "");
......
......@@ -352,12 +352,12 @@ void test_refs_normalize__buffer_has_to_be_big_enough_to_hold_the_normalized_ver
void test_refs_normalize__refspec_pattern(void)
{
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/*foo/bar");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/foo*/bar");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/f*o/bar");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/*foo/bar", "heads/*foo/bar");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/foo*/bar", "heads/foo*/bar");
ensure_refname_normalized(
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "heads/f*o/bar", "heads/f*o/bar");
ensure_refname_invalid(
GIT_REFERENCE_FORMAT_REFSPEC_PATTERN, "foo");
......
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