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>
This commit is contained in:
parent
0ad4a5ff50
commit
3eec3700fd
205
refspec.c
205
refspec.c
@ -14,110 +14,123 @@ static struct refspec_item s_tag_refspec = {
|
||||
/* See TAG_REFSPEC for the string version */
|
||||
const struct refspec_item *tag_refspec = &s_tag_refspec;
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
size_t llen;
|
||||
int is_glob;
|
||||
const char *lhs, *rhs;
|
||||
int flags;
|
||||
|
||||
is_glob = 0;
|
||||
|
||||
lhs = refspec;
|
||||
if (*lhs == '+') {
|
||||
item->force = 1;
|
||||
lhs++;
|
||||
}
|
||||
|
||||
rhs = strrchr(lhs, ':');
|
||||
|
||||
/*
|
||||
* Before going on, special case ":" (or "+:") as a refspec
|
||||
* for pushing matching refs.
|
||||
*/
|
||||
if (!fetch && rhs == lhs && rhs[1] == '\0') {
|
||||
item->matching = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (rhs) {
|
||||
size_t rlen = strlen(++rhs);
|
||||
is_glob = (1 <= rlen && strchr(rhs, '*'));
|
||||
item->dst = xstrndup(rhs, rlen);
|
||||
}
|
||||
|
||||
llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
|
||||
if (1 <= llen && memchr(lhs, '*', llen)) {
|
||||
if ((rhs && !is_glob) || (!rhs && fetch))
|
||||
return 0;
|
||||
is_glob = 1;
|
||||
} else if (rhs && is_glob) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
item->pattern = is_glob;
|
||||
item->src = xstrndup(lhs, llen);
|
||||
flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
|
||||
|
||||
if (fetch) {
|
||||
struct object_id unused;
|
||||
|
||||
/* LHS */
|
||||
if (!*item->src)
|
||||
; /* empty is ok; it means "HEAD" */
|
||||
else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(item->src, &unused))
|
||||
item->exact_sha1 = 1; /* ok */
|
||||
else if (!check_refname_format(item->src, flags))
|
||||
; /* valid looking ref is ok */
|
||||
else
|
||||
return 0;
|
||||
/* RHS */
|
||||
if (!item->dst)
|
||||
; /* missing is ok; it is the same as empty */
|
||||
else if (!*item->dst)
|
||||
; /* empty is ok; it means "do not store" */
|
||||
else if (!check_refname_format(item->dst, flags))
|
||||
; /* valid looking ref is ok */
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
/*
|
||||
* LHS
|
||||
* - empty is allowed; it means delete.
|
||||
* - when wildcarded, it must be a valid looking ref.
|
||||
* - otherwise, it must be an extended SHA-1, but
|
||||
* there is no existing way to validate this.
|
||||
*/
|
||||
if (!*item->src)
|
||||
; /* empty is ok */
|
||||
else if (is_glob) {
|
||||
if (check_refname_format(item->src, flags))
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
; /* anything goes, for now */
|
||||
/*
|
||||
* RHS
|
||||
* - missing is allowed, but LHS then must be a
|
||||
* valid looking ref.
|
||||
* - empty is not allowed.
|
||||
* - otherwise it must be a valid looking ref.
|
||||
*/
|
||||
if (!item->dst) {
|
||||
if (check_refname_format(item->src, flags))
|
||||
return 0;
|
||||
} else if (!*item->dst) {
|
||||
return 0;
|
||||
} else {
|
||||
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++) {
|
||||
size_t llen;
|
||||
int is_glob;
|
||||
const char *lhs, *rhs;
|
||||
int flags;
|
||||
|
||||
is_glob = 0;
|
||||
|
||||
lhs = refspec[i];
|
||||
if (*lhs == '+') {
|
||||
rs[i].force = 1;
|
||||
lhs++;
|
||||
}
|
||||
|
||||
rhs = strrchr(lhs, ':');
|
||||
|
||||
/*
|
||||
* Before going on, special case ":" (or "+:") as a refspec
|
||||
* for pushing matching refs.
|
||||
*/
|
||||
if (!fetch && rhs == lhs && rhs[1] == '\0') {
|
||||
rs[i].matching = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (rhs) {
|
||||
size_t rlen = strlen(++rhs);
|
||||
is_glob = (1 <= rlen && strchr(rhs, '*'));
|
||||
rs[i].dst = xstrndup(rhs, rlen);
|
||||
}
|
||||
|
||||
llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
|
||||
if (1 <= llen && memchr(lhs, '*', llen)) {
|
||||
if ((rhs && !is_glob) || (!rhs && fetch))
|
||||
goto invalid;
|
||||
is_glob = 1;
|
||||
} else if (rhs && is_glob) {
|
||||
if (!parse_refspec(&rs[i], refspec[i], fetch))
|
||||
goto invalid;
|
||||
}
|
||||
|
||||
rs[i].pattern = is_glob;
|
||||
rs[i].src = xstrndup(lhs, llen);
|
||||
flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
|
||||
|
||||
if (fetch) {
|
||||
struct object_id unused;
|
||||
|
||||
/* LHS */
|
||||
if (!*rs[i].src)
|
||||
; /* empty is ok; it means "HEAD" */
|
||||
else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(rs[i].src, &unused))
|
||||
rs[i].exact_sha1 = 1; /* ok */
|
||||
else if (!check_refname_format(rs[i].src, flags))
|
||||
; /* valid looking ref is ok */
|
||||
else
|
||||
goto invalid;
|
||||
/* RHS */
|
||||
if (!rs[i].dst)
|
||||
; /* missing is ok; it is the same as empty */
|
||||
else if (!*rs[i].dst)
|
||||
; /* empty is ok; it means "do not store" */
|
||||
else if (!check_refname_format(rs[i].dst, flags))
|
||||
; /* valid looking ref is ok */
|
||||
else
|
||||
goto invalid;
|
||||
} else {
|
||||
/*
|
||||
* LHS
|
||||
* - empty is allowed; it means delete.
|
||||
* - when wildcarded, it must be a valid looking ref.
|
||||
* - otherwise, it must be an extended SHA-1, but
|
||||
* there is no existing way to validate this.
|
||||
*/
|
||||
if (!*rs[i].src)
|
||||
; /* empty is ok */
|
||||
else if (is_glob) {
|
||||
if (check_refname_format(rs[i].src, flags))
|
||||
goto invalid;
|
||||
}
|
||||
else
|
||||
; /* anything goes, for now */
|
||||
/*
|
||||
* RHS
|
||||
* - missing is allowed, but LHS then must be a
|
||||
* valid looking ref.
|
||||
* - empty is not allowed.
|
||||
* - otherwise it must be a valid looking ref.
|
||||
*/
|
||||
if (!rs[i].dst) {
|
||||
if (check_refname_format(rs[i].src, flags))
|
||||
goto invalid;
|
||||
} else if (!*rs[i].dst) {
|
||||
goto invalid;
|
||||
} else {
|
||||
if (check_refname_format(rs[i].dst, flags))
|
||||
goto invalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rs;
|
||||
|
||||
invalid:
|
||||
|
Loading…
Reference in New Issue
Block a user