commit 41b0de1256a7a8a9ed3d4c0d66809ebfcbf1a58d from: Stefan Sperling date: Sat Mar 21 10:18:15 2020 UTC add support for listing remote branches and tags to 'got clone' and 'got fetch' commit - 1f03b8da6be221784414918f66390ccb0eb67908 commit + 41b0de1256a7a8a9ed3d4c0d66809ebfcbf1a58d blob - 869f13d9c5e81da78233fd60e855d60bb5c769be blob + 9b734106ce0c02a0c08f7dceeb7d5ac834988511 --- got/got.1 +++ got/got.1 @@ -136,7 +136,7 @@ follows the globbing rules documented in .It Cm im Short alias for .Cm import . -.It Cm clone Oo Fl a Oc Oo Fl b Ar branch Oc Oo Fl q Oc Oo Fl v Oc Ar repository-URL Op Ar directory +.It Cm clone Oo Fl a Oc Oo Fl b Ar branch Oc Oo Fl l Oc Oo Fl m Oc Oo Fl q Oc Oo Fl v Oc Ar repository-URL Op Ar directory Clone a Git repository at the specified .Ar repository-URL into the specified @@ -222,6 +222,11 @@ repository's HEAD reference will be fetched. Cannot be used together with the .Fl a option. +.It Fl l +List branches and tags available for cloning from the remote repository +and exit immediately. +Cannot be used together with any of the other options except +.Fl v . .It Fl m Create the cloned repository as a mirror of the original repository. This is useful if the cloned repository will not be used to store @@ -267,7 +272,7 @@ The maximum is 3. .It Cm cl Short alias for .Cm clone . -.It Cm fetch Oo Fl a Oc Oo Fl b Ar branch Oc Oo Fl r Ar repository-path Oc Oo Fl q Oc Oo Fl v Oc Op Ar remote-repository +.It Cm fetch Oo Fl a Oc Oo Fl b Ar branch Oc Oo Fl l Oc Oo Fl r Ar repository-path Oc Oo Fl q Oc Oo Fl v Oc Op Ar remote-repository Fetch new changes from a remote repository. If no .Ar remote-repository @@ -328,6 +333,13 @@ repository's HEAD reference will be fetched. Cannot be used together with the .Fl a option. +.It Fl l +List branches and tags available for fetching from the remote repository +and exit immediately. +Cannot be used together with any of the other options except +.Fl v +and +.Fl r . .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 blob - d0e6d7f2e6b486b9103d7efb0dd24322773ab138 blob + a1aea8a8405c27c3618d0bb30e4faaf8d51d9c7a --- got/got.c +++ got/got.c @@ -900,6 +900,35 @@ create_head_ref(struct got_reference *target_ref, stru } static const struct got_error * +list_remote_refs(struct got_pathlist_head *symrefs, + struct got_pathlist_head *refs) +{ + const struct got_error *err; + struct got_pathlist_entry *pe; + + TAILQ_FOREACH(pe, symrefs, entry) { + const char *refname = pe->path; + const char *targetref = pe->data; + + printf("%s: %s\n", refname, targetref); + } + + TAILQ_FOREACH(pe, refs, entry) { + const char *refname = pe->path; + struct got_object_id *id = pe->data; + char *id_str; + + err = got_object_id_str(&id_str, id); + if (err) + return err; + printf("%s: %s\n", refname, id_str); + free(id_str); + } + + return NULL; +} + +static const struct got_error * cmd_clone(int argc, char *argv[]) { const struct got_error *error = NULL; @@ -919,13 +948,14 @@ cmd_clone(int argc, char *argv[]) FILE *gitconfig_file = NULL; ssize_t n; int verbosity = 0, fetch_all_branches = 0, mirror_references = 0; + int list_refs_only = 0; struct got_reference *head_symref = NULL; TAILQ_INIT(&refs); TAILQ_INIT(&symrefs); TAILQ_INIT(&wanted_branches); - while ((ch = getopt(argc, argv, "ab:mvq")) != -1) { + while ((ch = getopt(argc, argv, "ab:lmvq")) != -1) { switch (ch) { case 'a': fetch_all_branches = 1; @@ -936,6 +966,9 @@ cmd_clone(int argc, char *argv[]) if (error) return error; break; + case 'l': + list_refs_only = 1; + break; case 'm': mirror_references = 1; break; @@ -957,7 +990,17 @@ cmd_clone(int argc, char *argv[]) argv += optind; if (fetch_all_branches && !TAILQ_EMPTY(&wanted_branches)) - errx(1, "-a and -b options are mutually exclusive\n"); + errx(1, "-a and -b options are mutually exclusive"); + if (list_refs_only) { + if (!TAILQ_EMPTY(&wanted_branches)) + errx(1, "-l and -b options are mutually exclusive"); + if (fetch_all_branches) + errx(1, "-l and -a options are mutually exclusive"); + if (mirror_references) + errx(1, "-l and -m options are mutually exclusive"); + if (verbosity == -1) + errx(1, "-l and -q options are mutually exclusive"); + } uri = argv[0]; @@ -1010,18 +1053,19 @@ cmd_clone(int argc, char *argv[]) } else repo_path = dirname; - error = got_path_mkdir(repo_path); - if (error) - goto done; + if (!list_refs_only) { + error = got_path_mkdir(repo_path); + if (error) + goto done; - error = got_repo_init(repo_path); - if (error) - goto done; + error = got_repo_init(repo_path); + if (error) + goto done; + error = got_repo_open(&repo, repo_path, NULL); + if (error) + goto done; + } - error = got_repo_open(&repo, repo_path, NULL); - if (error) - goto done; - if (strcmp(proto, "git+ssh") == 0 || strcmp(proto, "ssh") == 0) { if (unveil(GOT_FETCH_PATH_SSH, "x") != 0) { error = got_error_from_errno2("unveil", @@ -1029,7 +1073,7 @@ cmd_clone(int argc, char *argv[]) goto done; } } - error = apply_unveil(got_repo_get_path(repo), 0, NULL); + error = apply_unveil(repo ? got_repo_get_path(repo) : NULL, 0, NULL); if (error) goto done; @@ -1048,11 +1092,16 @@ cmd_clone(int argc, char *argv[]) fpa.verbosity = verbosity; error = got_fetch_pack(&pack_hash, &refs, &symrefs, GOT_FETCH_DEFAULT_REMOTE_NAME, mirror_references, - fetch_all_branches, &wanted_branches, fetchfd, - repo, fetch_progress, &fpa); + fetch_all_branches, &wanted_branches, list_refs_only, + fetchfd, repo, fetch_progress, &fpa); if (error) goto done; + if (list_refs_only) { + error = list_remote_refs(&symrefs, &refs); + goto done; + } + error = got_object_id_str(&id_str, pack_hash); if (error) goto done; @@ -1340,13 +1389,13 @@ cmd_fetch(int argc, char *argv[]) struct got_object_id *pack_hash = NULL; int i, ch, fetchfd = -1; struct got_fetch_progress_arg fpa; - int verbosity = 0, fetch_all_branches = 0; + int verbosity = 0, fetch_all_branches = 0, list_refs_only = 0; TAILQ_INIT(&refs); TAILQ_INIT(&symrefs); TAILQ_INIT(&wanted_branches); - while ((ch = getopt(argc, argv, "ab:r:vq")) != -1) { + while ((ch = getopt(argc, argv, "ab:lr:vq")) != -1) { switch (ch) { case 'a': fetch_all_branches = 1; @@ -1356,6 +1405,9 @@ cmd_fetch(int argc, char *argv[]) optarg, NULL); if (error) return error; + break; + case 'l': + list_refs_only = 1; break; case 'r': repo_path = realpath(optarg, NULL); @@ -1382,7 +1434,15 @@ cmd_fetch(int argc, char *argv[]) argv += optind; if (fetch_all_branches && !TAILQ_EMPTY(&wanted_branches)) - errx(1, "-a and -b options are mutually exclusive\n"); + errx(1, "-a and -b options are mutually exclusive"); + if (list_refs_only) { + if (!TAILQ_EMPTY(&wanted_branches)) + errx(1, "-l and -b options are mutually exclusive"); + if (fetch_all_branches) + errx(1, "-l and -a options are mutually exclusive"); + if (verbosity == -1) + errx(1, "-l and -q options are mutually exclusive"); + } if (argc == 0) remote_name = GOT_FETCH_DEFAULT_REMOTE_NAME; @@ -1487,10 +1547,15 @@ cmd_fetch(int argc, char *argv[]) fpa.verbosity = verbosity; error = got_fetch_pack(&pack_hash, &refs, &symrefs, remote->name, remote->mirror_references, fetch_all_branches, &wanted_branches, - fetchfd, repo, fetch_progress, &fpa); + list_refs_only, fetchfd, repo, fetch_progress, &fpa); if (error) goto done; + if (list_refs_only) { + error = list_remote_refs(&symrefs, &refs); + goto done; + } + if (pack_hash == NULL) { if (verbosity >= 0) printf("Already up-to-date\n"); blob - a7b9590dcef74fceec8004075319634cc5f5e462 blob + 9e26b62a0b5d1a4848d98980cd9a7b5bc73fd1aa --- include/got_fetch.h +++ include/got_fetch.h @@ -61,5 +61,5 @@ typedef const struct got_error *(*got_fetch_progress_c */ const struct got_error *got_fetch_pack(struct got_object_id **, struct got_pathlist_head *, struct got_pathlist_head *, const char *, - int, int, struct got_pathlist_head *, int, struct got_repository *, + int, int, struct got_pathlist_head *, int, int, struct got_repository *, got_fetch_progress_cb, void *); blob - d9e55b8853c1065604fa45460938e09c2444b97b blob + fcd9bb07bd25aa7e1ed09ad450f14bebbaf623b4 --- lib/fetch.c +++ lib/fetch.c @@ -388,8 +388,8 @@ const struct got_error* got_fetch_pack(struct got_object_id **pack_hash, struct got_pathlist_head *refs, struct got_pathlist_head *symrefs, const char *remote_name, int mirror_references, int fetch_all_branches, - struct got_pathlist_head *wanted_branches, int fetchfd, - struct got_repository *repo, + struct got_pathlist_head *wanted_branches, int list_refs_only, + int fetchfd, struct got_repository *repo, got_fetch_progress_cb progress_cb, void *progress_arg) { int imsg_fetchfds[2], imsg_idxfds[2]; @@ -401,7 +401,7 @@ got_fetch_pack(struct got_object_id **pack_hash, struc pid_t fetchpid, idxpid; char *tmppackpath = NULL, *tmpidxpath = NULL; char *packpath = NULL, *idxpath = NULL, *id_str = NULL; - const char *repo_path = got_repo_get_path_git_dir(repo); + const char *repo_path = NULL; struct got_pathlist_head have_refs; struct got_pathlist_entry *pe; struct got_reflist_head my_refs; @@ -411,6 +411,9 @@ got_fetch_pack(struct got_object_id **pack_hash, struc size_t ref_prefixlen = 0; char *path; char *progress = NULL; + + if (!list_refs_only) + repo_path = got_repo_get_path_git_dir(repo); *pack_hash = NULL; for (i = 0; i < nitems(tmpfds); i++) @@ -426,9 +429,12 @@ got_fetch_pack(struct got_object_id **pack_hash, struc ref_prefixlen = strlen(ref_prefix); } - err = got_ref_list(&my_refs, repo, NULL, got_ref_cmp_by_name, NULL); - if (err) - goto done; + if (!list_refs_only) { + err = got_ref_list(&my_refs, repo, NULL, + got_ref_cmp_by_name, NULL); + if (err) + goto done; + } SIMPLEQ_FOREACH(re, &my_refs, entry) { struct got_object_id *id; @@ -493,29 +499,45 @@ got_fetch_pack(struct got_object_id **pack_hash, struc } } - if (asprintf(&path, "%s/%s/fetching.pack", - repo_path, GOT_OBJECTS_PACK_DIR) == -1) { - err = got_error_from_errno("asprintf"); - goto done; + if (list_refs_only) { + packfd = got_opentempfd(); + if (packfd == -1) { + err = got_error_from_errno("got_opentempfd"); + goto done; + } + } else { + if (asprintf(&path, "%s/%s/fetching.pack", + repo_path, GOT_OBJECTS_PACK_DIR) == -1) { + err = got_error_from_errno("asprintf"); + goto done; + } + err = got_opentemp_named_fd(&tmppackpath, &packfd, path); + free(path); + if (err) + goto done; } - err = got_opentemp_named_fd(&tmppackpath, &packfd, path); - free(path); - if (err) - goto done; npackfd = dup(packfd); if (npackfd == -1) { err = got_error_from_errno("dup"); goto done; } - if (asprintf(&path, "%s/%s/fetching.idx", - repo_path, GOT_OBJECTS_PACK_DIR) == -1) { - err = got_error_from_errno("asprintf"); - goto done; + if (list_refs_only) { + idxfd = got_opentempfd(); + if (idxfd == -1) { + err = got_error_from_errno("got_opentempfd"); + goto done; + } + } else { + if (asprintf(&path, "%s/%s/fetching.idx", + repo_path, GOT_OBJECTS_PACK_DIR) == -1) { + err = got_error_from_errno("asprintf"); + goto done; + } + err = got_opentemp_named_fd(&tmpidxpath, &idxfd, path); + free(path); + if (err) + goto done; } - err = got_opentemp_named_fd(&tmpidxpath, &idxfd, path); - free(path); - if (err) - goto done; nidxfd = dup(idxfd); if (nidxfd == -1) { err = got_error_from_errno("dup"); @@ -555,7 +577,7 @@ got_fetch_pack(struct got_object_id **pack_hash, struc goto done; } err = got_privsep_send_fetch_req(&fetchibuf, nfetchfd, &have_refs, - fetch_all_branches, wanted_branches); + fetch_all_branches, wanted_branches, list_refs_only); if (err != NULL) goto done; nfetchfd = -1; @@ -591,7 +613,7 @@ got_fetch_pack(struct got_object_id **pack_hash, struc else free(id); } else if (refname && id) { - err = got_pathlist_append(refs, refname, id); + err = got_pathlist_insert(NULL, refs, refname, id); if (err) goto done; } else if (server_progress) { blob - ca92bcd3660a9b973c8c555f1cbb36a1c0fede5b blob + b542cec86ba90e8bd23eabe37271fc2faf08ce72 --- lib/got_lib_privsep.h +++ lib/got_lib_privsep.h @@ -257,6 +257,7 @@ struct got_imsg_fetch_wanted_branch { /* Structure for GOT_IMSG_FETCH_REQUEST data. */ struct got_imsg_fetch_request { int fetch_all_branches; + int list_refs_only; size_t n_have_refs; size_t n_wanted_branches; /* Followed by n_have_refs GOT_IMSG_FETCH_HAVE_REF messages. */ @@ -401,7 +402,7 @@ const struct got_error *got_privsep_send_index_pack_do const struct got_error *got_privsep_recv_index_progress(int *, int *, int *, int *, int *, struct imsgbuf *ibuf); const struct got_error *got_privsep_send_fetch_req(struct imsgbuf *, int, - struct got_pathlist_head *, int, struct got_pathlist_head *); + struct got_pathlist_head *, int, struct got_pathlist_head *, int); const struct got_error *got_privsep_send_fetch_outfd(struct imsgbuf *, int); const struct got_error *got_privsep_send_fetch_symrefs(struct imsgbuf *, struct got_pathlist_head *); blob - 805dd3e8bcf919be36494e99aa5351e30d121d66 blob + 2baa585778c31396c55ca867abadd1baae6a09a8 --- lib/privsep.c +++ lib/privsep.c @@ -413,7 +413,7 @@ got_privsep_send_obj(struct imsgbuf *ibuf, struct got_ const struct got_error * got_privsep_send_fetch_req(struct imsgbuf *ibuf, int fd, struct got_pathlist_head *have_refs, int fetch_all_branches, - struct got_pathlist_head *wanted_branches) + struct got_pathlist_head *wanted_branches, int list_refs_only) { const struct got_error *err = NULL; struct ibuf *wbuf; @@ -423,6 +423,7 @@ got_privsep_send_fetch_req(struct imsgbuf *ibuf, int f memset(&fetchreq, 0, sizeof(fetchreq)); fetchreq.fetch_all_branches = fetch_all_branches; + fetchreq.list_refs_only = list_refs_only; TAILQ_FOREACH(pe, have_refs, entry) fetchreq.n_have_refs++; TAILQ_FOREACH(pe, wanted_branches, entry) blob - cb84af601f60de1ffe71b64a1d15358acbcc11e8 blob + 123004c4d0700fee5e741fc9839cdcefe67d560b --- libexec/got-fetch-pack/got-fetch-pack.c +++ libexec/got-fetch-pack/got-fetch-pack.c @@ -483,7 +483,8 @@ fetch_error(const char *buf, size_t len) static const struct got_error * fetch_pack(int fd, int packfd, struct got_object_id *packid, struct got_pathlist_head *have_refs, int fetch_all_branches, - struct got_pathlist_head *wanted_branches, struct imsgbuf *ibuf) + struct got_pathlist_head *wanted_branches, int list_refs_only, + struct imsgbuf *ibuf) { const struct got_error *err = NULL; char buf[GOT_FETCH_PKTMAX]; @@ -561,7 +562,7 @@ fetch_pack(int fd, int packfd, struct got_object_id *p getprogname(), refname); if (strncmp(refname, "refs/heads/", 11) == 0) { - if (fetch_all_branches) { + if (fetch_all_branches || list_refs_only) { found_branch = 1; } else if (!TAILQ_EMPTY(wanted_branches)) { TAILQ_FOREACH(pe, wanted_branches, entry) { @@ -628,6 +629,9 @@ fetch_pack(int fd, int packfd, struct got_object_id *p nref++; } + if (list_refs_only) + goto done; + /* Abort if we haven't found any branch to fetch. */ if (!found_branch) { err = got_error(GOT_ERR_FETCH_NO_BRANCH); @@ -1006,7 +1010,8 @@ main(int argc, char **argv) packfd = imsg.fd; err = fetch_pack(fetchfd, packfd, &packid, &have_refs, - fetch_req.fetch_all_branches, &wanted_branches, &ibuf); + fetch_req.fetch_all_branches, &wanted_branches, + fetch_req.list_refs_only, &ibuf); done: TAILQ_FOREACH(pe, &have_refs, entry) { free((char *)pe->path);