remote: convert match_push_refs to use struct refspec
[gitweb.git] / remote.c
index 91eb010ca983c5493bbc17c5652ef31060390226..bce6e7ce4cd904442007b009710f407d201d2f66 100644 (file)
--- a/remote.c
+++ b/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"
 
 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;
@@ -108,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);
@@ -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))
@@ -887,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;
@@ -896,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;
@@ -913,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;
@@ -924,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;
 
@@ -944,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))
@@ -958,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);
 }
@@ -1167,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)
 {
@@ -1193,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;
@@ -1262,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;
@@ -1271,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;
@@ -1445,12 +1282,14 @@ 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 refspec = REFSPEC_INIT_PUSH;
        int ret = 0;
        int i;
 
-       for (i = 0; i < nr_refspec; i++) {
-               struct refspec *rs = refspec + i;
+       refspec_appendn(&refspec, refspec_names, nr_refspec);
+
+       for (i = 0; i < refspec.nr; i++) {
+               struct refspec_item *rs = &refspec.items[i];
 
                if (rs->pattern || rs->matching)
                        continue;
@@ -1458,7 +1297,7 @@ int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names)
                ret |= match_explicit_lhs(src, rs, NULL, NULL);
        }
 
-       free_refspec(nr_refspec, refspec);
+       refspec_clear(&refspec);
        return ret;
 }
 
@@ -1473,7 +1312,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 rs = REFSPEC_INIT_PUSH;
        int send_all = flags & MATCH_REFS_ALL;
        int send_mirror = flags & MATCH_REFS_MIRROR;
        int send_prune = flags & MATCH_REFS_PRUNE;
@@ -1486,17 +1325,17 @@ int match_push_refs(struct ref *src, struct ref **dst,
                nr_refspec = 1;
                refspec = default_refspec;
        }
-       rs = parse_push_refspec(nr_refspec, (const char **) refspec);
-       errs = match_explicit_refs(src, *dst, &dst_tail, rs, nr_refspec);
+       refspec_appendn(&rs, refspec, nr_refspec);
+       errs = match_explicit_refs(src, *dst, &dst_tail, rs.items, rs.nr);
 
        /* pick the remainder */
        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);
+               dst_name = get_ref_match(rs.items, rs.nr, ref, send_mirror, FROM_SRC, &pat);
                if (!dst_name)
                        continue;
 
@@ -1545,7 +1384,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
                                /* We're already sending something to this ref. */
                                continue;
 
-                       src_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_DST, NULL);
+                       src_name = get_ref_match(rs.items, rs.nr, ref, send_mirror, FROM_DST, NULL);
                        if (src_name) {
                                if (!src_ref_index.nr)
                                        prepare_ref_index(&src_ref_index, src);
@@ -1557,6 +1396,9 @@ int match_push_refs(struct ref *src, struct ref **dst,
                }
                string_list_clear(&src_ref_index, 0);
        }
+
+       refspec_clear(&rs);
+
        if (errs)
                return -1;
        return 0;
@@ -1849,7 +1691,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;
@@ -1914,7 +1756,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)
 {
@@ -2252,7 +2094,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;
 };
 
@@ -2261,9 +2103,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);
@@ -2294,7 +2136,7 @@ static int get_stale_heads_cb(const char *refname, const struct object_id *oid,
        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;