Download raw body.
Introduce one-line mode for got tag -l
On Tue, Dec 24, 2024 at 04:51:32PM +1100, Mark Jamsek wrote: > Lucas Gabriel Vuotto <lucas@sexy.is> wrote: > > Hi Mark, > > > > thanks for the review! Indeed, the part I doubted the most moving out > > print_tag was the bad_sigs bit. I believe your suggestion still isn't > > 100% compatible with the previous version: originally, err could be > > set to something on bad_sigs case (last iter + NULL commit). I decided > > to instead check for GOT_ERR_BAD_TAG_SIGNATURE in order to break. > > np! > > It is compatible with the previous behaviour because we carry the > BAD_TAG_SIGNATURE error case in the bad_sigs out parameter. As such, > even on the last iteration and a NULL commit case, if err is NULL but > bad_sigs is set, list_tags() sets err to GOT_ERR_BAD_TAG_SIGNATURE. > And bad_sigs is persistent--once set it's not cleared. Now we are > duplicating the check: we check for BAD_TAG_SIGNATURE in print_tag() and > set bad_sigs to carry this error state but still return the error to the > caller to check it again at the end of each iteration and ignore it, > then after the ref loop at the end of list_tags() we check bad_sigs for > the error state and set the error accordingly. > > I think it is cleaner and more consistent to clear err in print_tag() > when we set bad_sigs and don't add the extra BAD_TAG_SIGNATURE check at > the end of each loop iteration in list_tags(). > > But I'm happy as long as the behaviour is preserved so it's up to you :) After using the whole IRC channel as a rubber duck, I agree with you. > I would be happy with a slightly shorter prefix--I think 10 is currently > long enough for unique prefixes in src.git--but 12 has a higher chance > of being unique in super large repositories. And by omitting the full > tag reference name, we have the screen estate to spare a few extra > characters for a more likely unique prefix. We're quite uneven in here: tog 8, got log -s 7, got blame 8, merges 10, histedit 12, and that's what I found in a very quick search. I used 12 because I saw it before with histedit and seems more than reasonable (I believe only kernel.git gets to 12). Of the repos I have at hand, ports sits at 193074 commits with only 66 colliding short hashes with 7 digits, none with more than 2 common prefixes, and src sits at 237194 commits, with 104 colliding short hashes, again with no more than 2 common prefixes. For those numbers, and for 10 hex digits, the total amount of pairs account to 1.6% and 2.7% the total amount of digits combinations, making the chance of collision fairly low (in contrast, Linux is at 1324536 commits and number of pairs represent 0.3% of 2^12). What do I mean with all this? I'm fine with dropping it to 10 if we agree to that. :D ----------------------------------------------- commit 990c6f9204a728129973e0bb054cb6874573a166 from: Lucas Gabriel Vuotto <lucas@sexy.is> date: Tue Dec 24 15:02:19 2024 UTC got tag: change -s signer to -S signer We'll introduce a short output for tag listing and we'll use -s for consistency with got log. It also keeps it slightly more consistent with -V for verification. M got/got.1 M got/got.c M regress/cmdline/tag.sh diff 589b5832ea0e12318af1af49fb76e2887629e2b6 990c6f9204a728129973e0bb054cb6874573a166 commit - 589b5832ea0e12318af1af49fb76e2887629e2b6 commit + 990c6f9204a728129973e0bb054cb6874573a166 blob - e653af513ca5618a8e7dcf9459524bbb2f483e8d blob + 6c0da5ae7b8d571bd4eb6e9bf5204d8a615e9d3f --- got/got.1 +++ got/got.1 @@ -1729,7 +1729,7 @@ option to be used as well. .Op Fl c Ar commit .Op Fl m Ar message .Op Fl r Ar repository-path -.Op Fl s Ar signer-id +.Op Fl S Ar signer-id .Ar name .Xc Manage tags in a repository. @@ -1821,7 +1821,7 @@ working directory. If this directory is a .Nm work tree, use the repository path associated with this work tree. -.It Fl s Ar signer-id +.It Fl S Ar signer-id While creating a new tag, sign this tag with the identity given in .Ar signer-id . .Pp blob - 36655f1f322184d063373730e92b7dbf08b373a4 blob + b6dd736cec67d368d8bf2f51323d4bc76be2cb03 --- got/got.c +++ got/got.c @@ -7474,7 +7474,7 @@ __dead static void usage_tag(void) { fprintf(stderr, "usage: %s tag [-lVv] [-c commit] [-m message] " - "[-r repository-path] [-s signer-id] name\n", getprogname()); + "[-r repository-path] [-S signer-id] name\n", getprogname()); exit(1); } @@ -7904,7 +7904,7 @@ cmd_tag(int argc, char *argv[]) err(1, "pledge"); #endif - while ((ch = getopt(argc, argv, "c:lm:r:s:Vv")) != -1) { + while ((ch = getopt(argc, argv, "c:lm:r:S:Vv")) != -1) { switch (ch) { case 'c': commit_id_arg = optarg; @@ -7924,7 +7924,7 @@ cmd_tag(int argc, char *argv[]) } got_path_strip_trailing_slashes(repo_path); break; - case 's': + case 'S': signer_id = optarg; break; case 'V': blob - 005a6304020f8cb434ecb6fb450d1b44d9bcc66e blob + cbf6d6c4be7cf8b0f5fafcaf3e258266d9f5cb7c --- regress/cmdline/tag.sh +++ regress/cmdline/tag.sh @@ -295,7 +295,7 @@ test_tag_create_ssh_signed() { $testroot/repo/.git/got.conf # Create a signed tag based on repository's HEAD reference - got tag -s $testroot/id_ed25519 -m 'test' -r $testroot/repo -c HEAD \ + got tag -S $testroot/id_ed25519 -m 'test' -r $testroot/repo -c HEAD \ $tag > $testroot/stdout ret=$? if [ $ret -ne 0 ]; then @@ -390,7 +390,7 @@ test_tag_create_ssh_signed() { fi # Create another signed tag with a SHA1 commit ID - got tag -s $testroot/id_ed25519 -m 'test' -r $testroot/repo \ + got tag -S $testroot/id_ed25519 -m 'test' -r $testroot/repo \ -c $commit_id $tag2 > $testroot/stdout # Create another signed tag with key defined in got.conf(5) @@ -435,7 +435,7 @@ test_tag_create_ssh_signed_missing_key() { local tag=1.0.0 # Fail to create a signed tag due to a missing SSH key - got tag -s $testroot/bogus -m 'test' -r $testroot/repo \ + got tag -S $testroot/bogus -m 'test' -r $testroot/repo \ -c HEAD $tag > $testroot/stdout 2> $testroot/stderr ret=$? if [ $ret -eq 0 ]; then ----------------------------------------------- commit 7054aeed8ed916119bb599f3e95ab96e338de4a4 from: Lucas Gabriel Vuotto <lucas@sexy.is> date: Tue Dec 24 15:02:28 2024 UTC got tag: move tag printing into its own function in prepartion for a oneline output mode M got/got.c diff 990c6f9204a728129973e0bb054cb6874573a166 7054aeed8ed916119bb599f3e95ab96e338de4a4 commit - 990c6f9204a728129973e0bb054cb6874573a166 commit + 7054aeed8ed916119bb599f3e95ab96e338de4a4 blob - b6dd736cec67d368d8bf2f51323d4bc76be2cb03 blob + c48fbabb256916a3e3804cd2ab99be079164c24f --- got/got.c +++ got/got.c @@ -7554,6 +7554,80 @@ get_tag_refname(char **refname, const char *tag_name) } static const struct got_error * +print_tag(struct got_tag_object *tag, struct got_commit_object *commit, + const char *refname, const char *refstr, const char *tagger, + time_t tagger_time, const char *id_str, const char *ssh_sig, + const char *allowed_signers, const char *revoked_signers, int verbosity, + int *bad_sigs) +{ + static const struct got_error *err = NULL; + char datebuf[26]; + char *sig_msg = NULL, *tagmsg0 = NULL, *tagmsg, *line, *datestr; + + printf("%stag %s %s\n", GOT_COMMIT_SEP_STR, refname, refstr); + printf("from: %s\n", tagger); + datestr = get_datestr(&tagger_time, datebuf); + if (datestr) + printf("date: %s UTC\n", datestr); + if (commit) + printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT, id_str); + else { + switch (got_object_tag_get_object_type(tag)) { + case GOT_OBJ_TYPE_BLOB: + printf("object: %s %s\n", GOT_OBJ_LABEL_BLOB, id_str); + break; + case GOT_OBJ_TYPE_TREE: + printf("object: %s %s\n", GOT_OBJ_LABEL_TREE, id_str); + break; + case GOT_OBJ_TYPE_COMMIT: + printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT, id_str); + break; + case GOT_OBJ_TYPE_TAG: + printf("object: %s %s\n", GOT_OBJ_LABEL_TAG, id_str); + break; + default: + break; + } + } + + if (ssh_sig) { + err = got_sigs_verify_tag_ssh(&sig_msg, tag, ssh_sig, + allowed_signers, revoked_signers, verbosity); + if (err) { + if (err->code != GOT_ERR_BAD_TAG_SIGNATURE) + goto done; + *bad_sigs = 1; + err = NULL; + } + if (sig_msg) + printf("signature: %s", sig_msg); + else + printf("bad signature\n"); + free(sig_msg); + } + + if (commit) { + err = got_object_commit_get_logmsg(&tagmsg0, commit); + if (err) + goto done; + } else { + tagmsg0 = strdup(got_object_tag_get_message(tag)); + if (tagmsg0 == NULL) { + err = got_error_from_errno("strdup"); + goto done; + } + } + + tagmsg = tagmsg0; + while ((line = strsep(&tagmsg, "\n")) != NULL) + printf(" %s\n", line); + + done: + free(tagmsg0); + return err; +} + +static const struct got_error * list_tags(struct got_repository *repo, const char *tag_name, int verify_tags, const char *allowed_signers, const char *revoked_signers, int verbosity) { @@ -7583,10 +7657,8 @@ list_tags(struct got_repository *repo, const char *tag TAILQ_FOREACH(re, &refs, entry) { const char *refname; - char *refstr, *tagmsg0, *tagmsg, *line, *id_str, *datestr; - char datebuf[26]; + char *refstr, *id_str; const char *tagger, *ssh_sig = NULL; - char *sig_msg = NULL; time_t tagger_time; struct got_object_id *id; struct got_tag_object *tag; @@ -7648,71 +7720,19 @@ list_tags(struct got_repository *repo, const char *tag } } - printf("%stag %s %s\n", GOT_COMMIT_SEP_STR, refname, refstr); - free(refstr); - printf("from: %s\n", tagger); - datestr = get_datestr(&tagger_time, datebuf); - if (datestr) - printf("date: %s UTC\n", datestr); + err = print_tag(tag, commit, refname, refstr, tagger, + tagger_time, id_str, ssh_sig, allowed_signers, + revoked_signers, verbosity, &bad_sigs); + if (commit) - printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT, id_str); - else { - switch (got_object_tag_get_object_type(tag)) { - case GOT_OBJ_TYPE_BLOB: - printf("object: %s %s\n", GOT_OBJ_LABEL_BLOB, - id_str); - break; - case GOT_OBJ_TYPE_TREE: - printf("object: %s %s\n", GOT_OBJ_LABEL_TREE, - id_str); - break; - case GOT_OBJ_TYPE_COMMIT: - printf("object: %s %s\n", GOT_OBJ_LABEL_COMMIT, - id_str); - break; - case GOT_OBJ_TYPE_TAG: - printf("object: %s %s\n", GOT_OBJ_LABEL_TAG, - id_str); - break; - default: - break; - } - } - free(id_str); - - if (ssh_sig) { - err = got_sigs_verify_tag_ssh(&sig_msg, tag, ssh_sig, - allowed_signers, revoked_signers, verbosity); - if (err && err->code == GOT_ERR_BAD_TAG_SIGNATURE) - bad_sigs = 1; - else if (err) - break; - printf("signature: %s", sig_msg); - free(sig_msg); - sig_msg = NULL; - } - - if (commit) { - err = got_object_commit_get_logmsg(&tagmsg0, commit); - if (err) - break; got_object_commit_close(commit); - } else { - tagmsg0 = strdup(got_object_tag_get_message(tag)); + if (tag) got_object_tag_close(tag); - if (tagmsg0 == NULL) { - err = got_error_from_errno("strdup"); - break; - } - } + free(id_str); + free(refstr); - tagmsg = tagmsg0; - do { - line = strsep(&tagmsg, "\n"); - if (line) - printf(" %s\n", line); - } while (line); - free(tagmsg0); + if (err) + break; } done: got_ref_list_free(&refs); ----------------------------------------------- commit 88f8b57111b94d1bab250049555abe0bca17539b (tag-short) from: Lucas Gabriel Vuotto <lucas@sexy.is> date: Tue Dec 24 15:02:28 2024 UTC got tag: provide one-line output mode M got/got.1 M got/got.c M regress/cmdline/tag.sh diff 7054aeed8ed916119bb599f3e95ab96e338de4a4 88f8b57111b94d1bab250049555abe0bca17539b commit - 7054aeed8ed916119bb599f3e95ab96e338de4a4 commit + 88f8b57111b94d1bab250049555abe0bca17539b blob - 6c0da5ae7b8d571bd4eb6e9bf5204d8a615e9d3f blob + 96794d6aa787f704f409ac79ea9ef7d1ef02caee --- got/got.1 +++ got/got.1 @@ -1725,7 +1725,7 @@ option to be used as well. .El .It Xo .Cm tag -.Op Fl lVv +.Op Fl lsVv .Op Fl c Ar commit .Op Fl m Ar message .Op Fl r Ar repository-path @@ -1839,6 +1839,12 @@ command, using the signature namespace .Dq git for compatibility with .Xr git 1 . +.It Fl s +Display a short one-line summary of each tag, instead of the default +history format. +Can only be used with the +.Fl l +option. .It Fl V Verify tag object signatures. If a blob - c48fbabb256916a3e3804cd2ab99be079164c24f blob + 99f9541a311e03b9afc15c14768edfe442560d9b --- got/got.c +++ got/got.c @@ -7473,7 +7473,7 @@ done: __dead static void usage_tag(void) { - fprintf(stderr, "usage: %s tag [-lVv] [-c commit] [-m message] " + fprintf(stderr, "usage: %s tag [-lsVv] [-c commit] [-m message] " "[-r repository-path] [-S signer-id] name\n", getprogname()); exit(1); } @@ -7554,6 +7554,70 @@ get_tag_refname(char **refname, const char *tag_name) } static const struct got_error * +print_tag_oneline(struct got_tag_object *tag, struct got_commit_object *commit, + const char *refname, const char *refstr, time_t tagger_time, + const char *id_str) +{ + static const struct got_error *err = NULL; + const char *label = NULL; + struct tm tm; + char *tagmsg0 = NULL, *tagmsg; + char datebuf[11]; + + if (gmtime_r(&tagger_time, &tm) == NULL) + return got_error_from_errno("gmtime_r"); + if (strftime(datebuf, sizeof(datebuf), "%F", &tm) == 0) + return got_error(GOT_ERR_NO_SPACE); + + if (commit) { + err = got_object_commit_get_logmsg(&tagmsg0, commit); + if (err) + return err; + } else { + tagmsg0 = strdup(got_object_tag_get_message(tag)); + if (tagmsg0 == NULL) + return got_error_from_errno("strdup"); + } + + tagmsg = tagmsg0; + while (isspace((unsigned char)*tagmsg)) + tagmsg++; + tagmsg[strcspn(tagmsg, "\n")] = '\0'; + + if (commit) + label = GOT_OBJ_LABEL_COMMIT; + else { + switch (got_object_tag_get_object_type(tag)) { + case GOT_OBJ_TYPE_BLOB: + label = GOT_OBJ_LABEL_BLOB; + break; + case GOT_OBJ_TYPE_TREE: + label = GOT_OBJ_LABEL_TREE; + break; + case GOT_OBJ_TYPE_COMMIT: + label = GOT_OBJ_LABEL_COMMIT; + break; + case GOT_OBJ_TYPE_TAG: + label = GOT_OBJ_LABEL_TAG; + break; + default: + break; + } + } + + if (label) + printf("%s %s:%.12s %s: %s\n", datebuf, label, id_str, refname, + tagmsg); + else + printf("%s tag:%.12s %s: %s\n", datebuf, refstr, refname, + tagmsg); + + free(tagmsg0); + + return err; +} + +static const struct got_error * print_tag(struct got_tag_object *tag, struct got_commit_object *commit, const char *refname, const char *refstr, const char *tagger, time_t tagger_time, const char *id_str, const char *ssh_sig, @@ -7629,7 +7693,8 @@ print_tag(struct got_tag_object *tag, struct got_commi static const struct got_error * list_tags(struct got_repository *repo, const char *tag_name, int verify_tags, - const char *allowed_signers, const char *revoked_signers, int verbosity) + const char *allowed_signers, const char *revoked_signers, int verbosity, + int oneline) { static const struct got_error *err = NULL; struct got_reflist_head refs; @@ -7720,9 +7785,13 @@ list_tags(struct got_repository *repo, const char *tag } } - err = print_tag(tag, commit, refname, refstr, tagger, - tagger_time, id_str, ssh_sig, allowed_signers, - revoked_signers, verbosity, &bad_sigs); + if (oneline) + err = print_tag_oneline(tag, commit, refname, refstr, + tagger_time, id_str); + else + err = print_tag(tag, commit, refname, refstr, tagger, + tagger_time, id_str, ssh_sig, allowed_signers, + revoked_signers, verbosity, &bad_sigs); if (commit) got_object_commit_close(commit); @@ -7915,7 +7984,7 @@ cmd_tag(int argc, char *argv[]) char *allowed_signers = NULL, *revoked_signers = NULL, *editor = NULL; const char *signer_id = NULL; const char *tag_name = NULL, *commit_id_arg = NULL, *tagmsg = NULL; - int ch, do_list = 0, verify_tags = 0, verbosity = 0; + int ch, do_list = 0, oneline = 0, verify_tags = 0, verbosity = 0; int *pack_fds = NULL; #ifndef PROFILE @@ -7924,7 +7993,7 @@ cmd_tag(int argc, char *argv[]) err(1, "pledge"); #endif - while ((ch = getopt(argc, argv, "c:lm:r:S:Vv")) != -1) { + while ((ch = getopt(argc, argv, "c:lm:r:S:sVv")) != -1) { switch (ch) { case 'c': commit_id_arg = optarg; @@ -7947,6 +8016,9 @@ cmd_tag(int argc, char *argv[]) case 'S': signer_id = optarg; break; + case 's': + oneline = 1; + break; case 'V': verify_tags = 1; break; @@ -7965,7 +8037,9 @@ cmd_tag(int argc, char *argv[]) argc -= optind; argv += optind; - if (do_list || verify_tags) { + if (oneline && !do_list) + errx(1, "-S option con only be used when listing tags"); + else if (do_list || verify_tags) { if (commit_id_arg != NULL) errx(1, "-c option can only be used when creating a tag"); @@ -8055,7 +8129,7 @@ cmd_tag(int argc, char *argv[]) if (error) goto done; error = list_tags(repo, tag_name, verify_tags, allowed_signers, - revoked_signers, verbosity); + revoked_signers, verbosity, oneline); } else { error = get_gitconfig_path(&gitconfig_path); if (error) blob - cbf6d6c4be7cf8b0f5fafcaf3e258266d9f5cb7c blob + 2ace9e32e901960e9507e544db469d4be5139629 --- regress/cmdline/tag.sh +++ regress/cmdline/tag.sh @@ -223,6 +223,60 @@ test_tag_list() { test_done "$testroot" "$ret" } +test_tag_list_oneline() { + local testroot=`test_init tag_list` + local commit_id=`git_show_head $testroot/repo` + local tag=1.0.0 + local tag2=2.0.0 + + local head_ref=`got ref -r $testroot/repo -l | sed -n 's/^HEAD: //p'` + local tag_commit_id=`got ref -r $testroot/repo -l "$head_ref" | + sed -n "s:^$head_ref\: ::p"` + + # create tag with Git + git -C $testroot/repo tag -a -m 'test' $tag + # create tag with Got + (cd $testroot/repo && got tag -m 'test' $tag2 > /dev/null) + + local tagger_time=`git_show_tagger_time $testroot/repo $tag` + d1=`date -u -r $tagger_time +"%F"` + local tagger_time2=`git_show_tagger_time $testroot/repo $tag2` + d2=`date -u -r $tagger_time2 +"%F"` + + got tag -r $testroot/repo -ls > $testroot/stdout + + echo "$d2 commit:$(trim_obj_id 12 "$tag_commit_id") $tag2: test" > $testroot/stdout.expected + echo "$d1 commit:$(trim_obj_id 12 "$tag_commit_id") $tag: test" >> $testroot/stdout.expected + cmp -s $testroot/stdout $testroot/stdout.expected + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + got tag -r $testroot/repo -ls $tag > $testroot/stdout + + echo "$d1 commit:$(trim_obj_id 12 "$tag_commit_id") $tag: test" > $testroot/stdout.expected + cmp -s $testroot/stdout $testroot/stdout.expected + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/stdout.expected $testroot/stdout + test_done "$testroot" "$ret" + return 1 + fi + + got tag -r $testroot/repo -ls $tag2 > $testroot/stdout + + echo "$d2 commit:$(trim_obj_id 12 "$tag_commit_id") $tag2: test" > $testroot/stdout.expected + cmp -s $testroot/stdout $testroot/stdout.expected + ret=$? + if [ $ret -ne 0 ]; then + diff -u $testroot/stdout.expected $testroot/stdout + fi + test_done "$testroot" "$ret" +} + test_tag_list_lightweight() { local testroot=`test_init tag_list_lightweight` local commit_id=`git_show_head $testroot/repo` @@ -573,6 +627,7 @@ test_parseargs "$@" run_test test_tag_create run_test test_tag_list run_test test_tag_list_lightweight +run_test test_tag_list_oneline run_test test_tag_create_ssh_signed run_test test_tag_create_ssh_signed_missing_key run_test test_tag_commit_keywords
Introduce one-line mode for got tag -l