[PATCH] Add support for host aliases in config files

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This allows users with different preferences for access methods to the
same remote repositories to rewrite each other's URLs by pattern
matching across a large set of similiarly set up repositories to each
get the desired access.

Signed-off-by: Daniel Barkalow <barkalow@xxxxxxxxxxxx>
---
I still need to work more on the documentation (and I think I'd failed to 
come up with an organization for it that I liked), but I'd like to get the 
code portion out there are reviewed, at least, since I think last time, 
the patch only got as far as a discussion of how I should explain what it 
does.

 Documentation/config.txt |   22 +++++++++
 Documentation/urls.txt   |   25 ++++++++++
 remote.c                 |  112 ++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 156 insertions(+), 3 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index f2f6a77..6ccd59f 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -646,6 +646,28 @@ help.format::
 	Values 'man', 'info', 'web' and 'html' are supported. 'man' is
 	the default. 'web' and 'html' are the same.
 
+host.<name>.*::
+	These options provide a way to rewrite URLs when there is a
+	pattern of URLs with a common prefix which should be replaced
+	with a different prefix. For every 'alias' prefix given, any
+	URL git receives that starts with that prefix will be
+	rewritten to have the 'base' prefix instead. In cases where
+	some site serves a large number of repositories, and serves
+	them with multiple access methods, and some users need to use
+	different access 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.
+
+host.<name>.base::
+	The base URL which should be used for this particular
+	host.
+
+host.<name>.rewritebase::
+	Additional base URLs which refer to this host. If a URL
+	matches this, any access to it will use the URL formed with
+	the corresponding base URL instead of the given URL.
+
 http.proxy::
 	Override the HTTP proxy, normally configured using the 'http_proxy'
 	environment variable (see linkgit:curl[1]).  This can be overridden
diff --git a/Documentation/urls.txt b/Documentation/urls.txt
index 81ac17f..11c05db 100644
--- a/Documentation/urls.txt
+++ b/Documentation/urls.txt
@@ -44,3 +44,28 @@ endif::git-clone[]
 ifdef::git-clone[]
 They are equivalent, except the former implies --local option.
 endif::git-clone[]
+
+
+If there are a large number of similarly-named remote repositories and
+you want to use a different format for them (such that the URLs you
+use will be rewritten into URLs that work), you can create a
+configuration section of the form:
+
+------------
+	[host "<host>"]
+		base = <actual url base>
+		rewritebase = <other url base>
+------------
+
+If you have a section:
+
+------------
+	[host "xz"]
+		base = git://git.host.xz/
+		rewritebase = host.xz:/path/to/
+		rewritebase = work:
+------------
+
+a URL like "work:repo.git" or like "host.xz:/path/to/repo.git" will be
+rewritten in any context that takes a URL to be
+"git://git.host.xz/repo.git".
diff --git a/remote.c b/remote.c
index 6b56473..59338a3 100644
--- a/remote.c
+++ b/remote.c
@@ -2,6 +2,15 @@
 #include "remote.h"
 #include "refs.h"
 
+struct host {
+	const char *name;
+
+	const char *base;
+
+	const char **alias;
+	int alias_nr;
+};
+
 static struct remote **remotes;
 static int allocated_remotes;
 
@@ -11,9 +20,32 @@ static int allocated_branches;
 static struct branch *current_branch;
 static const char *default_remote_name;
 
+static struct host **hosts;
+static int allocated_hosts;
+
 #define BUF_SIZE (2048)
 static char buffer[BUF_SIZE];
 
+static const char *alias_url(const char *url)
+{
+	int i, j;
+	for (i = 0; i < allocated_hosts; i++) {
+		if (!hosts[i])
+			continue;
+		for (j = 0; j < hosts[i]->alias_nr; j++) {
+			if (!prefixcmp(url, hosts[i]->alias[j])) {
+				char *ret = malloc(strlen(hosts[i]->base) -
+						   strlen(hosts[i]->alias[j]) +
+						   strlen(url) + 1);
+				strcpy(ret, hosts[i]->base);
+				strcat(ret, url + strlen(hosts[i]->alias[j]));
+				return ret;
+			}
+		}
+	}
+	return url;
+}
+
 static void add_push_refspec(struct remote *remote, const char *ref)
 {
 	int nr = remote->push_refspec_nr + 1;
@@ -41,6 +73,11 @@ static void add_url(struct remote *remote, const char *url)
 	remote->url_nr = nr;
 }
 
+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;
@@ -121,6 +158,48 @@ static struct branch *make_branch(const char *name, int len)
 	return branches[empty];
 }
 
+static struct host *make_host(const char *name, int len)
+{
+	int i, empty = -1;
+
+	for (i = 0; i < allocated_hosts; i++) {
+		if (!hosts[i]) {
+			if (empty < 0)
+				empty = i;
+		} else {
+			if (len ? (!strncmp(name, hosts[i]->name, len) &&
+				   !hosts[i]->name[len]) :
+			    !strcmp(name, hosts[i]->name))
+				return hosts[i];
+		}
+	}
+
+	if (empty < 0) {
+		empty = allocated_hosts;
+		allocated_hosts += allocated_hosts ? allocated_hosts : 1;
+		hosts = xrealloc(hosts,
+				 sizeof(*hosts) * allocated_hosts);
+		memset(hosts + empty, 0,
+		       (allocated_hosts - empty) * sizeof(*hosts));
+	}
+	hosts[empty] = xcalloc(1, sizeof(struct host));
+	if (len)
+		hosts[empty]->name = xstrndup(name, len);
+	else
+		hosts[empty]->name = xstrdup(name);
+
+	return hosts[empty];
+}
+
+static void add_alias(struct host *host, const char *name)
+{
+	int nr = host->alias_nr + 1;
+	host->alias =
+		xrealloc(host->alias, nr * sizeof(char *));
+	host->alias[nr-1] = name;
+	host->alias_nr = nr;
+}
+
 static void read_remotes_file(struct remote *remote)
 {
 	FILE *f = fopen(git_path("remotes/%s", remote->name), "r");
@@ -154,7 +233,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 +285,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 */
 }
@@ -236,6 +315,20 @@ static int handle_config(const char *key, const char *value)
 		}
 		return 0;
 	}
+	if (!prefixcmp(key, "host.")) {
+		struct host *host;
+		name = key + 5;
+		subkey = strrchr(name, '.');
+		if (!subkey)
+			return 0;
+		host = make_host(name, subkey - name);
+		if (!value)
+			return 0;
+		if (!strcmp(subkey, ".base"))
+			host->base = xstrdup(value);
+		else if (!strcmp(subkey, ".rewritebase"))
+			add_alias(host, xstrdup(value));
+	}
 	if (prefixcmp(key,  "remote."))
 		return 0;
 	name = key + 7;
@@ -287,6 +380,18 @@ static int handle_config(const char *key, const char *value)
 	return 0;
 }
 
+static void alias_all_urls(void)
+{
+	int i, j;
+	for (i = 0; i < allocated_remotes; 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];
@@ -303,6 +408,7 @@ 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)
@@ -368,7 +474,7 @@ struct remote *remote_get(const char *name)
 			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);
-- 
1.5.4.1.1350.g2b9ee
-
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux