Commit 863dabda by Vicent Marti

Merge pull request #2465 from libgit2/cmn/refspec-start-middle

Support refspecs with the asterisk in the middle
parents 356b891e 9fef46de
...@@ -32,3 +32,6 @@ v0.21 + 1 ...@@ -32,3 +32,6 @@ v0.21 + 1
* git_clone_into and git_clone_local_into have been removed from the * git_clone_into and git_clone_local_into have been removed from the
public API in favour of git_clone callbacks public API in favour of git_clone callbacks
* Add support for refspecs with the asterisk in the middle of a
pattern.
...@@ -181,39 +181,63 @@ int git_refspec_dst_matches(const git_refspec *refspec, const char *refname) ...@@ -181,39 +181,63 @@ 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' */
} assert(from_star && to_star);
/* 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);
if (from_len > 0) /* ignore trailing '*' from 'from' */ /* then we copy over the replacement, from the star's offset to the next slash in 'name' */
from_len--; name_slash = strchr(name + star_offset, '/');
if (from_len > name_len) if (!name_slash)
from_len = name_len; name_slash = strrchr(name, '\0');
return git_buf_put(out, name + from_len, name_len - from_len); /* 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)
{ {
git_buf_sanitize(out);
if (!spec->pattern)
return git_buf_puts(out, spec->dst);
return refspec_transform(out, spec->src, spec->dst, name); return refspec_transform(out, spec->src, spec->dst, name);
} }
int git_refspec_rtransform(git_buf *out, const git_refspec *spec, const char *name) int git_refspec_rtransform(git_buf *out, const git_refspec *spec, const char *name)
{ {
git_buf_sanitize(out);
if (!spec->pattern)
return git_buf_puts(out, spec->src);
return refspec_transform(out, spec->dst, spec->src, name); return refspec_transform(out, spec->dst, spec->src, name);
} }
......
...@@ -84,4 +84,27 @@ void test_network_refspecs__parsing(void) ...@@ -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");
} }
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