commit 1ea7ccc6f361b1b07c3f3c301b033ea50b17cf54 from: Stefan Sperling via: Thomas Adam date: Mon Nov 15 17:07:41 2021 UTC let gotadmin find the repository automatically if invoked in a work tree Move a small amount of code from worktree.c to a new file worktree_open.c, which contains everything required to open and close a work tree and inspect some of its basic parameters. This can be used by gotadmin. ok tracey commit - f89000039096e46ad7d5f9abfad6749034d02a41 commit + 1ea7ccc6f361b1b07c3f3c301b033ea50b17cf54 blob - 95a7aa49c8f72ab6c542ca943a37c5fc2cca1932 blob + f0ef0abde989951cff823fdaf07ad4a0528aca1f --- gotadmin/gotadmin.1 +++ gotadmin/gotadmin.1 @@ -68,6 +68,9 @@ are as follows: 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 +.Xr got 1 +work tree, use the repository path associated with this work tree. .El .It Cm pack Oo Fl a Oc Oo Fl r Ar repository-path Oc Oo Fl x Ar reference Oc Op Ar reference ... Generate a new pack file and a corresponding pack file index. @@ -101,6 +104,9 @@ Unless this option is specified, only loose objects wi 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 +.Xr got 1 +work tree, use the repository path associated with this work tree. .It Fl x Ar reference Exclude objects reachable via the specified .Ar reference @@ -274,6 +280,9 @@ remove any files from disk. 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 +.Xr got 1 +work tree, use the repository path associated with this work tree. .It Fl q Suppress progress reporting and disk space summary output. .El blob - a86569641450d3ae54d222474ede59531dbe00ef blob + 938baf072aa45776f93886d1d0df6671f3de3c56 --- gotadmin/gotadmin.c +++ gotadmin/gotadmin.c @@ -41,6 +41,7 @@ #include "got_path.h" #include "got_privsep.h" #include "got_opentemp.h" +#include "got_worktree.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) @@ -231,10 +232,43 @@ usage_info(void) } static const struct got_error * +get_repo_path(char **repo_path) +{ + const struct got_error *err = NULL; + struct got_worktree *worktree = NULL; + char *cwd; + + *repo_path = NULL; + + cwd = getcwd(NULL, 0); + if (cwd == NULL) + return got_error_from_errno("getcwd"); + + err = got_worktree_open(&worktree, cwd); + if (err) { + if (err->code != GOT_ERR_NOT_WORKTREE) + goto done; + err = NULL; + } + + if (worktree) + *repo_path = strdup(got_worktree_get_repo_path(worktree)); + else + *repo_path = strdup(cwd); + if (*repo_path == NULL) + err = got_error_from_errno("strdup"); +done: + if (worktree) + got_worktree_close(worktree); + free(cwd); + return err; +} + +static const struct got_error * cmd_info(int argc, char *argv[]) { const struct got_error *error = NULL; - char *cwd = NULL, *repo_path = NULL; + char *repo_path = NULL; struct got_repository *repo = NULL; const struct got_gotconfig *gotconfig = NULL; int ch, npackfiles, npackedobj, nobj; @@ -264,13 +298,12 @@ cmd_info(int argc, char *argv[]) NULL) == -1) err(1, "pledge"); #endif - cwd = getcwd(NULL, 0); - if (cwd == NULL) { - error = got_error_from_errno("getcwd"); - goto done; + if (repo_path == NULL) { + error = get_repo_path(&repo_path); + if (error) + goto done; } - - error = got_repo_open(&repo, repo_path ? repo_path : cwd, NULL); + error = got_repo_open(&repo, repo_path, NULL); if (error) goto done; @@ -332,7 +365,7 @@ cmd_info(int argc, char *argv[]) done: if (repo) got_repo_close(repo); - free(cwd); + free(repo_path); return error; } @@ -520,7 +553,7 @@ static const struct got_error * cmd_pack(int argc, char *argv[]) { const struct got_error *error = NULL; - char *cwd = NULL, *repo_path = NULL; + char *repo_path = NULL; struct got_repository *repo = NULL; int ch, i, loose_obj_only = 1; struct got_object_id *pack_hash = NULL; @@ -570,13 +603,12 @@ cmd_pack(int argc, char *argv[]) NULL) == -1) err(1, "pledge"); #endif - cwd = getcwd(NULL, 0); - if (cwd == NULL) { - error = got_error_from_errno("getcwd"); - goto done; + if (repo_path == NULL) { + error = get_repo_path(&repo_path); + if (error) + goto done; } - - error = got_repo_open(&repo, repo_path ? repo_path : cwd, NULL); + error = got_repo_open(&repo, repo_path, NULL); if (error) goto done; @@ -650,7 +682,7 @@ done: got_ref_list_free(&include_refs); free(id_str); free(pack_hash); - free(cwd); + free(repo_path); return error; } @@ -1001,7 +1033,7 @@ static const struct got_error * cmd_cleanup(int argc, char *argv[]) { const struct got_error *error = NULL; - char *cwd = NULL, *repo_path = NULL; + char *repo_path = NULL; struct got_repository *repo = NULL; int ch, dry_run = 0, npacked = 0, verbosity = 0; int remove_lonely_packidx = 0, ignore_mtime = 0; @@ -1049,13 +1081,12 @@ cmd_cleanup(int argc, char *argv[]) NULL) == -1) err(1, "pledge"); #endif - cwd = getcwd(NULL, 0); - if (cwd == NULL) { - error = got_error_from_errno("getcwd"); - goto done; + if (repo_path == NULL) { + error = get_repo_path(&repo_path); + if (error) + goto done; } - - error = got_repo_open(&repo, repo_path ? repo_path : cwd, NULL); + error = got_repo_open(&repo, repo_path, NULL); if (error) goto done; @@ -1120,6 +1151,6 @@ cmd_cleanup(int argc, char *argv[]) done: if (repo) got_repo_close(repo); - free(cwd); + free(repo_path); return error; } blob - f3111e0b046c0a015967d9caba4e8e93a57c937d blob + f9980ca34fe6e0e1c431bd61173a4af6fed70df8 --- lib/worktree.c +++ lib/worktree.c @@ -112,70 +112,6 @@ done: if (fclose(tmpfile) == EOF && err == NULL) err = got_error_from_errno2("fclose", tmppath); free(tmppath); - return err; -} - -static const struct got_error * -read_meta_file(char **content, const char *path_got, const char *name) -{ - const struct got_error *err = NULL; - char *path; - int fd = -1; - ssize_t n; - struct stat sb; - - *content = NULL; - - if (asprintf(&path, "%s/%s", path_got, name) == -1) { - err = got_error_from_errno("asprintf"); - path = NULL; - goto done; - } - - fd = open(path, O_RDONLY | O_NOFOLLOW); - if (fd == -1) { - if (errno == ENOENT) - err = got_error_path(path, GOT_ERR_WORKTREE_META); - else - err = got_error_from_errno2("open", path); - goto done; - } - if (flock(fd, LOCK_SH | LOCK_NB) == -1) { - err = (errno == EWOULDBLOCK ? got_error(GOT_ERR_WORKTREE_BUSY) - : got_error_from_errno2("flock", path)); - goto done; - } - - if (fstat(fd, &sb) != 0) { - err = got_error_from_errno2("fstat", path); - goto done; - } - *content = calloc(1, sb.st_size); - if (*content == NULL) { - err = got_error_from_errno("calloc"); - goto done; - } - - n = read(fd, *content, sb.st_size); - if (n != sb.st_size) { - err = (n == -1 ? got_error_from_errno2("read", path) : - got_error_path(path, GOT_ERR_WORKTREE_META)); - goto done; - } - if ((*content)[sb.st_size - 1] != '\n') { - err = got_error_path(path, GOT_ERR_WORKTREE_META); - goto done; - } - (*content)[sb.st_size - 1] = '\0'; - -done: - if (fd != -1 && close(fd) == -1 && err == NULL) - err = got_error_from_errno2("close", path_got); - free(path); - if (err) { - free(*content); - *content = NULL; - } return err; } @@ -318,226 +254,7 @@ done: return err; } -static const struct got_error * -open_worktree(struct got_worktree **worktree, const char *path) -{ - const struct got_error *err = NULL; - char *path_got; - char *formatstr = NULL; - char *uuidstr = NULL; - char *path_lock = NULL; - char *base_commit_id_str = NULL; - int version, fd = -1; - const char *errstr; - struct got_repository *repo = NULL; - uint32_t uuid_status; - - *worktree = NULL; - - if (asprintf(&path_got, "%s/%s", path, GOT_WORKTREE_GOT_DIR) == -1) { - err = got_error_from_errno("asprintf"); - path_got = NULL; - goto done; - } - - if (asprintf(&path_lock, "%s/%s", path_got, GOT_WORKTREE_LOCK) == -1) { - err = got_error_from_errno("asprintf"); - path_lock = NULL; - goto done; - } - - fd = open(path_lock, O_RDWR | O_EXLOCK | O_NONBLOCK); - if (fd == -1) { - err = (errno == EWOULDBLOCK ? got_error(GOT_ERR_WORKTREE_BUSY) - : got_error_from_errno2("open", path_lock)); - goto done; - } - - err = read_meta_file(&formatstr, path_got, GOT_WORKTREE_FORMAT); - if (err) - goto done; - - version = strtonum(formatstr, 1, INT_MAX, &errstr); - if (errstr) { - err = got_error_msg(GOT_ERR_WORKTREE_META, - "could not parse work tree format version number"); - goto done; - } - if (version != GOT_WORKTREE_FORMAT_VERSION) { - err = got_error(GOT_ERR_WORKTREE_VERS); - goto done; - } - - *worktree = calloc(1, sizeof(**worktree)); - if (*worktree == NULL) { - err = got_error_from_errno("calloc"); - goto done; - } - (*worktree)->lockfd = -1; - - (*worktree)->root_path = realpath(path, NULL); - if ((*worktree)->root_path == NULL) { - err = got_error_from_errno2("realpath", path); - goto done; - } - err = read_meta_file(&(*worktree)->repo_path, path_got, - GOT_WORKTREE_REPOSITORY); - if (err) - goto done; - - err = read_meta_file(&(*worktree)->path_prefix, path_got, - GOT_WORKTREE_PATH_PREFIX); - if (err) - goto done; - - err = read_meta_file(&base_commit_id_str, path_got, - GOT_WORKTREE_BASE_COMMIT); - if (err) - goto done; - - err = read_meta_file(&uuidstr, path_got, GOT_WORKTREE_UUID); - if (err) - goto done; - uuid_from_string(uuidstr, &(*worktree)->uuid, &uuid_status); - if (uuid_status != uuid_s_ok) { - err = got_error_uuid(uuid_status, "uuid_from_string"); - goto done; - } - - err = got_repo_open(&repo, (*worktree)->repo_path, NULL); - if (err) - goto done; - - err = got_object_resolve_id_str(&(*worktree)->base_commit_id, repo, - base_commit_id_str); - if (err) - goto done; - - err = read_meta_file(&(*worktree)->head_ref_name, path_got, - GOT_WORKTREE_HEAD_REF); - if (err) - goto done; - - if (asprintf(&(*worktree)->gotconfig_path, "%s/%s/%s", - (*worktree)->root_path, - GOT_WORKTREE_GOT_DIR, GOT_GOTCONFIG_FILENAME) == -1) { - err = got_error_from_errno("asprintf"); - goto done; - } - - err = got_gotconfig_read(&(*worktree)->gotconfig, - (*worktree)->gotconfig_path); - - (*worktree)->root_fd = open((*worktree)->root_path, O_DIRECTORY); - if ((*worktree)->root_fd == -1) { - err = got_error_from_errno2("open", (*worktree)->root_path); - goto done; - } -done: - if (repo) { - const struct got_error *close_err = got_repo_close(repo); - if (err == NULL) - err = close_err; - } - free(path_got); - free(path_lock); - free(base_commit_id_str); - free(uuidstr); - free(formatstr); - if (err) { - if (fd != -1) - close(fd); - if (*worktree != NULL) - got_worktree_close(*worktree); - *worktree = NULL; - } else - (*worktree)->lockfd = fd; - - return err; -} - const struct got_error * -got_worktree_open(struct got_worktree **worktree, const char *path) -{ - const struct got_error *err = NULL; - char *worktree_path; - - worktree_path = strdup(path); - if (worktree_path == NULL) - return got_error_from_errno("strdup"); - - for (;;) { - char *parent_path; - - err = open_worktree(worktree, worktree_path); - if (err && !(err->code == GOT_ERR_ERRNO && errno == ENOENT)) { - free(worktree_path); - return err; - } - if (*worktree) { - free(worktree_path); - return NULL; - } - if (worktree_path[0] == '/' && worktree_path[1] == '\0') - break; - err = got_path_dirname(&parent_path, worktree_path); - if (err) { - if (err->code != GOT_ERR_BAD_PATH) { - free(worktree_path); - return err; - } - break; - } - free(worktree_path); - worktree_path = parent_path; - } - - free(worktree_path); - return got_error(GOT_ERR_NOT_WORKTREE); -} - -const struct got_error * -got_worktree_close(struct got_worktree *worktree) -{ - const struct got_error *err = NULL; - - if (worktree->lockfd != -1) { - if (close(worktree->lockfd) == -1) - err = got_error_from_errno2("close", - got_worktree_get_root_path(worktree)); - } - if (close(worktree->root_fd) == -1 && err == NULL) - err = got_error_from_errno2("close", - got_worktree_get_root_path(worktree)); - free(worktree->repo_path); - free(worktree->path_prefix); - free(worktree->base_commit_id); - free(worktree->head_ref_name); - free(worktree->root_path); - free(worktree->gotconfig_path); - got_gotconfig_free(worktree->gotconfig); - free(worktree); - return err; -} - -const char * -got_worktree_get_root_path(struct got_worktree *worktree) -{ - return worktree->root_path; -} - -const char * -got_worktree_get_repo_path(struct got_worktree *worktree) -{ - return worktree->repo_path; -} -const char * -got_worktree_get_path_prefix(struct got_worktree *worktree) -{ - return worktree->path_prefix; -} - -const struct got_error * got_worktree_match_path_prefix(int *match, struct got_worktree *worktree, const char *path_prefix) { blob - /dev/null blob + 4a589cf5ece62d780a9e4fac1215b2df6a5ea5cc (mode 644) --- /dev/null +++ lib/worktree_open.c @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2018, 2019, 2020 Stefan Sperling + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "got_cancel.h" +#include "got_error.h" +#include "got_reference.h" +#include "got_path.h" +#include "got_worktree.h" +#include "got_repository.h" +#include "got_gotconfig.h" +#include "got_object.h" + +#include "got_lib_worktree.h" +#include "got_lib_gotconfig.h" + +static const struct got_error * +read_meta_file(char **content, const char *path_got, const char *name) +{ + const struct got_error *err = NULL; + char *path; + int fd = -1; + ssize_t n; + struct stat sb; + + *content = NULL; + + if (asprintf(&path, "%s/%s", path_got, name) == -1) { + err = got_error_from_errno("asprintf"); + path = NULL; + goto done; + } + + fd = open(path, O_RDONLY | O_NOFOLLOW); + if (fd == -1) { + if (errno == ENOENT) + err = got_error_path(path, GOT_ERR_WORKTREE_META); + else + err = got_error_from_errno2("open", path); + goto done; + } + if (flock(fd, LOCK_SH | LOCK_NB) == -1) { + err = (errno == EWOULDBLOCK ? got_error(GOT_ERR_WORKTREE_BUSY) + : got_error_from_errno2("flock", path)); + goto done; + } + + if (fstat(fd, &sb) != 0) { + err = got_error_from_errno2("fstat", path); + goto done; + } + *content = calloc(1, sb.st_size); + if (*content == NULL) { + err = got_error_from_errno("calloc"); + goto done; + } + + n = read(fd, *content, sb.st_size); + if (n != sb.st_size) { + err = (n == -1 ? got_error_from_errno2("read", path) : + got_error_path(path, GOT_ERR_WORKTREE_META)); + goto done; + } + if ((*content)[sb.st_size - 1] != '\n') { + err = got_error_path(path, GOT_ERR_WORKTREE_META); + goto done; + } + (*content)[sb.st_size - 1] = '\0'; + +done: + if (fd != -1 && close(fd) == -1 && err == NULL) + err = got_error_from_errno2("close", path_got); + free(path); + if (err) { + free(*content); + *content = NULL; + } + return err; +} + +static const struct got_error * +open_worktree(struct got_worktree **worktree, const char *path) +{ + const struct got_error *err = NULL; + char *path_got; + char *formatstr = NULL; + char *uuidstr = NULL; + char *path_lock = NULL; + char *base_commit_id_str = NULL; + int version, fd = -1; + const char *errstr; + struct got_repository *repo = NULL; + uint32_t uuid_status; + + *worktree = NULL; + + if (asprintf(&path_got, "%s/%s", path, GOT_WORKTREE_GOT_DIR) == -1) { + err = got_error_from_errno("asprintf"); + path_got = NULL; + goto done; + } + + if (asprintf(&path_lock, "%s/%s", path_got, GOT_WORKTREE_LOCK) == -1) { + err = got_error_from_errno("asprintf"); + path_lock = NULL; + goto done; + } + + fd = open(path_lock, O_RDWR | O_EXLOCK | O_NONBLOCK); + if (fd == -1) { + err = (errno == EWOULDBLOCK ? got_error(GOT_ERR_WORKTREE_BUSY) + : got_error_from_errno2("open", path_lock)); + goto done; + } + + err = read_meta_file(&formatstr, path_got, GOT_WORKTREE_FORMAT); + if (err) + goto done; + + version = strtonum(formatstr, 1, INT_MAX, &errstr); + if (errstr) { + err = got_error_msg(GOT_ERR_WORKTREE_META, + "could not parse work tree format version number"); + goto done; + } + if (version != GOT_WORKTREE_FORMAT_VERSION) { + err = got_error(GOT_ERR_WORKTREE_VERS); + goto done; + } + + *worktree = calloc(1, sizeof(**worktree)); + if (*worktree == NULL) { + err = got_error_from_errno("calloc"); + goto done; + } + (*worktree)->lockfd = -1; + + (*worktree)->root_path = realpath(path, NULL); + if ((*worktree)->root_path == NULL) { + err = got_error_from_errno2("realpath", path); + goto done; + } + err = read_meta_file(&(*worktree)->repo_path, path_got, + GOT_WORKTREE_REPOSITORY); + if (err) + goto done; + + err = read_meta_file(&(*worktree)->path_prefix, path_got, + GOT_WORKTREE_PATH_PREFIX); + if (err) + goto done; + + err = read_meta_file(&base_commit_id_str, path_got, + GOT_WORKTREE_BASE_COMMIT); + if (err) + goto done; + + err = read_meta_file(&uuidstr, path_got, GOT_WORKTREE_UUID); + if (err) + goto done; + uuid_from_string(uuidstr, &(*worktree)->uuid, &uuid_status); + if (uuid_status != uuid_s_ok) { + err = got_error_uuid(uuid_status, "uuid_from_string"); + goto done; + } + + err = got_repo_open(&repo, (*worktree)->repo_path, NULL); + if (err) + goto done; + + err = got_object_resolve_id_str(&(*worktree)->base_commit_id, repo, + base_commit_id_str); + if (err) + goto done; + + err = read_meta_file(&(*worktree)->head_ref_name, path_got, + GOT_WORKTREE_HEAD_REF); + if (err) + goto done; + + if (asprintf(&(*worktree)->gotconfig_path, "%s/%s/%s", + (*worktree)->root_path, + GOT_WORKTREE_GOT_DIR, GOT_GOTCONFIG_FILENAME) == -1) { + err = got_error_from_errno("asprintf"); + goto done; + } + + err = got_gotconfig_read(&(*worktree)->gotconfig, + (*worktree)->gotconfig_path); + + (*worktree)->root_fd = open((*worktree)->root_path, O_DIRECTORY); + if ((*worktree)->root_fd == -1) { + err = got_error_from_errno2("open", (*worktree)->root_path); + goto done; + } +done: + if (repo) { + const struct got_error *close_err = got_repo_close(repo); + if (err == NULL) + err = close_err; + } + free(path_got); + free(path_lock); + free(base_commit_id_str); + free(uuidstr); + free(formatstr); + if (err) { + if (fd != -1) + close(fd); + if (*worktree != NULL) + got_worktree_close(*worktree); + *worktree = NULL; + } else + (*worktree)->lockfd = fd; + + return err; +} + +const struct got_error * +got_worktree_open(struct got_worktree **worktree, const char *path) +{ + const struct got_error *err = NULL; + char *worktree_path; + + worktree_path = strdup(path); + if (worktree_path == NULL) + return got_error_from_errno("strdup"); + + for (;;) { + char *parent_path; + + err = open_worktree(worktree, worktree_path); + if (err && !(err->code == GOT_ERR_ERRNO && errno == ENOENT)) { + free(worktree_path); + return err; + } + if (*worktree) { + free(worktree_path); + return NULL; + } + if (worktree_path[0] == '/' && worktree_path[1] == '\0') + break; + err = got_path_dirname(&parent_path, worktree_path); + if (err) { + if (err->code != GOT_ERR_BAD_PATH) { + free(worktree_path); + return err; + } + break; + } + free(worktree_path); + worktree_path = parent_path; + } + + free(worktree_path); + return got_error(GOT_ERR_NOT_WORKTREE); +} + +const struct got_error * +got_worktree_close(struct got_worktree *worktree) +{ + const struct got_error *err = NULL; + + if (worktree->lockfd != -1) { + if (close(worktree->lockfd) == -1) + err = got_error_from_errno2("close", + got_worktree_get_root_path(worktree)); + } + if (close(worktree->root_fd) == -1 && err == NULL) + err = got_error_from_errno2("close", + got_worktree_get_root_path(worktree)); + free(worktree->repo_path); + free(worktree->path_prefix); + free(worktree->base_commit_id); + free(worktree->head_ref_name); + free(worktree->root_path); + free(worktree->gotconfig_path); + got_gotconfig_free(worktree->gotconfig); + free(worktree); + return err; +} + +const char * +got_worktree_get_root_path(struct got_worktree *worktree) +{ + return worktree->root_path; +} + +const char * +got_worktree_get_repo_path(struct got_worktree *worktree) +{ + return worktree->repo_path; +} + +const char * +got_worktree_get_path_prefix(struct got_worktree *worktree) +{ + return worktree->path_prefix; +}