builtin-name-rev.c: split deeply nested part from the main function
[git.git] / remote.c
index 9e4f2b84d90cb97a6cb19779325f9ea443a76e43..5f687b2e298c98e82d775b022743f957fa2fcdfc 100644 (file)
--- a/remote.c
+++ b/remote.c
@@ -2,6 +2,16 @@
 #include "remote.h"
 #include "refs.h"
 
+static struct refspec s_tag_refspec = {
+       0,
+       1,
+       0,
+       "refs/tags/",
+       "refs/tags/"
+};
+
+const struct refspec *tag_refspec = &s_tag_refspec;
+
 struct counted_string {
        size_t len;
        const char *s;
@@ -288,7 +298,7 @@ static void read_branches_file(struct remote *remote)
        remote->fetch_tags = 1; /* always auto-follow */
 }
 
-static int handle_config(const char *key, const char *value)
+static int handle_config(const char *key, const char *value, void *cb)
 {
        const char *name;
        const char *subkey;
@@ -410,10 +420,32 @@ static void read_config(void)
                current_branch =
                        make_branch(head_ref + strlen("refs/heads/"), 0);
        }
-       git_config(handle_config);
+       git_config(handle_config, NULL);
        alias_all_urls();
 }
 
+/*
+ * We need to make sure the tracking branches are well formed, but a
+ * wildcard refspec in "struct refspec" must have a trailing slash. We
+ * temporarily drop the trailing '/' while calling check_ref_format(),
+ * and put it back.  The caller knows that a CHECK_REF_FORMAT_ONELEVEL
+ * error return is Ok for a wildcard refspec.
+ */
+static int verify_refname(char *name, int is_glob)
+{
+       int result, len = -1;
+
+       if (is_glob) {
+               len = strlen(name);
+               assert(name[len - 1] == '/');
+               name[len - 1] = '\0';
+       }
+       result = check_ref_format(name);
+       if (is_glob)
+               name[len - 1] = '/';
+       return result;
+}
+
 static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
 {
        int i;
@@ -421,11 +453,11 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
        struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec);
 
        for (i = 0; i < nr_refspec; i++) {
-               size_t llen, rlen;
+               size_t llen;
                int is_glob;
                const char *lhs, *rhs;
 
-               llen = rlen = is_glob = 0;
+               llen = is_glob = 0;
 
                lhs = refspec[i];
                if (*lhs == '+') {
@@ -445,12 +477,9 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
                }
 
                if (rhs) {
-                       rhs++;
-                       rlen = strlen(rhs);
+                       size_t rlen = strlen(++rhs);
                        is_glob = (2 <= rlen && !strcmp(rhs + rlen - 2, "/*"));
-                       if (is_glob)
-                               rlen -= 2;
-                       rs[i].dst = xstrndup(rhs, rlen);
+                       rs[i].dst = xstrndup(rhs, rlen - is_glob);
                }
 
                llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
@@ -458,7 +487,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
                        if ((rhs && !is_glob) || (!rhs && fetch))
                                goto invalid;
                        is_glob = 1;
-                       llen -= 2;
+                       llen--;
                } else if (rhs && is_glob) {
                        goto invalid;
                }
@@ -475,7 +504,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
                        if (!*rs[i].src)
                                ; /* empty is ok */
                        else {
-                               st = check_ref_format(rs[i].src);
+                               st = verify_refname(rs[i].src, is_glob);
                                if (st && st != CHECK_REF_FORMAT_ONELEVEL)
                                        goto invalid;
                        }
@@ -490,7 +519,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
                        } else if (!*rs[i].dst) {
                                ; /* ok */
                        } else {
-                               st = check_ref_format(rs[i].dst);
+                               st = verify_refname(rs[i].dst, is_glob);
                                if (st && st != CHECK_REF_FORMAT_ONELEVEL)
                                        goto invalid;
                        }
@@ -505,7 +534,7 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
                        if (!*rs[i].src)
                                ; /* empty is ok */
                        else if (is_glob) {
-                               st = check_ref_format(rs[i].src);
+                               st = verify_refname(rs[i].src, is_glob);
                                if (st && st != CHECK_REF_FORMAT_ONELEVEL)
                                        goto invalid;
                        }
@@ -519,13 +548,13 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
                         * - otherwise it must be a valid looking ref.
                         */
                        if (!rs[i].dst) {
-                               st = check_ref_format(rs[i].src);
+                               st = verify_refname(rs[i].src, is_glob);
                                if (st && st != CHECK_REF_FORMAT_ONELEVEL)
                                        goto invalid;
                        } else if (!*rs[i].dst) {
                                goto invalid;
                        } else {
-                               st = check_ref_format(rs[i].dst);
+                               st = verify_refname(rs[i].dst, is_glob);
                                if (st && st != CHECK_REF_FORMAT_ONELEVEL)
                                        goto invalid;
                        }
@@ -674,8 +703,7 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec)
                if (!fetch->dst)
                        continue;
                if (fetch->pattern) {
-                       if (!prefixcmp(needle, key) &&
-                           needle[strlen(key)] == '/') {
+                       if (!prefixcmp(needle, key)) {
                                *result = xmalloc(strlen(value) +
                                                  strlen(needle) -
                                                  strlen(key) + 1);
@@ -857,8 +885,7 @@ static char *guess_ref(const char *name, struct ref *peer)
 
 static int match_explicit(struct ref *src, struct ref *dst,
                          struct ref ***dst_tail,
-                         struct refspec *rs,
-                         int errs)
+                         struct refspec *rs)
 {
        struct ref *matched_src, *matched_dst;
 
@@ -866,7 +893,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
        char *dst_guess;
 
        if (rs->pattern || rs->matching)
-               return errs;
+               return 0;
 
        matched_src = matched_dst = NULL;
        switch (count_refspec_match(rs->src, src, &matched_src)) {
@@ -879,23 +906,16 @@ static int match_explicit(struct ref *src, struct ref *dst,
                 */
                matched_src = try_explicit_object_name(rs->src);
                if (!matched_src)
-                       error("src refspec %s does not match any.", rs->src);
+                       return error("src refspec %s does not match any.", rs->src);
                break;
        default:
-               matched_src = NULL;
-               error("src refspec %s matches more than one.", rs->src);
-               break;
+               return error("src refspec %s matches more than one.", rs->src);
        }
 
-       if (!matched_src)
-               errs = 1;
-
        if (!dst_value) {
                unsigned char sha1[20];
                int flag;
 
-               if (!matched_src)
-                       return errs;
                dst_value = resolve_ref(matched_src->name, sha1, 1, &flag);
                if (!dst_value ||
                    ((flag & REF_ISSYMREF) &&
@@ -926,18 +946,16 @@ static int match_explicit(struct ref *src, struct ref *dst,
                      dst_value);
                break;
        }
-       if (errs || !matched_dst)
-               return 1;
-       if (matched_dst->peer_ref) {
-               errs = 1;
-               error("dst ref %s receives from more than one src.",
+       if (!matched_dst)
+               return -1;
+       if (matched_dst->peer_ref)
+               return error("dst ref %s receives from more than one src.",
                      matched_dst->name);
-       }
        else {
                matched_dst->peer_ref = matched_src;
                matched_dst->force = rs->force;
        }
-       return errs;
+       return 0;
 }
 
 static int match_explicit_refs(struct ref *src, struct ref *dst,
@@ -946,8 +964,8 @@ static int match_explicit_refs(struct ref *src, struct ref *dst,
 {
        int i, errs;
        for (i = errs = 0; i < rs_nr; i++)
-               errs |= match_explicit(src, dst, dst_tail, &rs[i], errs);
-       return -errs;
+               errs += match_explicit(src, dst, dst_tail, &rs[i]);
+       return errs;
 }
 
 static const struct refspec *check_pattern_match(const struct refspec *rs,
@@ -963,9 +981,7 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,
                        continue;
                }
 
-               if (rs[i].pattern &&
-                   !prefixcmp(src->name, rs[i].src) &&
-                   src->name[strlen(rs[i].src)] == '/')
+               if (rs[i].pattern && !prefixcmp(src->name, rs[i].src))
                        return rs + i;
        }
        if (matching_refs != -1)