summaryrefslogtreecommitdiff
path: root/init-db.c
diff options
context:
space:
mode:
authorJunio C Hamano <junkio@cox.net>2005-08-02 23:45:21 (GMT)
committerJunio C Hamano <junkio@cox.net>2005-08-03 23:27:38 (GMT)
commit8d5afef0f9b3a252f7b90406d35c295dc698e26d (patch)
tree0656bdb1282ecb419ab8fe2a2ce9b702b16e19ed /init-db.c
parentee639140c9d3d7d0c8821e6b7d36c75ae578b326 (diff)
downloadgit-8d5afef0f9b3a252f7b90406d35c295dc698e26d.zip
git-8d5afef0f9b3a252f7b90406d35c295dc698e26d.tar.gz
git-8d5afef0f9b3a252f7b90406d35c295dc698e26d.tar.bz2
Install sample hooks
A template mechanism to populate newly initialized repository with default set of files is introduced. Use it to ship example hooks that can be used for update and post update checks, as Josef Weidendorfer suggests. Signed-off-by: Junio C Hamano <junkio@cox.net>
Diffstat (limited to 'init-db.c')
-rw-r--r--init-db.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/init-db.c b/init-db.c
index c78c495..fcb55f6 100644
--- a/init-db.c
+++ b/init-db.c
@@ -15,6 +15,147 @@ static void safe_create_dir(const char *dir)
}
}
+static int copy_file(const char *dst, const char *src, int mode)
+{
+ int fdi, fdo;
+
+ mode = (mode & 0111) ? 0777 : 0666;
+ if ((fdi = open(src, O_RDONLY)) < 0)
+ return fdi;
+ if ((fdo = open(dst, O_WRONLY | O_CREAT | O_EXCL, mode)) < 0) {
+ close(fdi);
+ return fdo;
+ }
+ while (1) {
+ char buf[BUFSIZ];
+ ssize_t leni, leno, ofs;
+ leni = read(fdi, buf, sizeof(buf));
+ if (leni < 0) {
+ error_return:
+ close(fdo);
+ close(fdi);
+ return -1;
+ }
+ if (!leni)
+ break;
+ ofs = 0;
+ do {
+ leno = write(fdo, buf+ofs, leni);
+ if (leno < 0)
+ goto error_return;
+ leni -= leno;
+ ofs += leno;
+ } while (0 < leni);
+ }
+ close(fdo);
+ close(fdi);
+ return 0;
+}
+
+static void copy_templates_1(char *path, int baselen,
+ char *template, int template_baselen,
+ DIR *dir)
+{
+ struct dirent *de;
+
+ /* Note: if ".git/hooks" file exists in the repository being
+ * re-initialized, /etc/core-git/templates/hooks/update would
+ * cause git-init-db to fail here. I think this is sane but
+ * it means that the set of templates we ship by default, along
+ * with the way the namespace under .git/ is organized, should
+ * be really carefully chosen.
+ */
+ safe_create_dir(path);
+ while ((de = readdir(dir)) != NULL) {
+ struct stat st_git, st_template;
+ int namelen;
+ int exists = 0;
+
+ if (de->d_name[0] == '.')
+ continue;
+ namelen = strlen(de->d_name);
+ if ((PATH_MAX <= baselen + namelen) ||
+ (PATH_MAX <= template_baselen + namelen))
+ die("insanely long template name %s", de->d_name);
+ memcpy(path + baselen, de->d_name, namelen+1);
+ memcpy(template + template_baselen, de->d_name, namelen+1);
+ if (lstat(path, &st_git)) {
+ if (errno != ENOENT)
+ die("cannot stat %s", path);
+ }
+ else
+ exists = 1;
+
+ if (lstat(template, &st_template))
+ die("cannot stat template %s", template);
+
+ if (S_ISDIR(st_template.st_mode)) {
+ DIR *subdir = opendir(template);
+ int baselen_sub = baselen + namelen;
+ int template_baselen_sub = template_baselen + namelen;
+ if (!subdir)
+ die("cannot opendir %s", template);
+ path[baselen_sub++] =
+ template[template_baselen_sub++] = '/';
+ path[baselen_sub] =
+ template[template_baselen_sub] = 0;
+ copy_templates_1(path, baselen_sub,
+ template, template_baselen_sub,
+ subdir);
+ closedir(subdir);
+ }
+ else if (exists)
+ continue;
+ else if (S_ISLNK(st_template.st_mode)) {
+ char lnk[256];
+ int len;
+ len = readlink(template, lnk, sizeof(lnk));
+ if (len < 0)
+ die("cannot readlink %s", template);
+ if (sizeof(lnk) <= len)
+ die("insanely long symlink %s", template);
+ lnk[len] = 0;
+ if (symlink(lnk, path))
+ die("cannot symlink %s %s", lnk, path);
+ }
+ else if (S_ISREG(st_template.st_mode)) {
+ if (copy_file(path, template, st_template.st_mode))
+ die("cannot copy %s to %s", template, path);
+ }
+ else
+ error("ignoring template %s", template);
+ }
+}
+
+static void copy_templates(const char *git_dir)
+{
+ char path[PATH_MAX];
+ char template_path[PATH_MAX];
+ char *template_dir;
+ int len, template_len;
+ DIR *dir;
+
+ strcpy(path, git_dir);
+ len = strlen(path);
+ template_dir = gitenv(TEMPLATE_DIR_ENVIRONMENT);
+ if (!template_dir)
+ template_dir = DEFAULT_GIT_TEMPLATE_ENVIRONMENT;
+ strcpy(template_path, template_dir);
+ template_len = strlen(template_path);
+ if (template_path[template_len-1] != '/') {
+ template_path[template_len++] = '/';
+ template_path[template_len] = 0;
+ }
+
+ dir = opendir(template_path);
+ if (!dir)
+ return;
+ copy_templates_1(path, len,
+ template_path, template_len,
+ dir);
+ closedir(dir);
+}
+
static void create_default_files(const char *git_dir)
{
unsigned len = strlen(git_dir);
@@ -48,6 +189,7 @@ static void create_default_files(const char *git_dir)
exit(1);
}
}
+ copy_templates(path);
}
/*