git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] Add support for host aliases in config files
@ 2008-01-25 18:39 Daniel Barkalow
  2008-01-25 18:52 ` Jakub Narebski
  0 siblings, 1 reply; 16+ messages in thread
From: Daniel Barkalow @ 2008-01-25 18:39 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

This allows users with different preferences for access methods to the
same remote repositories to rewrite each other's URLs to get the
desired access.

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
---
 Documentation/config.txt |   15 ++++++
 remote.c                 |  112 ++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 124 insertions(+), 3 deletions(-)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 877eda9..dae79ce 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -596,6 +596,21 @@ help.format::
 	Values 'man', 'info', 'web' and 'html' are supported. 'man' is
 	the default. 'web' and 'html' are the same.
 
+host.<name>.base::
+	The base URL which should be used for this particular
+	host. This can be used by a user who has a better access
+	method to a repository than other users to make use of the
+	preferable path despite getting URLs from other users using
+	more commonly-available methods. Alternatively, a user who
+	only has less privileged access to a repository than the usual
+	audience can use this mechanism to replace disallowed methods
+	with public ones.
+
+host.<name>.alias::
+	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/remote.c b/remote.c
index 0e00680..76ed576 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 */
 }
@@ -233,6 +312,20 @@ static int handle_config(const char *key, const char *value)
 			add_merge(branch, xstrdup(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, ".alias"))
+			add_alias(host, xstrdup(value));
+	}
 	if (prefixcmp(key,  "remote."))
 		return 0;
 	name = key + 7;
@@ -284,6 +377,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];
@@ -300,6 +405,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)
@@ -355,7 +461,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.rc3.4.g16335

^ permalink raw reply related	[flat|nested] 16+ messages in thread
* [PATCH] Add support for host aliases in config files
@ 2008-02-17 18:38 Daniel Barkalow
  2008-02-17 18:48 ` Jakub Narebski
                   ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: Daniel Barkalow @ 2008-02-17 18:38 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

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@iabervon.org>
---
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

^ permalink raw reply related	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2008-02-18 19:30 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-01-25 18:39 [PATCH] Add support for host aliases in config files Daniel Barkalow
2008-01-25 18:52 ` Jakub Narebski
2008-01-25 19:01   ` Junio C Hamano
2008-01-25 19:09   ` Daniel Barkalow
2008-01-25 19:33     ` Jakub Narebski
2008-01-25 19:53       ` Daniel Barkalow
2008-01-25 21:51         ` Jakub Narebski
2008-01-25 20:19       ` Junio C Hamano
2008-01-25 21:12         ` Daniel Barkalow
2008-01-25 21:48           ` Jakub Narebski
  -- strict thread matches above, loose matches on Subject: below --
2008-02-17 18:38 Daniel Barkalow
2008-02-17 18:48 ` Jakub Narebski
2008-02-17 18:58   ` Daniel Barkalow
2008-02-17 19:36 ` Johannes Schindelin
2008-02-18  4:52 ` Junio C Hamano
2008-02-18 19:29   ` Daniel Barkalow

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).