From ec0cb496553ac82f97205a415ca77618406b30e3 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 16 May 2018 15:57:48 -0700 Subject: 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 Signed-off-by: Junio C Hamano --- refspec.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 refspec.c (limited to 'refspec.c') diff --git a/refspec.c b/refspec.c new file mode 100644 index 0000000000..50892f864c --- /dev/null +++ b/refspec.c @@ -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); +} -- cgit v1.2.3 From 0ad4a5ff50dbc839ae26aa60c03b55bf416b6000 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 16 May 2018 15:57:49 -0700 Subject: refspec: rename struct refspec to struct refspec_item In preparation for introducing an abstraction around a collection of refspecs (much like how a 'struct pathspec' is a collection of 'struct pathspec_item's) rename the existing 'struct refspec' to 'struct refspec_item'. Signed-off-by: Brandon Williams Signed-off-by: Junio C Hamano --- branch.c | 6 +++--- builtin/clone.c | 4 ++-- builtin/fast-export.c | 4 ++-- builtin/fetch.c | 12 +++++------ builtin/pull.c | 2 +- builtin/push.c | 4 ++-- builtin/remote.c | 8 ++++---- builtin/submodule--helper.c | 4 ++-- checkout.c | 4 ++-- refspec.c | 16 +++++++-------- refspec.h | 10 ++++----- remote.c | 50 ++++++++++++++++++++++----------------------- remote.h | 16 +++++++-------- transport-helper.c | 2 +- transport.c | 4 ++-- 15 files changed, 73 insertions(+), 73 deletions(-) (limited to 'refspec.c') diff --git a/branch.c b/branch.c index 32ccefc6b5..f967c98f63 100644 --- a/branch.c +++ b/branch.c @@ -9,7 +9,7 @@ #include "worktree.h" struct tracking { - struct refspec spec; + struct refspec_item spec; char *src; const char *remote; int matches; @@ -219,8 +219,8 @@ int validate_new_branchname(const char *name, struct strbuf *ref, int force) static int check_tracking_branch(struct remote *remote, void *cb_data) { char *tracking_branch = cb_data; - struct refspec query; - memset(&query, 0, sizeof(struct refspec)); + struct refspec_item query; + memset(&query, 0, sizeof(struct refspec_item)); query.dst = tracking_branch; return !remote_find_tracking(remote, &query); } diff --git a/builtin/clone.c b/builtin/clone.c index 6d1614ed37..854088a3a2 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -547,7 +547,7 @@ static struct ref *find_remote_branch(const struct ref *refs, const char *branch } static struct ref *wanted_peer_refs(const struct ref *refs, - struct refspec *refspec) + struct refspec_item *refspec) { struct ref *head = copy_ref(find_ref_by_name(refs, "HEAD")); struct ref *local_refs = head; @@ -895,7 +895,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix) int err = 0, complete_refs_before_fetch = 1; int submodule_progress; - struct refspec *refspec; + struct refspec_item *refspec; const char *fetch_pattern; fetch_if_missing = 0; diff --git a/builtin/fast-export.c b/builtin/fast-export.c index a13b7c8ef3..6f105dc798 100644 --- a/builtin/fast-export.c +++ b/builtin/fast-export.c @@ -36,7 +36,7 @@ static int use_done_feature; static int no_data; static int full_tree; static struct string_list extra_refs = STRING_LIST_INIT_NODUP; -static struct refspec *refspecs; +static struct refspec_item *refspecs; static int refspecs_nr; static int anonymize; @@ -979,7 +979,7 @@ static void handle_deletes(void) { int i; for (i = 0; i < refspecs_nr; i++) { - struct refspec *refspec = &refspecs[i]; + struct refspec_item *refspec = &refspecs[i]; if (*refspec->src) continue; diff --git a/builtin/fetch.c b/builtin/fetch.c index 1fce68e9ac..745020a108 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -203,7 +203,7 @@ static void add_merge_config(struct ref **head, for (i = 0; i < branch->merge_nr; i++) { struct ref *rm, **old_tail = *tail; - struct refspec refspec; + struct refspec_item refspec; for (rm = *head; rm; rm = rm->next) { if (branch_merge_matches(branch, i, rm->name)) { @@ -340,7 +340,7 @@ static void find_non_local_tags(struct transport *transport, } static struct ref *get_ref_map(struct transport *transport, - struct refspec *refspecs, int refspec_count, + struct refspec_item *refspecs, int refspec_count, int tags, int *autotags) { int i; @@ -371,7 +371,7 @@ static struct ref *get_ref_map(struct transport *transport, argv_array_clear(&ref_prefixes); if (refspec_count) { - struct refspec *fetch_refspec; + struct refspec_item *fetch_refspec; int fetch_refspec_nr; for (i = 0; i < refspec_count; i++) { @@ -965,7 +965,7 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map) return ret; } -static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map, +static int prune_refs(struct refspec_item *refs, int ref_count, struct ref *ref_map, const char *raw_url) { int url_len, i, result = 0; @@ -1115,7 +1115,7 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map) } static int do_fetch(struct transport *transport, - struct refspec *refs, int ref_count) + struct refspec_item *refs, int ref_count) { struct string_list existing_refs = STRING_LIST_INIT_DUP; struct ref *ref_map; @@ -1357,7 +1357,7 @@ static inline void fetch_one_setup_partial(struct remote *remote) static int fetch_one(struct remote *remote, int argc, const char **argv, int prune_tags_ok) { static const char **refs = NULL; - struct refspec *refspec; + struct refspec_item *refspec; int ref_nr = 0; int j = 0; int exit_code; diff --git a/builtin/pull.c b/builtin/pull.c index 6247c956d7..5a79deae5d 100644 --- a/builtin/pull.c +++ b/builtin/pull.c @@ -676,7 +676,7 @@ static const char *get_upstream_branch(const char *remote) */ static const char *get_tracking_branch(const char *remote, const char *refspec) { - struct refspec *spec; + struct refspec_item *spec; const char *spec_src; const char *merge_branch; diff --git a/builtin/push.c b/builtin/push.c index fa65999b27..00d81fb1dd 100644 --- a/builtin/push.c +++ b/builtin/push.c @@ -80,8 +80,8 @@ static const char *map_refspec(const char *ref, return ref; if (remote->push) { - struct refspec query; - memset(&query, 0, sizeof(struct refspec)); + struct refspec_item query; + memset(&query, 0, sizeof(struct refspec_item)); query.src = matched->name; if (!query_refspecs(remote->push, remote->push_refspec_nr, &query) && query.dst) { diff --git a/builtin/remote.c b/builtin/remote.c index c495139954..d9da82dc81 100644 --- a/builtin/remote.c +++ b/builtin/remote.c @@ -442,7 +442,7 @@ static int get_push_ref_states_noquery(struct ref_states *states) info->dest = xstrdup(item->string); } for (i = 0; i < remote->push_refspec_nr; i++) { - struct refspec *spec = remote->push + i; + struct refspec_item *spec = remote->push + i; if (spec->matching) item = string_list_append(&states->push, _("(matching)")); else if (strlen(spec->src)) @@ -462,7 +462,7 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat { struct ref *ref, *matches; struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map; - struct refspec refspec; + struct refspec_item refspec; refspec.force = 0; refspec.pattern = 1; @@ -515,7 +515,7 @@ static int add_branch_for_removal(const char *refname, const struct object_id *oid, int flags, void *cb_data) { struct branches_for_remote *branches = cb_data; - struct refspec refspec; + struct refspec_item refspec; struct known_remote *kr; memset(&refspec, 0, sizeof(refspec)); @@ -834,7 +834,7 @@ static int append_ref_to_tracked_list(const char *refname, const struct object_id *oid, int flags, void *cb_data) { struct ref_states *states = cb_data; - struct refspec refspec; + struct refspec_item refspec; if (flags & REF_ISSYMREF) return 0; diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 6ab032acb1..c0c4db0073 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -1746,11 +1746,11 @@ static int push_check(int argc, const char **argv, const char *prefix) if (argc > 2) { int i, refspec_nr = argc - 2; struct ref *local_refs = get_local_heads(); - struct refspec *refspec = parse_push_refspec(refspec_nr, + struct refspec_item *refspec = parse_push_refspec(refspec_nr, argv + 2); for (i = 0; i < refspec_nr; i++) { - struct refspec *rs = refspec + i; + struct refspec_item *rs = refspec + i; if (rs->pattern || rs->matching) continue; diff --git a/checkout.c b/checkout.c index 193ba85675..bdefc888ba 100644 --- a/checkout.c +++ b/checkout.c @@ -13,8 +13,8 @@ struct tracking_name_data { static int check_tracking_name(struct remote *remote, void *cb_data) { struct tracking_name_data *cb = cb_data; - struct refspec query; - memset(&query, 0, sizeof(struct refspec)); + struct refspec_item query; + memset(&query, 0, sizeof(struct refspec_item)); query.src = cb->src_ref; if (remote_find_tracking(remote, &query) || get_oid(query.dst, cb->dst_oid)) { diff --git a/refspec.c b/refspec.c index 50892f864c..22188f0106 100644 --- a/refspec.c +++ b/refspec.c @@ -2,7 +2,7 @@ #include "refs.h" #include "refspec.h" -static struct refspec s_tag_refspec = { +static struct refspec_item s_tag_refspec = { 0, 1, 0, @@ -12,12 +12,12 @@ static struct refspec s_tag_refspec = { }; /* See TAG_REFSPEC for the string version */ -const struct refspec *tag_refspec = &s_tag_refspec; +const struct refspec_item *tag_refspec = &s_tag_refspec; -static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify) +static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify) { int i; - struct refspec *rs = xcalloc(nr_refspec, sizeof(*rs)); + struct refspec_item *rs = xcalloc(nr_refspec, sizeof(*rs)); for (i = 0; i < nr_refspec; i++) { size_t llen; @@ -135,24 +135,24 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp int valid_fetch_refspec(const char *fetch_refspec_str) { - struct refspec *refspec; + struct refspec_item *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) +struct refspec_item *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) +struct refspec_item *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) +void free_refspec(int nr_refspec, struct refspec_item *refspec) { int i; diff --git a/refspec.h b/refspec.h index 62625c23a3..fc9c1af775 100644 --- a/refspec.h +++ b/refspec.h @@ -2,9 +2,9 @@ #define REFSPEC_H #define TAG_REFSPEC "refs/tags/*:refs/tags/*" -extern const struct refspec *tag_refspec; +extern const struct refspec_item *tag_refspec; -struct refspec { +struct refspec_item { unsigned force : 1; unsigned pattern : 1; unsigned matching : 1; @@ -15,9 +15,9 @@ struct refspec { }; 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); +struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec); +struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec); -void free_refspec(int nr_refspec, struct refspec *refspec); +void free_refspec(int nr_refspec, struct refspec_item *refspec); #endif /* REFSPEC_H */ diff --git a/remote.c b/remote.c index 4d67c061a0..89820c4769 100644 --- a/remote.c +++ b/remote.c @@ -97,7 +97,7 @@ void add_prune_tags_to_fetch_refspec(struct remote *remote) { int nr = remote->fetch_refspec_nr; int bufsize = nr + 1; - int size = sizeof(struct refspec); + int size = sizeof(struct refspec_item); remote->fetch = xrealloc(remote->fetch, size * bufsize); memcpy(&remote->fetch[nr], tag_refspec, size); @@ -724,7 +724,7 @@ static int match_name_with_pattern(const char *key, const char *name, return ret; } -static void query_refspecs_multiple(struct refspec *refs, int ref_count, struct refspec *query, struct string_list *results) +static void query_refspecs_multiple(struct refspec_item *refs, int ref_count, struct refspec_item *query, struct string_list *results) { int i; int find_src = !query->src; @@ -733,7 +733,7 @@ static void query_refspecs_multiple(struct refspec *refs, int ref_count, struct error("query_refspecs_multiple: need either src or dst"); for (i = 0; i < ref_count; i++) { - struct refspec *refspec = &refs[i]; + struct refspec_item *refspec = &refs[i]; const char *key = find_src ? refspec->dst : refspec->src; const char *value = find_src ? refspec->src : refspec->dst; const char *needle = find_src ? query->dst : query->src; @@ -750,7 +750,7 @@ static void query_refspecs_multiple(struct refspec *refs, int ref_count, struct } } -int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query) +int query_refspecs(struct refspec_item *refs, int ref_count, struct refspec_item *query) { int i; int find_src = !query->src; @@ -761,7 +761,7 @@ int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query) return error("query_refspecs: need either src or dst"); for (i = 0; i < ref_count; i++) { - struct refspec *refspec = &refs[i]; + struct refspec_item *refspec = &refs[i]; const char *key = find_src ? refspec->dst : refspec->src; const char *value = find_src ? refspec->src : refspec->dst; @@ -781,12 +781,12 @@ int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query) return -1; } -char *apply_refspecs(struct refspec *refspecs, int nr_refspec, +char *apply_refspecs(struct refspec_item *refspecs, int nr_refspec, const char *name) { - struct refspec query; + struct refspec_item query; - memset(&query, 0, sizeof(struct refspec)); + memset(&query, 0, sizeof(struct refspec_item)); query.src = (char *)name; if (query_refspecs(refspecs, nr_refspec, &query)) @@ -795,7 +795,7 @@ char *apply_refspecs(struct refspec *refspecs, int nr_refspec, return query.dst; } -int remote_find_tracking(struct remote *remote, struct refspec *refspec) +int remote_find_tracking(struct remote *remote, struct refspec_item *refspec) { return query_refspecs(remote->fetch, remote->fetch_refspec_nr, refspec); } @@ -1004,7 +1004,7 @@ static char *guess_ref(const char *name, struct ref *peer) } static int match_explicit_lhs(struct ref *src, - struct refspec *rs, + struct refspec_item *rs, struct ref **match, int *allocated_match) { @@ -1030,7 +1030,7 @@ static int match_explicit_lhs(struct ref *src, static int match_explicit(struct ref *src, struct ref *dst, struct ref ***dst_tail, - struct refspec *rs) + struct refspec_item *rs) { struct ref *matched_src, *matched_dst; int allocated_src; @@ -1099,7 +1099,7 @@ static int match_explicit(struct ref *src, struct ref *dst, } static int match_explicit_refs(struct ref *src, struct ref *dst, - struct ref ***dst_tail, struct refspec *rs, + struct ref ***dst_tail, struct refspec_item *rs, int rs_nr) { int i, errs; @@ -1108,10 +1108,10 @@ static int match_explicit_refs(struct ref *src, struct ref *dst, return errs; } -static char *get_ref_match(const struct refspec *rs, int rs_nr, const struct ref *ref, - int send_mirror, int direction, const struct refspec **ret_pat) +static char *get_ref_match(const struct refspec_item *rs, int rs_nr, const struct ref *ref, + int send_mirror, int direction, const struct refspec_item **ret_pat) { - const struct refspec *pat; + const struct refspec_item *pat; char *name; int i; int matching_refs = -1; @@ -1282,12 +1282,12 @@ static void prepare_ref_index(struct string_list *ref_index, struct ref *ref) */ int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names) { - struct refspec *refspec = parse_push_refspec(nr_refspec, refspec_names); + struct refspec_item *refspec = parse_push_refspec(nr_refspec, refspec_names); int ret = 0; int i; for (i = 0; i < nr_refspec; i++) { - struct refspec *rs = refspec + i; + struct refspec_item *rs = refspec + i; if (rs->pattern || rs->matching) continue; @@ -1310,7 +1310,7 @@ int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names) int match_push_refs(struct ref *src, struct ref **dst, int nr_refspec, const char **refspec, int flags) { - struct refspec *rs; + struct refspec_item *rs; int send_all = flags & MATCH_REFS_ALL; int send_mirror = flags & MATCH_REFS_MIRROR; int send_prune = flags & MATCH_REFS_PRUNE; @@ -1330,7 +1330,7 @@ int match_push_refs(struct ref *src, struct ref **dst, for (ref = src; ref; ref = ref->next) { struct string_list_item *dst_item; struct ref *dst_peer; - const struct refspec *pat = NULL; + const struct refspec_item *pat = NULL; char *dst_name; dst_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_SRC, &pat); @@ -1686,7 +1686,7 @@ static int ignore_symref_update(const char *refname) * local symbolic ref. */ static struct ref *get_expanded_map(const struct ref *remote_refs, - const struct refspec *refspec) + const struct refspec_item *refspec) { const struct ref *ref; struct ref *ret = NULL; @@ -1751,7 +1751,7 @@ static struct ref *get_local_ref(const char *name) } int get_fetch_map(const struct ref *remote_refs, - const struct refspec *refspec, + const struct refspec_item *refspec, struct ref ***tail, int missing_ok) { @@ -2089,7 +2089,7 @@ struct ref *guess_remote_head(const struct ref *head, struct stale_heads_info { struct string_list *ref_names; struct ref **stale_refs_tail; - struct refspec *refs; + struct refspec_item *refs; int ref_count; }; @@ -2098,9 +2098,9 @@ static int get_stale_heads_cb(const char *refname, const struct object_id *oid, { struct stale_heads_info *info = cb_data; struct string_list matches = STRING_LIST_INIT_DUP; - struct refspec query; + struct refspec_item query; int i, stale = 1; - memset(&query, 0, sizeof(struct refspec)); + memset(&query, 0, sizeof(struct refspec_item)); query.dst = (char *)refname; query_refspecs_multiple(info->refs, info->ref_count, &query, &matches); @@ -2131,7 +2131,7 @@ clean_exit: return 0; } -struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map) +struct ref *get_stale_heads(struct refspec_item *refs, int ref_count, struct ref *fetch_map) { struct ref *ref, *stale_refs = NULL; struct string_list ref_names = STRING_LIST_INIT_NODUP; diff --git a/remote.h b/remote.h index 386ced9012..3657bd43d1 100644 --- a/remote.h +++ b/remote.h @@ -28,12 +28,12 @@ struct remote { int pushurl_alloc; const char **push_refspec; - struct refspec *push; + struct refspec_item *push; int push_refspec_nr; int push_refspec_alloc; const char **fetch_refspec; - struct refspec *fetch; + struct refspec_item *fetch; int fetch_refspec_nr; int fetch_refspec_alloc; @@ -163,8 +163,8 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid); */ struct ref *ref_remove_duplicates(struct ref *ref_map); -extern int query_refspecs(struct refspec *specs, int nr, struct refspec *query); -char *apply_refspecs(struct refspec *refspecs, int nr_refspec, +extern int query_refspecs(struct refspec_item *specs, int nr, struct refspec_item *query); +char *apply_refspecs(struct refspec_item *refspecs, int nr_refspec, const char *name); int check_push_refs(struct ref *src, int nr_refspec, const char **refspec); @@ -185,7 +185,7 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror, * missing_ok is usually false, but when we are adding branch.$name.merge * it is Ok if the branch is not at the remote anymore. */ -int get_fetch_map(const struct ref *remote_refs, const struct refspec *refspec, +int get_fetch_map(const struct ref *remote_refs, const struct refspec_item *refspec, struct ref ***tail, int missing_ok); struct ref *get_remote_ref(const struct ref *remote_refs, const char *name); @@ -193,7 +193,7 @@ struct ref *get_remote_ref(const struct ref *remote_refs, const char *name); /* * For the given remote, reads the refspec's src and sets the other fields. */ -int remote_find_tracking(struct remote *remote, struct refspec *refspec); +int remote_find_tracking(struct remote *remote, struct refspec_item *refspec); struct branch { const char *name; @@ -203,7 +203,7 @@ struct branch { const char *pushremote_name; const char **merge_name; - struct refspec **merge; + struct refspec_item **merge; int merge_nr; int merge_alloc; @@ -272,7 +272,7 @@ struct ref *guess_remote_head(const struct ref *head, int all); /* Return refs which no longer exist on remote */ -struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map); +struct ref *get_stale_heads(struct refspec_item *refs, int ref_count, struct ref *fetch_map); /* * Compare-and-swap diff --git a/transport-helper.c b/transport-helper.c index b99e1cce9e..b156a37e7d 100644 --- a/transport-helper.c +++ b/transport-helper.c @@ -36,7 +36,7 @@ struct helper_data { char *export_marks; char *import_marks; /* These go from remote name (as in "list") to private name */ - struct refspec *refspecs; + struct refspec_item *refspecs; int refspec_nr; /* Transport options for fetch-pack/send-pack (should one of * those be invoked). diff --git a/transport.c b/transport.c index 2cf63d18b7..3ad4d37dc0 100644 --- a/transport.c +++ b/transport.c @@ -390,7 +390,7 @@ int transport_refs_pushed(struct ref *ref) void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose) { - struct refspec rs; + struct refspec_item rs; if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE) return; @@ -1111,7 +1111,7 @@ int transport_push(struct transport *transport, int porcelain = flags & TRANSPORT_PUSH_PORCELAIN; int pretend = flags & TRANSPORT_PUSH_DRY_RUN; int push_ret, ret, err; - struct refspec *tmp_rs; + struct refspec_item *tmp_rs; struct argv_array ref_prefixes = ARGV_ARRAY_INIT; int i; -- cgit v1.2.3 From 3eec3700fdc4d5b0a33729d45e7fb9735ed7e0f5 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 16 May 2018 15:57:50 -0700 Subject: 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 Signed-off-by: Junio C Hamano --- refspec.c | 195 +++++++++++++++++++++++++++++++++----------------------------- 1 file changed, 104 insertions(+), 91 deletions(-) (limited to 'refspec.c') diff --git a/refspec.c b/refspec.c index 22188f0106..8bf4ebbd3d 100644 --- a/refspec.c +++ b/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; -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)); + size_t llen; + int is_glob; + const char *lhs, *rhs; + int flags; - for (i = 0; i < nr_refspec; i++) { - size_t llen; - int is_glob; - const char *lhs, *rhs; - int flags; + is_glob = 0; - is_glob = 0; + lhs = refspec; + if (*lhs == '+') { + item->force = 1; + lhs++; + } - lhs = refspec[i]; - if (*lhs == '+') { - rs[i].force = 1; - lhs++; - } + rhs = strrchr(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 { /* - * Before going on, special case ":" (or "+:") as a refspec - * for pushing matching refs. + * 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 (!fetch && rhs == lhs && rhs[1] == '\0') { - rs[i].matching = 1; - continue; + if (!*item->src) + ; /* empty is ok */ + else if (is_glob) { + if (check_refname_format(item->src, flags)) + return 0; } - - if (rhs) { - size_t rlen = strlen(++rhs); - is_glob = (1 <= rlen && strchr(rhs, '*')); - rs[i].dst = xstrndup(rhs, rlen); + 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; } + } - 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; - } + return 1; +} - 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; - } - } +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; } + return rs; invalid: -- cgit v1.2.3 From 6d4c05785946e302e611be9ac1f5ca0b5ada9214 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 16 May 2018 15:57:51 -0700 Subject: refspec: introduce struct refspec Introduce 'struct refspec', an abstraction around a collection of 'struct refspec_item's much like how 'struct pathspec' holds a collection of 'struct pathspec_item's. A refspec struct also contains an array of the original refspec strings which will be used to facilitate the migration to using this new abstraction throughout the code base. Signed-off-by: Brandon Williams Signed-off-by: Junio C Hamano --- refspec.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ refspec.h | 25 +++++++++++++++++++++++++ 2 files changed, 89 insertions(+) (limited to 'refspec.c') diff --git a/refspec.c b/refspec.c index 8bf4ebbd3d..af9d0d4b30 100644 --- a/refspec.c +++ b/refspec.c @@ -178,3 +178,67 @@ void free_refspec(int nr_refspec, struct refspec_item *refspec) } free(refspec); } + +void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch) +{ + memset(item, 0, sizeof(*item)); + + if (!parse_refspec(item, refspec, fetch)) + die("Invalid refspec '%s'", refspec); +} + +void refspec_item_clear(struct refspec_item *item) +{ + FREE_AND_NULL(item->src); + FREE_AND_NULL(item->dst); + item->force = 0; + item->pattern = 0; + item->matching = 0; + item->exact_sha1 = 0; +} + +void refspec_init(struct refspec *rs, int fetch) +{ + memset(rs, 0, sizeof(*rs)); + rs->fetch = fetch; +} + +void refspec_append(struct refspec *rs, const char *refspec) +{ + struct refspec_item item; + + refspec_item_init(&item, refspec, rs->fetch); + + ALLOC_GROW(rs->items, rs->nr + 1, rs->alloc); + rs->items[rs->nr++] = item; + + ALLOC_GROW(rs->raw, rs->raw_nr + 1, rs->raw_alloc); + rs->raw[rs->raw_nr++] = xstrdup(refspec); +} + +void refspec_appendn(struct refspec *rs, const char **refspecs, int nr) +{ + int i; + for (i = 0; i < nr; i++) + refspec_append(rs, refspecs[i]); +} + +void refspec_clear(struct refspec *rs) +{ + int i; + + for (i = 0; i < rs->nr; i++) + refspec_item_clear(&rs->items[i]); + + FREE_AND_NULL(rs->items); + rs->alloc = 0; + rs->nr = 0; + + for (i = 0; i < rs->raw_nr; i++) + free((char *)rs->raw[i]); + FREE_AND_NULL(rs->raw); + rs->raw_alloc = 0; + rs->raw_nr = 0; + + rs->fetch = 0; +} diff --git a/refspec.h b/refspec.h index fc9c1af775..da3135825f 100644 --- a/refspec.h +++ b/refspec.h @@ -20,4 +20,29 @@ struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec); void free_refspec(int nr_refspec, struct refspec_item *refspec); +#define REFSPEC_FETCH 1 +#define REFSPEC_PUSH 0 + +#define REFSPEC_INIT_FETCH { .fetch = REFSPEC_FETCH } +#define REFSPEC_INIT_PUSH { .fetch = REFSPEC_PUSH } + +struct refspec { + struct refspec_item *items; + int alloc; + int nr; + + const char **raw; + int raw_alloc; + int raw_nr; + + int fetch; +}; + +void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch); +void refspec_item_clear(struct refspec_item *item); +void refspec_init(struct refspec *rs, int fetch); +void refspec_append(struct refspec *rs, const char *refspec); +void refspec_appendn(struct refspec *rs, const char **refspecs, int nr); +void refspec_clear(struct refspec *rs); + #endif /* REFSPEC_H */ -- cgit v1.2.3 From c8fa9efe3a8765f44eacc5b0e114053a0297dfff Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 16 May 2018 15:57:52 -0700 Subject: refspec: convert valid_fetch_refspec to use parse_refspec Convert 'valid_fetch_refspec()' to use the new 'parse_refspec()' function to only parse a single refspec and eliminate an allocation. Signed-off-by: Brandon Williams Signed-off-by: Junio C Hamano --- refspec.c | 17 ++++++++--------- refspec.h | 3 ++- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'refspec.c') diff --git a/refspec.c b/refspec.c index af9d0d4b30..ab37b5ba1e 100644 --- a/refspec.c +++ b/refspec.c @@ -146,15 +146,6 @@ static struct refspec_item *parse_refspec_internal(int nr_refspec, const char ** die("Invalid refspec '%s'", refspec[i]); } -int valid_fetch_refspec(const char *fetch_refspec_str) -{ - struct refspec_item *refspec; - - refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1); - free_refspec(1, refspec); - return !!refspec; -} - struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec) { return parse_refspec_internal(nr_refspec, refspec, 1, 0); @@ -242,3 +233,11 @@ void refspec_clear(struct refspec *rs) rs->fetch = 0; } + +int valid_fetch_refspec(const char *fetch_refspec_str) +{ + struct refspec_item refspec; + int ret = parse_refspec(&refspec, fetch_refspec_str, REFSPEC_FETCH); + refspec_item_clear(&refspec); + return ret; +} diff --git a/refspec.h b/refspec.h index da3135825f..1063c64ccc 100644 --- a/refspec.h +++ b/refspec.h @@ -14,7 +14,6 @@ struct refspec_item { char *dst; }; -int valid_fetch_refspec(const char *refspec); struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec); struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec); @@ -45,4 +44,6 @@ void refspec_append(struct refspec *rs, const char *refspec); void refspec_appendn(struct refspec *rs, const char **refspecs, int nr); void refspec_clear(struct refspec *rs); +int valid_fetch_refspec(const char *refspec); + #endif /* REFSPEC_H */ -- cgit v1.2.3 From 860fdf1e6ebd767cf702d952e2dcdccd86e7a208 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 16 May 2018 15:58:06 -0700 Subject: refspec: remove the deprecated functions Now that there are no callers of 'parse_push_refspec()', 'parse_fetch_refspec()', and 'free_refspec()', remove these functions. Signed-off-by: Brandon Williams Signed-off-by: Junio C Hamano --- refspec.c | 49 ------------------------------------------------- refspec.h | 5 ----- 2 files changed, 54 deletions(-) (limited to 'refspec.c') diff --git a/refspec.c b/refspec.c index ab37b5ba1e..97e76e8b1d 100644 --- a/refspec.c +++ b/refspec.c @@ -121,55 +121,6 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet 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; - } - - 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]); -} - -struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec) -{ - return parse_refspec_internal(nr_refspec, refspec, 1, 0); -} - -struct refspec_item *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_item *refspec) -{ - int i; - - if (!refspec) - return; - - for (i = 0; i < nr_refspec; i++) { - free(refspec[i].src); - free(refspec[i].dst); - } - free(refspec); -} - void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch) { memset(item, 0, sizeof(*item)); diff --git a/refspec.h b/refspec.h index 1063c64ccc..7e1ff94ac9 100644 --- a/refspec.h +++ b/refspec.h @@ -14,11 +14,6 @@ struct refspec_item { char *dst; }; -struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec); -struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec); - -void free_refspec(int nr_refspec, struct refspec_item *refspec); - #define REFSPEC_FETCH 1 #define REFSPEC_PUSH 0 -- cgit v1.2.3 From 6373cb598e1a4e0340583ad75d5abba01ff79774 Mon Sep 17 00:00:00 2001 From: Brandon Williams Date: Wed, 16 May 2018 16:48:21 -0700 Subject: refspec: consolidate ref-prefix generation logic When using protocol v2 a client constructs a list of ref-prefixes which are sent across the wire so that the server can do server-side filtering of the ref-advertisement. The logic that does this exists for both fetch and push (even though no push support for v2 currently exists yet) and is roughly the same so lets consolidate this logic and make it general enough that it can be used for both the push and fetch cases. Signed-off-by: Brandon Williams Signed-off-by: Junio C Hamano --- builtin/fetch.c | 13 +------------ refspec.c | 29 +++++++++++++++++++++++++++++ refspec.h | 4 ++++ transport.c | 21 +-------------------- 4 files changed, 35 insertions(+), 32 deletions(-) (limited to 'refspec.c') diff --git a/builtin/fetch.c b/builtin/fetch.c index 3fad1f0db9..80bb143707 100644 --- a/builtin/fetch.c +++ b/builtin/fetch.c @@ -351,18 +351,7 @@ static struct ref *get_ref_map(struct transport *transport, const struct ref *remote_refs; - for (i = 0; i < rs->nr; i++) { - const struct refspec_item *item = &rs->items[i]; - if (!item->exact_sha1) { - const char *glob = strchr(item->src, '*'); - if (glob) - argv_array_pushf(&ref_prefixes, "%.*s", - (int)(glob - item->src), - item->src); - else - expand_ref_prefix(&ref_prefixes, item->src); - } - } + refspec_ref_prefixes(rs, &ref_prefixes); remote_refs = transport_get_remote_refs(transport, &ref_prefixes); diff --git a/refspec.c b/refspec.c index 97e76e8b1d..c59a4ccf1e 100644 --- a/refspec.c +++ b/refspec.c @@ -1,4 +1,5 @@ #include "cache.h" +#include "argv-array.h" #include "refs.h" #include "refspec.h" @@ -192,3 +193,31 @@ int valid_fetch_refspec(const char *fetch_refspec_str) refspec_item_clear(&refspec); return ret; } + +void refspec_ref_prefixes(const struct refspec *rs, + struct argv_array *ref_prefixes) +{ + int i; + for (i = 0; i < rs->nr; i++) { + const struct refspec_item *item = &rs->items[i]; + const char *prefix = NULL; + + if (rs->fetch == REFSPEC_FETCH) + prefix = item->src; + else if (item->dst) + prefix = item->dst; + else if (item->src && !item->exact_sha1) + prefix = item->src; + + if (prefix) { + if (item->pattern) { + const char *glob = strchr(prefix, '*'); + argv_array_pushf(ref_prefixes, "%.*s", + (int)(glob - prefix), + prefix); + } else { + expand_ref_prefix(ref_prefixes, prefix); + } + } + } +} diff --git a/refspec.h b/refspec.h index 7e1ff94ac9..01b700e094 100644 --- a/refspec.h +++ b/refspec.h @@ -41,4 +41,8 @@ void refspec_clear(struct refspec *rs); int valid_fetch_refspec(const char *refspec); +struct argv_array; +void refspec_ref_prefixes(const struct refspec *rs, + struct argv_array *ref_prefixes); + #endif /* REFSPEC_H */ diff --git a/transport.c b/transport.c index 7e0b9abba3..cbf0044c3e 100644 --- a/transport.c +++ b/transport.c @@ -1088,30 +1088,11 @@ int transport_push(struct transport *transport, int pretend = flags & TRANSPORT_PUSH_DRY_RUN; int push_ret, ret, err; struct argv_array ref_prefixes = ARGV_ARRAY_INIT; - int i; if (check_push_refs(local_refs, rs) < 0) return -1; - for (i = 0; i < rs->nr; i++) { - const struct refspec_item *item = &rs->items[i]; - const char *prefix = NULL; - - if (item->dst) - prefix = item->dst; - else if (item->src && !item->exact_sha1) - prefix = item->src; - - if (prefix) { - const char *glob = strchr(prefix, '*'); - if (glob) - argv_array_pushf(&ref_prefixes, "%.*s", - (int)(glob - prefix), - prefix); - else - expand_ref_prefix(&ref_prefixes, prefix); - } - } + refspec_ref_prefixes(rs, &ref_prefixes); remote_refs = transport->vtable->get_refs_list(transport, 1, &ref_prefixes); -- cgit v1.2.3