git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: skimo@liacs.nl
To: git@vger.kernel.org, Junio C Hamano <junkio@cox.net>
Cc: Martin Waitz <tali@admingilde.org>, Alex Riesen <raa.lkml@gmail.com>
Subject: [PATCH 16/22] unpack-trees.c: optionally clone submodules for later checkout
Date: Thu, 24 May 2007 00:23:05 +0200	[thread overview]
Message-ID: <11799589931789-git-send-email-skimo@liacs.nl> (raw)
In-Reply-To: <11799589913153-git-send-email-skimo@liacs.nl>

From: Sven Verdoolaege <skimo@kotnet.org>

When the --submodules option is specified and a submodule
to be checked out is not available locally, git-checkout will
search for submodule.<submodule>.url options in the remote
configuration and clone each submodule using the first url that
it can use from the local site.

Signed-off-by: Sven Verdoolaege <skimo@kotnet.org>
---
 Documentation/config.txt |    3 +
 Makefile                 |    4 +-
 submodules.c             |  211 ++++++++++++++++++++++++++++++++++++++++++++++
 submodules.h             |    7 ++
 unpack-trees.c           |   50 +++++++++++
 5 files changed, 273 insertions(+), 2 deletions(-)
 create mode 100644 submodules.c
 create mode 100644 submodules.h

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 5045443..2a2e142 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -615,6 +615,9 @@ showbranch.default::
 	The default set of branches for gitlink:git-show-branch[1].
 	See gitlink:git-show-branch[1].
 
+submodule.<submodule>.url
+	The URL of a submodule.  See gitlink:git-clone[1].
+
 tar.umask::
 	By default, gitlink:git-tar-tree[1] sets file and directories modes
 	to 0666 or 0777. While this is both useful and acceptable for projects
diff --git a/Makefile b/Makefile
index 1fa1896..39bf2d4 100644
--- a/Makefile
+++ b/Makefile
@@ -298,7 +298,7 @@ LIB_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 \
-	mailmap.h remote.h
+	mailmap.h remote.h submodules.h
 
 DIFF_OBJS = \
 	diff.o diff-lib.o diffcore-break.o diffcore-order.o \
@@ -321,7 +321,7 @@ LIB_OBJS = \
 	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 mailmap.o symlinks.o remote.o \
-	$(HTTP_CONFIG_OBJ)
+	$(HTTP_CONFIG_OBJ) submodules.o
 
 BUILTIN_OBJS = \
 	builtin-add.o \
diff --git a/submodules.c b/submodules.c
new file mode 100644
index 0000000..44c0f2c
--- /dev/null
+++ b/submodules.c
@@ -0,0 +1,211 @@
+#include "cache.h"
+#include "refs.h"
+#include "submodules.h"
+#include "run-command.h"
+
+int is_checkedout_submodule(const char *path)
+{
+	unsigned char sha1[20];
+	return resolve_gitlink_ref(path, "HEAD", sha1) == 0;
+}
+
+struct key_val_list {
+	struct key_val_list *next;
+	char *key;
+	char *val;
+};
+
+static void free_key_val_list(struct key_val_list *list)
+{
+	struct key_val_list *next;
+	for (; list; list = next) {
+		next = list->next;
+		free(list->key);
+		free(list->val);
+		free(list);
+	}
+}
+
+static struct key_val_list *find_key_val_list(struct key_val_list *list,
+						const char *key)
+{
+	while (list && strcmp(list->key, key))
+		list = list->next;
+	return list;
+}
+
+struct collect_urls_data {
+	struct key_val_list **next;
+
+	const char *type;
+};
+
+static int collect_urls(const char *var, const char *value, void *cb_data)
+{
+	struct collect_urls_data *cb = (struct collect_urls_data*)cb_data;
+	int typelen = strlen(cb->type);
+	int len;
+	char *doturl;
+	struct key_val_list *item;
+
+	if (prefixcmp(var, cb->type))
+		return 0;
+
+	if (var[typelen] != '.')
+		return 0;
+
+	var += typelen+1;
+
+	doturl = strrchr(var, '.');
+	if (!doturl || strcmp(doturl, ".url"))
+		return 0;
+
+	len = doturl-var;
+	if (len <= 0)
+		return 0;
+
+	item = xmalloc(sizeof(struct key_val_list));
+	item->key = xmalloc(len+1);
+	memcpy(item->key, var, len);
+	item->key[len] = 0;
+	item->val = xstrdup(value);
+	item->next = NULL;
+	*cb->next = item;
+	cb->next = &item->next;
+
+	return 0;
+}
+
+static const char *local_URL(const char *remote, const char *url)
+{
+	static char local_url[PATH_MAX];
+
+	if (!prefixcmp(url, "https://"))
+		return url;
+
+	if (!prefixcmp(url, "http://"))
+		return url;
+
+	if (!prefixcmp(url, "ftp://"))
+		return url;
+
+	if (!prefixcmp(remote, "/"))
+		return url;
+
+	if (!prefixcmp(remote, "ssh://") && !prefixcmp(url, "/")) {
+		char *slash;
+		int len = strlen(url);
+
+		slash = strchr(remote+6, '/');
+		if (!slash || (slash-remote)+len+1 > sizeof(local_url))
+			return NULL;
+		memcpy(local_url, remote, slash-remote);
+		memcpy(local_url+(slash-remote), url, len+1);
+		return local_url;
+	}
+
+	return NULL;
+}
+
+static int fetch_submodule_urls(struct key_val_list **next_url)
+{
+	struct key_val_list *remotes = NULL;
+	struct collect_urls_data remotes_data = { &remotes, "remote" };
+	struct key_val_list *remote;
+	static char key[1024];
+
+	git_config(collect_urls, &remotes_data);
+	for (remote = remotes; remote; remote = remote->next) {
+		struct key_val_list *submodules = NULL;
+		struct collect_urls_data submodules_data =
+			{ &submodules, "submodule" };
+		struct key_val_list *submodule;
+		char *dest;
+
+		dest = xstrdup(remote->val);
+		git_config_from_remote(collect_urls, dest, &submodules_data);
+		free(dest);
+		for (submodule = submodules; submodule; submodule = submodule->next) {
+			const char *local_url;
+			struct key_val_list *item;
+
+			local_url = local_URL(remote->val, submodule->val);
+			if (!local_url)
+				continue;
+
+			if (snprintf(key, sizeof(key),
+			    "submodule.%s.url", submodule->key) > sizeof(key))
+				return error("submodule name too long");
+
+			git_config_set(key, local_url);
+
+			item = xmalloc(sizeof(struct key_val_list));
+			item->key = xstrdup(submodule->key);
+			item->val = xstrdup(local_url);
+			item->next = NULL;
+			*next_url = item;
+			next_url = &item->next;
+		}
+
+		free_key_val_list(submodules);
+	}
+
+	free_key_val_list(remotes);
+
+	return 0;
+}
+
+int clone_submodule(const char *submodule)
+{
+	struct key_val_list *submodules = NULL;
+	struct collect_urls_data submodules_data = { &submodules, "submodule" };
+	struct key_val_list *item;
+	char *path;
+	int err;
+	const char *args[10];
+	int argc;
+
+	git_config(collect_urls, &submodules_data);
+	item = find_key_val_list(submodules, submodule);
+	if (!item) {
+		err = fetch_submodule_urls(submodules_data.next);
+		if (err)
+			return err;
+		item = find_key_val_list(*submodules_data.next, submodule);
+		if (!item)
+			return error("don't know where to get submodule '%s'",
+					submodule);
+	}
+
+	path = git_path("submodules/%s", submodule);
+
+	argc = 0;
+	args[argc++] = "clone";
+	args[argc++] = "--submodules";
+	args[argc++] = "-n";
+	args[argc++] = item->val;
+	args[argc++] = path;
+	args[argc] = NULL;
+
+	err = run_command_v_opt(args, RUN_GIT_CMD|RUN_COMMAND_CLEAR_GIT_ENV);
+
+	path = git_path("submodules/%s/.git", submodule);
+
+	argc = 0;
+	args[argc++] = "update-ref";
+	args[argc++] = "--no-deref";
+	args[argc++] = "HEAD";
+	args[argc++] = "0000000000000000000000000000000000000000";
+	args[argc] = NULL;
+
+	if (!err)
+		err = run_command_v_opt_cd(args,
+				RUN_GIT_CMD|RUN_COMMAND_CLEAR_GIT_ENV, path);
+
+	if (err)
+		return error("failed to clone submodule '%s'", submodule);
+
+	free_key_val_list(submodules);
+
+	return 0;
+}
diff --git a/submodules.h b/submodules.h
new file mode 100644
index 0000000..bf3f118
--- /dev/null
+++ b/submodules.h
@@ -0,0 +1,7 @@
+#ifndef SUBMODULES_H
+#define SUBMODULES_H
+
+int is_checkedout_submodule(const char *path);
+int clone_submodule(const char *submodule);
+
+#endif
diff --git a/unpack-trees.c b/unpack-trees.c
index d5e458d..ddefb51 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -6,6 +6,7 @@
 #include "unpack-trees.h"
 #include "progress.h"
 #include "refs.h"
+#include "submodules.h"
 
 #define DBRT_DEBUG 1
 
@@ -804,6 +805,35 @@ int threeway_merge(struct cache_entry **stages,
 	return count;
 }
 
+static int ensure_submodule(struct cache_entry *ce,
+			    struct unpack_trees_options *o)
+{
+	struct stat st;
+	char *path;
+
+	if (!ce)
+		return 0;
+
+	if (!S_ISGITLINK(ntohl(ce->ce_mode)))
+		return 0;
+
+	if (!is_checkedout_submodule(ce->name) && !o->submodules)
+		return 0;
+
+	path = mkpath("%s/.git", ce->name);
+	if (lstat(path, &st)) {
+		path = git_path("submodules/%s/.git", ce->name);
+		if (lstat(path, &st)) {
+			if (clone_submodule(ce->name))
+				return -1;
+		}
+	}
+
+	/* Now check that the commit is available and fetch if needed */
+
+	return 0;
+}
+
 /*
  * Two-way merge.
  *
@@ -829,6 +859,17 @@ int twoway_merge(struct cache_entry **src,
 	if (newtree == o->df_conflict_entry)
 		newtree = NULL;
 
+	if (o->update) {
+		int err;
+		err = ensure_submodule(current, o);
+		if (!err)
+			err = ensure_submodule(oldtree, o);
+		if (!err)
+			err = ensure_submodule(newtree, o);
+		if (err)
+			return err;
+	}
+
 	if (current) {
 		if ((!oldtree && !newtree) || /* 4 and 5 */
 		    (!oldtree && newtree &&
@@ -905,6 +946,15 @@ int oneway_merge(struct cache_entry **src,
 		return error("Cannot do a oneway merge of %d trees",
 			     o->merge_size);
 
+	if (o->update) {
+		int err;
+		err = ensure_submodule(old, o);
+		if (!err)
+			err = ensure_submodule(a, o);
+		if (err)
+			return err;
+	}
+
 	if (!a)
 		return deleted_entry(old, old, o);
 	if (old && same(old, a)) {
-- 
1.5.2.784.g5532e

  parent reply	other threads:[~2007-05-23 22:23 UTC|newest]

Thread overview: 94+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-05-23 22:22 [RFC] Fourth round of support for cloning submodules skimo
2007-05-23 22:22 ` [PATCH 01/22] git_connect: unset CONFIG_ENVIRONMENT in child skimo
2007-05-23 22:22 ` [PATCH 02/22] Add dump-config skimo
2007-05-23 22:22 ` [PATCH 03/22] git-config: add --remote option for reading config from remote repo skimo
2007-05-23 22:22 ` [PATCH 04/22] http.h: make fill_active_slots a function pointer skimo
2007-05-23 22:22 ` [PATCH 05/22] git-config: read remote config files over HTTP skimo
2007-05-23 22:22 ` [PATCH 06/22] unpack-trees.c: pass cache_entry * to verify_absent rather than just the name skimo
2007-05-23 22:22 ` [PATCH 07/22] git-read-tree: take --submodules option skimo
2007-05-23 22:22 ` [PATCH 08/22] unpack-trees.c: assume submodules are clean skimo
2007-05-23 22:22 ` [PATCH 09/22] Add run_command_v_opt_cd: chdir into a directory before exec skimo
2007-05-23 22:22 ` [PATCH 10/22] run-command: optionally clear git environment skimo
2007-05-24  6:57   ` Alex Riesen
2007-05-24  7:15     ` Shawn O. Pearce
2007-05-24  7:19       ` Alex Riesen
2007-05-23 22:23 ` [PATCH 11/22] entry.c: optionally checkout submodules skimo
2007-05-24  6:59   ` Alex Riesen
2007-05-24  7:18     ` Shawn O. Pearce
2007-05-24  7:27       ` Sven Verdoolaege
2007-05-24  7:29       ` Alex Riesen
2007-05-24 16:21       ` Martin Waitz
2007-05-25  0:49         ` Shawn O. Pearce
2007-05-23 22:23 ` [PATCH 12/22] git-checkout: pass --submodules option to git-read-tree skimo
2007-05-23 22:23 ` [PATCH 13/22] git-read-tree: treat null commit as empty tree skimo
2007-05-23 22:23 ` [PATCH 14/22] git_config: add void * for callback data skimo
2007-05-23 22:23 ` [PATCH 15/22] make redirecting stdout to /dev/null available via run_command_v_opt skimo
2007-05-23 22:23 ` skimo [this message]
2007-05-23 22:23 ` [PATCH 17/22] entry.c: optionally checkout newly cloned submodules skimo
2007-05-24 13:28   ` Johannes Sixt
2007-05-23 22:23 ` [PATCH 18/22] git-clone: add --submodules for cloning submodules skimo
2007-05-23 22:23 ` [PATCH 19/22] test for simple submodule checkout support skimo
2007-05-23 22:23 ` [PATCH 20/22] checkout_submodule: checkout submodule on forced checkout of submodule dir skimo
2007-05-23 22:23 ` [PATCH 21/22] run-command: optionally redirect stderr to /dev/null skimo
2007-05-23 22:23 ` [PATCH 22/22] ensure_submodule: fetch missing revisions skimo
2007-05-23 23:40 ` [RFC] Fourth round of support for cloning submodules Johannes Schindelin
2007-05-24  0:50   ` Junio C Hamano
2007-05-24  7:22     ` Sven Verdoolaege
2007-05-24  7:29       ` Shawn O. Pearce
2007-05-24  7:36         ` Sven Verdoolaege
2007-05-24  9:41           ` Johannes Schindelin
2007-05-24 10:51             ` Sven Verdoolaege
2007-05-24 11:02               ` Johannes Schindelin
2007-05-24 11:16                 ` Sven Verdoolaege
2007-05-24 11:31                   ` Johannes Schindelin
2007-05-24 11:43                     ` Sven Verdoolaege
2007-05-24 12:16                       ` Johannes Schindelin
2007-05-24 12:23                         ` Johannes Sixt
2007-05-24 13:14                           ` Johannes Schindelin
2007-05-24 12:39                         ` Sven Verdoolaege
2007-05-24 13:17                           ` Johannes Schindelin
2007-05-24 13:24                             ` Sven Verdoolaege
2007-05-24 13:52                               ` Johannes Schindelin
2007-05-24 17:42                                 ` Sven Verdoolaege
2007-05-24 18:07                                   ` Johannes Schindelin
2007-05-24 12:41                         ` Lars Hjemli
2007-05-24 13:11                           ` Sven Verdoolaege
2007-05-24 13:32                             ` Lars Hjemli
2007-05-24 17:13                           ` Junio C Hamano
2007-05-24 17:33                             ` Lars Hjemli
2007-05-24 17:38                             ` Sven Verdoolaege
2007-05-24 17:40                             ` Linus Torvalds
2007-05-24 17:55                               ` Sven Verdoolaege
2007-05-24 18:09                                 ` Linus Torvalds
2007-05-24 18:45                                   ` Junio C Hamano
2007-05-24 19:13                                     ` Lars Hjemli
2007-05-24 19:25                                       ` Johannes Schindelin
2007-05-24 18:11                                 ` Johannes Schindelin
2007-05-25 10:00                                   ` Sven Verdoolaege
2007-05-25 16:16                                     ` Junio C Hamano
2007-05-25 16:28                                       ` Sven Verdoolaege
2007-05-25 16:43                                         ` Johannes Schindelin
2007-05-24 18:38                               ` Junio C Hamano
2007-05-25 12:27                               ` Josef Weidendorfer
2007-05-25 12:44                                 ` Johannes Schindelin
2007-05-25 13:59                                   ` Josef Weidendorfer
2007-05-25 14:16                                     ` Johannes Schindelin
2007-05-25 14:38                                       ` Sven Verdoolaege
2007-05-25 14:51                                         ` Johannes Schindelin
2007-05-25 14:51                                       ` Josef Weidendorfer
2007-05-25 14:54                                         ` Johannes Schindelin
2007-05-25 15:35                                     ` Linus Torvalds
2007-05-25 16:23                                       ` Josef Weidendorfer
2007-05-25 16:37                                         ` Johannes Schindelin
2007-05-25 17:09                                           ` Josef Weidendorfer
2007-05-25 12:22                         ` Jakub Narebski
2007-05-25 12:32                           ` Johannes Schindelin
2007-05-24 12:23                       ` Santi Béjar
2007-05-27 20:34                 ` Martin Waitz
2007-05-27 20:40                   ` Sven Verdoolaege
2007-05-24 13:35     ` Martin Waitz
2007-05-24  7:24   ` Sven Verdoolaege
2007-05-24  9:35     ` Johannes Schindelin
2007-05-24 10:54       ` Sven Verdoolaege
2007-05-24 12:38       ` Petr Baudis
2007-05-24 13:13         ` Johannes Schindelin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=11799589931789-git-send-email-skimo@liacs.nl \
    --to=skimo@liacs.nl \
    --cc=git@vger.kernel.org \
    --cc=junkio@cox.net \
    --cc=raa.lkml@gmail.com \
    --cc=tali@admingilde.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).