commit 2c7829a4ca20def05fcbfb4e1557e8f7abbf9c1b from: Stefan Sperling date: Mon Jun 17 12:15:05 2019 UTC implement 'got init' commit - 102ff934b46daf842c7e393a017ab35d9449c577 commit + 2c7829a4ca20def05fcbfb4e1557e8f7abbf9c1b blob - c9d5eab615151bbeb5480b7be1367ad4ea6e6f9b blob + 7eb019a21f9eef0e5f7ea682d71c44f495124d79 --- got/got.1 +++ got/got.1 @@ -60,6 +60,12 @@ The commands for .Nm are as follows: .Bl -tag -width checkout +.It Cm init Ar path +Create a new empty repository at the specified +.Ar path . +If +.Ar path +already exists, it must be an empty directory. .It Cm checkout [ Fl b Ar branch ] [ Fl c Ar commit ] [ Fl p Ar path-prefix ] repository-path [ work-tree-path ] Copy files from a repository into a new work tree. If the blob - 01f304f9b44e4b62576f8d26aca2b3756f8d99b0 blob + b45405f0c457c310049eeec2fa105400ab12c10a --- got/got.c +++ got/got.c @@ -74,6 +74,7 @@ struct cmd { }; __dead static void usage(void); +__dead static void usage_init(void); __dead static void usage_checkout(void); __dead static void usage_update(void); __dead static void usage_log(void); @@ -89,6 +90,7 @@ __dead static void usage_commit(void); __dead static void usage_cherrypick(void); __dead static void usage_backout(void); +static const struct got_error* cmd_init(int, char *[]); static const struct got_error* cmd_checkout(int, char *[]); static const struct got_error* cmd_update(int, char *[]); static const struct got_error* cmd_log(int, char *[]); @@ -105,6 +107,8 @@ static const struct got_error* cmd_cherrypick(int, ch static const struct got_error* cmd_backout(int, char *[]); static struct cmd got_commands[] = { + { "init", cmd_init, usage_init, + "create a new empty repository" }, { "checkout", cmd_checkout, usage_checkout, "check out a new work tree from a repository" }, { "update", cmd_update, usage_update, @@ -270,6 +274,62 @@ apply_unveil(const char *repo_path, int repo_read_only return got_error_from_errno("unveil"); return NULL; +} + +__dead static void +usage_init(void) +{ + fprintf(stderr, "usage: %s init path\n", getprogname()); + exit(1); +} + +static const struct got_error * +cmd_init(int argc, char *argv[]) +{ + const struct got_error *error = NULL; + char *repo_path = NULL; + int ch; + + while ((ch = getopt(argc, argv, "")) != -1) { + switch (ch) { + default: + usage_init(); + /* NOTREACHED */ + } + } + + argc -= optind; + argv += optind; + +#ifndef PROFILE + if (pledge("stdio rpath wpath cpath unveil", NULL) == -1) + err(1, "pledge"); +#endif + if (argc != 1) + usage_checkout(); + + repo_path = strdup(argv[0]); + if (repo_path == NULL) + return got_error_from_errno("strdup"); + + got_path_strip_trailing_slashes(repo_path); + + error = got_path_mkdir(repo_path); + if (error && + !(error->code == GOT_ERR_ERRNO && errno == EEXIST)) + goto done; + + error = apply_unveil(repo_path, 0, NULL, 0); + if (error) + goto done; + + error = got_repo_init(repo_path); + if (error != NULL) + goto done; + +done: + free(repo_path); + return error; } __dead static void blob - 999fdf6ddce081722e9bfc9da58ae4feafdc6c18 blob + 0930f71c8146155d8882f672a15be677ed8eadc5 --- include/got_path.h +++ include/got_path.h @@ -101,3 +101,6 @@ void got_path_strip_trailing_slashes(char *); /* Look up the absolute path of a program in $PATH */ const struct got_error *got_path_find_prog(char **, const char *); + +/* Create a new file at a specified path, with optional content. */ +const struct got_error *got_path_create_file(const char *, const char *); blob - c026e9bdbd4e6a2294da9829b38751ccbf812f54 blob + 0b61b49e3ed0680170a01636840b554aac156059 --- include/got_repository.h +++ include/got_repository.h @@ -54,3 +54,6 @@ int got_repo_is_bare(struct got_repository *); /* Attempt to map an arbitrary path to a path within the repository. */ const struct got_error *got_repo_map_path(char **, struct got_repository *, const char *, int); + +/* Create a new repository in an empty directory at a specified path. */ +const struct got_error *got_repo_init(const char *); blob - a0cd8335240385644aab73fbf3221f9c2da0960c blob + fb283d460760a9d031f838d8fb9053fc63930ebd --- lib/path.c +++ lib/path.c @@ -20,6 +20,7 @@ #include #include +#include #include #include #include @@ -433,4 +434,31 @@ got_path_find_prog(char **filename, const char *prog) } free(path); return NULL; +} + +const struct got_error * +got_path_create_file(const char *path, const char *content) +{ + const struct got_error *err = NULL; + int fd = -1; + + fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, + GOT_DEFAULT_FILE_MODE); + if (fd == -1) { + err = got_error_from_errno2("open", path); + goto done; + } + + if (content) { + int len = dprintf(fd, "%s\n", content); + if (len != strlen(content) + 1) { + err = got_error_from_errno("dprintf"); + goto done; + } + } + +done: + if (fd != -1 && close(fd) == -1 && err == NULL) + err = got_error_from_errno("close"); + return err; } blob - 0277a4437dc809ba033a7083ce7d917e0a36fd81 blob + 3e583b28ea58e79e805fdf160253840f7f33b6da --- lib/repository.c +++ lib/repository.c @@ -815,7 +815,63 @@ got_repo_get_cached_pack(struct got_repository *repo, break; if (strcmp(pack->path_packfile, path_packfile) == 0) return pack; + } + + return NULL; +} + +const struct got_error * +got_repo_init(const char *repo_path) +{ + const struct got_error *err = NULL; + const char *dirnames[] = { + GOT_OBJECTS_DIR, + GOT_OBJECTS_PACK_DIR, + GOT_REFS_DIR, + }; + const char *description_str = "Unnamed repository; " + "edit this file 'description' to name the repository."; + const char *headref_str = "ref: refs/heads/master"; + const char *gitconfig_str = "[core]\n" + "\trepositoryformatversion = 0\n" + "\tfilemode = true\n" + "\tbare = true\n"; + char *path; + int i; + + if (!got_path_dir_is_empty(repo_path)) + return got_error(GOT_ERR_DIR_NOT_EMPTY); + + for (i = 0; i < nitems(dirnames); i++) { + if (asprintf(&path, "%s/%s", repo_path, dirnames[i]) == -1) { + return got_error_from_errno("asprintf"); + } + err = got_path_mkdir(path); + free(path); + if (err) + return err; } + if (asprintf(&path, "%s/%s", repo_path, "description") == -1) + return got_error_from_errno("asprintf"); + err = got_path_create_file(path, description_str); + free(path); + if (err) + return err; + + if (asprintf(&path, "%s/%s", repo_path, GOT_HEAD_FILE) == -1) + return got_error_from_errno("asprintf"); + err = got_path_create_file(path, headref_str); + free(path); + if (err) + return err; + + if (asprintf(&path, "%s/%s", repo_path, "config") == -1) + return got_error_from_errno("asprintf"); + err = got_path_create_file(path, gitconfig_str); + free(path); + if (err) + return err; + return NULL; } blob - 9c8e0f6aa7469f287229ba2c42433b98972f6c62 blob + b0e00b1694127e0786c2ba99bebc3d6873e007a3 --- lib/worktree.c +++ lib/worktree.c @@ -63,32 +63,11 @@ create_meta_file(const char *path_got, const char *nam { const struct got_error *err = NULL; char *path; - int fd = -1; - if (asprintf(&path, "%s/%s", path_got, name) == -1) { - err = got_error_from_errno("asprintf"); - path = NULL; - goto done; - } - - fd = open(path, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, - GOT_DEFAULT_FILE_MODE); - if (fd == -1) { - err = got_error_from_errno2("open", path); - goto done; - } + if (asprintf(&path, "%s/%s", path_got, name) == -1) + return got_error_from_errno("asprintf"); - if (content) { - int len = dprintf(fd, "%s\n", content); - if (len != strlen(content) + 1) { - err = got_error_from_errno("dprintf"); - goto done; - } - } - -done: - if (fd != -1 && close(fd) == -1 && err == NULL) - err = got_error_from_errno("close"); + err = got_path_create_file(path, content); free(path); return err; }