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