mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-30 22:24:56 +00:00
refspec: support asterisks in the middle of a pattern
We used to assume a refspec would only have an asterisk in the middle of their respective pattern. This has not been a valid assumption for some time now with git. Instead of assuming where the asterisk is going to be, change the logic to treat each pattern as having two halves with a replacement bit in the middle, where the asterisk is.
This commit is contained in:
parent
9ed104a8fa
commit
f5287fa6c3
@ -181,30 +181,44 @@ int git_refspec_dst_matches(const git_refspec *refspec, const char *refname)
|
|||||||
static int refspec_transform(
|
static int refspec_transform(
|
||||||
git_buf *out, const char *from, const char *to, const char *name)
|
git_buf *out, const char *from, const char *to, const char *name)
|
||||||
{
|
{
|
||||||
size_t to_len = to ? strlen(to) : 0;
|
const char *from_star, *to_star;
|
||||||
size_t from_len = from ? strlen(from) : 0;
|
const char *name_slash, *from_slash;
|
||||||
size_t name_len = name ? strlen(name) : 0;
|
size_t replacement_len, star_offset;
|
||||||
|
|
||||||
git_buf_sanitize(out);
|
git_buf_sanitize(out);
|
||||||
|
git_buf_clear(out);
|
||||||
|
|
||||||
if (git_buf_set(out, to, to_len) < 0)
|
/*
|
||||||
return -1;
|
* There are two parts to each side of a refspec, the bit
|
||||||
|
* before the star and the bit after it. The star can be in
|
||||||
if (to_len > 0) {
|
* the middle of the pattern, so we need to look at each bit
|
||||||
/* No '*' at the end of 'to' means that refspec is mapped to one
|
* individually.
|
||||||
* specific branch, so no actual transformation is needed.
|
|
||||||
*/
|
*/
|
||||||
if (out->ptr[to_len - 1] != '*')
|
from_star = strchr(from, '*');
|
||||||
return 0;
|
to_star = strchr(to, '*');
|
||||||
git_buf_shorten(out, 1); /* remove trailing '*' copied from 'to' */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (from_len > 0) /* ignore trailing '*' from 'from' */
|
assert(from_star && to_star);
|
||||||
from_len--;
|
|
||||||
if (from_len > name_len)
|
|
||||||
from_len = name_len;
|
|
||||||
|
|
||||||
return git_buf_put(out, name + from_len, name_len - from_len);
|
/* star offset, both in 'from' and in 'name' */
|
||||||
|
star_offset = from_star - from;
|
||||||
|
|
||||||
|
/* the first half is copied over */
|
||||||
|
git_buf_put(out, to, to_star - to);
|
||||||
|
|
||||||
|
/* then we copy over the replacement, from the star's offset to the next slash in 'name' */
|
||||||
|
name_slash = strchr(name + star_offset, '/');
|
||||||
|
if (!name_slash)
|
||||||
|
name_slash = strrchr(name, '\0');
|
||||||
|
|
||||||
|
/* if there is no slash after the star in 'from', we want to copy everything over */
|
||||||
|
from_slash = strchr(from + star_offset, '/');
|
||||||
|
if (!from_slash)
|
||||||
|
name_slash = strrchr(name, '\0');
|
||||||
|
|
||||||
|
replacement_len = (name_slash - name) - star_offset;
|
||||||
|
git_buf_put(out, name + star_offset, replacement_len);
|
||||||
|
|
||||||
|
return git_buf_puts(out, to_star + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
int git_refspec_transform(git_buf *out, const git_refspec *spec, const char *name)
|
int git_refspec_transform(git_buf *out, const git_refspec *spec, const char *name)
|
||||||
|
@ -84,4 +84,27 @@ void test_network_refspecs__parsing(void)
|
|||||||
|
|
||||||
assert_refspec(GIT_DIRECTION_FETCH, "master", true);
|
assert_refspec(GIT_DIRECTION_FETCH, "master", true);
|
||||||
assert_refspec(GIT_DIRECTION_PUSH, "master", true);
|
assert_refspec(GIT_DIRECTION_PUSH, "master", true);
|
||||||
|
|
||||||
|
assert_refspec(GIT_DIRECTION_FETCH, "refs/pull/*/head:refs/remotes/origin/pr/*", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void assert_transform(const char *refspec, const char *name, const char *result)
|
||||||
|
{
|
||||||
|
git_refspec spec;
|
||||||
|
git_buf buf = GIT_BUF_INIT;
|
||||||
|
|
||||||
|
git_refspec__parse(&spec, refspec, true);
|
||||||
|
cl_git_pass(git_refspec_transform(&buf, &spec, name));
|
||||||
|
cl_assert_equal_s(result, buf.ptr);
|
||||||
|
|
||||||
|
git_buf_free(&buf);
|
||||||
|
git_refspec__free(&spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_network_refspecs__transform_mid_star(void)
|
||||||
|
{
|
||||||
|
assert_transform("refs/pull/*/head:refs/remotes/origin/pr/*", "refs/pull/23/head", "refs/remotes/origin/pr/23");
|
||||||
|
assert_transform("refs/heads/*:refs/remotes/origin/*", "refs/heads/master", "refs/remotes/origin/master");
|
||||||
|
assert_transform("refs/heads/*:refs/heads/*", "refs/heads/master", "refs/heads/master");
|
||||||
|
assert_transform("refs/*:refs/*", "refs/heads/master", "refs/heads/master");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user