Commit 199a402734c6e8d1b44fd3f607459b9fb94e0cb0

Stefan Sperling 2019-02-02T15:00:28

make 'got log' show packed refs and HEAD ref (pther refs not shown yet)

diff --git a/got/got.c b/got/got.c
index f51496b..587273c 100644
--- a/got/got.c
+++ b/got/got.c
@@ -610,20 +610,41 @@ get_datestr(time_t *time, char *datebuf)
 
 static const struct got_error *
 print_commit(struct got_commit_object *commit, struct got_object_id *id,
-    struct got_repository *repo, int show_patch, int diff_context)
+    struct got_repository *repo, int show_patch, int diff_context,
+    struct got_reflist_head *refs)
 {
 	const struct got_error *err = NULL;
 	char *id_str, *datestr, *logmsg0, *logmsg, *line;
 	char datebuf[26];
 	time_t committer_time;
 	const char *author, *committer;
+	char *refs_str = NULL;
+	struct got_reflist_entry *re;
 
+	SIMPLEQ_FOREACH(re, refs, entry) {
+		char *s;
+		const char *name;
+		if (got_object_id_cmp(re->id, id) != 0)
+			continue;
+		name = got_ref_get_name(re->ref);
+		if (strncmp(name, "refs/", 5) == 0)
+			name += 5;
+		s = refs_str;
+		if (asprintf(&refs_str, "%s%s%s", s ? s : "", s ? ", " : "",
+		    name) == -1) {
+			err = got_error_from_errno();
+			free(s);
+			break;
+		}
+		free(s);
+	}
 	err = got_object_id_str(&id_str, id);
 	if (err)
 		return err;
 
 	printf("-----------------------------------------------\n");
-	printf("commit %s\n", id_str);
+	printf("commit %s%s%s%s\n", id_str, refs_str ? " (" : "",
+	    refs_str ? refs_str : "", refs_str ? ")" : "");
 	free(id_str);
 	printf("from: %s\n", got_object_commit_get_author(commit));
 	committer_time = got_object_commit_get_committer_time(commit);
@@ -672,7 +693,7 @@ print_commit(struct got_commit_object *commit, struct got_object_id *id,
 static const struct got_error *
 print_commits(struct got_object_id *root_id, struct got_repository *repo,
     char *path, int show_patch, int diff_context, int limit,
-    int first_parent_traversal)
+    int first_parent_traversal, struct got_reflist_head *refs)
 {
 	const struct got_error *err;
 	struct got_commit_graph *graph;
@@ -711,7 +732,8 @@ print_commits(struct got_object_id *root_id, struct got_repository *repo,
 		err = got_object_open_as_commit(&commit, repo, id);
 		if (err)
 			break;
-		err = print_commit(commit, id, repo, show_patch, diff_context);
+		err = print_commit(commit, id, repo, show_patch, diff_context,
+		    refs);
 		got_object_commit_close(commit);
 		if (err || (limit && --limit == 0))
 			break;
@@ -741,6 +763,7 @@ cmd_log(int argc, char *argv[])
 	int diff_context = 3, ch;
 	int show_patch = 0, limit = 0, first_parent_traversal = 0;
 	const char *errstr;
+	struct got_reflist_head refs;
 
 #ifndef PROFILE
 	if (pledge("stdio rpath wpath cpath flock proc exec sendfd unveil",
@@ -882,8 +905,13 @@ cmd_log(int argc, char *argv[])
 		path = in_repo_path;
 	}
 
+	SIMPLEQ_INIT(&refs);
+	error = got_ref_list(&refs, repo);
+	if (error)
+		goto done;
+
 	error = print_commits(id, repo, path, show_patch,
-	    diff_context, limit, first_parent_traversal);
+	    diff_context, limit, first_parent_traversal, &refs);
 done:
 	free(path);
 	free(repo_path);
diff --git a/include/got_reference.h b/include/got_reference.h
index 3845b3e..18c0c22 100644
--- a/include/got_reference.h
+++ b/include/got_reference.h
@@ -54,3 +54,15 @@ const struct got_error *got_ref_resolve(struct got_object_id **,
  * The caller must dispose of it with free(3).
  */
 char *got_ref_to_str(struct got_reference *);
+
+/* A list of references and the object ID which they resolve to. */
+struct got_reflist_entry {
+	SIMPLEQ_ENTRY(got_reflist_entry) entry;
+	struct got_reference *ref;
+	struct got_object_id *id;
+};
+SIMPLEQ_HEAD(got_reflist_head, got_reflist_entry);
+
+/* Append all known references to a caller-provided ref list head. */
+const struct got_error *got_ref_list(struct got_reflist_head *,
+    struct got_repository *);
diff --git a/lib/reference.c b/lib/reference.c
index b10ac6f..8cf17a7 100644
--- a/lib/reference.c
+++ b/lib/reference.c
@@ -182,12 +182,15 @@ parse_packed_ref_line(struct got_reference **ref, const char *abs_refname,
 	if (!got_parse_sha1_digest(digest, line))
 		return got_error(GOT_ERR_NOT_REF);
 
-	if (strcmp(line + SHA1_DIGEST_STRING_LENGTH, abs_refname) != 0)
-		return NULL;
+	if (abs_refname) {
+		if (strcmp(line + SHA1_DIGEST_STRING_LENGTH, abs_refname) != 0)
+			return NULL;
 
-	name = strdup(abs_refname);
-	if (name == NULL)
-		return got_error_from_errno();
+		name = strdup(abs_refname);
+		if (name == NULL)
+			return got_error_from_errno();
+	} else
+		name = strdup(line + SHA1_DIGEST_STRING_LENGTH);
 
 	*ref = calloc(1, sizeof(**ref));
 	if (*ref == NULL)
@@ -425,3 +428,71 @@ got_ref_get_name(struct got_reference *ref)
 
 	return ref->ref.ref.name;
 }
+
+static const struct got_error *
+append_ref(struct got_reflist_head *refs, struct got_reference *ref,
+    struct got_repository *repo)
+{
+	const struct got_error *err;
+	struct got_object_id *id;
+	struct got_reflist_entry *entry;
+
+	err = got_ref_resolve(&id, repo, ref);
+	if (err)
+		return err;
+	entry = malloc(sizeof(*entry));
+	if (entry == NULL)
+		return got_error_from_errno();
+	entry->ref = ref;
+	entry->id = id;
+	SIMPLEQ_INSERT_TAIL(refs, entry, entry);
+	return NULL;
+}
+
+const struct got_error *
+got_ref_list(struct got_reflist_head *refs, struct got_repository *repo)
+{
+	const struct got_error *err;
+	char *packed_refs_path, *path_refs;
+	FILE *f;
+	struct got_reference *ref;
+
+	packed_refs_path = got_repo_get_path_packed_refs(repo);
+	if (packed_refs_path == NULL)
+		return got_error_from_errno();
+
+	f = fopen(packed_refs_path, "r");
+	free(packed_refs_path);
+	if (f) {
+		char *line;
+		size_t len;
+		const char delim[3] = {'\0', '\0', '\0'};
+		while (1) {
+			line = fparseln(f, &len, NULL, delim, 0);
+			if (line == NULL)
+				break;
+			err = parse_packed_ref_line(&ref, NULL, line);
+			if (err)
+				goto done;
+			if (ref)
+				append_ref(refs, ref, repo);
+		}
+	}
+
+	/* HEAD ref should always exist. */
+	path_refs = get_refs_dir_path(repo, GOT_REF_HEAD);
+	if (path_refs == NULL) {
+		err = got_error_from_errno();
+		goto done;
+	}
+	err = open_ref(&ref, path_refs, "", GOT_REF_HEAD);
+	free(path_refs);
+	if (err)
+		goto done;
+	append_ref(refs, ref, repo);
+
+done:
+	if (f)
+		fclose(f);
+	return err;
+}