Commit dc34da6e8140c034c3673d0f82c896be9d66ef1c

Russell Belfer 2012-05-08T13:50:40

Improve repo initialization to be more like git This adds a bunch of template files to the initialization for hooks, info/exclude, and description. This makes our initialized repo look more like core gits.

diff --git a/src/repository.c b/src/repository.c
index 886de58..9031c59 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -684,6 +684,62 @@ static int repo_init_config(const char *git_dir, int is_bare)
 	return 0;
 }
 
+#define GIT_HOOKS_DIR "hooks/"
+#define GIT_HOOKS_DIR_MODE 0755
+
+#define GIT_HOOKS_README_FILE GIT_HOOKS_DIR "README.sample"
+#define GIT_HOOKS_README_MODE 0755
+#define GIT_HOOKS_README_CONTENT \
+"#!/bin/sh\n"\
+"#\n"\
+"# Place appropriately named executable hook scripts into this directory\n"\
+"# to intercept various actions that git takes.  See `git help hooks` for\n"\
+"# more information.\n"
+
+#define GIT_INFO_DIR "info/"
+#define GIT_INFO_DIR_MODE 0755
+
+#define GIT_INFO_EXCLUDE_FILE GIT_INFO_DIR "exclude"
+#define GIT_INFO_EXCLUDE_MODE 0644
+#define GIT_INFO_EXCLUDE_CONTENT \
+"# File patterns to ignore; see `git help ignore` for more information.\n"\
+"# Lines that start with '#' are comments.\n"
+
+#define GIT_DESC_FILE "description"
+#define GIT_DESC_MODE 0644
+#define GIT_DESC_CONTENT "Unnamed repository; edit this file 'description' to name the repository.\n"
+
+static int repo_write_template(
+	const char *git_dir, const char *file, mode_t mode, const char *content)
+{
+	git_buf path = GIT_BUF_INIT;
+	int fd;
+
+	if (git_buf_joinpath(&path, git_dir, file) < 0)
+		return -1;
+
+	fd = p_open(git_buf_cstr(&path), O_WRONLY | O_CREAT | O_EXCL, mode);
+	if (fd < 0) {
+		git_buf_free(&path);
+		if (errno == EEXIST)
+			return 0;
+		goto fail;
+	}
+
+	if (p_write(fd, content, strlen(content)) < 0)
+		goto fail;
+
+	p_close(fd);
+
+	return 0;
+
+fail:
+	git_buf_free(&path);
+	giterr_set(GITERR_OS,
+		"Failed to initialize repository with template '%s'", file);
+	return -1;
+}
+
 static int repo_init_structure(const char *git_dir, int is_bare)
 {
 	int i;
@@ -692,8 +748,16 @@ static int repo_init_structure(const char *git_dir, int is_bare)
 		{ GIT_OBJECTS_PACK_DIR, GIT_OBJECT_DIR_MODE }, /* '/objects/pack/' */
 		{ GIT_REFS_HEADS_DIR, GIT_REFS_DIR_MODE },     /* '/refs/heads/' */
 		{ GIT_REFS_TAGS_DIR, GIT_REFS_DIR_MODE },      /* '/refs/tags/' */
+		{ GIT_HOOKS_DIR, GIT_HOOKS_DIR_MODE },         /* '/hooks/' */
+		{ GIT_INFO_DIR, GIT_INFO_DIR_MODE },           /* '/info/' */
 		{ NULL, 0 }
 	};
+	struct { const char *file; mode_t mode; const char *content; } tmpl[] = {
+		{ GIT_DESC_FILE, GIT_DESC_MODE, GIT_DESC_CONTENT },
+		{ GIT_HOOKS_README_FILE, GIT_HOOKS_README_MODE, GIT_HOOKS_README_CONTENT },
+		{ GIT_INFO_EXCLUDE_FILE, GIT_INFO_EXCLUDE_MODE, GIT_INFO_EXCLUDE_CONTENT },
+		{ NULL, 0, NULL }
+	};
 
 	/* Make the base directory */
 	if (git_futils_mkdir_r(git_dir, NULL, is_bare ? GIT_BARE_DIR_MODE : GIT_DIR_MODE) < 0)
@@ -716,7 +780,13 @@ static int repo_init_structure(const char *git_dir, int is_bare)
 			return -1;
 	}
 
-	/* TODO: what's left? templates? */
+	/* Make template files as needed */
+	for (i = 0; tmpl[i].file != NULL; ++i) {
+		if (repo_write_template(
+				git_dir, tmpl[i].file, tmpl[i].mode, tmpl[i].content) < 0)
+			return -1;
+	}
+
 	return 0;
 }