From: Stefan Sperling Subject: add got.conf(5) to worktree meta-data area To: gameoftrees@openbsd.org Date: Fri, 11 Sep 2020 10:10:01 +0200 This adds a per-worktree got.conf(5) file. This can be useful in cases where repository-wide settings need to be overridden. One hypothetical scenario is multiple user accounts sharing a repository. In this use case author information configured in the repository's got.conf will override everyone's GOT_AUTHOR environment variable. With the patch below, each user can now configure author information in their respective work trees in order to override any repository-wide default. The repository-wide got.conf must override GOT_AUTHOR to support the use case where a single user account uses multiple repositories with differing author identities. Based on the above considerations, I came up with the following priority scheme, which is documented in a comment added by the patch (and documented in relevant sections of man pages): + * Priority of potential author information sources, from most + * significant to least significant: + * 1) work tree's .got/got.conf file + * 2) repository's got.conf file + * 3) repository's git config file + * 4) environment variables + * 5) global git config files (in user's home directory or /etc) In the future, the same priority scheme could be applied to other settings, such as the $EDITOR to use. ok? M got/Makefile M got/git-repository.5 M got/got-worktree.5 M got/got.1 M got/got.c M got/got.conf.5 M gotweb/Makefile A include/got_gotconfig.h M include/got_repository.h M include/got_worktree.h A lib/got_lib_gotconfig.h M lib/got_lib_repository.h M lib/got_lib_worktree.h A lib/gotconfig.c M lib/repository.c M lib/worktree.c M regress/cmdline/commit.sh M regress/cmdline/fetch.sh M regress/fetch/Makefile M tog/Makefile diff 1255748cb9b4a8d7ff0bdeea4ea3384865e4e1ab b610588364b6aef22a59c6ffd6d7063db1c04533 blob - 27b8780c69c81f08f6abd29001c803e5e4e2f601 blob + c244659a0df74322caa231ad293ecbe3d0c6656e --- got/Makefile +++ got/Makefile @@ -8,7 +8,8 @@ SRCS= got.c blame.c commit_graph.c delta.c diff.c \ object_idset.c object_parse.c opentemp.c path.c pack.c \ privsep.c reference.c repository.c sha1.c worktree.c \ inflate.c buf.c rcsutil.c diff3.c lockfile.c \ - deflate.c object_create.c delta_cache.c fetch.c + deflate.c object_create.c delta_cache.c fetch.c \ + gotconfig.c MAN = ${PROG}.1 got-worktree.5 git-repository.5 CPPFLAGS = -I${.CURDIR}/../include -I${.CURDIR}/../lib blob - c3d8db9ba60678629dd9370b6ba329c9404d86e8 blob + bd2b0aec4cc1520b2e11a1932a8969d74cd65804 --- got/git-repository.5 +++ got/git-repository.5 @@ -162,6 +162,11 @@ See .Xr git-config 1 . .It Pa description A human-readable description of the repository. +.It Pa got.conf +Configuration file for +.Xr got 1 . +See +.Xr got.conf 5 . .It Pa hooks/ This directory contains hook scripts to run when certain events occur. .It Pa index @@ -201,6 +206,7 @@ was bare. .Xr deflate 3 , .Xr SHA1 3 , .Xr got-worktree 5 +.Xr got.conf 5 .Sh HISTORY The Git repository format was initially designed by Linus Torvalds in 2005 and has since been extended by various people involved in the development blob - 49ede63463e6753340669f22f44dd1d2dc419a94 blob + 8f8ac0e97ca4c5e796623f8c6c176dbabf331a52 --- got/got-worktree.5 +++ got/got-worktree.5 @@ -161,6 +161,11 @@ SHA1 hex-string representation of the current base com File status information. .It Pa format Work tree format number. +.It Pa got.conf +Configuration file for +.Xr got 1 . +See +.Xr got.conf 5 . .It Pa head-ref Name of the reference to the current branch. .It Pa lock @@ -178,4 +183,5 @@ A universal unique identifier for the work tree. .Xr stat 2 , .Xr umask 2 , .Xr lockf 3 , -.Xr git-repository 5 +.Xr git-repository 5 , +.Xr got.conf 5 blob - fc2c1967ab5a100d7afd85ed536d8bec33d4c31f blob + 19a06c86f792b3c3404b00fa130431da3857d9c2 --- got/got.1 +++ got/got.1 @@ -315,9 +315,9 @@ If no is specified, .Dq origin will be used. -The remote repository's URL is obtained from the corresponding entry in the +The remote repository's URL is obtained from the corresponding entry in .Xr got.conf 5 -or +or Git's .Pa config file of the local repository, as created by .Cm got clone . @@ -1930,18 +1930,15 @@ attempts to reject .Ev GOT_AUTHOR environment variables with a missing email address. .Pp -If present, -configuration settings in -.Xr got.conf 5 , -or Git's +.Ev GOT_AUTHOR will be overriden by configuration settings in +.Xr got.conf 5 +or by Git's .Dv user.name and .Dv user.email configuration settings in the repository's .Pa .git/config -file, -will override the value of -.Ev GOT_AUTHOR . +file. The .Dv user.name and @@ -1970,8 +1967,24 @@ This variable will be silently ignored if it is set to .It Pa got.conf Repository-wide configuration settings for .Nm . -If present, this configuration file is located in the root directory -of a Git repository and supersedes any relevant settings in Git's +If present, a +.Xr got.conf 5 +configuration file located in the root directory of a Git repository +supersedes any relevant settings in Git's +.Pa config +file. +.Pp +.It Pa .got/got.conf +Worktree-specific configuration settings for +.Nm . +If present, a +.Xr got.conf +configuration file in the +.Pa .got +meta-data directory of a work tree supersedes any relevant settings in +the repository's +.Xr got.conf 5 +configuration file and Git's .Pa config file. .El blob - 3a7013aa09b5952fd99ebb4cbf7e06235e769d42 blob + f51c668647291caa2517c4565190ec31f8c24aa5 --- got/got.c +++ got/got.c @@ -54,6 +54,7 @@ #include "got_blame.h" #include "got_privsep.h" #include "got_opentemp.h" +#include "got_gotconfig.h" #ifndef nitems #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) @@ -516,14 +517,33 @@ import_progress(void *arg, const char *path) } static const struct got_error * -get_author(char **author, struct got_repository *repo) +get_author(char **author, struct got_repository *repo, + struct got_worktree *worktree) { const struct got_error *err = NULL; - const char *got_author, *name, *email; + const char *got_author = NULL, *name, *email; + const struct got_gotconfig *worktree_conf = NULL, *repo_conf = NULL; *author = NULL; - got_author = got_repo_get_gotconfig_author(repo); + if (worktree) + worktree_conf = got_worktree_get_gotconfig(worktree); + repo_conf = got_repo_get_gotconfig(repo); + + /* + * Priority of potential author information sources, from most + * significant to least significant: + * 1) work tree's .got/got.conf file + * 2) repository's got.conf file + * 3) repository's git config file + * 4) environment variables + * 5) global git config files (in user's home directory or /etc) + */ + + if (worktree_conf) + got_author = got_gotconfig_get_author(worktree_conf); + if (got_author == NULL) + got_author = got_gotconfig_get_author(repo_conf); if (got_author == NULL) { name = got_repo_get_gitconfig_author_name(repo); email = got_repo_get_gitconfig_author_email(repo); @@ -672,7 +692,7 @@ cmd_import(int argc, char *argv[]) if (error) goto done; - error = get_author(&author, repo); + error = get_author(&author, repo, NULL); if (error) return error; @@ -1654,7 +1674,8 @@ done: static const struct got_error * delete_missing_refs(struct got_pathlist_head *their_refs, - struct got_pathlist_head *their_symrefs, struct got_remote_repo *remote, + struct got_pathlist_head *their_symrefs, + const struct got_remote_repo *remote, int verbosity, struct got_repository *repo) { const struct got_error *err = NULL, *unlock_err; @@ -1780,11 +1801,12 @@ cmd_fetch(int argc, char *argv[]) const char *remote_name; char *proto = NULL, *host = NULL, *port = NULL; char *repo_name = NULL, *server_path = NULL; - struct got_remote_repo *remotes, *remote = NULL; + const struct got_remote_repo *remotes, *remote = NULL; int nremotes; char *id_str = NULL; struct got_repository *repo = NULL; struct got_worktree *worktree = NULL; + const struct got_gotconfig *repo_conf = NULL, *worktree_conf = NULL; struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs; struct got_pathlist_entry *pe; struct got_object_id *pack_hash = NULL; @@ -1901,24 +1923,42 @@ cmd_fetch(int argc, char *argv[]) if (error) goto done; - got_repo_get_gotconfig_remotes(&nremotes, &remotes, repo); - for (i = 0; i < nremotes; i++) { - remote = &remotes[i]; - if (strcmp(remote->name, remote_name) == 0) - break; + if (worktree) { + worktree_conf = got_worktree_get_gotconfig(worktree); + if (worktree_conf) { + got_gotconfig_get_remotes(&nremotes, &remotes, + worktree_conf); + for (i = 0; i < nremotes; i++) { + remote = &remotes[i]; + if (strcmp(remote->name, remote_name) == 0) + break; + } + } } - if (i == nremotes) { + if (remote == NULL) { + repo_conf = got_repo_get_gotconfig(repo); + if (repo_conf) { + got_gotconfig_get_remotes(&nremotes, &remotes, + repo_conf); + for (i = 0; i < nremotes; i++) { + remote = &remotes[i]; + if (strcmp(remote->name, remote_name) == 0) + break; + } + } + } + if (remote == NULL) { got_repo_get_gitconfig_remotes(&nremotes, &remotes, repo); for (i = 0; i < nremotes; i++) { remote = &remotes[i]; if (strcmp(remote->name, remote_name) == 0) break; } - if (i == nremotes) { - error = got_error_path(remote_name, GOT_ERR_NO_REMOTE); - goto done; - } } + if (remote == NULL) { + error = got_error_path(remote_name, GOT_ERR_NO_REMOTE); + goto done; + } error = got_fetch_parse_uri(&proto, &host, &port, &server_path, &repo_name, remote->url); @@ -5684,8 +5724,8 @@ done: } static const struct got_error * -add_tag(struct got_repository *repo, const char *tag_name, - const char *commit_arg, const char *tagmsg_arg) +add_tag(struct got_repository *repo, struct got_worktree *worktree, + const char *tag_name, const char *commit_arg, const char *tagmsg_arg) { const struct got_error *err = NULL; struct got_object_id *commit_id = NULL, *tag_id = NULL; @@ -5703,7 +5743,7 @@ add_tag(struct got_repository *repo, const char *tag_n if (tag_name[0] == '-') return got_error_path(tag_name, GOT_ERR_REF_NAME_MINUS); - err = get_author(&tagger, repo); + err = get_author(&tagger, repo, worktree); if (err) return err; @@ -5923,7 +5963,7 @@ cmd_tag(int argc, char *argv[]) goto done; } - error = add_tag(repo, tag_name, + error = add_tag(repo, worktree, tag_name, commit_id_str ? commit_id_str : commit_id_arg, tagmsg); } done: @@ -6629,7 +6669,7 @@ cmd_commit(int argc, char *argv[]) if (error != NULL) goto done; - error = get_author(&author, repo); + error = get_author(&author, repo, worktree); if (error) return error; blob - d6d11e44ab3797c4469bc5d41a882b8be638c18d blob + 734c2588bf80cb8172f32339ab787239afdda279 --- got/got.conf.5 +++ got/got.conf.5 @@ -24,6 +24,15 @@ is the run-time configuration file for .Xr got 1 . .Pp +.Nm +may be present in the root directory of a Git repository for +repository-wide settings, or in the +.Pa .got +meta-data directory of a work tree to override repository-wide +settings for +.Xr got 1 +commands executed within this work tree. +.Pp The file format is line-based, with one configuration directive per line. Any lines beginning with a .Sq # @@ -144,13 +153,27 @@ remote "origin" { .Sh FILES .Bl -tag -width Ds -compact .It Pa got.conf -If present, the +If present, .Nm -configuration file is located in the root directory of a Git repository -and supersedes any relevant settings in Git's +located in the root directory of a Git repository supersedes any relevant +settings in Git's .Pa config file. +.Pp +.It Pa .got/got.conf +If present, +.Nm +located in the +.Pa .got +meta-data directory of a +.Xr got 1 +work tree supersedes any relevant settings in the repository's +.Nm +configuration file and Git's +.Pa config +file. .El .Sh SEE ALSO .Xr got 1 , -.Xr git-repository 5 +.Xr git-repository 5, +.Xr got-worktree 5 blob - f22b8bb81af7cfdf1f29b916d2c0fb8cfe1a58a4 blob + 86cf8bc92c4952d24ebe4dce99160c0be49ac598 --- gotweb/Makefile +++ gotweb/Makefile @@ -11,7 +11,7 @@ SRCS = gotweb.c parse.y blame.c commit_graph.c delta. object_idset.c object_parse.c opentemp.c path.c pack.c \ privsep.c reference.c repository.c sha1.c worktree.c \ inflate.c buf.c rcsutil.c diff3.c lockfile.c \ - deflate.c object_create.c delta_cache.c + deflate.c object_create.c delta_cache.c gotconfig.c MAN = ${PROG}.conf.5 ${PROG}.8 CPPFLAGS += -I${.CURDIR}/../include -I${.CURDIR}/../lib -I${.CURDIR} \ blob - /dev/null blob + 3dbe5d7d43cf45ec0e7997d43f266c3ce0c9fcbe (mode 644) --- /dev/null +++ include/got_gotconfig.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 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. + */ + +struct got_gotconfig; + +/* + * Obtain the commit author parsed from got.conf. + * Return NULL if no configuration file or author could be found. + */ +const char *got_gotconfig_get_author(const struct got_gotconfig *); + +/* + * Obtain the list of remote repositories parsed from got.conf. + * Return 0 and NULL if no configuration file or remote repository + * could be found. + */ +void got_gotconfig_get_remotes(int *, const struct got_remote_repo **, + const struct got_gotconfig *); blob - bc9bddc1aebed32b0412d1f87f93b3ec0b753271 blob + 2b104798d08e7adbf100ae6c9d7a0877630dacdd --- include/got_repository.h +++ include/got_repository.h @@ -59,16 +59,15 @@ struct got_remote_repo { int mirror_references; }; -/* Obtain the commit author if parsed from got.conf, else NULL. */ -const char *got_repo_get_gotconfig_author(struct got_repository *); - /* Obtain the list of remote repositories parsed from gitconfig. */ -void got_repo_get_gitconfig_remotes(int *, struct got_remote_repo **, +void got_repo_get_gitconfig_remotes(int *, const struct got_remote_repo **, struct got_repository *); -/* Obtain the list of remote repositories parsed from got.conf. */ -void got_repo_get_gotconfig_remotes(int *, struct got_remote_repo **, - struct got_repository *); +/* + * Obtain a parsed representation of this repository's got.conf file. + * Return NULL if this configuration file could not be read. + */ +const struct got_gotconfig *got_repo_get_gotconfig(struct got_repository *); /* * Obtain paths to various directories within a repository. blob - c655d810c3ca855bdbd7d38b7191e1243efb8b91 blob + 24fddd52e81d96ff7b1800a61de1f80319326a3e --- include/got_worktree.h +++ include/got_worktree.h @@ -108,6 +108,12 @@ struct got_object_id *got_worktree_get_base_commit_id( const struct got_error *got_worktree_set_base_commit_id(struct got_worktree *, struct got_repository *, struct got_object_id *); +/* + * Obtain a parsed representation of this worktree's got.conf file. + * Return NULL if this configuration file could not be read. + */ +const struct got_gotconfig *got_worktree_get_gotconfig(struct got_worktree *); + /* A callback function which is invoked when a path is checked out. */ typedef const struct got_error *(*got_worktree_checkout_cb)(void *, unsigned char, const char *); blob - /dev/null blob + 5e02aa1efeff0dd226e617da410a4663d8376d9a (mode 644) --- /dev/null +++ lib/got_lib_gotconfig.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 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. + */ + +#define GOT_GOTCONFIG_FILENAME "got.conf" + +struct got_gotconfig { + char *author; + int nremotes; + struct got_remote_repo *remotes; +}; + +const struct got_error *got_gotconfig_read(struct got_gotconfig **, + const char *); +void got_gotconfig_free(struct got_gotconfig *); blob - 53390eff4e10f3f105c870ac188b9a0db1df2416 blob + 87f25580cb957d598ce95524a992a2d67f95d9ad --- lib/got_lib_repository.h +++ lib/got_lib_repository.h @@ -21,7 +21,6 @@ #define GOT_REFS_DIR "refs" #define GOT_HEAD_FILE "HEAD" #define GOT_GITCONFIG "config" -#define GOT_GOTCONFIG "got.conf" /* Other files and directories inside the git directory. */ #define GOT_FETCH_HEAD_FILE "FETCH_HEAD" @@ -67,9 +66,7 @@ struct got_repository { char *gitconfig_owner; /* Settings read from got.conf. */ - char *gotconfig_author; - int ngotconfig_remotes; - struct got_remote_repo *gotconfig_remotes; + struct got_gotconfig *gotconfig; }; const struct got_error*got_repo_cache_object(struct got_repository *, blob - c45a95888b5015de44ca323f6dd4759e19eb36f4 blob + 067bac22c55a94684a7dcb779417671747de7972 --- lib/got_lib_worktree.h +++ lib/got_lib_worktree.h @@ -33,6 +33,12 @@ struct got_worktree { * shared lock must be upgraded to an exclusive lock. */ int lockfd; + + /* Absolute path to worktree's got.conf file. */ + char *gotconfig_path; + + /* Settings read from got.conf. */ + struct got_gotconfig *gotconfig; }; struct got_commitable { blob - /dev/null blob + c52b0ab71b1a027b3dde159ef7941c99e8811c52 (mode 644) --- /dev/null +++ lib/gotconfig.c @@ -0,0 +1,158 @@ +/* + * Copyright (c) 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 +#include + +#include "got_error.h" +#include "got_object.h" +#include "got_repository.h" + +#include "got_lib_delta.h" +#include "got_lib_object.h" +#include "got_lib_privsep.h" +#include "got_lib_gotconfig.h" + +const struct got_error * +got_gotconfig_read(struct got_gotconfig **conf, const char *gotconfig_path) +{ + const struct got_error *err = NULL, *child_err = NULL; + int fd = -1; + int imsg_fds[2] = { -1, -1 }; + pid_t pid; + struct imsgbuf *ibuf; + + *conf = calloc(1, sizeof(**conf)); + if (*conf == NULL) + return got_error_from_errno("calloc"); + + fd = open(gotconfig_path, O_RDONLY); + if (fd == -1) { + if (errno == ENOENT) + return NULL; + return got_error_from_errno2("open", gotconfig_path); + } + + ibuf = calloc(1, sizeof(*ibuf)); + if (ibuf == NULL) { + err = got_error_from_errno("calloc"); + goto done; + } + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) { + err = got_error_from_errno("socketpair"); + goto done; + } + + pid = fork(); + if (pid == -1) { + err = got_error_from_errno("fork"); + goto done; + } else if (pid == 0) { + got_privsep_exec_child(imsg_fds, GOT_PATH_PROG_READ_GOTCONFIG, + gotconfig_path); + /* not reached */ + } + + if (close(imsg_fds[1]) == -1) { + err = got_error_from_errno("close"); + goto done; + } + imsg_fds[1] = -1; + imsg_init(ibuf, imsg_fds[0]); + + err = got_privsep_send_gotconfig_parse_req(ibuf, fd); + if (err) + goto done; + fd = -1; + + err = got_privsep_send_gotconfig_author_req(ibuf); + if (err) + goto done; + + err = got_privsep_recv_gotconfig_str(&(*conf)->author, ibuf); + if (err) + goto done; + + err = got_privsep_send_gotconfig_remotes_req(ibuf); + if (err) + goto done; + + err = got_privsep_recv_gotconfig_remotes(&(*conf)->remotes, + &(*conf)->nremotes, ibuf); + if (err) + goto done; + + imsg_clear(ibuf); + err = got_privsep_send_stop(imsg_fds[0]); + child_err = got_privsep_wait_for_child(pid); + if (child_err && err == NULL) + err = child_err; +done: + if (imsg_fds[0] != -1 && close(imsg_fds[0]) == -1 && err == NULL) + err = got_error_from_errno("close"); + if (imsg_fds[1] != -1 && close(imsg_fds[1]) == -1 && err == NULL) + err = got_error_from_errno("close"); + if (fd != -1 && close(fd) == -1 && err == NULL) + err = got_error_from_errno2("close", gotconfig_path); + if (err) { + got_gotconfig_free(*conf); + *conf = NULL; + } + free(ibuf); + return err; +} + +void +got_gotconfig_free(struct got_gotconfig *conf) +{ + int i; + + free(conf->author); + + for (i = 0; i < conf->nremotes; i++) { + free(conf->remotes[i].name); + free(conf->remotes[i].url); + } + free(conf->remotes); + free(conf); +} + +const char * +got_gotconfig_get_author(const struct got_gotconfig *conf) +{ + return conf->author; +} + +void +got_gotconfig_get_remotes(int *nremotes, const struct got_remote_repo **remotes, + const struct got_gotconfig *conf) +{ + *nremotes = conf->nremotes; + *remotes = conf->remotes; +} blob - 803b58014d1ed3dce991365b1c035c4c54f45af9 blob + 84e9477170999aa739a81012b9df1b76060ec4f2 --- lib/repository.c +++ lib/repository.c @@ -60,6 +60,7 @@ #include "got_lib_sha1.h" #include "got_lib_object_cache.h" #include "got_lib_repository.h" +#include "got_lib_gotconfig.h" #ifndef nitems #define nitems(_a) (sizeof(_a) / sizeof((_a)[0])) @@ -164,29 +165,21 @@ got_repo_get_path_gitconfig(struct got_repository *rep char * got_repo_get_path_gotconfig(struct got_repository *repo) { - return get_path_git_child(repo, GOT_GOTCONFIG); + return get_path_git_child(repo, GOT_GOTCONFIG_FILENAME); } -void -got_repo_get_gitconfig_remotes(int *nremotes, struct got_remote_repo **remotes, - struct got_repository *repo) +const struct got_gotconfig * +got_repo_get_gotconfig(struct got_repository *repo) { - *nremotes = repo->ngitconfig_remotes; - *remotes = repo->gitconfig_remotes; + return repo->gotconfig; } -const char * -got_repo_get_gotconfig_author(struct got_repository *repo) -{ - return repo->gotconfig_author; -} - void -got_repo_get_gotconfig_remotes(int *nremotes, struct got_remote_repo **remotes, - struct got_repository *repo) +got_repo_get_gitconfig_remotes(int *nremotes, + const struct got_remote_repo **remotes, struct got_repository *repo) { - *nremotes = repo->ngotconfig_remotes; - *remotes = repo->gotconfig_remotes; + *nremotes = repo->ngitconfig_remotes; + *remotes = repo->gitconfig_remotes; } static int @@ -539,107 +532,6 @@ done: } static const struct got_error * -parse_gotconfig_file(char **author, - struct got_remote_repo **remotes, int *nremotes, - const char *gotconfig_path) -{ - const struct got_error *err = NULL, *child_err = NULL; - int fd = -1; - int imsg_fds[2] = { -1, -1 }; - pid_t pid; - struct imsgbuf *ibuf; - - if (author) - *author = NULL; - if (remotes) - *remotes = NULL; - if (nremotes) - *nremotes = 0; - - fd = open(gotconfig_path, O_RDONLY); - if (fd == -1) { - if (errno == ENOENT) - return NULL; - return got_error_from_errno2("open", gotconfig_path); - } - - ibuf = calloc(1, sizeof(*ibuf)); - if (ibuf == NULL) { - err = got_error_from_errno("calloc"); - goto done; - } - - if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, imsg_fds) == -1) { - err = got_error_from_errno("socketpair"); - goto done; - } - - pid = fork(); - if (pid == -1) { - err = got_error_from_errno("fork"); - goto done; - } else if (pid == 0) { - got_privsep_exec_child(imsg_fds, GOT_PATH_PROG_READ_GOTCONFIG, - gotconfig_path); - /* not reached */ - } - - if (close(imsg_fds[1]) == -1) { - err = got_error_from_errno("close"); - goto done; - } - imsg_fds[1] = -1; - imsg_init(ibuf, imsg_fds[0]); - - err = got_privsep_send_gotconfig_parse_req(ibuf, fd); - if (err) - goto done; - fd = -1; - - if (author) { - err = got_privsep_send_gotconfig_author_req(ibuf); - if (err) - goto done; - - err = got_privsep_recv_gotconfig_str(author, ibuf); - if (err) - goto done; - } - - if (remotes && nremotes) { - err = got_privsep_send_gotconfig_remotes_req(ibuf); - if (err) - goto done; - - err = got_privsep_recv_gotconfig_remotes(remotes, - nremotes, ibuf); - if (err) - goto done; - } - - imsg_clear(ibuf); - err = got_privsep_send_stop(imsg_fds[0]); - child_err = got_privsep_wait_for_child(pid); - if (child_err && err == NULL) - err = child_err; -done: - if (imsg_fds[0] != -1 && close(imsg_fds[0]) == -1 && err == NULL) - err = got_error_from_errno("close"); - if (imsg_fds[1] != -1 && close(imsg_fds[1]) == -1 && err == NULL) - err = got_error_from_errno("close"); - if (fd != -1 && close(fd) == -1 && err == NULL) - err = got_error_from_errno2("close", gotconfig_path); - if (err) { - if (author) { - free(*author); - *author = NULL; - } - } - free(ibuf); - return err; -} - -static const struct got_error * read_gotconfig(struct got_repository *repo) { const struct got_error *err = NULL; @@ -649,9 +541,7 @@ read_gotconfig(struct got_repository *repo) if (gotconfig_path == NULL) return got_error_from_errno("got_repo_get_path_gotconfig"); - err = parse_gotconfig_file(&repo->gotconfig_author, - &repo->gotconfig_remotes, &repo->ngotconfig_remotes, - gotconfig_path); + err = got_gotconfig_read(&repo->gotconfig, gotconfig_path); free(gotconfig_path); return err; } @@ -788,12 +678,8 @@ got_repo_close(struct got_repository *repo) err = got_error_from_errno("close"); } - free(repo->gotconfig_author); - for (i = 0; i < repo->ngotconfig_remotes; i++) { - free(repo->gotconfig_remotes[i].name); - free(repo->gotconfig_remotes[i].url); - } - free(repo->gotconfig_remotes); + if (repo->gotconfig) + got_gotconfig_free(repo->gotconfig); free(repo->gitconfig_author_name); free(repo->gitconfig_author_email); for (i = 0; i < repo->ngitconfig_remotes; i++) { blob - 8afc4c2596b52c558eca6fd9e0ac8678040d308f blob + f5fa3485648a42a4ee5b7d43aaf7f4dceb6ed763 --- lib/worktree.c +++ lib/worktree.c @@ -55,6 +55,7 @@ #include "got_lib_object_create.h" #include "got_lib_object_idset.h" #include "got_lib_diff.h" +#include "got_lib_gotconfig.h" #ifndef MIN #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b)) @@ -416,6 +417,18 @@ open_worktree(struct got_worktree **worktree, const ch 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); done: if (repo) got_repo_close(repo); @@ -468,6 +481,8 @@ got_worktree_close(struct got_worktree *worktree) err = got_error_from_errno2("close", got_worktree_get_root_path(worktree)); free(worktree->root_path); + free(worktree->gotconfig_path); + got_gotconfig_free(worktree->gotconfig); free(worktree); return err; } @@ -483,7 +498,6 @@ got_worktree_get_repo_path(struct got_worktree *worktr { return worktree->repo_path; } - const char * got_worktree_get_path_prefix(struct got_worktree *worktree) { @@ -596,6 +610,12 @@ done: free(id_str); free(path_got); return err; +} + +const struct got_gotconfig * +got_worktree_get_gotconfig(struct got_worktree *worktree) +{ + return worktree->gotconfig; } static const struct got_error * blob - 13a4e58bcc3693cd4eb419089a8e29ea5e377524 blob + 7e2e93f01cb45ae2344a72007a67db4942a023f5 --- regress/cmdline/commit.sh +++ regress/cmdline/commit.sh @@ -736,6 +736,45 @@ function test_commit_gotconfig_author { test_done "$testroot" "$ret" } +function test_commit_gotconfig_worktree_author { + local testroot=`test_init commit_gotconfig_worktree_author` + + got checkout $testroot/repo $testroot/wt > /dev/null + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + echo 'author "Flan Luck "' \ + > $testroot/repo/.git/got.conf + echo 'author "Flan Squee "' \ + > $testroot/wt/.got/got.conf + + echo "modified alpha" > $testroot/wt/alpha + (cd $testroot/wt && got commit -m 'test gotconfig author' > /dev/null) + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + (cd $testroot/repo && got log -l1 | grep ^from: > $testroot/stdout) + ret="$?" + if [ "$ret" != "0" ]; then + test_done "$testroot" "$ret" + return 1 + fi + + echo "from: Flan Squee " \ + > $testroot/stdout.expected + cmp -s $testroot/stdout.expected $testroot/stdout + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + fi + test_done "$testroot" "$ret" +} + function test_commit_gitconfig_author { local testroot=`test_init commit_gitconfig_author` @@ -1335,6 +1374,7 @@ run_test test_commit_outside_refs_heads run_test test_commit_no_email run_test test_commit_tree_entry_sorting run_test test_commit_gotconfig_author +run_test test_commit_gotconfig_worktree_author run_test test_commit_gitconfig_author run_test test_commit_xbit_change run_test test_commit_normalizes_filemodes blob - 22fde4a90a75e2c5a0bb28cb02c1fa209ef6f3e2 blob + a131768e455946cd8609feb790b2dd1a83b1644c --- regress/cmdline/fetch.sh +++ regress/cmdline/fetch.sh @@ -948,6 +948,85 @@ function test_fetch_headref_deleted_locally { test_done "$testroot" "$ret" } +function test_fetch_gotconfig_remote_repo { + local testroot=`test_init fetch_gotconfig_remote_repo` + local testurl=ssh://127.0.0.1/$testroot + local commit_id=`git_show_head $testroot/repo` + + got branch -r $testroot/repo -c $commit_id foo + got ref -r $testroot/repo -c $commit_id refs/hoo/boo/zoo + got tag -r $testroot/repo -c $commit_id -m tag "1.0" >/dev/null + + got clone -q $testurl/repo $testroot/repo-clone + ret="$?" + if [ "$ret" != "0" ]; then + echo "got clone command failed unexpectedly" >&2 + test_done "$testroot" "$ret" + return 1 + fi + +cat > $testroot/repo-clone/got.conf < $testroot/stdout) + ret="$?" + if [ "$ret" != "0" ]; then + echo "got fetch command failed unexpectedly" >&2 + test_done "$testroot" "$ret" + return 1 + fi + + echo "Connecting to \"foobar\" 127.0.0.1" > $testroot/stdout.expected + got ref -l -r $testroot/repo >> $testroot/stdout.expected + + cmp -s $testroot/stdout $testroot/stdout.expected + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + got checkout $testroot/repo $testroot/wt > /dev/null + +cat > $testroot/wt/.got/got.conf < $testroot/stdout) + ret="$?" + if [ "$ret" != "0" ]; then + echo "got fetch command failed unexpectedly" >&2 + test_done "$testroot" "$ret" + return 1 + fi + + echo "Connecting to \"barbaz\" 127.0.0.1" > $testroot/stdout.expected + got ref -l -r $testroot/repo >> $testroot/stdout.expected + + cmp -s $testroot/stdout $testroot/stdout.expected + ret="$?" + if [ "$ret" != "0" ]; then + diff -u $testroot/stdout.expected $testroot/stdout + fi + test_done "$testroot" "$ret" + +} + test_parseargs "$@" run_test test_fetch_basic run_test test_fetch_list @@ -960,3 +1039,4 @@ run_test test_fetch_reference run_test test_fetch_replace_symref run_test test_fetch_update_headref run_test test_fetch_headref_deleted_locally +run_test test_fetch_gotconfig_remote_repo blob - 9834aeeb0ffac0003745cb75c3ecbe20d3a2d6ff blob + f9e0d6b0ee0b8e3d702b742b51baa3819d382ff2 --- regress/fetch/Makefile +++ regress/fetch/Makefile @@ -4,7 +4,7 @@ PROG = fetch_test SRCS = error.c privsep.c reference.c sha1.c object.c object_parse.c path.c \ opentemp.c repository.c lockfile.c object_cache.c pack.c inflate.c \ deflate.c delta.c delta_cache.c object_idset.c object_create.c \ - fetch.c fetch_test.c + fetch.c gotconfig.c fetch_test.c CPPFLAGS = -I${.CURDIR}/../../include -I${.CURDIR}/../../lib LDADD = -lutil -lz blob - aafde1a4c7fe645f39e2b0acb46faa64767369c7 blob + 41af3bef58e4bdab819c0a659369ee2a3c2f2e2f --- tog/Makefile +++ tog/Makefile @@ -8,7 +8,8 @@ SRCS= tog.c blame.c commit_graph.c delta.c diff.c \ object_idset.c object_parse.c opentemp.c path.c pack.c \ privsep.c reference.c repository.c sha1.c worktree.c \ utf8.c inflate.c buf.c rcsutil.c diff3.c \ - lockfile.c deflate.c object_create.c delta_cache.c + lockfile.c deflate.c object_create.c delta_cache.c \ + gotconfig.c MAN = ${PROG}.1 CPPFLAGS = -I${.CURDIR}/../include -I${.CURDIR}/../lib