commit d0eebce407bebae4a055cc39f9d54695533b4265 from: Stefan Sperling date: Mon Mar 11 16:02:14 2019 UTC add 'got ref' subcommand; no support for symbolic refs yet commit - 2d2e137815eff05e7c6e6c23416aa281ad17d8cc commit + d0eebce407bebae4a055cc39f9d54695533b4265 blob - 5d11ec962e2aa555e428742810acdc50377403a6 blob + a66952acd39b2364c670b6528a97e0e30767454e --- got/got.1 +++ got/got.1 @@ -255,7 +255,35 @@ work tree, use the repository path associated with thi Show object IDs of files (blob objects) and directories (tree objects). .It Fl R Recurse into sub-directories in the repository. +.El +.It Cm ref [ Fl r Ar repository-path ] [ Fl l ] [ Fl d Ar name ] [ Ar name Ar object ] +Manage references in a repository. +.Pp +If no options are passed, expect two arguments and attempt to create, +or update, the reference with the given +.Ar name , +and make it point at the given +.Ar object . +The object argument is a SHA1 hash which corresponds to an existing +object in the repository. +.Pp +The options for +.Cm got ref +are as follows: +.Bl -tag -width Ds +.It Fl r Ar repository-path +Use the repository at the specified path. +If not specified, assume the repository is located at or above the current +working directory. +If this directory is a +.Nm +work tree, use the repository path associated with this work tree. +.It Fl l +List all existing references in the repository. +.It Fl d Ar name +Delete the reference with the specified name from the repository. .El +.El .Sh EXIT STATUS .Ex -std got .Sh EXAMPLES blob - 25bce12aa5b13b5847413f0e95ca91be8389e3ae blob + 35d5afb09c6b15cffc6e6456f777c0f691a1ec6a --- got/got.c +++ got/got.c @@ -76,6 +76,7 @@ __dead static void usage_diff(void); __dead static void usage_blame(void); __dead static void usage_tree(void); __dead static void usage_status(void); +__dead static void usage_ref(void); static const struct got_error* cmd_checkout(int, char *[]); static const struct got_error* cmd_update(int, char *[]); @@ -84,6 +85,7 @@ static const struct got_error* cmd_diff(int, char *[] static const struct got_error* cmd_blame(int, char *[]); static const struct got_error* cmd_tree(int, char *[]); static const struct got_error* cmd_status(int, char *[]); +static const struct got_error* cmd_ref(int, char *[]); static struct cmd got_commands[] = { { "checkout", cmd_checkout, usage_checkout, @@ -100,6 +102,8 @@ static struct cmd got_commands[] = { " list files and directories in repository" }, { "status", cmd_status, usage_status, "show modification status of files" }, + { "ref", cmd_ref, usage_ref, + "manage references in repository" }, }; int @@ -172,11 +176,12 @@ usage(void) } static const struct got_error * -apply_unveil(const char *repo_path, const char *worktree_path) +apply_unveil(const char *repo_path, int repo_read_only, + const char *worktree_path) { const struct got_error *error; - if (repo_path && unveil(repo_path, "r") != 0) + if (repo_path && unveil(repo_path, repo_read_only ? "r" : "rwc") != 0) return got_error_from_errno(); if (worktree_path && unveil(worktree_path, "rwc") != 0) @@ -359,7 +364,7 @@ cmd_checkout(int argc, char *argv[]) } else usage_checkout(); - error = apply_unveil(repo_path, worktree_path); + error = apply_unveil(repo_path, 1, worktree_path); if (error) goto done; @@ -497,7 +502,7 @@ cmd_update(int argc, char *argv[]) if (error != NULL) goto done; - error = apply_unveil(got_repo_get_path(repo), + error = apply_unveil(got_repo_get_path(repo), 1, got_worktree_get_root_path(worktree)); if (error) goto done; @@ -844,7 +849,7 @@ cmd_log(int argc, char *argv[]) goto done; } - error = apply_unveil(repo_path, + error = apply_unveil(repo_path, 1, worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; @@ -1136,7 +1141,7 @@ cmd_diff(int argc, char *argv[]) return got_error_from_errno(); } - error = apply_unveil(repo_path, + error = apply_unveil(repo_path, 1, worktree ? got_worktree_get_root_path(worktree) : NULL); if (error) goto done; @@ -1297,7 +1302,7 @@ cmd_blame(int argc, char *argv[]) } } - error = apply_unveil(repo_path, NULL); + error = apply_unveil(repo_path, 1, NULL); if (error) goto done; @@ -1524,7 +1529,7 @@ cmd_tree(int argc, char *argv[]) } } - error = apply_unveil(repo_path, NULL); + error = apply_unveil(repo_path, 1, NULL); if (error) goto done; @@ -1656,7 +1661,7 @@ cmd_status(int argc, char *argv[]) if (error != NULL) goto done; - error = apply_unveil(got_repo_get_path(repo), + error = apply_unveil(got_repo_get_path(repo), 1, got_worktree_get_root_path(worktree)); if (error) goto done; @@ -1666,5 +1671,176 @@ cmd_status(int argc, char *argv[]) done: free(cwd); free(path); + return error; +} + +__dead static void +usage_ref(void) +{ + fprintf(stderr, + "usage: %s ref [-r repository] -l | -d name | name object\n", + getprogname()); + exit(1); +} + +static const struct got_error * +list_refs(struct got_repository *repo) +{ + static const struct got_error *err = NULL; + struct got_reflist_head refs; + struct got_reflist_entry *re; + + SIMPLEQ_INIT(&refs); + err = got_ref_list(&refs, repo); + if (err) + return err; + + SIMPLEQ_FOREACH(re, &refs, entry) { + char *refstr; + refstr = got_ref_to_str(re->ref); + if (refstr == NULL) + return got_error_from_errno(); + printf("%s: %s\n", got_ref_get_name(re->ref), refstr); + free(refstr); + } + + return NULL; +} + +static const struct got_error * +delete_ref(struct got_repository *repo, const char *refname) +{ + const struct got_error *err = NULL; + struct got_reference *ref; + + err = got_ref_open(&ref, repo, refname); + if (err) + return err; + + err = got_ref_delete(ref, repo); + got_ref_close(ref); + return err; +} + +static const struct got_error * +add_ref(struct got_repository *repo, const char *refname, const char *id_str) +{ + const struct got_error *err = NULL; + struct got_object_id *id; + struct got_reference *ref = NULL; + + err = got_object_resolve_id_str(&id, repo, id_str); + if (err) + return err; + + err = got_ref_alloc(&ref, refname, id); + if (err) + goto done; + + err = got_ref_write(ref, repo); +done: + if (ref) + got_ref_close(ref); + free(id); + return err; +} + +static const struct got_error * +cmd_ref(int argc, char *argv[]) +{ + const struct got_error *error = NULL; + struct got_repository *repo = NULL; + struct got_worktree *worktree = NULL; + char *cwd = NULL, *repo_path = NULL; + int ch, do_list = 0; + const char *delref = NULL; + + /* TODO: Add -s option for adding symbolic references. */ + while ((ch = getopt(argc, argv, "d:r:l")) != -1) { + switch (ch) { + case 'd': + delref = optarg; + break; + case 'r': + repo_path = realpath(optarg, NULL); + if (repo_path == NULL) + err(1, "-r option"); + break; + case 'l': + do_list = 1; + break; + default: + usage_ref(); + /* NOTREACHED */ + } + } + + if (do_list && delref) + errx(1, "-l and -d options are mutually exclusive\n"); + + argc -= optind; + argv += optind; + + if (do_list || delref) { + if (argc > 0) + usage_ref(); + } else if (argc != 2) + usage_ref(); + +#ifndef PROFILE + if (pledge("stdio rpath wpath cpath fattr flock proc exec sendfd " + "unveil", NULL) == -1) + err(1, "pledge"); +#endif + cwd = getcwd(NULL, 0); + if (cwd == NULL) { + error = got_error_from_errno(); + goto done; + } + + if (repo_path == NULL) { + error = got_worktree_open(&worktree, cwd); + if (error && error->code != GOT_ERR_NOT_WORKTREE) + goto done; + else + error = NULL; + if (worktree) { + repo_path = + strdup(got_worktree_get_repo_path(worktree)); + if (repo_path == NULL) + error = got_error_from_errno(); + if (error) + goto done; + } else { + repo_path = strdup(cwd); + if (repo_path == NULL) { + error = got_error_from_errno(); + goto done; + } + } + } + + error = apply_unveil(repo_path, do_list, + worktree ? got_worktree_get_root_path(worktree) : NULL); + if (error) + goto done; + + error = got_repo_open(&repo, repo_path); + if (error != NULL) + goto done; + + if (do_list) + error = list_refs(repo); + else if (delref) + error = delete_ref(repo, delref); + else + error = add_ref(repo, argv[0], argv[1]); +done: + if (repo) + got_repo_close(repo); + if (worktree) + got_worktree_close(worktree); + free(cwd); + free(repo_path); return error; }