@matheusbsbs / matheus-bagliano / commits / abd2bde78b
Fork 0

Support '*' in the middle of a refspec

In order to keep the requirements strict, each * has to be a full path component, and there may only be one * per side. This requirement is enforced entirely by check_ref_format(); the matching implementation will substitute the whatever matches the * in the lhs for the * in the rhs. Signed-off-by: Daniel Barkalow <barkalow@iabervon.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Daniel Barkalow committed Mar 7, 2009 at 01:11 UTC abd2bde78bd994166900290434a2048e660dabed
3 files changed +36 -11
refs.c
+7 -4
@@ -694,6 +694,7 @@ static inline int bad_ref_char(int ch)
694 int check_ref_format(const char *ref)
695 {
696 int ch, level, bad_type;
697 + int ret = CHECK_REF_FORMAT_OK;
698 const char *cp = ref;
699
700 level = 0;
@@ -709,9 +710,11 @@ int check_ref_format(const char *ref)
710 return CHECK_REF_FORMAT_ERROR;
711 bad_type = bad_ref_char(ch);
712 if (bad_type) {
712 - return (bad_type == 2 && !*cp)
713 - ? CHECK_REF_FORMAT_WILDCARD
714 - : CHECK_REF_FORMAT_ERROR;
713 + if (bad_type == 2 && (!*cp || *cp == '/') &&
714 + ret == CHECK_REF_FORMAT_OK)
715 + ret = CHECK_REF_FORMAT_WILDCARD;
716 + else
717 + return CHECK_REF_FORMAT_ERROR;
718 }
719
720 /* scan the rest of the path component */
@@ -729,7 +732,7 @@ int check_ref_format(const char *ref)
732 if (!ch) {
733 if (level < 2)
734 return CHECK_REF_FORMAT_ONELEVEL;
732 - return CHECK_REF_FORMAT_OK;
735 + return ret;
736 }
737 }
738 }
remote.c
+17 -7
@@ -511,12 +511,12 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
511
512 if (rhs) {
513 size_t rlen = strlen(++rhs);
514 - is_glob = (2 <= rlen && !strcmp(rhs + rlen - 2, "/*"));
514 + is_glob = (1 <= rlen && strchr(rhs, '*'));
515 rs[i].dst = xstrndup(rhs, rlen);
516 }
517
518 llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
519 - if (2 <= llen && !memcmp(lhs + llen - 2, "/*", 2)) {
519 + if (1 <= llen && memchr(lhs, '*', llen)) {
520 if ((rhs && !is_glob) || (!rhs && fetch))
521 goto invalid;
522 is_glob = 1;
@@ -718,22 +718,32 @@ static int match_name_with_pattern(const char *key, const char *name,
718 {
719 const char *kstar = strchr(key, '*');
720 size_t klen;
721 + size_t ksuffixlen;
722 + size_t namelen;
723 int ret;
724 if (!kstar)
725 die("Key '%s' of pattern had no '*'", key);
726 klen = kstar - key;
725 - ret = !strncmp(key, name, klen);
727 + ksuffixlen = strlen(kstar + 1);
728 + namelen = strlen(name);
729 + ret = !strncmp(name, key, klen) && namelen >= klen + ksuffixlen &&
730 + !memcmp(name + namelen - ksuffixlen, kstar + 1, ksuffixlen);
731 if (ret && value) {
732 const char *vstar = strchr(value, '*');
733 size_t vlen;
734 + size_t vsuffixlen;
735 if (!vstar)
736 die("Value '%s' of pattern has no '*'", value);
737 vlen = vstar - value;
732 - *result = xmalloc(vlen +
738 + vsuffixlen = strlen(vstar + 1);
739 + *result = xmalloc(vlen + vsuffixlen +
740 strlen(name) -
734 - klen + 1);
735 - strcpy(*result, value);
736 - strcpy(*result + vlen, name + klen);
741 + klen - ksuffixlen + 1);
742 + strncpy(*result, value, vlen);
743 + strncpy(*result + vlen,
744 + name + klen, namelen - klen - ksuffixlen);
745 + strcpy(*result + vlen + namelen - klen - ksuffixlen,
746 + vstar + 1);
747 }
748 return ret;
749 }
t/t5511-refspec.sh
+12
@@ -72,4 +72,16 @@ test_refspec fetch ':refs/remotes/frotz/HEAD-to-me'
72 test_refspec push ':refs/remotes/frotz/delete me' invalid
73 test_refspec fetch ':refs/remotes/frotz/HEAD to me' invalid
74
75 +test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid
76 +test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*-blah' invalid
77 +
78 +test_refspec fetch 'refs/heads*/for-linus:refs/remotes/mine/*' invalid
79 +test_refspec push 'refs/heads*/for-linus:refs/remotes/mine/*' invalid
80 +
81 +test_refspec fetch 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid
82 +test_refspec push 'refs/heads/*/*/for-linus:refs/remotes/mine/*' invalid
83 +
84 +test_refspec fetch 'refs/heads/*/for-linus:refs/remotes/mine/*'
85 +test_refspec push 'refs/heads/*/for-linus:refs/remotes/mine/*'
86 +
87 test_done