summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCarlos Martín Nieto <cmn@dwim.me>2014-07-04 17:17:23 +0200
committerCarlos Martín Nieto <cmn@dwim.me>2014-07-04 18:00:20 +0200
commitf5287fa6c39762072e30140329c41e9f304d7c04 (patch)
treed207cbde4ff25dacc34c76cfffd704a029b51785 /src
parent9ed104a8fa9fc28bb29a0ff53c68094696e13aea (diff)
downloadlibgit2-f5287fa6c39762072e30140329c41e9f304d7c04.tar.gz
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.
Diffstat (limited to 'src')
-rw-r--r--src/refspec.c50
1 files changed, 32 insertions, 18 deletions
diff --git a/src/refspec.c b/src/refspec.c
index 48d34cd95..77c58c84e 100644
--- a/src/refspec.c
+++ b/src/refspec.c
@@ -181,30 +181,44 @@ int git_refspec_dst_matches(const git_refspec *refspec, const char *refname)
static int refspec_transform(
git_buf *out, const char *from, const char *to, const char *name)
{
- size_t to_len = to ? strlen(to) : 0;
- size_t from_len = from ? strlen(from) : 0;
- size_t name_len = name ? strlen(name) : 0;
+ const char *from_star, *to_star;
+ const char *name_slash, *from_slash;
+ size_t replacement_len, star_offset;
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
+ * the middle of the pattern, so we need to look at each bit
+ * individually.
+ */
+ from_star = strchr(from, '*');
+ to_star = strchr(to, '*');
- if (to_len > 0) {
- /* No '*' at the end of 'to' means that refspec is mapped to one
- * specific branch, so no actual transformation is needed.
- */
- if (out->ptr[to_len - 1] != '*')
- return 0;
- 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);
+
+ /* 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');
- if (from_len > 0) /* ignore trailing '*' from 'from' */
- from_len--;
- if (from_len > name_len)
- from_len = name_len;
+ replacement_len = (name_slash - name) - star_offset;
+ git_buf_put(out, name + star_offset, replacement_len);
- return git_buf_put(out, name + from_len, name_len - from_len);
+ return git_buf_puts(out, to_star + 1);
}
int git_refspec_transform(git_buf *out, const git_refspec *spec, const char *name)