commit 99495ddb79841fe89b0746d35a49bb81e9220096 from: Stefan Sperling date: Sun Jan 10 23:48:51 2021 UTC add a 'reference' directive to remote repositories in got.conf(5) Make use of this in 'got clone' to persist -R option arguments given on the command line in the cloned repository's got.conf(5) file. commit - 1255c02f3e117fa4fd07f9cc6fbcf62383755e5d commit + 99495ddb79841fe89b0746d35a49bb81e9220096 blob - 17b5f0720dd626a7af6459cf23be329bb9b96e21 blob + 4a92790860d73b08d6ba18a5daf45eed2583c62f --- got/got.1 +++ got/got.1 @@ -193,8 +193,10 @@ and .Pa config files of the cloned repository to store the .Ar repository-url -and +and any .Ar branch +or +.Ar reference arguments for future use by .Cm got fetch or blob - 53829fbd5cf6cd49d4f93619417cf7218d2bbd1e blob + 588f144e15210cef646e4d3b143f8cb74e7e5abe --- got/got.c +++ got/got.c @@ -927,6 +927,7 @@ struct got_fetch_progress_arg { struct { struct got_pathlist_head *symrefs; struct got_pathlist_head *wanted_branches; + struct got_pathlist_head *wanted_refs; const char *proto; const char *host; const char *port; @@ -942,7 +943,8 @@ static const struct got_error * create_config_files(const char *proto, const char *host, const char *port, const char *remote_repo_path, const char *git_url, int fetch_all_branches, int mirror_references, struct got_pathlist_head *symrefs, - struct got_pathlist_head *wanted_branches, struct got_repository *repo); + struct got_pathlist_head *wanted_branches, + struct got_pathlist_head *wanted_refs, struct got_repository *repo); static const struct got_error * fetch_progress(void *arg, const char *message, off_t packfile_size, @@ -969,7 +971,8 @@ fetch_progress(void *arg, const char *message, off_t p a->config_info.fetch_all_branches, a->config_info.mirror_references, a->config_info.symrefs, - a->config_info.wanted_branches, a->repo); + a->config_info.wanted_branches, + a->config_info.wanted_refs, a->repo); if (err) return err; a->configs_created = 1; @@ -1165,14 +1168,15 @@ static const struct got_error * create_gotconfig(const char *proto, const char *host, const char *port, const char *remote_repo_path, const char *default_branch, int fetch_all_branches, struct got_pathlist_head *wanted_branches, - int mirror_references, struct got_repository *repo) + struct got_pathlist_head *wanted_refs, int mirror_references, + struct got_repository *repo) { const struct got_error *err = NULL; char *gotconfig_path = NULL; char *gotconfig = NULL; FILE *gotconfig_file = NULL; const char *branchname = NULL; - char *branches = NULL; + char *branches = NULL, *refs = NULL; ssize_t n; if (!fetch_all_branches && !TAILQ_EMPTY(wanted_branches)) { @@ -1197,6 +1201,22 @@ create_gotconfig(const char *proto, const char *host, if (asprintf(&branches, "\"%s\" ", branchname) == -1) { err = got_error_from_errno("asprintf"); goto done; + } + } + if (!TAILQ_EMPTY(wanted_refs)) { + struct got_pathlist_entry *pe; + TAILQ_FOREACH(pe, wanted_refs, entry) { + char *s; + const char *refname = pe->path; + if (strncmp(refname, "refs/", 5) == 0) + branchname += 5; + if (asprintf(&s, "%s\"%s\" ", + refs ? refs : "", refname) == -1) { + err = got_error_from_errno("asprintf"); + goto done; + } + free(refs); + refs = s; } } @@ -1218,6 +1238,7 @@ create_gotconfig(const char *proto, const char *host, "%s%s%s" "\trepository \"%s\"\n" "%s%s%s" + "%s%s%s" "%s" "%s" "}\n", @@ -1225,6 +1246,7 @@ create_gotconfig(const char *proto, const char *host, port ? "\tport " : "", port ? port : "", port ? "\n" : "", remote_repo_path, branches ? "\tbranch { " : "", branches ? branches : "", branches ? "}\n" : "", + refs ? "\treference { " : "", refs ? refs : "", refs ? "}\n" : "", mirror_references ? "\tmirror-references yes\n" : "", fetch_all_branches ? "\tfetch-all-branches yes\n" : "") == -1) { err = got_error_from_errno("asprintf"); @@ -1247,13 +1269,14 @@ done: static const struct got_error * create_gitconfig(const char *git_url, const char *default_branch, int fetch_all_branches, struct got_pathlist_head *wanted_branches, - int mirror_references, struct got_repository *repo) + struct got_pathlist_head *wanted_refs, int mirror_references, + struct got_repository *repo) { const struct got_error *err = NULL; char *gitconfig_path = NULL; char *gitconfig = NULL; FILE *gitconfig_file = NULL; - char *branches = NULL; + char *branches = NULL, *refs = NULL; const char *branchname, *mirror = NULL; ssize_t n; @@ -1317,15 +1340,36 @@ create_gitconfig(const char *git_url, const char *defa branchname) == -1) { err = got_error_from_errno("asprintf"); goto done; + } + } + if (!mirror_references && !TAILQ_EMPTY(wanted_refs)) { + struct got_pathlist_entry *pe; + TAILQ_FOREACH(pe, wanted_refs, entry) { + char *s; + const char *refname = pe->path; + if (strncmp(refname, "refs/", 5) == 0) + refname += 5; + if (asprintf(&s, + "%s\tfetch = +refs/%s:refs/remotes/%s/%s\n", + refs ? refs : "", + refname, GOT_FETCH_DEFAULT_REMOTE_NAME, + refname) == -1) { + err = got_error_from_errno("asprintf"); + goto done; + } + free(refs); + refs = s; } } + if (asprintf(&gitconfig, "[remote \"%s\"]\n" "\turl = %s\n" "%s" + "%s" "%s", GOT_FETCH_DEFAULT_REMOTE_NAME, git_url, branches ? branches : "", - mirror ? mirror : "") == -1) { + refs ? refs : "", mirror ? mirror : "") == -1) { err = got_error_from_errno("asprintf"); goto done; } @@ -1346,7 +1390,8 @@ static const struct got_error * create_config_files(const char *proto, const char *host, const char *port, const char *remote_repo_path, const char *git_url, int fetch_all_branches, int mirror_references, struct got_pathlist_head *symrefs, - struct got_pathlist_head *wanted_branches, struct got_repository *repo) + struct got_pathlist_head *wanted_branches, + struct got_pathlist_head *wanted_refs, struct got_repository *repo) { const struct got_error *err = NULL; const char *default_branch = NULL; @@ -1376,13 +1421,13 @@ create_config_files(const char *proto, const char *hos /* Create got.conf(5). */ err = create_gotconfig(proto, host, port, remote_repo_path, default_branch, fetch_all_branches, wanted_branches, - mirror_references, repo); + wanted_refs, mirror_references, repo); if (err) return err; /* Create a config file Git can understand. */ return create_gitconfig(git_url, default_branch, fetch_all_branches, - wanted_branches, mirror_references, repo); + wanted_branches, wanted_refs, mirror_references, repo); } static const struct got_error * @@ -1566,6 +1611,7 @@ cmd_clone(int argc, char *argv[]) fpa.repo = repo; fpa.config_info.symrefs = &symrefs; fpa.config_info.wanted_branches = &wanted_branches; + fpa.config_info.wanted_refs = &wanted_refs; fpa.config_info.proto = proto; fpa.config_info.host = host; fpa.config_info.port = port; @@ -2218,6 +2264,12 @@ cmd_fetch(int argc, char *argv[]) for (i = 0; i < remote->nbranches; i++) { got_pathlist_append(&wanted_branches, remote->branches[i], NULL); + } + } + if (TAILQ_EMPTY(&wanted_refs)) { + for (i = 0; i < remote->nrefs; i++) { + got_pathlist_append(&wanted_refs, + remote->refs[i], NULL); } } blob - b4fe08c8227db5b27b1d37237b58cef45adbbdb8 blob + 846205a43f056559a960ab6d0c0ebb5076e6ba20 --- got/got.conf.5 +++ got/got.conf.5 @@ -125,6 +125,26 @@ command line with the option, and any .Cm branch configuration settings for this remote repository will be ignored. +.It Ic reference Brq Ar reference ... +Specify one or more arbitrary references which +.Cm got fetch +should fetch by default, in addition to the branches and tags that will +be fetched. +The list of references specified here can be overridden at the +.Cm got fetch +command line with the +.Fl R +option. +.Cm got fetch +will refuse to fetch references from the remote repository's +.Dq refs/remotes/ +or +.Dq refs/got/ +namespace. +In any case, references in the +.Dq refs/tags/ +namespace will always be fetched and mapped directly to local references +in the same namespace. .It Ic mirror-references Ar yes | no This option controls the behaviour of .Cm got fetch blob - 8cc337b5791e1261b077f0b81458c6a6fa7a3672 blob + 56d5bf0fafeca5450bd82577d1eb163c53c74a9e --- include/got_repository.h +++ include/got_repository.h @@ -70,6 +70,10 @@ struct got_remote_repo { /* Branches to fetch by default. */ int nbranches; char **branches; + + /* Other arbitrary references to fetch by default. */ + int nrefs; + char **refs; }; /* blob - fba84c449fe93dd2034e7f391c26ffcc869e1bd9 blob + 8dbb8d0ba06da245e90c69b5db067658d496e0b0 --- lib/got_lib_privsep.h +++ lib/got_lib_privsep.h @@ -380,9 +380,11 @@ struct got_imsg_remote { int mirror_references; int fetch_all_branches; int nbranches; + int nrefs; /* Followed by name_len + url_len data bytes. */ /* Followed by nbranches GOT_IMSG_GITCONFIG_STR_VAL messages. */ + /* Followed by nrefs GOT_IMSG_GITCONFIG_STR_VAL messages. */ } __attribute__((__packed__)); /* blob - a4c526b34cd96016e55eeea3f87de869709e3eed blob + 4fb6f24032dafb92991f1671b8252d6b045fa81b --- lib/privsep.c +++ lib/privsep.c @@ -1808,6 +1808,9 @@ free_remote_data(struct got_remote_repo *remote) for (i = 0; i < remote->nbranches; i++) free(remote->branches[i]); free(remote->branches); + for (i = 0; i < remote->nrefs; i++) + free(remote->refs[i]); + free(remote->refs); } const struct got_error * @@ -1892,6 +1895,8 @@ got_privsep_recv_gitconfig_remotes(struct got_remote_r remote->fetch_all_branches = iremote.fetch_all_branches; remote->nbranches = 0; remote->branches = NULL; + remote->nrefs = 0; + remote->refs = NULL; (*nremotes)++; break; default: @@ -2117,7 +2122,28 @@ got_privsep_recv_gotconfig_remotes(struct got_remote_r } remote->branches[i] = branch; remote->nbranches++; + } + if (iremote.nrefs > 0) { + remote->refs = recallocarray(NULL, 0, + iremote.nrefs, sizeof(char *)); + if (remote->refs == NULL) { + err = got_error_from_errno("calloc"); + free_remote_data(remote); + break; + } } + remote->nrefs = 0; + for (i = 0; i < iremote.nrefs; i++) { + char *ref; + err = got_privsep_recv_gotconfig_str(&ref, + ibuf); + if (err) { + free_remote_data(remote); + goto done; + } + remote->refs[i] = ref; + remote->nrefs++; + } (*nremotes)++; break; default: blob - 70e993212984e95be5ad134c51a5705fd98e7417 blob + 2fe537dc6e1f300194d9d5d74a0b2e170c9a0010 --- libexec/got-read-gotconfig/got-read-gotconfig.c +++ libexec/got-read-gotconfig/got-read-gotconfig.c @@ -143,15 +143,23 @@ send_gotconfig_remotes(struct imsgbuf *ibuf, size_t len = sizeof(iremote); struct ibuf *wbuf; struct node_branch *branch; - int nbranches = 0; + struct node_ref *ref; + int nbranches = 0, nrefs = 0; branch = repo->branch; while (branch) { branch = branch->next; nbranches++; + } + + ref = repo->ref; + while (ref) { + ref = ref->next; + nrefs++; } iremote.nbranches = nbranches; + iremote.nrefs = nrefs; iremote.mirror_references = repo->mirror_references; iremote.fetch_all_branches = repo->fetch_all_branches; @@ -207,6 +215,14 @@ send_gotconfig_remotes(struct imsgbuf *ibuf, break; branch = branch->next; } + + ref = repo->ref; + while (ref) { + err = send_gotconfig_str(ibuf, ref->ref_name); + if (err) + break; + ref = ref->next; + } } free(url); blob - 212b87b75f0b8d817b88f63b9c5d417d6499a93c blob + 5f1429f97e35fc3f76e9a1054a203794f783e4c7 --- libexec/got-read-gotconfig/gotconfig.h +++ libexec/got-read-gotconfig/gotconfig.h @@ -21,6 +21,12 @@ struct node_branch { struct node_branch *tail; }; +struct node_ref { + char *ref_name; + struct node_ref *next; + struct node_ref *tail; +}; + struct gotconfig_remote_repo { TAILQ_ENTRY(gotconfig_remote_repo) entry; char *name; @@ -31,6 +37,7 @@ struct gotconfig_remote_repo { int mirror_references; int fetch_all_branches; struct node_branch *branch; + struct node_ref *ref; }; TAILQ_HEAD(gotconfig_remote_repo_list, gotconfig_remote_repo); blob - 07d4556e67f6c9a4b929b7ada11df90e97e2ebd7 blob + 821eff3050b8f45ad0cd9b5475874eca2aa1117d --- libexec/got-read-gotconfig/parse.y +++ libexec/got-read-gotconfig/parse.y @@ -87,6 +87,7 @@ typedef struct { long long number; char *string; struct node_branch *branch; + struct node_ref *ref; } v; int lineno; } YYSTYPE; @@ -95,12 +96,13 @@ typedef struct { %token ERROR %token REMOTE REPOSITORY SERVER PORT PROTOCOL MIRROR_REFERENCES BRANCH -%token AUTHOR FETCH_ALL_BRANCHES +%token AUTHOR FETCH_ALL_BRANCHES REFERENCE %token STRING %token NUMBER %type boolean portplain %type numberstring %type branch xbranch branch_list +%type ref xref ref_list %% @@ -163,7 +165,27 @@ branch_list : xbranch optnl { $$ = $1; } $$ = $1; } ; - +ref : /* empty */ { $$ = NULL; } + | xref { $$ = $1; } + | '{' optnl ref_list '}' { $$ = $3; } + ; +xref : STRING { + $$ = calloc(1, sizeof(struct node_ref)); + if ($$ == NULL) { + yyerror("calloc"); + YYERROR; + } + $$->ref_name = $1; + $$->tail = $$; + } + ; +ref_list : xref optnl { $$ = $1; } + | ref_list comma xref optnl { + $1->tail->next = $3; + $1->tail = $3; + $$ = $1; + } + ; remoteopts2 : remoteopts2 remoteopts1 nl | remoteopts1 optnl ; @@ -205,6 +227,9 @@ remoteopts1 : REPOSITORY STRING { } | BRANCH branch { remote->branch = $2; + } + | REFERENCE ref { + remote->ref = $2; } ; remote : REMOTE STRING { @@ -293,6 +318,7 @@ lookup(char *s) {"mirror-references", MIRROR_REFERENCES}, {"port", PORT}, {"protocol", PROTOCOL}, + {"reference", REFERENCE}, {"remote", REMOTE}, {"repository", REPOSITORY}, {"server", SERVER}, blob - b36a5f40a0b3db3547f0990d5fd2b2b947fc4821 blob + 44c5e030d3c0d68974cecd35b85f6edabc096ee3 --- regress/cmdline/clone.sh +++ regress/cmdline/clone.sh @@ -492,6 +492,7 @@ remote "origin" { protocol ssh repository "$testroot/repo" branch { "master" } + reference { "hoo" } } EOF cmp -s $testroot/repo-clone/got.conf $testroot/got.conf.expected @@ -512,6 +513,7 @@ EOF [remote "origin"] url = ssh://127.0.0.1$testroot/repo fetch = +refs/heads/master:refs/remotes/origin/master + fetch = +refs/hoo:refs/remotes/origin/hoo EOF cmp -s $testroot/repo-clone/config $testroot/config.expected ret="$?" @@ -565,6 +567,7 @@ remote "origin" { protocol ssh repository "$testroot/repo" branch { "foo" } + reference { "hoo/boo/zoo" } } EOF cmp -s $testroot/repo-clone/got.conf $testroot/got.conf.expected @@ -585,6 +588,7 @@ EOF [remote "origin"] url = ssh://127.0.0.1$testroot/repo fetch = +refs/heads/foo:refs/remotes/origin/foo + fetch = +refs/hoo/boo/zoo:refs/remotes/origin/hoo/boo/zoo EOF cmp -s $testroot/repo-clone/config $testroot/config.expected ret="$?" @@ -635,6 +639,7 @@ remote "origin" { protocol ssh repository "$testroot/repo" branch { "master" } + reference { "hoo" } mirror-references yes } EOF blob - 0af6ce58eaded1d0d98284d9acdf7306a7405494 blob + fa4ff0524821f4d1b0e9bc984f084f50e656bdb0 --- regress/cmdline/fetch.sh +++ regress/cmdline/fetch.sh @@ -1050,11 +1050,46 @@ EOF ret="$?" if [ "$ret" != "0" ]; then diff -u $testroot/stdout.expected $testroot/stdout - fi - test_done "$testroot" "$ret" + test_done "$testroot" "$ret" + return 1 + fi +cat > $testroot/repo-clone/got.conf < $testroot/stdout) + local tag_id=`got ref -r $testroot/repo -l \ + | grep "^refs/tags/1.0" | tr -d ' ' | cut -d: -f2` + echo "HEAD: refs/heads/master" > $testroot/stdout.expected + echo "refs/heads/foo: $commit_id" >> $testroot/stdout.expected + echo "refs/heads/master: $commit_id" >> $testroot/stdout.expected + echo "refs/remotes/origin/HEAD: refs/remotes/origin/master" \ + >> $testroot/stdout.expected + echo "refs/remotes/origin/foo: $commit_id" \ + >> $testroot/stdout.expected + echo "refs/remotes/origin/hoo/boo/zoo: $commit_id" \ + >> $testroot/stdout.expected + echo "refs/remotes/origin/master: $commit_id" \ + >> $testroot/stdout.expected + echo "refs/tags/1.0: $tag_id" >> $testroot/stdout.expected + + got ref -l -r $testroot/repo-clone > $testroot/stdout + + 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