commit b8bad2ba42b397e4040667df22fbd795f6c796f6 from: Stefan Sperling date: Fri Aug 23 18:01:06 2019 UTC make 'got tag -l' list tags by time stamp in descending order 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;