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:
Brandon Williams 2018-05-16 15:57:48 -07:00 коммит произвёл Junio C Hamano
Родитель ccdcbd54c4
Коммит ec0cb49655
17 изменённых файлов: 204 добавлений и 184 удалений

Просмотреть файл

@ -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

Просмотреть файл

@ -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 {

167
refspec.c Normal file
Просмотреть файл

@ -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);
}

23
refspec.h Normal file
Просмотреть файл

@ -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
Просмотреть файл

@ -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))

Просмотреть файл

@ -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"