Commit Diff


commit - 29606af7a3a58767bf817a38035490899609d13e
commit + b8bad2ba42b397e4040667df22fbd795f6c796f6
blob - 6148cc965ebf17c3b6dd0d792bd4f3d7261ddb6e
blob + 9ae1a22c521640c7b65b692d41af663d2e4fb9df
--- got/got.c
+++ got/got.c
@@ -1763,7 +1763,7 @@ cmd_log(int argc, char *argv[])
 		path = in_repo_path;
 	}
 
-	error = got_ref_list(&refs, repo, NULL);
+	error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
 	if (error)
 		goto done;
 
@@ -2825,7 +2825,7 @@ list_refs(struct got_repository *repo)
 	struct got_reflist_entry *re;
 
 	SIMPLEQ_INIT(&refs);
-	err = got_ref_list(&refs, repo, NULL);
+	err = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
 	if (err)
 		return err;
 
@@ -3065,7 +3065,8 @@ list_branches(struct got_repository *repo, struct got_
 
 	SIMPLEQ_INIT(&refs);
 
-	err = got_ref_list(&refs, repo, "refs/heads");
+	err = got_ref_list(&refs, repo, "refs/heads",
+	    got_ref_cmp_by_name, NULL);
 	if (err)
 		return err;
 
@@ -3302,9 +3303,112 @@ usage_tag(void)
 	    "usage: %s tag [-r repository] | -l | "
 	        "[-m message] name [commit]\n", getprogname());
 	exit(1);
+}
+
+#if 0
+static const struct got_error *
+sort_tags(struct got_reflist_head *sorted, struct got_reflist_head *tags)
+{
+	const struct got_error *err = NULL;
+	struct got_reflist_entry *re, *se, *new;
+	struct got_object_id *re_id, *se_id;
+	struct got_tag_object *re_tag, *se_tag;
+	time_t re_time, se_time;
+
+	SIMPLEQ_FOREACH(re, tags, entry) {
+		se = SIMPLEQ_FIRST(sorted);
+		if (se == NULL) {
+			err = got_reflist_entry_dup(&new, re);
+			if (err)
+				return err;
+			SIMPLEQ_INSERT_HEAD(sorted, new, entry);
+			continue;
+		} else {
+			err = got_ref_resolve(&re_id, repo, re->ref);
+			if (err)
+				break;
+			err = got_object_open_as_tag(&re_tag, repo, re_id);
+			free(re_id);
+			if (err)
+				break;
+			re_time = got_object_tag_get_tagger_time(re_tag);
+			got_object_tag_close(re_tag);
+		}
+
+		while (se) {
+			err = got_ref_resolve(&se_id, repo, re->ref);
+			if (err)
+				break;
+			err = got_object_open_as_tag(&se_tag, repo, se_id);
+			free(se_id);
+			if (err)
+				break;
+			se_time = got_object_tag_get_tagger_time(se_tag);
+			got_object_tag_close(se_tag);
+
+			if (se_time > re_time) {
+				err = got_reflist_entry_dup(&new, re);
+				if (err)
+					return err;
+				SIMPLEQ_INSERT_AFTER(sorted, se, new, entry);
+				break;
+			}
+			se = SIMPLEQ_NEXT(se, entry);
+			continue;
+		}
+	}
+done:
+	return err;
 }
+#endif
 
 static const struct got_error *
+cmp_tags(void *arg, int *cmp, struct got_reference *ref1,
+    struct got_reference *ref2)
+{
+	const struct got_error *err = NULL;
+	struct got_repository *repo = arg;
+	struct got_object_id *id1, *id2 = NULL;
+	struct got_tag_object *tag1 = NULL, *tag2 = NULL;
+	time_t time1, time2;
+
+	*cmp = 0;
+
+	err = got_ref_resolve(&id1, repo, ref1);
+	if (err)
+		return err;
+	err = got_object_open_as_tag(&tag1, repo, id1);
+	if (err)
+		goto done;
+
+	err = got_ref_resolve(&id2, repo, ref2);
+	if (err)
+		goto done;
+	err = got_object_open_as_tag(&tag2, repo, id2);
+	if (err)
+		goto done;
+
+	time1 = got_object_tag_get_tagger_time(tag1);
+	time2 = got_object_tag_get_tagger_time(tag2);
+
+	/* Put latest tags first. */
+	if (time1 < time2)
+		*cmp = 1;
+	else if (time1 > time2)
+		*cmp = -1;
+	else
+		err = got_ref_cmp_by_name(NULL, cmp, ref2, ref1);
+done:
+	free(id1);
+	free(id2);
+	if (tag1)
+		got_object_tag_close(tag1);
+	if (tag2)
+		got_object_tag_close(tag2);
+	return err;
+}
+
+static const struct got_error *
 list_tags(struct got_repository *repo, struct got_worktree *worktree)
 {
 	static const struct got_error *err = NULL;
@@ -3313,7 +3417,7 @@ list_tags(struct got_repository *repo, struct got_work
 
 	SIMPLEQ_INIT(&refs);
 
-	err = got_ref_list(&refs, repo, "refs/tags");
+	err = got_ref_list(&refs, repo, "refs/tags", cmp_tags, repo);
 	if (err)
 		return err;
 
blob - 67fa4cc7d1bd16dc97d7c1f3fb658a7d84b9d4ab
blob + 50ff76771483d382370d47f5134048a4573e6788
--- include/got_reference.h
+++ include/got_reference.h
@@ -83,13 +83,26 @@ struct got_reflist_entry {
 };
 SIMPLEQ_HEAD(got_reflist_head, got_reflist_entry);
 
+/* Duplicate a reference list entry. Caller must dispose of it with free(3). */
+const struct got_error *got_reflist_entry_dup(struct got_reflist_entry **,
+    struct got_reflist_entry *);
+
+/* A function which compares two references. Used with got_ref_list(). */
+typedef const struct got_error *(*got_ref_cmp_cb)(void *, int *,
+    struct got_reference *, struct got_reference *);
+
+/* An implementation of got_ref_cmp_cb which compares two references by name. */
+const struct got_error *got_ref_cmp_by_name(void *, int *,
+    struct got_reference *, struct got_reference *);
+
 /*
  * Append all known references to a caller-provided ref list head.
  * Optionally limit references returned to those within a given
- * reference namespace.
+ * reference namespace. Sort the list with the provided reference comparison
+ * function, usually got_ref_cmp_by_name().
  */
 const struct got_error *got_ref_list(struct got_reflist_head *,
-    struct got_repository *, const char *);
+    struct got_repository *, const char *, got_ref_cmp_cb, void *);
 
 /* Free all references on a ref list. */
 void got_ref_list_free(struct got_reflist_head *);
blob - 27bcf86d4d2492625ca6d33f449ada7ce71b6c69
blob + c4723d5692b318f338242ac11195e9f2a00f13a9
--- lib/reference.c
+++ lib/reference.c
@@ -526,7 +526,39 @@ got_ref_dup(struct got_reference *ref)
 
 	return ret;
 }
+
+const struct got_error *
+got_reflist_entry_dup(struct got_reflist_entry **newp,
+    struct got_reflist_entry *re)
+{
+	const struct got_error *err = NULL;
+	struct got_reflist_entry *new;
+
+	*newp = NULL;
+
+	new = malloc(sizeof(*new));
+	if (new == NULL)
+		return got_error_from_errno("malloc");
 
+	new->ref = got_ref_dup(re->ref);
+	if (new->ref == NULL) {
+		err = got_error_from_errno("got_ref_dup");
+		free(new);
+		return err;
+	}
+
+	new->id = got_object_id_dup(re->id);
+	if (new->id == NULL) {
+		err = got_error_from_errno("got_ref_dup");
+		free(new->id);
+		free(new);
+		return err;
+	}
+
+	*newp = new;
+	return NULL;
+}
+
 static const struct got_error *
 resolve_symbolic_ref(struct got_reference **resolved,
     struct got_repository *repo, struct got_reference *ref)
@@ -616,13 +648,25 @@ got_ref_get_symref_target(struct got_reference *ref)
 {
 	if (ref->flags & GOT_REF_IS_SYMBOLIC)
 		return ref->ref.symref.ref;
+
+	return NULL;
+}
+
+const struct got_error *
+got_ref_cmp_by_name(void *arg, int *cmp, struct got_reference *re1,
+    struct got_reference* re2)
+{
+	const char *name1 = got_ref_get_name(re1);
+	const char *name2 = got_ref_get_name(re2);
 
+	*cmp = got_path_cmp(name1, name2, strlen(name1), strlen(name2));
 	return NULL;
 }
 
 static const struct got_error *
 insert_ref(struct got_reflist_entry **newp, struct got_reflist_head *refs,
-    struct got_reference *ref, struct got_repository *repo)
+    struct got_reference *ref, struct got_repository *repo,
+    got_ref_cmp_cb cmp_cb, void *cmp_arg)
 {
 	const struct got_error *err;
 	struct got_object_id *id;
@@ -652,10 +696,9 @@ insert_ref(struct got_reflist_entry **newp, struct got
 	 */
 	re = SIMPLEQ_FIRST(refs);
 	while (re) {
-		const char *name = got_ref_get_name(re->ref);
-		const char *new_name = got_ref_get_name(new->ref);
-		cmp = got_path_cmp(name, new_name, strlen(name),
-		    strlen(new_name));
+		err = (*cmp_cb)(cmp_arg, &cmp, re->ref, new->ref);
+		if (err)
+			return err;
 		if (cmp == 0) {
 			/* duplicate */
 			free(new->id);
@@ -680,7 +723,8 @@ insert_ref(struct got_reflist_entry **newp, struct got
 
 static const struct got_error *
 gather_on_disk_refs(struct got_reflist_head *refs, const char *path_refs,
-    const char *subdir, struct got_repository *repo)
+    const char *subdir, struct got_repository *repo,
+    got_ref_cmp_cb cmp_cb, void *cmp_arg)
 {
 	const struct got_error *err = NULL;
 	DIR *d = NULL;
@@ -714,7 +758,8 @@ gather_on_disk_refs(struct got_reflist_head *refs, con
 				goto done;
 			if (ref) {
 				struct got_reflist_entry *new;
-				err = insert_ref(&new, refs, ref, repo);
+				err = insert_ref(&new, refs, ref, repo,
+				    cmp_cb, cmp_arg);
 				if (err || new == NULL /* duplicate */)
 					got_ref_close(ref);
 				if (err)
@@ -727,7 +772,8 @@ gather_on_disk_refs(struct got_reflist_head *refs, con
 				err = got_error_from_errno("asprintf");
 				break;
 			}
-			err = gather_on_disk_refs(refs, path_refs, child, repo);
+			err = gather_on_disk_refs(refs, path_refs, child, repo,
+			    cmp_cb, cmp_arg);
 			free(child);
 			break;
 		default:
@@ -743,7 +789,7 @@ done:
 
 const struct got_error *
 got_ref_list(struct got_reflist_head *refs, struct got_repository *repo,
-    const char *ref_namespace)
+    const char *ref_namespace, got_ref_cmp_cb cmp_cb, void *cmp_arg)
 {
 	const struct got_error *err;
 	char *packed_refs_path, *path_refs = NULL;
@@ -761,7 +807,7 @@ got_ref_list(struct got_reflist_head *refs, struct got
 		err = open_ref(&ref, path_refs, "", GOT_REF_HEAD, 0);
 		if (err)
 			goto done;
-		err = insert_ref(&new, refs, ref, repo);
+		err = insert_ref(&new, refs, ref, repo, cmp_cb, cmp_arg);
 		if (err || new == NULL /* duplicate */)
 			got_ref_close(ref);
 		if (err)
@@ -779,7 +825,7 @@ got_ref_list(struct got_reflist_head *refs, struct got
 		goto done;
 	}
 	err = gather_on_disk_refs(refs, path_refs,
-	    ref_namespace ? ref_namespace : "", repo);
+	    ref_namespace ? ref_namespace : "", repo, cmp_cb, cmp_arg);
 	if (err)
 		goto done;
 
@@ -821,7 +867,8 @@ got_ref_list(struct got_reflist_head *refs, struct got
 						continue;
 					}
 				}
-				err = insert_ref(&new, refs, ref, repo);
+				err = insert_ref(&new, refs, ref, repo,
+				    cmp_cb, cmp_arg);
 				if (err || new == NULL /* duplicate */)
 					got_ref_close(ref);
 				if (err)
@@ -1051,7 +1098,8 @@ delete_packed_ref(struct got_reference *delref, struct
 			continue;
 		}
 
-		err = insert_ref(&new, &refs, ref, repo);
+		err = insert_ref(&new, &refs, ref, repo,
+		    got_ref_cmp_by_name, NULL);
 		if (err || new == NULL /* duplicate */)
 			got_ref_close(ref);
 		if (err)
blob - 4ed88ead1f4f6151d23365d58166fb12931f06e7
blob + eeffa65542fb24958cb041d67effcdf464713ded
--- lib/repository.c
+++ lib/repository.c
@@ -1128,7 +1128,7 @@ got_repo_object_match_tag(struct got_tag_object **tag,
 	SIMPLEQ_INIT(&refs);
 	*tag = NULL;
 
-	err = got_ref_list(&refs, repo, "refs/tags");
+	err = got_ref_list(&refs, repo, "refs/tags", got_ref_cmp_by_name, NULL);
 	if (err)
 		return err;
 
blob - dd28ecc607e0e077b5ab8ef39621b8e522e0ae52
blob + db9528a8d563d08559533e1edb30d63c3e7a4beb
--- regress/cmdline/tag.sh
+++ regress/cmdline/tag.sh
@@ -146,7 +146,7 @@ function test_tag_list {
 
 	echo "-----------------------------------------------" \
 		> $testroot/stdout.expected
-	echo "tag $tag $tag_id" >> $testroot/stdout.expected
+	echo "tag $tag2 $tag_id2" >> $testroot/stdout.expected
 	echo "from: $GOT_AUTHOR" >> $testroot/stdout.expected
 	echo "date: $d1" >> $testroot/stdout.expected
 	echo "object: commit $commit_id" >> $testroot/stdout.expected
@@ -155,7 +155,7 @@ function test_tag_list {
 	echo " " >> $testroot/stdout.expected
 	echo "-----------------------------------------------" \
 		>> $testroot/stdout.expected
-	echo "tag $tag2 $tag_id2" >> $testroot/stdout.expected
+	echo "tag $tag $tag_id" >> $testroot/stdout.expected
 	echo "from: $GOT_AUTHOR" >> $testroot/stdout.expected
 	echo "date: $d2" >> $testroot/stdout.expected
 	echo "object: commit $commit_id" >> $testroot/stdout.expected
blob - a1865a54165076e33e14a3daa3b0728f43f23017
blob + d5a10ac995e03463cd40984b797f33f7f214f61d
--- tog/tog.c
+++ tog/tog.c
@@ -2303,7 +2303,7 @@ cmd_log(int argc, char *argv[])
 	if (error != NULL)
 		goto done;
 
-	error = got_ref_list(&refs, repo, NULL);
+	error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
 	if (error)
 		goto done;
 
@@ -2928,7 +2928,7 @@ cmd_diff(int argc, char *argv[])
 	if (error)
 		goto done;
 
-	error = got_ref_list(&refs, repo, NULL);
+	error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
 	if (error)
 		goto done;
 
@@ -3832,7 +3832,7 @@ cmd_blame(int argc, char *argv[])
 	if (error != NULL)
 		goto done;
 
-	error = got_ref_list(&refs, repo, NULL);
+	error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
 	if (error)
 		goto done;
 
@@ -4589,7 +4589,7 @@ cmd_tree(int argc, char *argv[])
 	if (error != NULL)
 		goto done;
 
-	error = got_ref_list(&refs, repo, NULL);
+	error = got_ref_list(&refs, repo, NULL, got_ref_cmp_by_name, NULL);
 	if (error)
 		goto done;