From 844112cac07d6413b9bb42d38527d2f7ca7c7801 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sun, 24 Feb 2008 22:25:04 -0800 Subject: [PATCH] url rewriting: take longest and first match Earlier we had a cop-out in the documentation to make the behaviour "undefined" if configuration had more than one insteadOf that would match the target URL, like this: [url "git://git.or.cz/"] insteadOf = "git.or.cz:" ; (1) insteadOf = "repo.or.cz:" ; (2) [url "/local/mirror/"] insteadOf = "git.or.cz:myrepo" ; (3) insteadOf = "repo.or.cz:" ; (4) It would be most natural to take the longest and first match, i.e. - rewrite "git.or.cz:frotz" to "git://git.or.cz/frotz" by using (1), - rewrite "git.or.cz:myrepo/xyzzy" to "/local/mirror/xyzzy" by favoring (3) over (1), and - rewrite "repo.or.cz:frotz" to "git://git.or.cz/frotz" by favoring (2) over (4). Signed-off-by: Junio C Hamano --- Documentation/config.txt | 5 ++-- remote.c | 54 ++++++++++++++++++++++++++++------------ 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/Documentation/config.txt b/Documentation/config.txt index 298138917..57b9b9986 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -894,9 +894,8 @@ url..insteadOf:: methods, this feature allows people to specify any of the equivalent URLs and have git automatically rewrite the URL to the best alternative for the particular user, even for a - never-before-seen repository on the site. The effect of - having multiple `insteadOf` values from different - `` match to an URL is undefined. + never-before-seen repository on the site. When more than one + insteadOf strings match a given URL, the longest match is used. user.email:: Your email address to be recorded in any newly created commits. diff --git a/remote.c b/remote.c index 0012954b6..1f8369675 100644 --- a/remote.c +++ b/remote.c @@ -2,9 +2,14 @@ #include "remote.h" #include "refs.h" +struct counted_string { + size_t len; + const char *s; +}; struct rewrite { const char *base; - const char **instead_of; + size_t baselen; + struct counted_string *instead_of; int instead_of_nr; int instead_of_alloc; }; @@ -30,21 +35,32 @@ 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])) { - char *ret = malloc(strlen(rewrite[i]->base) - - strlen(rewrite[i]->instead_of[j]) + - strlen(url) + 1); - strcpy(ret, rewrite[i]->base); - strcat(ret, url + strlen(rewrite[i]->instead_of[j])); - return ret; + 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; } } } - return url; + 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) @@ -137,27 +153,33 @@ static struct rewrite *make_rewrite(const char *base, int len) int i; for (i = 0; i < rewrite_nr; i++) { - if (len ? (!strncmp(base, rewrite[i]->base, len) && - !rewrite[i]->base[len]) : - !strcmp(base, rewrite[i]->base)) + 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) + if (len) { ret->base = xstrndup(base, len); - else + ret->baselen = len; + } + else { ret->base = xstrdup(base); - + ret->baselen = strlen(base); + } return ret; } 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++] = instead_of; + 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) -- 2.30.2