X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=remote.c;h=9700a33c57d796144a3b2f2e47b53d1d32d14c0d;hb=02b00e16bb372fd13e1ac440e9fbafd223d43af0;hp=bec2ba1adbed02af54572be924dcfbb47bf9c423;hpb=7666cdedb4e73948690587cda61b256ea2367c56;p=git.git diff --git a/remote.c b/remote.c index bec2ba1ad..9700a33c5 100644 --- a/remote.c +++ b/remote.c @@ -2,123 +2,184 @@ #include "remote.h" #include "refs.h" +struct counted_string { + size_t len; + const char *s; +}; +struct rewrite { + const char *base; + size_t baselen; + struct counted_string *instead_of; + int instead_of_nr; + int instead_of_alloc; +}; + static struct remote **remotes; -static int allocated_remotes; +static int remotes_alloc; +static int remotes_nr; static struct branch **branches; -static int allocated_branches; +static int branches_alloc; +static int branches_nr; static struct branch *current_branch; static const char *default_remote_name; +static struct rewrite **rewrite; +static int rewrite_alloc; +static int rewrite_nr; + #define BUF_SIZE (2048) static char buffer[BUF_SIZE]; +static const char *alias_url(const char *url) +{ + int i, j; + char *ret; + struct counted_string *longest; + int longest_i; + + longest = NULL; + longest_i = -1; + for (i = 0; i < rewrite_nr; i++) { + if (!rewrite[i]) + continue; + for (j = 0; j < rewrite[i]->instead_of_nr; j++) { + if (!prefixcmp(url, rewrite[i]->instead_of[j].s) && + (!longest || + longest->len < rewrite[i]->instead_of[j].len)) { + longest = &(rewrite[i]->instead_of[j]); + longest_i = i; + } + } + } + if (!longest) + return url; + + ret = malloc(rewrite[longest_i]->baselen + + (strlen(url) - longest->len) + 1); + strcpy(ret, rewrite[longest_i]->base); + strcpy(ret + rewrite[longest_i]->baselen, url + longest->len); + return ret; +} + static void add_push_refspec(struct remote *remote, const char *ref) { - int nr = remote->push_refspec_nr + 1; - remote->push_refspec = - xrealloc(remote->push_refspec, nr * sizeof(char *)); - remote->push_refspec[nr-1] = ref; - remote->push_refspec_nr = nr; + ALLOC_GROW(remote->push_refspec, + remote->push_refspec_nr + 1, + remote->push_refspec_alloc); + remote->push_refspec[remote->push_refspec_nr++] = ref; } static void add_fetch_refspec(struct remote *remote, const char *ref) { - int nr = remote->fetch_refspec_nr + 1; - remote->fetch_refspec = - xrealloc(remote->fetch_refspec, nr * sizeof(char *)); - remote->fetch_refspec[nr-1] = ref; - remote->fetch_refspec_nr = nr; + ALLOC_GROW(remote->fetch_refspec, + remote->fetch_refspec_nr + 1, + remote->fetch_refspec_alloc); + remote->fetch_refspec[remote->fetch_refspec_nr++] = ref; } static void add_url(struct remote *remote, const char *url) { - int nr = remote->url_nr + 1; - remote->url = - xrealloc(remote->url, nr * sizeof(char *)); - remote->url[nr-1] = url; - remote->url_nr = nr; + ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc); + remote->url[remote->url_nr++] = url; +} + +static void add_url_alias(struct remote *remote, const char *url) +{ + add_url(remote, alias_url(url)); } static struct remote *make_remote(const char *name, int len) { - int i, empty = -1; + struct remote *ret; + int i; - for (i = 0; i < allocated_remotes; i++) { - if (!remotes[i]) { - if (empty < 0) - empty = i; - } else { - if (len ? (!strncmp(name, remotes[i]->name, len) && - !remotes[i]->name[len]) : - !strcmp(name, remotes[i]->name)) - return remotes[i]; - } + for (i = 0; i < remotes_nr; i++) { + if (len ? (!strncmp(name, remotes[i]->name, len) && + !remotes[i]->name[len]) : + !strcmp(name, remotes[i]->name)) + return remotes[i]; } - if (empty < 0) { - empty = allocated_remotes; - allocated_remotes += allocated_remotes ? allocated_remotes : 1; - remotes = xrealloc(remotes, - sizeof(*remotes) * allocated_remotes); - memset(remotes + empty, 0, - (allocated_remotes - empty) * sizeof(*remotes)); - } - remotes[empty] = xcalloc(1, sizeof(struct remote)); + ret = xcalloc(1, sizeof(struct remote)); + ALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc); + remotes[remotes_nr++] = ret; if (len) - remotes[empty]->name = xstrndup(name, len); + ret->name = xstrndup(name, len); else - remotes[empty]->name = xstrdup(name); - return remotes[empty]; + ret->name = xstrdup(name); + return ret; } static void add_merge(struct branch *branch, const char *name) { - int nr = branch->merge_nr + 1; - branch->merge_name = - xrealloc(branch->merge_name, nr * sizeof(char *)); - branch->merge_name[nr-1] = name; - branch->merge_nr = nr; + ALLOC_GROW(branch->merge_name, branch->merge_nr + 1, + branch->merge_alloc); + branch->merge_name[branch->merge_nr++] = name; } static struct branch *make_branch(const char *name, int len) { - int i, empty = -1; + struct branch *ret; + int i; char *refname; - for (i = 0; i < allocated_branches; i++) { - if (!branches[i]) { - if (empty < 0) - empty = i; - } else { - if (len ? (!strncmp(name, branches[i]->name, len) && - !branches[i]->name[len]) : - !strcmp(name, branches[i]->name)) - return branches[i]; - } + for (i = 0; i < branches_nr; i++) { + if (len ? (!strncmp(name, branches[i]->name, len) && + !branches[i]->name[len]) : + !strcmp(name, branches[i]->name)) + return branches[i]; } - if (empty < 0) { - empty = allocated_branches; - allocated_branches += allocated_branches ? allocated_branches : 1; - branches = xrealloc(branches, - sizeof(*branches) * allocated_branches); - memset(branches + empty, 0, - (allocated_branches - empty) * sizeof(*branches)); - } - branches[empty] = xcalloc(1, sizeof(struct branch)); + ALLOC_GROW(branches, branches_nr + 1, branches_alloc); + ret = xcalloc(1, sizeof(struct branch)); + branches[branches_nr++] = ret; if (len) - branches[empty]->name = xstrndup(name, len); + ret->name = xstrndup(name, len); else - branches[empty]->name = xstrdup(name); + ret->name = xstrdup(name); refname = malloc(strlen(name) + strlen("refs/heads/") + 1); strcpy(refname, "refs/heads/"); - strcpy(refname + strlen("refs/heads/"), - branches[empty]->name); - branches[empty]->refname = refname; + strcpy(refname + strlen("refs/heads/"), ret->name); + ret->refname = refname; + + return ret; +} + +static struct rewrite *make_rewrite(const char *base, int len) +{ + struct rewrite *ret; + int i; + + for (i = 0; i < rewrite_nr; i++) { + if (len + ? (len == rewrite[i]->baselen && + !strncmp(base, rewrite[i]->base, len)) + : !strcmp(base, rewrite[i]->base)) + return rewrite[i]; + } + + ALLOC_GROW(rewrite, rewrite_nr + 1, rewrite_alloc); + ret = xcalloc(1, sizeof(struct rewrite)); + rewrite[rewrite_nr++] = ret; + if (len) { + ret->base = xstrndup(base, len); + ret->baselen = len; + } + else { + ret->base = xstrdup(base); + ret->baselen = strlen(base); + } + return ret; +} - return branches[empty]; +static void add_instead_of(struct rewrite *rewrite, const char *instead_of) +{ + ALLOC_GROW(rewrite->instead_of, rewrite->instead_of_nr + 1, rewrite->instead_of_alloc); + rewrite->instead_of[rewrite->instead_of_nr].s = instead_of; + rewrite->instead_of[rewrite->instead_of_nr].len = strlen(instead_of); + rewrite->instead_of_nr++; } static void read_remotes_file(struct remote *remote) @@ -154,7 +215,7 @@ static void read_remotes_file(struct remote *remote) switch (value_list) { case 0: - add_url(remote, xstrdup(s)); + add_url_alias(remote, xstrdup(s)); break; case 1: add_push_refspec(remote, xstrdup(s)); @@ -206,7 +267,7 @@ static void read_branches_file(struct remote *remote) } else { branch = "refs/heads/master"; } - add_url(remote, p); + add_url_alias(remote, p); add_fetch_refspec(remote, branch); remote->fetch_tags = 1; /* always auto-follow */ } @@ -220,19 +281,35 @@ static int handle_config(const char *key, const char *value) if (!prefixcmp(key, "branch.")) { name = key + 7; subkey = strrchr(name, '.'); - branch = make_branch(name, subkey - name); if (!subkey) return 0; - if (!value) - return 0; + branch = make_branch(name, subkey - name); if (!strcmp(subkey, ".remote")) { + if (!value) + return config_error_nonbool(key); branch->remote_name = xstrdup(value); if (branch == current_branch) default_remote_name = branch->remote_name; - } else if (!strcmp(subkey, ".merge")) + } else if (!strcmp(subkey, ".merge")) { + if (!value) + return config_error_nonbool(key); add_merge(branch, xstrdup(value)); + } return 0; } + if (!prefixcmp(key, "url.")) { + struct rewrite *rewrite; + name = key + 5; + subkey = strrchr(name, '.'); + if (!subkey) + return 0; + rewrite = make_rewrite(name, subkey - name); + if (!strcmp(subkey, ".insteadof")) { + if (!value) + return config_error_nonbool(key); + add_instead_of(rewrite, xstrdup(value)); + } + } if (prefixcmp(key, "remote.")) return 0; name = key + 7; @@ -278,10 +355,25 @@ static int handle_config(const char *key, const char *value) } else if (!strcmp(subkey, ".tagopt")) { if (!strcmp(value, "--no-tags")) remote->fetch_tags = -1; - } + } else if (!strcmp(subkey, ".proxy")) { + remote->http_proxy = xstrdup(value); + } else if (!strcmp(subkey, ".skipdefaultupdate")) + remote->skip_default_update = 1; return 0; } +static void alias_all_urls(void) +{ + int i, j; + for (i = 0; i < remotes_nr; i++) { + if (!remotes[i]) + continue; + for (j = 0; j < remotes[i]->url_nr; j++) { + remotes[i]->url[j] = alias_url(remotes[i]->url[j]); + } + } +} + static void read_config(void) { unsigned char sha1[20]; @@ -298,11 +390,13 @@ static void read_config(void) make_branch(head_ref + strlen("refs/heads/"), 0); } git_config(handle_config); + alias_all_urls(); } struct refspec *parse_ref_spec(int nr_refspec, const char **refspec) { int i; + int st; struct refspec *rs = xcalloc(sizeof(*rs), nr_refspec); for (i = 0; i < nr_refspec; i++) { const char *sp, *ep, *gp; @@ -311,13 +405,15 @@ struct refspec *parse_ref_spec(int nr_refspec, const char **refspec) rs[i].force = 1; sp++; } - gp = strchr(sp, '*'); + gp = strstr(sp, "/*"); ep = strchr(sp, ':'); if (gp && ep && gp > ep) gp = NULL; if (ep) { if (ep[1]) { - const char *glob = strchr(ep + 1, '*'); + const char *glob = strstr(ep + 1, "/*"); + if (glob && glob[2]) + glob = NULL; if (!glob) gp = NULL; if (gp) @@ -329,15 +425,38 @@ struct refspec *parse_ref_spec(int nr_refspec, const char **refspec) } else { ep = sp + strlen(sp); } + if (gp && gp + 2 != ep) + gp = NULL; if (gp) { rs[i].pattern = 1; ep = gp; } rs[i].src = xstrndup(sp, ep - sp); + + if (*rs[i].src) { + st = check_ref_format(rs[i].src); + if (st && st != CHECK_REF_FORMAT_ONELEVEL) + die("Invalid refspec '%s'", refspec[i]); + } + if (rs[i].dst && *rs[i].dst) { + st = check_ref_format(rs[i].dst); + if (st && st != CHECK_REF_FORMAT_ONELEVEL) + die("Invalid refspec '%s'", refspec[i]); + } } return rs; } +static int valid_remote_nick(const char *name) +{ + if (!name[0] || /* not empty */ + (name[0] == '.' && /* not "." */ + (!name[1] || /* not ".." */ + (name[1] == '.' && !name[2])))) + return 0; + return !strchr(name, '/'); /* no slash */ +} + struct remote *remote_get(const char *name) { struct remote *ret; @@ -346,14 +465,14 @@ struct remote *remote_get(const char *name) if (!name) name = default_remote_name; ret = make_remote(name, 0); - if (name[0] != '/') { + if (valid_remote_nick(name)) { if (!ret->url) read_remotes_file(ret); if (!ret->url) read_branches_file(ret); } if (!ret->url) - add_url(ret, name); + add_url_alias(ret, name); if (!ret->url) return NULL; ret->fetch = parse_ref_spec(ret->fetch_refspec_nr, ret->fetch_refspec); @@ -365,7 +484,7 @@ int for_each_remote(each_remote_fn fn, void *priv) { int i, result = 0; read_config(); - for (i = 0; i < allocated_remotes && !result; i++) { + for (i = 0; i < remotes_nr && !result; i++) { struct remote *r = remotes[i]; if (!r) continue; @@ -417,25 +536,6 @@ int remote_has_url(struct remote *remote, const char *url) return 0; } -/* - * Returns true if, under the matching rules for fetching, name is the - * same as the given full name. - */ -static int ref_matches_abbrev(const char *name, const char *full) -{ - if (!prefixcmp(name, "refs/") || !strcmp(name, "HEAD")) - return !strcmp(name, full); - if (prefixcmp(full, "refs/")) - return 0; - if (!prefixcmp(name, "heads/") || - !prefixcmp(name, "tags/") || - !prefixcmp(name, "remotes/")) - return !strcmp(name, full + 5); - if (prefixcmp(full + 5, "heads/")) - return 0; - return !strcmp(full + 11, name); -} - int remote_find_tracking(struct remote *remote, struct refspec *refspec) { int find_src = refspec->src == NULL; @@ -459,7 +559,8 @@ int remote_find_tracking(struct remote *remote, struct refspec *refspec) if (!fetch->dst) continue; if (fetch->pattern) { - if (!prefixcmp(needle, key)) { + if (!prefixcmp(needle, key) && + needle[strlen(key)] == '/') { *result = xmalloc(strlen(value) + strlen(needle) - strlen(key) + 1); @@ -485,7 +586,7 @@ struct ref *alloc_ref(unsigned namelen) return ret; } -static struct ref *copy_ref(struct ref *ref) +static struct ref *copy_ref(const struct ref *ref) { struct ref *ret = xmalloc(sizeof(struct ref) + strlen(ref->name) + 1); memcpy(ret, ref, sizeof(struct ref) + strlen(ref->name) + 1); @@ -493,13 +594,24 @@ static struct ref *copy_ref(struct ref *ref) return ret; } +struct ref *copy_ref_list(const struct ref *ref) +{ + struct ref *ret = NULL; + struct ref **tail = &ret; + while (ref) { + *tail = copy_ref(ref); + ref = ref->next; + tail = &((*tail)->next); + } + return ret; +} + void free_refs(struct ref *ref) { struct ref *next; while (ref) { next = ref->next; - if (ref->peer_ref) - free(ref->peer_ref); + free(ref->peer_ref); free(ref); ref = next; } @@ -519,10 +631,7 @@ static int count_refspec_match(const char *pattern, char *name = refs->name; int namelen = strlen(name); - if (namelen < patlen || - memcmp(name + namelen - patlen, pattern, patlen)) - continue; - if (namelen != patlen && name[namelen - patlen - 1] != '/') + if (!refname_match(pattern, name, ref_rev_parse_rules)) continue; /* A match is "weak" if it is with refs outside @@ -638,9 +747,17 @@ static int match_explicit(struct ref *src, struct ref *dst, errs = 1; if (!dst_value) { + unsigned char sha1[20]; + int flag; + if (!matched_src) return errs; - dst_value = matched_src->name; + dst_value = resolve_ref(matched_src->name, sha1, 1, &flag); + if (!dst_value || + ((flag & REF_ISSYMREF) && + prefixcmp(dst_value, "refs/heads/"))) + die("%s cannot be resolved to branch.", + matched_src->name); } switch (count_refspec_match(dst_value, dst, &matched_dst)) { @@ -684,21 +801,15 @@ static int match_explicit_refs(struct ref *src, struct ref *dst, return -errs; } -static struct ref *find_ref_by_name(struct ref *list, const char *name) -{ - for ( ; list; list = list->next) - if (!strcmp(list->name, name)) - return list; - return NULL; -} - static const struct refspec *check_pattern_match(const struct refspec *rs, int rs_nr, const struct ref *src) { int i; for (i = 0; i < rs_nr; i++) { - if (rs[i].pattern && !prefixcmp(src->name, rs[i].src)) + if (rs[i].pattern && + !prefixcmp(src->name, rs[i].src) && + src->name[strlen(rs[i].src)] == '/') return rs + i; } return NULL; @@ -710,10 +821,12 @@ static const struct refspec *check_pattern_match(const struct refspec *rs, * without thinking. */ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, - int nr_refspec, char **refspec, int all) + int nr_refspec, const char **refspec, int flags) { struct refspec *rs = parse_ref_spec(nr_refspec, (const char **) refspec); + int send_all = flags & MATCH_REFS_ALL; + int send_mirror = flags & MATCH_REFS_MIRROR; if (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec)) return -1; @@ -730,7 +843,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, if (!pat) continue; } - else if (prefixcmp(src->name, "refs/heads/")) + else if (!send_mirror && prefixcmp(src->name, "refs/heads/")) /* * "matching refs"; traditionally we pushed everything * including refs outside refs/heads/ hierarchy, but @@ -751,10 +864,13 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail, if (dst_peer && dst_peer->peer_ref) /* We're already sending something to this ref. */ goto free_name; - if (!dst_peer && !nr_refspec && !all) - /* Remote doesn't have it, and we have no + + if (!dst_peer && !nr_refspec && !(send_all || send_mirror)) + /* + * Remote doesn't have it, and we have no * explicit pattern, and we don't have - * --all. */ + * --all nor --mirror. + */ goto free_name; if (!dst_peer) { /* Create a new one and link it */ @@ -807,13 +923,13 @@ int branch_merge_matches(struct branch *branch, { if (!branch || i < 0 || i >= branch->merge_nr) return 0; - return ref_matches_abbrev(branch->merge[i]->src, refname); + return refname_match(branch->merge[i]->src, refname, ref_fetch_rules); } -static struct ref *get_expanded_map(struct ref *remote_refs, +static struct ref *get_expanded_map(const struct ref *remote_refs, const struct refspec *refspec) { - struct ref *ref; + const struct ref *ref; struct ref *ret = NULL; struct ref **tail = &ret; @@ -824,7 +940,7 @@ static struct ref *get_expanded_map(struct ref *remote_refs, if (strchr(ref->name, '^')) continue; /* a dereference item */ if (!prefixcmp(ref->name, refspec->src)) { - char *match; + const char *match; struct ref *cpy = copy_ref(ref); match = ref->name + remote_prefix_len; @@ -842,19 +958,19 @@ static struct ref *get_expanded_map(struct ref *remote_refs, return ret; } -static struct ref *find_ref_by_name_abbrev(struct ref *refs, const char *name) +static const struct ref *find_ref_by_name_abbrev(const struct ref *refs, const char *name) { - struct ref *ref; + const struct ref *ref; for (ref = refs; ref; ref = ref->next) { - if (ref_matches_abbrev(name, ref->name)) + if (refname_match(name, ref->name, ref_fetch_rules)) return ref; } return NULL; } -struct ref *get_remote_ref(struct ref *remote_refs, const char *name) +struct ref *get_remote_ref(const struct ref *remote_refs, const char *name) { - struct ref *ref = find_ref_by_name_abbrev(remote_refs, name); + const struct ref *ref = find_ref_by_name_abbrev(remote_refs, name); if (!ref) return NULL; @@ -887,12 +1003,12 @@ static struct ref *get_local_ref(const char *name) return ret; } -int get_fetch_map(struct ref *remote_refs, +int get_fetch_map(const struct ref *remote_refs, const struct refspec *refspec, struct ref ***tail, int missing_ok) { - struct ref *ref_map, *rm; + struct ref *ref_map, **rmp; if (refspec->pattern) { ref_map = get_expanded_map(remote_refs, refspec); @@ -909,10 +1025,20 @@ int get_fetch_map(struct ref *remote_refs, } } - for (rm = ref_map; rm; rm = rm->next) { - if (rm->peer_ref && check_ref_format(rm->peer_ref->name + 5)) - die("* refusing to create funny ref '%s' locally", - rm->peer_ref->name); + for (rmp = &ref_map; *rmp; ) { + if ((*rmp)->peer_ref) { + int st = check_ref_format((*rmp)->peer_ref->name + 5); + if (st && st != CHECK_REF_FORMAT_ONELEVEL) { + struct ref *ignore = *rmp; + error("* Ignoring funny ref '%s' locally", + (*rmp)->peer_ref->name); + *rmp = (*rmp)->next; + free(ignore->peer_ref); + free(ignore); + continue; + } + } + rmp = &((*rmp)->next); } if (ref_map)