зеркало из https://github.com/microsoft/git.git
refspec: move refspec parsing logic into its own file
In preparation for performing a refactor on refspec related code, move the refspec parsing logic into its own file. Signed-off-by: Brandon Williams <bmwill@google.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Родитель
ccdcbd54c4
Коммит
ec0cb49655
1
Makefile
1
Makefile
|
@ -928,6 +928,7 @@ LIB_OBJS += refs/files-backend.o
|
|||
LIB_OBJS += refs/iterator.o
|
||||
LIB_OBJS += refs/packed-backend.o
|
||||
LIB_OBJS += refs/ref-cache.o
|
||||
LIB_OBJS += refspec.o
|
||||
LIB_OBJS += ref-filter.o
|
||||
LIB_OBJS += remote.o
|
||||
LIB_OBJS += replace-object.o
|
||||
|
|
1
branch.c
1
branch.c
|
@ -3,6 +3,7 @@
|
|||
#include "config.h"
|
||||
#include "branch.h"
|
||||
#include "refs.h"
|
||||
#include "refspec.h"
|
||||
#include "remote.h"
|
||||
#include "commit.h"
|
||||
#include "worktree.h"
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "parse-options.h"
|
||||
#include "fetch-pack.h"
|
||||
#include "refs.h"
|
||||
#include "refspec.h"
|
||||
#include "tree.h"
|
||||
#include "tree-walk.h"
|
||||
#include "unpack-trees.h"
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "cache.h"
|
||||
#include "config.h"
|
||||
#include "refs.h"
|
||||
#include "refspec.h"
|
||||
#include "commit.h"
|
||||
#include "object.h"
|
||||
#include "tag.h"
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "config.h"
|
||||
#include "repository.h"
|
||||
#include "refs.h"
|
||||
#include "refspec.h"
|
||||
#include "commit.h"
|
||||
#include "builtin.h"
|
||||
#include "string-list.h"
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "run-command.h"
|
||||
#include "diff.h"
|
||||
#include "refs.h"
|
||||
#include "refspec.h"
|
||||
#include "commit.h"
|
||||
#include "diffcore.h"
|
||||
#include "revision.h"
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "remote.h"
|
||||
#include "dir.h"
|
||||
#include "refs.h"
|
||||
#include "refspec.h"
|
||||
#include "revision.h"
|
||||
#include "submodule.h"
|
||||
#include "submodule-config.h"
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include "cache.h"
|
||||
#include "config.h"
|
||||
#include "refs.h"
|
||||
#include "refspec.h"
|
||||
#include "run-command.h"
|
||||
#include "builtin.h"
|
||||
#include "remote.h"
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "strbuf.h"
|
||||
#include "run-command.h"
|
||||
#include "refs.h"
|
||||
#include "refspec.h"
|
||||
#include "argv-array.h"
|
||||
|
||||
static const char * const builtin_remote_usage[] = {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "run-command.h"
|
||||
#include "remote.h"
|
||||
#include "refs.h"
|
||||
#include "refspec.h"
|
||||
#include "connect.h"
|
||||
#include "revision.h"
|
||||
#include "diffcore.h"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "cache.h"
|
||||
#include "remote.h"
|
||||
#include "refspec.h"
|
||||
#include "checkout.h"
|
||||
|
||||
struct tracking_name_data {
|
||||
|
|
|
@ -0,0 +1,167 @@
|
|||
#include "cache.h"
|
||||
#include "refs.h"
|
||||
#include "refspec.h"
|
||||
|
||||
static struct refspec s_tag_refspec = {
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
"refs/tags/*",
|
||||
"refs/tags/*"
|
||||
};
|
||||
|
||||
/* See TAG_REFSPEC for the string version */
|
||||
const struct refspec *tag_refspec = &s_tag_refspec;
|
||||
|
||||
static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
|
||||
{
|
||||
int i;
|
||||
struct refspec *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) {
|
||||
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:
|
||||
if (verify) {
|
||||
/*
|
||||
* nr_refspec must be greater than zero and i must be valid
|
||||
* since it is only possible to reach this point from within
|
||||
* the for loop above.
|
||||
*/
|
||||
free_refspec(i+1, rs);
|
||||
return NULL;
|
||||
}
|
||||
die("Invalid refspec '%s'", refspec[i]);
|
||||
}
|
||||
|
||||
int valid_fetch_refspec(const char *fetch_refspec_str)
|
||||
{
|
||||
struct refspec *refspec;
|
||||
|
||||
refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1);
|
||||
free_refspec(1, refspec);
|
||||
return !!refspec;
|
||||
}
|
||||
|
||||
struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec)
|
||||
{
|
||||
return parse_refspec_internal(nr_refspec, refspec, 1, 0);
|
||||
}
|
||||
|
||||
struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
|
||||
{
|
||||
return parse_refspec_internal(nr_refspec, refspec, 0, 0);
|
||||
}
|
||||
|
||||
void free_refspec(int nr_refspec, struct refspec *refspec)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!refspec)
|
||||
return;
|
||||
|
||||
for (i = 0; i < nr_refspec; i++) {
|
||||
free(refspec[i].src);
|
||||
free(refspec[i].dst);
|
||||
}
|
||||
free(refspec);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef REFSPEC_H
|
||||
#define REFSPEC_H
|
||||
|
||||
#define TAG_REFSPEC "refs/tags/*:refs/tags/*"
|
||||
extern const struct refspec *tag_refspec;
|
||||
|
||||
struct refspec {
|
||||
unsigned force : 1;
|
||||
unsigned pattern : 1;
|
||||
unsigned matching : 1;
|
||||
unsigned exact_sha1 : 1;
|
||||
|
||||
char *src;
|
||||
char *dst;
|
||||
};
|
||||
|
||||
int valid_fetch_refspec(const char *refspec);
|
||||
struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec);
|
||||
struct refspec *parse_push_refspec(int nr_refspec, const char **refspec);
|
||||
|
||||
void free_refspec(int nr_refspec, struct refspec *refspec);
|
||||
|
||||
#endif /* REFSPEC_H */
|
165
remote.c
165
remote.c
|
@ -2,6 +2,7 @@
|
|||
#include "config.h"
|
||||
#include "remote.h"
|
||||
#include "refs.h"
|
||||
#include "refspec.h"
|
||||
#include "commit.h"
|
||||
#include "diff.h"
|
||||
#include "revision.h"
|
||||
|
@ -13,18 +14,6 @@
|
|||
|
||||
enum map_direction { FROM_SRC, FROM_DST };
|
||||
|
||||
static struct refspec s_tag_refspec = {
|
||||
0,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
"refs/tags/*",
|
||||
"refs/tags/*"
|
||||
};
|
||||
|
||||
/* See TAG_REFSPEC for the string version */
|
||||
const struct refspec *tag_refspec = &s_tag_refspec;
|
||||
|
||||
struct counted_string {
|
||||
size_t len;
|
||||
const char *s;
|
||||
|
@ -499,158 +488,6 @@ static void read_config(void)
|
|||
alias_all_urls();
|
||||
}
|
||||
|
||||
static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
|
||||
{
|
||||
int i;
|
||||
struct refspec *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) {
|
||||
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:
|
||||
if (verify) {
|
||||
/*
|
||||
* nr_refspec must be greater than zero and i must be valid
|
||||
* since it is only possible to reach this point from within
|
||||
* the for loop above.
|
||||
*/
|
||||
free_refspec(i+1, rs);
|
||||
return NULL;
|
||||
}
|
||||
die("Invalid refspec '%s'", refspec[i]);
|
||||
}
|
||||
|
||||
int valid_fetch_refspec(const char *fetch_refspec_str)
|
||||
{
|
||||
struct refspec *refspec;
|
||||
|
||||
refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1);
|
||||
free_refspec(1, refspec);
|
||||
return !!refspec;
|
||||
}
|
||||
|
||||
struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec)
|
||||
{
|
||||
return parse_refspec_internal(nr_refspec, refspec, 1, 0);
|
||||
}
|
||||
|
||||
struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
|
||||
{
|
||||
return parse_refspec_internal(nr_refspec, refspec, 0, 0);
|
||||
}
|
||||
|
||||
void free_refspec(int nr_refspec, struct refspec *refspec)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!refspec)
|
||||
return;
|
||||
|
||||
for (i = 0; i < nr_refspec; i++) {
|
||||
free(refspec[i].src);
|
||||
free(refspec[i].dst);
|
||||
}
|
||||
free(refspec);
|
||||
}
|
||||
|
||||
static int valid_remote_nick(const char *name)
|
||||
{
|
||||
if (!name[0] || is_dot_or_dotdot(name))
|
||||
|
|
20
remote.h
20
remote.h
|
@ -68,18 +68,6 @@ int for_each_remote(each_remote_fn fn, void *priv);
|
|||
|
||||
int remote_has_url(struct remote *remote, const char *url);
|
||||
|
||||
struct refspec {
|
||||
unsigned force : 1;
|
||||
unsigned pattern : 1;
|
||||
unsigned matching : 1;
|
||||
unsigned exact_sha1 : 1;
|
||||
|
||||
char *src;
|
||||
char *dst;
|
||||
};
|
||||
|
||||
extern const struct refspec *tag_refspec;
|
||||
|
||||
struct ref {
|
||||
struct ref *next;
|
||||
struct object_id old_oid;
|
||||
|
@ -175,12 +163,6 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);
|
|||
*/
|
||||
struct ref *ref_remove_duplicates(struct ref *ref_map);
|
||||
|
||||
int valid_fetch_refspec(const char *refspec);
|
||||
struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec);
|
||||
extern struct refspec *parse_push_refspec(int nr_refspec, const char **refspec);
|
||||
|
||||
void free_refspec(int nr_refspec, struct refspec *refspec);
|
||||
|
||||
extern int query_refspecs(struct refspec *specs, int nr, struct refspec *query);
|
||||
char *apply_refspecs(struct refspec *refspecs, int nr_refspec,
|
||||
const char *name);
|
||||
|
@ -313,8 +295,6 @@ extern int parseopt_push_cas_option(const struct option *, const char *arg, int
|
|||
extern int is_empty_cas(const struct push_cas_option *);
|
||||
void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
|
||||
|
||||
#define TAG_REFSPEC "refs/tags/*:refs/tags/*"
|
||||
|
||||
void add_prune_tags_to_fetch_refspec(struct remote *remote);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "sigchain.h"
|
||||
#include "argv-array.h"
|
||||
#include "refs.h"
|
||||
#include "refspec.h"
|
||||
#include "transport-internal.h"
|
||||
#include "protocol.h"
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "bundle.h"
|
||||
#include "dir.h"
|
||||
#include "refs.h"
|
||||
#include "refspec.h"
|
||||
#include "branch.h"
|
||||
#include "url.h"
|
||||
#include "submodule.h"
|
||||
|
|
Загрузка…
Ссылка в новой задаче