"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Mark Jamsek <mark@jamsek.com>
Subject:
tog: make ref view selection of non-commit tags non-fatal
To:
gameoftrees@openbsd.org
Date:
Thu, 26 Dec 2024 01:46:39 +1100

Download raw body.

Thread
Git allows tags to point to commits, trees, blobs, and even other tags.
Currently, selecting a tag that points to anything but a commit causes a
fatal error in tog's ref view. This change instead draws a message to
the status line, and also enables selecting nested tags that resolve to
a commit.

I've run out of time tonight to write a test case--I'll do this after
zzz--but to test the nested tag to commit case:

  # make tag to base commit
  $ got tag -m "test tag" testtag
  # make tag to previous tag
  $ git tag -a nestedtag -m "nested tag" testtag

then invoke `tog ref` without this diff and select refs/tags/nestedtag:

  tog: wrong type of object

With this diff, the log view will instead open starting traversal from
the tagged commit in the first tag (i.e., testtag).

To test a tag to a blob or tree object, you need to use git to create
the tag as this is not allowed by design in got:

  $ git tag tag2blob $blobid

Selecting the refs/tags/tag2blob entry in tog's ref view without this
diff causes tog to exit with a fatal error. With this diff, a message is
drawn to the status line: "commit reference required". This is also a
good test case for why the wtimeout(3) fix is needed: without that fix,
the message is not visible when selecting tag2blob after entering a
compound key (e.g., 2j).


commit 754667b95534144f355facd02c994a66baca0aa1 (main)
from: Mark Jamsek <mark@jamsek.dev>
date: Wed Dec 25 13:57:30 2024 UTC

tog: make ref view selection of non-commit tags non-fatal

Tags can point to all git objects: commits, trees, blobs, and tags.
Selecting a tag that points to any object other than a commit causes a
fatal error. Instead, report a message to the status line. Similarly,
nested tags may resolve to a commit, which currently errors. Instead,
keep peeling till we reach the bottom and if it's a commit, use it for
the requested view.

M  tog/tog.c  |  32+  16-

1 file changed, 32 insertions(+), 16 deletions(-)

commit - cfe9343a9f6a872cd65b1086e6dab68010b19d98
commit + 754667b95534144f355facd02c994a66baca0aa1
blob - 7dd3a24c5a2515f0073943bd56830d25bf86f45a
blob + 17f68383e6756d777cb62720ac994c2ed1f81c0b
--- tog/tog.c
+++ tog/tog.c
@@ -1320,8 +1320,16 @@ view_request_new(struct tog_view **requested, struct t
 		view_get_split(view, &y, &x);
 
 	err = view_dispatch_request(&new_view, view, request, y, x);
-	if (err)
-		return err;
+	if (err) {
+		/*
+		 * The ref view expects its selected entry to resolve to
+		 * a commit object id to open either a log or tree view.
+		 */
+		if (err->code != GOT_ERR_OBJ_TYPE)
+			return err;
+		view->action = "commit reference required";
+		return NULL;
+	}
 
 	if (view_is_parent_view(view) && view->mode == TOG_VIEW_SPLIT_HRZN &&
 	    request != TOG_VIEW_HELP) {
@@ -10026,24 +10034,32 @@ resolve_reflist_entry(struct got_object_id **commit_id
 		*commit_id = obj_id;
 		break;
 	case GOT_OBJ_TYPE_TAG:
-		err = got_object_open_as_tag(&tag, repo, obj_id);
-		if (err)
-			goto done;
-		free(obj_id);
-		err = got_object_get_type(&obj_type, repo,
-		    got_object_tag_get_object_id(tag));
-		if (err)
-			goto done;
+		/*
+		 * Git allows nested tags that point to tags; keep peeling
+		 * till we reach the bottom, which is always a non-tag ref.
+		 */
+		while (obj_type == GOT_OBJ_TYPE_TAG) {
+			if (tag != NULL)
+				got_object_tag_close(tag);
+			err = got_object_open_as_tag(&tag, repo, obj_id);
+			free(obj_id);
+			if (err)
+				goto done;
+			obj_id = got_object_id_dup(
+			    got_object_tag_get_object_id(tag));
+			if (obj_id == NULL) {
+				err = got_error_from_errno("got_object_id_dup");
+				goto done;
+			}
+			err = got_object_get_type(&obj_type, repo, obj_id);
+			if (err)
+				goto done;
+		}
+		*commit_id = obj_id;
 		if (obj_type != GOT_OBJ_TYPE_COMMIT) {
 			err = got_error(GOT_ERR_OBJ_TYPE);
 			goto done;
 		}
-		*commit_id = got_object_id_dup(
-		    got_object_tag_get_object_id(tag));
-		if (*commit_id == NULL) {
-			err = got_error_from_errno("got_object_id_dup");
-			goto done;
-		}
 		break;
 	default:
 		err = got_error(GOT_ERR_OBJ_TYPE);


-- 
Mark Jamsek <https://bsdbox.org>
GPG: F2FF 13DE 6A06 C471 CA80  E6E2 2930 DC66 86EE CF68