[PATCH 2/5] Add remote functions

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

 



Make a struct and a set of functions to handle the parsing of remote
configurations (branches files, remotes files, and config sections),
and do some simple operations on lists of refspecs in the struct.

Signed-off-by: Daniel Barkalow <barkalow@xxxxxxxxxxxx>
---
 Makefile |    4 +-
 remote.c |  241 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 remote.h |   25 +++++++
 3 files changed, 268 insertions(+), 2 deletions(-)
 create mode 100644 remote.c
 create mode 100644 remote.h

diff --git a/Makefile b/Makefile
index 60c41fd..98916f7 100644
--- a/Makefile
+++ b/Makefile
@@ -288,7 +288,7 @@ LIB_H = \
 	diff.h object.h pack.h pkt-line.h quote.h refs.h list-objects.h sideband.h \
 	run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h \
 	tree-walk.h log-tree.h dir.h path-list.h unpack-trees.h builtin.h \
-	utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h
+	utf8.h reflog-walk.h patch-ids.h attr.h decorate.h progress.h remote.h
 
 DIFF_OBJS = \
 	diff.o diff-lib.o diffcore-break.o diffcore-order.o \
@@ -310,7 +310,7 @@ LIB_OBJS = \
 	write_or_die.o trace.o list-objects.o grep.o match-trees.o \
 	alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
 	color.o wt-status.o archive-zip.o archive-tar.o shallow.o utf8.o \
-	convert.o attr.o decorate.o progress.o
+	convert.o attr.o decorate.o progress.o remote.o
 
 BUILTIN_OBJS = \
 	builtin-add.o \
diff --git a/remote.c b/remote.c
new file mode 100644
index 0000000..58e6a96
--- /dev/null
+++ b/remote.c
@@ -0,0 +1,241 @@
+#include "cache.h"
+#include "remote.h"
+
+#define MAX_REMOTES 16
+
+static struct remote *remotes[MAX_REMOTES];
+
+#define BUF_SIZE (2084)
+static char buffer[BUF_SIZE];
+
+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;
+}
+
+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;
+}
+
+static void add_uri(struct remote *remote, const char *uri)
+{
+	int i;
+	for (i = 0; i < MAX_REMOTE_URI; i++) {
+		if (!remote->uri[i]) {
+			remote->uri[i] = uri;
+			return;
+		}
+	}
+	error("ignoring excess uri");
+}
+
+static struct remote *make_remote(const char *name, int len)
+{
+	int i, empty = -1;
+
+	for (i = 0; i < MAX_REMOTES; i++) {
+		if (!remotes[i]) {
+			if (empty < 0)
+				empty = i;
+		} else {
+			if (len ? !strncmp(name, remotes[i]->name, len) :
+			    !strcmp(name, remotes[i]->name))
+				return remotes[i];
+		}
+	}
+
+	if (empty < 0)
+		die("Too many remotes");
+	remotes[empty] = xcalloc(1, sizeof(struct remote));
+	if (len)
+		remotes[empty]->name = xstrndup(name, len);
+	else
+		remotes[empty]->name = xstrdup(name);
+	return remotes[empty];
+}
+
+static void read_remotes_file(struct remote *remote)
+{
+	FILE *f = fopen(git_path("remotes/%s", remote->name), "r");
+
+	if (!f)
+		return;
+	while (fgets(buffer, BUF_SIZE, f)) {
+		int is_refspec;
+		char *s, *p;
+
+		if (!prefixcmp(buffer, "URL:")) {
+			is_refspec = 0;
+			s = buffer + 4;
+		} else if (!prefixcmp(buffer, "Push:")) {
+			is_refspec = 1;
+			s = buffer + 5;
+		} else if (!prefixcmp(buffer, "Pull:")) {
+			is_refspec = 2;
+			s = buffer + 5;
+		} else
+			continue;
+
+		while (isspace(*s))
+			s++;
+		if (!*s)
+			continue;
+
+		p = s + strlen(s);
+		while (isspace(p[-1]))
+			*--p = 0;
+
+		switch (is_refspec) {
+		case 0:
+			add_uri(remote, xstrdup(s));
+			break;
+		case 1:
+			add_push_refspec(remote, xstrdup(s));
+			break;
+		case 2:
+			add_fetch_refspec(remote, xstrdup(s));
+			break;
+		}
+	}
+}
+
+static void read_branches_file(struct remote *remote)
+{
+	const char *slash = strchr(remote->name, '/');
+	int n = slash ? slash - remote->name : 1000;
+	FILE *f = fopen(git_path("branches/%.*s", n, remote->name), "r");
+	char *s, *p;
+	int len;
+
+	if (!f)
+		return;
+	s = fgets(buffer, BUF_SIZE, f);
+	fclose(f);
+	if (!s)
+		return;
+	while (isspace(*s))
+		s++;
+	if (!*s)
+		return;
+	p = s + strlen(s);
+	while (isspace(p[-1]))
+		*--p = 0;
+	len = p - s;
+	if (slash)
+		len += strlen(slash);
+	p = xmalloc(len + 1);
+	strcpy(p, s);
+	if (slash)
+		strcat(p, slash);
+	remote->uri[0] = p;
+}
+
+static const char *default_remote_name = NULL;
+static const char *current_branch = NULL;
+static int current_branch_len = 0;
+
+static int handle_config(const char *key, const char *value)
+{
+	const char *name;
+	const char *subkey;
+	struct remote *remote;
+	if (!prefixcmp(key, "branch.") && current_branch &&
+	    !strncmp(key + 7, current_branch, current_branch_len) &&
+	    !strcmp(key + 7 + current_branch_len, ".remote")) {
+		default_remote_name = xstrdup(value);
+	}
+	if (prefixcmp(key,  "remote."))
+		return 0;
+	name = key + 7;
+	subkey = strchr(name, '.');
+	if (!subkey)
+		return error("Config with no key for remote %s", name);
+	remote = make_remote(name, subkey - name);
+	if (!strcmp(subkey, ".url")) {
+		add_uri(remote, xstrdup(value));
+	} else if (!strcmp(subkey, ".push")) {
+		add_push_refspec(remote, xstrdup(value));
+	} else if (!strcmp(subkey, ".fetch")) {
+		add_fetch_refspec(remote, xstrdup(value));
+	} else if (!strcmp(subkey, ".receivepack")) {
+		if (!remote->receivepack)
+			remote->receivepack = xstrdup(value);
+		else
+			error("more than one receivepack given, using the first");
+	}
+	return 0;
+}
+
+static void read_config(void)
+{
+	if (default_remote_name) // did this already
+		return;
+	default_remote_name = xstrdup("origin");
+	current_branch = NULL;
+	git_config(handle_config);
+}
+
+struct remote *remote_get(const char *name)
+{
+	struct remote *ret;
+
+	read_config();
+	if (!name)
+		name = default_remote_name;
+	ret = make_remote(name, 0);
+	if (*name == '/')
+		ret->uri[0] = name;
+	if (!ret->uri[0])
+		read_remotes_file(ret);
+	if (!ret->uri[0])
+		read_branches_file(ret);
+	if (!ret->uri[0])
+		return NULL;
+	return ret;
+}
+
+int remote_has_uri(struct remote *remote, const char *uri)
+{
+	int i;
+	for (i = 0; i < MAX_REMOTE_URI; i++) {
+		if (remote->uri[i] && !strcmp(remote->uri[i], uri))
+			return 1;
+	}
+	return 0;
+}
+
+char *remote_fetch_to(struct remote *remote, const char *ref)
+{
+	int i;
+	for (i = 0; i < remote->fetch_refspec_nr; i++) {
+		const char *refspec = remote->fetch_refspec[i];
+		const char *cons = strchr(refspec, ':');
+		const char *glob = strchr(refspec, '*');
+		if (*refspec == '+')
+			refspec++;
+		if (glob) {
+			if (!strncmp(ref, refspec, glob - refspec)) {
+				const char *cons_glob = strchr(cons, '*');
+				char *ret =
+					xmalloc(cons_glob - cons + strlen(ref) - (glob - refspec));
+				memcpy(ret, cons + 1, cons_glob - cons - 1);
+				memcpy(ret + (cons_glob - cons) - 1,
+				       ref + (glob - refspec),
+				       strlen(ref) - (glob - refspec) + 1);
+				return ret;
+			}
+		} else if (!strncmp(ref, refspec, cons - refspec)) {
+			return xstrdup(cons + 1);
+		}
+	}
+	return NULL;
+}
diff --git a/remote.h b/remote.h
new file mode 100644
index 0000000..7e881f7
--- /dev/null
+++ b/remote.h
@@ -0,0 +1,25 @@
+#ifndef _REMOTE_H
+#define _REMOTE_H
+
+#define MAX_REMOTE_URI 16
+
+struct remote {
+	const char *name;
+	const char *uri[MAX_REMOTE_URI];
+
+	const char **push_refspec;
+	int push_refspec_nr;
+
+	const char **fetch_refspec;
+	int fetch_refspec_nr;
+
+	const char *receivepack;
+};
+
+struct remote *remote_get(const char *name);
+
+int remote_has_uri(struct remote *remote, const char *uri);
+
+char *remote_fetch_to(struct remote *remote, const char *ref);
+
+#endif
-- 
1.5.1.2.255.g6ead4-dirty

-
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]