refspec: factor out parsing a single refspec

Factor out the logic which parses a single refspec into its own
function.  This makes it easier to reuse this logic in a future patch.

Signed-off-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
Brandon Williams 2018-05-16 15:57:50 -07:00 committed by Junio C Hamano
parent 0ad4a5ff50
commit 3eec3700fd
1 changed files with 109 additions and 96 deletions

View File

@ -14,12 +14,12 @@ static struct refspec_item s_tag_refspec = {
/* See TAG_REFSPEC for the string version */ /* See TAG_REFSPEC for the string version */
const struct refspec_item *tag_refspec = &s_tag_refspec; const struct refspec_item *tag_refspec = &s_tag_refspec;


static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify) /*
* Parses the provided refspec 'refspec' and populates the refspec_item 'item'.
* Returns 1 if successful and 0 if the refspec is invalid.
*/
static int parse_refspec(struct refspec_item *item, const char *refspec, int fetch)
{ {
int i;
struct refspec_item *rs = xcalloc(nr_refspec, sizeof(*rs));

for (i = 0; i < nr_refspec; i++) {
size_t llen; size_t llen;
int is_glob; int is_glob;
const char *lhs, *rhs; const char *lhs, *rhs;
@ -27,9 +27,9 @@ static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **


is_glob = 0; is_glob = 0;


lhs = refspec[i]; lhs = refspec;
if (*lhs == '+') { if (*lhs == '+') {
rs[i].force = 1; item->force = 1;
lhs++; lhs++;
} }


@ -40,50 +40,50 @@ static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **
* for pushing matching refs. * for pushing matching refs.
*/ */
if (!fetch && rhs == lhs && rhs[1] == '\0') { if (!fetch && rhs == lhs && rhs[1] == '\0') {
rs[i].matching = 1; item->matching = 1;
continue; return 1;
} }


if (rhs) { if (rhs) {
size_t rlen = strlen(++rhs); size_t rlen = strlen(++rhs);
is_glob = (1 <= rlen && strchr(rhs, '*')); is_glob = (1 <= rlen && strchr(rhs, '*'));
rs[i].dst = xstrndup(rhs, rlen); item->dst = xstrndup(rhs, rlen);
} }


llen = (rhs ? (rhs - lhs - 1) : strlen(lhs)); llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
if (1 <= llen && memchr(lhs, '*', llen)) { if (1 <= llen && memchr(lhs, '*', llen)) {
if ((rhs && !is_glob) || (!rhs && fetch)) if ((rhs && !is_glob) || (!rhs && fetch))
goto invalid; return 0;
is_glob = 1; is_glob = 1;
} else if (rhs && is_glob) { } else if (rhs && is_glob) {
goto invalid; return 0;
} }


rs[i].pattern = is_glob; item->pattern = is_glob;
rs[i].src = xstrndup(lhs, llen); item->src = xstrndup(lhs, llen);
flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0); flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);


if (fetch) { if (fetch) {
struct object_id unused; struct object_id unused;


/* LHS */ /* LHS */
if (!*rs[i].src) if (!*item->src)
; /* empty is ok; it means "HEAD" */ ; /* empty is ok; it means "HEAD" */
else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(rs[i].src, &unused)) else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(item->src, &unused))
rs[i].exact_sha1 = 1; /* ok */ item->exact_sha1 = 1; /* ok */
else if (!check_refname_format(rs[i].src, flags)) else if (!check_refname_format(item->src, flags))
; /* valid looking ref is ok */ ; /* valid looking ref is ok */
else else
goto invalid; return 0;
/* RHS */ /* RHS */
if (!rs[i].dst) if (!item->dst)
; /* missing is ok; it is the same as empty */ ; /* missing is ok; it is the same as empty */
else if (!*rs[i].dst) else if (!*item->dst)
; /* empty is ok; it means "do not store" */ ; /* empty is ok; it means "do not store" */
else if (!check_refname_format(rs[i].dst, flags)) else if (!check_refname_format(item->dst, flags))
; /* valid looking ref is ok */ ; /* valid looking ref is ok */
else else
goto invalid; return 0;
} else { } else {
/* /*
* LHS * LHS
@ -92,11 +92,11 @@ static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **
* - otherwise, it must be an extended SHA-1, but * - otherwise, it must be an extended SHA-1, but
* there is no existing way to validate this. * there is no existing way to validate this.
*/ */
if (!*rs[i].src) if (!*item->src)
; /* empty is ok */ ; /* empty is ok */
else if (is_glob) { else if (is_glob) {
if (check_refname_format(rs[i].src, flags)) if (check_refname_format(item->src, flags))
goto invalid; return 0;
} }
else else
; /* anything goes, for now */ ; /* anything goes, for now */
@ -107,17 +107,30 @@ static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **
* - empty is not allowed. * - empty is not allowed.
* - otherwise it must be a valid looking ref. * - otherwise it must be a valid looking ref.
*/ */
if (!rs[i].dst) { if (!item->dst) {
if (check_refname_format(rs[i].src, flags)) if (check_refname_format(item->src, flags))
goto invalid; return 0;
} else if (!*rs[i].dst) { } else if (!*item->dst) {
goto invalid; return 0;
} else { } else {
if (check_refname_format(rs[i].dst, flags)) if (check_refname_format(item->dst, flags))
return 0;
}
}

return 1;
}

static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
{
int i;
struct refspec_item *rs = xcalloc(nr_refspec, sizeof(*rs));

for (i = 0; i < nr_refspec; i++) {
if (!parse_refspec(&rs[i], refspec[i], fetch))
goto invalid; goto invalid;
} }
}
}
return rs; return rs;


invalid: invalid: