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>

Brandon Williams committed May 16, 2018 at 15:57 UTC ec0cb496553ac82f97205a415ca77618406b30e3
17 files changed +204 -184
Makefile
+1
@@ -928,6 +928,7 @@ LIB_OBJS += refs/files-backend.o
928 LIB_OBJS += refs/iterator.o
929 LIB_OBJS += refs/packed-backend.o
930 LIB_OBJS += refs/ref-cache.o
931 +LIB_OBJS += refspec.o
932 LIB_OBJS += ref-filter.o
933 LIB_OBJS += remote.o
934 LIB_OBJS += replace-object.o
branch.c
+1
@@ -3,6 +3,7 @@
3 #include "config.h"
4 #include "branch.h"
5 #include "refs.h"
6 +#include "refspec.h"
7 #include "remote.h"
8 #include "commit.h"
9 #include "worktree.h"
builtin/clone.c
+1
@@ -14,6 +14,7 @@
14 #include "parse-options.h"
15 #include "fetch-pack.h"
16 #include "refs.h"
17 +#include "refspec.h"
18 #include "tree.h"
19 #include "tree-walk.h"
20 #include "unpack-trees.h"
builtin/fast-export.c
+1
@@ -7,6 +7,7 @@
7 #include "cache.h"
8 #include "config.h"
9 #include "refs.h"
10 +#include "refspec.h"
11 #include "commit.h"
12 #include "object.h"
13 #include "tag.h"
builtin/fetch.c
+1
@@ -5,6 +5,7 @@
5 #include "config.h"
6 #include "repository.h"
7 #include "refs.h"
8 +#include "refspec.h"
9 #include "commit.h"
10 #include "builtin.h"
11 #include "string-list.h"
builtin/merge.c
+1
@@ -14,6 +14,7 @@
14 #include "run-command.h"
15 #include "diff.h"
16 #include "refs.h"
17 +#include "refspec.h"
18 #include "commit.h"
19 #include "diffcore.h"
20 #include "revision.h"
builtin/pull.c
+1
@@ -15,6 +15,7 @@
15 #include "remote.h"
16 #include "dir.h"
17 #include "refs.h"
18 +#include "refspec.h"
19 #include "revision.h"
20 #include "submodule.h"
21 #include "submodule-config.h"
builtin/push.c
+1
@@ -4,6 +4,7 @@
4 #include "cache.h"
5 #include "config.h"
6 #include "refs.h"
7 +#include "refspec.h"
8 #include "run-command.h"
9 #include "builtin.h"
10 #include "remote.h"
builtin/remote.c
+1
@@ -7,6 +7,7 @@
7 #include "strbuf.h"
8 #include "run-command.h"
9 #include "refs.h"
10 +#include "refspec.h"
11 #include "argv-array.h"
12
13 static const char * const builtin_remote_usage[] = {
builtin/submodule--helper.c
+1
@@ -12,6 +12,7 @@
12 #include "run-command.h"
13 #include "remote.h"
14 #include "refs.h"
15 +#include "refspec.h"
16 #include "connect.h"
17 #include "revision.h"
18 #include "diffcore.h"
checkout.c
+1
@@ -1,5 +1,6 @@
1 #include "cache.h"
2 #include "remote.h"
3 +#include "refspec.h"
4 #include "checkout.h"
5
6 struct tracking_name_data {
refspec.c new
+167
@@ -0,0 +1,167 @@
1 +#include "cache.h"
2 +#include "refs.h"
3 +#include "refspec.h"
4 +
5 +static struct refspec s_tag_refspec = {
6 + 0,
7 + 1,
8 + 0,
9 + 0,
10 + "refs/tags/*",
11 + "refs/tags/*"
12 +};
13 +
14 +/* See TAG_REFSPEC for the string version */
15 +const struct refspec *tag_refspec = &s_tag_refspec;
16 +
17 +static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
18 +{
19 + int i;
20 + struct refspec *rs = xcalloc(nr_refspec, sizeof(*rs));
21 +
22 + for (i = 0; i < nr_refspec; i++) {
23 + size_t llen;
24 + int is_glob;
25 + const char *lhs, *rhs;
26 + int flags;
27 +
28 + is_glob = 0;
29 +
30 + lhs = refspec[i];
31 + if (*lhs == '+') {
32 + rs[i].force = 1;
33 + lhs++;
34 + }
35 +
36 + rhs = strrchr(lhs, ':');
37 +
38 + /*
39 + * Before going on, special case ":" (or "+:") as a refspec
40 + * for pushing matching refs.
41 + */
42 + if (!fetch && rhs == lhs && rhs[1] == '\0') {
43 + rs[i].matching = 1;
44 + continue;
45 + }
46 +
47 + if (rhs) {
48 + size_t rlen = strlen(++rhs);
49 + is_glob = (1 <= rlen && strchr(rhs, '*'));
50 + rs[i].dst = xstrndup(rhs, rlen);
51 + }
52 +
53 + llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
54 + if (1 <= llen && memchr(lhs, '*', llen)) {
55 + if ((rhs && !is_glob) || (!rhs && fetch))
56 + goto invalid;
57 + is_glob = 1;
58 + } else if (rhs && is_glob) {
59 + goto invalid;
60 + }
61 +
62 + rs[i].pattern = is_glob;
63 + rs[i].src = xstrndup(lhs, llen);
64 + flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
65 +
66 + if (fetch) {
67 + struct object_id unused;
68 +
69 + /* LHS */
70 + if (!*rs[i].src)
71 + ; /* empty is ok; it means "HEAD" */
72 + else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(rs[i].src, &unused))
73 + rs[i].exact_sha1 = 1; /* ok */
74 + else if (!check_refname_format(rs[i].src, flags))
75 + ; /* valid looking ref is ok */
76 + else
77 + goto invalid;
78 + /* RHS */
79 + if (!rs[i].dst)
80 + ; /* missing is ok; it is the same as empty */
81 + else if (!*rs[i].dst)
82 + ; /* empty is ok; it means "do not store" */
83 + else if (!check_refname_format(rs[i].dst, flags))
84 + ; /* valid looking ref is ok */
85 + else
86 + goto invalid;
87 + } else {
88 + /*
89 + * LHS
90 + * - empty is allowed; it means delete.
91 + * - when wildcarded, it must be a valid looking ref.
92 + * - otherwise, it must be an extended SHA-1, but
93 + * there is no existing way to validate this.
94 + */
95 + if (!*rs[i].src)
96 + ; /* empty is ok */
97 + else if (is_glob) {
98 + if (check_refname_format(rs[i].src, flags))
99 + goto invalid;
100 + }
101 + else
102 + ; /* anything goes, for now */
103 + /*
104 + * RHS
105 + * - missing is allowed, but LHS then must be a
106 + * valid looking ref.
107 + * - empty is not allowed.
108 + * - otherwise it must be a valid looking ref.
109 + */
110 + if (!rs[i].dst) {
111 + if (check_refname_format(rs[i].src, flags))
112 + goto invalid;
113 + } else if (!*rs[i].dst) {
114 + goto invalid;
115 + } else {
116 + if (check_refname_format(rs[i].dst, flags))
117 + goto invalid;
118 + }
119 + }
120 + }
121 + return rs;
122 +
123 + invalid:
124 + if (verify) {
125 + /*
126 + * nr_refspec must be greater than zero and i must be valid
127 + * since it is only possible to reach this point from within
128 + * the for loop above.
129 + */
130 + free_refspec(i+1, rs);
131 + return NULL;
132 + }
133 + die("Invalid refspec '%s'", refspec[i]);
134 +}
135 +
136 +int valid_fetch_refspec(const char *fetch_refspec_str)
137 +{
138 + struct refspec *refspec;
139 +
140 + refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1);
141 + free_refspec(1, refspec);
142 + return !!refspec;
143 +}
144 +
145 +struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec)
146 +{
147 + return parse_refspec_internal(nr_refspec, refspec, 1, 0);
148 +}
149 +
150 +struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
151 +{
152 + return parse_refspec_internal(nr_refspec, refspec, 0, 0);
153 +}
154 +
155 +void free_refspec(int nr_refspec, struct refspec *refspec)
156 +{
157 + int i;
158 +
159 + if (!refspec)
160 + return;
161 +
162 + for (i = 0; i < nr_refspec; i++) {
163 + free(refspec[i].src);
164 + free(refspec[i].dst);
165 + }
166 + free(refspec);
167 +}
refspec.h new
+23
@@ -0,0 +1,23 @@
1 +#ifndef REFSPEC_H
2 +#define REFSPEC_H
3 +
4 +#define TAG_REFSPEC "refs/tags/*:refs/tags/*"
5 +extern const struct refspec *tag_refspec;
6 +
7 +struct refspec {
8 + unsigned force : 1;
9 + unsigned pattern : 1;
10 + unsigned matching : 1;
11 + unsigned exact_sha1 : 1;
12 +
13 + char *src;
14 + char *dst;
15 +};
16 +
17 +int valid_fetch_refspec(const char *refspec);
18 +struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec);
19 +struct refspec *parse_push_refspec(int nr_refspec, const char **refspec);
20 +
21 +void free_refspec(int nr_refspec, struct refspec *refspec);
22 +
23 +#endif /* REFSPEC_H */
remote.c
+1 -164
@@ -2,6 +2,7 @@
2 #include "config.h"
3 #include "remote.h"
4 #include "refs.h"
5 +#include "refspec.h"
6 #include "commit.h"
7 #include "diff.h"
8 #include "revision.h"
@@ -13,18 +14,6 @@
14
15 enum map_direction { FROM_SRC, FROM_DST };
16
16 -static struct refspec s_tag_refspec = {
17 - 0,
18 - 1,
19 - 0,
20 - 0,
21 - "refs/tags/*",
22 - "refs/tags/*"
23 -};
24 -
25 -/* See TAG_REFSPEC for the string version */
26 -const struct refspec *tag_refspec = &s_tag_refspec;
27 -
17 struct counted_string {
18 size_t len;
19 const char *s;
@@ -499,158 +488,6 @@ static void read_config(void)
488 alias_all_urls();
489 }
490
502 -static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
503 -{
504 - int i;
505 - struct refspec *rs = xcalloc(nr_refspec, sizeof(*rs));
506 -
507 - for (i = 0; i < nr_refspec; i++) {
508 - size_t llen;
509 - int is_glob;
510 - const char *lhs, *rhs;
511 - int flags;
512 -
513 - is_glob = 0;
514 -
515 - lhs = refspec[i];
516 - if (*lhs == '+') {
517 - rs[i].force = 1;
518 - lhs++;
519 - }
520 -
521 - rhs = strrchr(lhs, ':');
522 -
523 - /*
524 - * Before going on, special case ":" (or "+:") as a refspec
525 - * for pushing matching refs.
526 - */
527 - if (!fetch && rhs == lhs && rhs[1] == '\0') {
528 - rs[i].matching = 1;
529 - continue;
530 - }
531 -
532 - if (rhs) {
533 - size_t rlen = strlen(++rhs);
534 - is_glob = (1 <= rlen && strchr(rhs, '*'));
535 - rs[i].dst = xstrndup(rhs, rlen);
536 - }
537 -
538 - llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
539 - if (1 <= llen && memchr(lhs, '*', llen)) {
540 - if ((rhs && !is_glob) || (!rhs && fetch))
541 - goto invalid;
542 - is_glob = 1;
543 - } else if (rhs && is_glob) {
544 - goto invalid;
545 - }
546 -
547 - rs[i].pattern = is_glob;
548 - rs[i].src = xstrndup(lhs, llen);
549 - flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
550 -
551 - if (fetch) {
552 - struct object_id unused;
553 -
554 - /* LHS */
555 - if (!*rs[i].src)
556 - ; /* empty is ok; it means "HEAD" */
557 - else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(rs[i].src, &unused))
558 - rs[i].exact_sha1 = 1; /* ok */
559 - else if (!check_refname_format(rs[i].src, flags))
560 - ; /* valid looking ref is ok */
561 - else
562 - goto invalid;
563 - /* RHS */
564 - if (!rs[i].dst)
565 - ; /* missing is ok; it is the same as empty */
566 - else if (!*rs[i].dst)
567 - ; /* empty is ok; it means "do not store" */
568 - else if (!check_refname_format(rs[i].dst, flags))
569 - ; /* valid looking ref is ok */
570 - else
571 - goto invalid;
572 - } else {
573 - /*
574 - * LHS
575 - * - empty is allowed; it means delete.
576 - * - when wildcarded, it must be a valid looking ref.
577 - * - otherwise, it must be an extended SHA-1, but
578 - * there is no existing way to validate this.
579 - */
580 - if (!*rs[i].src)
581 - ; /* empty is ok */
582 - else if (is_glob) {
583 - if (check_refname_format(rs[i].src, flags))
584 - goto invalid;
585 - }
586 - else
587 - ; /* anything goes, for now */
588 - /*
589 - * RHS
590 - * - missing is allowed, but LHS then must be a
591 - * valid looking ref.
592 - * - empty is not allowed.
593 - * - otherwise it must be a valid looking ref.
594 - */
595 - if (!rs[i].dst) {
596 - if (check_refname_format(rs[i].src, flags))
597 - goto invalid;
598 - } else if (!*rs[i].dst) {
599 - goto invalid;
600 - } else {
601 - if (check_refname_format(rs[i].dst, flags))
602 - goto invalid;
603 - }
604 - }
605 - }
606 - return rs;
607 -
608 - invalid:
609 - if (verify) {
610 - /*
611 - * nr_refspec must be greater than zero and i must be valid
612 - * since it is only possible to reach this point from within
613 - * the for loop above.
614 - */
615 - free_refspec(i+1, rs);
616 - return NULL;
617 - }
618 - die("Invalid refspec '%s'", refspec[i]);
619 -}
620 -
621 -int valid_fetch_refspec(const char *fetch_refspec_str)
622 -{
623 - struct refspec *refspec;
624 -
625 - refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1);
626 - free_refspec(1, refspec);
627 - return !!refspec;
628 -}
629 -
630 -struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec)
631 -{
632 - return parse_refspec_internal(nr_refspec, refspec, 1, 0);
633 -}
634 -
635 -struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
636 -{
637 - return parse_refspec_internal(nr_refspec, refspec, 0, 0);
638 -}
639 -
640 -void free_refspec(int nr_refspec, struct refspec *refspec)
641 -{
642 - int i;
643 -
644 - if (!refspec)
645 - return;
646 -
647 - for (i = 0; i < nr_refspec; i++) {
648 - free(refspec[i].src);
649 - free(refspec[i].dst);
650 - }
651 - free(refspec);
652 -}
653 -
491 static int valid_remote_nick(const char *name)
492 {
493 if (!name[0] || is_dot_or_dotdot(name))
remote.h
-20
@@ -68,18 +68,6 @@ int for_each_remote(each_remote_fn fn, void *priv);
68
69 int remote_has_url(struct remote *remote, const char *url);
70
71 -struct refspec {
72 - unsigned force : 1;
73 - unsigned pattern : 1;
74 - unsigned matching : 1;
75 - unsigned exact_sha1 : 1;
76 -
77 - char *src;
78 - char *dst;
79 -};
80 -
81 -extern const struct refspec *tag_refspec;
82 -
71 struct ref {
72 struct ref *next;
73 struct object_id old_oid;
@@ -175,12 +163,6 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);
163 */
164 struct ref *ref_remove_duplicates(struct ref *ref_map);
165
178 -int valid_fetch_refspec(const char *refspec);
179 -struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec);
180 -extern struct refspec *parse_push_refspec(int nr_refspec, const char **refspec);
181 -
182 -void free_refspec(int nr_refspec, struct refspec *refspec);
183 -
166 extern int query_refspecs(struct refspec *specs, int nr, struct refspec *query);
167 char *apply_refspecs(struct refspec *refspecs, int nr_refspec,
168 const char *name);
@@ -313,8 +295,6 @@ extern int parseopt_push_cas_option(const struct option *, const char *arg, int
295 extern int is_empty_cas(const struct push_cas_option *);
296 void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
297
316 -#define TAG_REFSPEC "refs/tags/*:refs/tags/*"
317 -
298 void add_prune_tags_to_fetch_refspec(struct remote *remote);
299
300 #endif
transport-helper.c
+1
@@ -11,6 +11,7 @@
11 #include "sigchain.h"
12 #include "argv-array.h"
13 #include "refs.h"
14 +#include "refspec.h"
15 #include "transport-internal.h"
16 #include "protocol.h"
17
transport.c
+1
@@ -11,6 +11,7 @@
11 #include "bundle.h"
12 #include "dir.h"
13 #include "refs.h"
14 +#include "refspec.h"
15 #include "branch.h"
16 #include "url.h"
17 #include "submodule.h"