use git_reference for tags and branches, sort branches also - stagit-gopher - A git gopher frontend. (mirror)
 (HTM) git clone git://bitreich.org/stagit-gopher/ git://enlrupgkhuxnvlhsf6lc3fziv5h2hhfrinws65d7roiv6bfj7d652fid.onion/stagit-gopher/
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Tags
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit 87360fe2526f7713c4626d04da521579141fcf68
 (DIR) parent c750958b95624fd6bd45f817e255fe19aa412534
 (HTM) Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Wed,  6 Jan 2016 17:45:02 +0100
       
       use git_reference for tags and branches, sort branches also
       
       this removes some lines and somewhat simplifies it
       
       Diffstat:
         M stagit.c                            |     285 ++++++++++++-------------------
       
       1 file changed, 113 insertions(+), 172 deletions(-)
       ---
 (DIR) diff --git a/stagit.c b/stagit.c
       @@ -775,199 +775,140 @@ err:
        }
        
        int
       -writebranches(FILE *fp)
       +refs_cmp(const void *v1, const void *v2)
        {
       -        struct commitinfo *ci;
       -        git_branch_iterator *it = NULL;
       -        git_branch_t branch;
       -        git_reference *ref = NULL, *dref = NULL;
       -        const git_oid *id = NULL;
       -        const char *branchname = NULL;
       -        size_t len;
       -        int ret = -1;
       -
       -        /* log for local branches */
       -        if (git_branch_iterator_new(&it, repo, GIT_BRANCH_LOCAL))
       -                return -1;
       -
       -        fputs("<h2>Branches</h2><table id=\"branches\"><thead>\n<tr><td>Branch</td><td>Age</td>"
       -                  "<td>Commit message</td>"
       -                  "<td>Author</td><td>Files</td><td class=\"num\">+</td>"
       -                  "<td class=\"num\">-</td></tr>\n</thead><tbody>\n", fp);
       -
       -        while (!git_branch_next(&ref, &branch, it)) {
       -                if (git_branch_name(&branchname, ref))
       -                        continue;
       -
       -                id = NULL;
       -                switch (git_reference_type(ref)) {
       -                case GIT_REF_SYMBOLIC:
       -                        if (git_reference_resolve(&dref, ref))
       -                                goto err;
       -                        id = git_reference_target(dref);
       -                        break;
       -                case GIT_REF_OID:
       -                        id = git_reference_target(ref);
       -                        break;
       -                default:
       -                        continue;
       -                }
       -                if (!id)
       -                        goto err;
       -                if (!(ci = commitinfo_getbyoid(id)))
       -                        break;
       -
       -                relpath = "";
       -
       -                fputs("<tr><td>", fp);
       -                xmlencode(fp, branchname, strlen(branchname));
       -                fputs("</td><td>", fp);
       -                if (ci->author)
       -                        printtimeshort(fp, &(ci->author->when));
       -                fputs("</td><td>", fp);
       -                if (ci->summary) {
       -                        if ((len = strlen(ci->summary)) > summarylen) {
       -                                xmlencode(fp, ci->summary, summarylen - 1);
       -                                fputs("…", fp);
       -                        } else {
       -                                xmlencode(fp, ci->summary, len);
       -                        }
       -                }
       -                fputs("</td><td>", fp);
       -                if (ci->author)
       -                        xmlencode(fp, ci->author->name, strlen(ci->author->name));
       -                fputs("</td><td class=\"num\">", fp);
       -                fprintf(fp, "%zu", ci->filecount);
       -                fputs("</td><td class=\"num\">", fp);
       -                fprintf(fp, "+%zu", ci->addcount);
       -                fputs("</td><td class=\"num\">", fp);
       -                fprintf(fp, "-%zu", ci->delcount);
       -                fputs("</td></tr>\n", fp);
       -
       -                relpath = "../";
       +        git_reference *r1 = (*(git_reference **)v1);
       +        git_reference *r2 = (*(git_reference **)v2);
       +        int t1, t2;
        
       -                commitinfo_free(ci);
       -                git_reference_free(ref);
       -                git_reference_free(dref);
       -                ref = NULL;
       -                dref = NULL;
       -        }
       -        ret = 0;
       +        t1 = git_reference_is_branch(r1);
       +        t2 = git_reference_is_branch(r2);
        
       -err:
       -        fputs("</tbody></table>", fp);
       -        git_reference_free(ref);
       -        git_reference_free(dref);
       -        git_branch_iterator_free(it);
       +        if (t1 != t2)
       +                return t1 - t2;
        
       -        return ret;
       +        return strcmp(git_reference_shorthand(r1),
       +                      git_reference_shorthand(r2));
        }
        
        int
       -tagcompare(void *s1, void *s2)
       -{
       -        return strcmp(*(char **)s1, *(char **)s2);
       -}
       -
       -int
       -writetags(FILE *fp)
       +writerefs(FILE *fp)
        {
                struct commitinfo *ci;
       -        git_strarray tagnames;
       -        git_object *obj = NULL;
       -        git_tag *tag = NULL;
                const git_oid *id = NULL;
       -        size_t i, len;
       -
       -        /* summary page with branches and tags */
       -        memset(&tagnames, 0, sizeof(tagnames));
       -        if (git_tag_list(&tagnames, repo))
       +        git_object *obj = NULL;
       +        git_reference *dref = NULL, *r, *ref = NULL;
       +        git_reference_iterator *it = NULL;
       +        git_reference **refs = NULL;
       +        size_t count, i, j, len, refcount = 0;
       +        const char *cols[] = { "Branch", "Tag" }; /* first column title */
       +        const char *titles[] = { "Branches", "Tags" };
       +        const char *ids[] = { "branches", "tags" };
       +        const char *name;
       +
       +        if (git_reference_iterator_new(&it, repo))
                        return -1;
       -        if (!tagnames.count) {
       -                git_strarray_free(&tagnames);
       -                return 0;
       -        }
       -
       -        /* sort names */
       -        qsort(tagnames.strings, tagnames.count, sizeof(char *),
       -              (int (*)(const void *, const void *))&tagcompare);
       -
       -        fputs("<h2>Tags</h2><table id=\"tags\"><thead>\n<tr><td>Tag</td>"
       -              "<td>Age</td><td>Commit message</td>"
       -              "<td>Author</td><td>Files</td><td class=\"num\">+</td>"
       -              "<td class=\"num\">-</td></tr>\n</thead><tbody>\n", fp);
       -
       -        for (i = 0; i < tagnames.count; i++) {
       -                if (git_revparse_single(&obj, repo, tagnames.strings[i]))
       -                        continue;
       -                id = git_object_id(obj);
        
       -                /* lookup actual commit (from annotated tag etc) */
       -                if (!git_tag_lookup(&tag, repo, id)) {
       -                        git_object_free(obj);
       -                        obj = NULL;
       -                        if (git_tag_peel(&obj, tag))
       +        for (refcount = 0; !git_reference_next(&ref, it); refcount++) {
       +                if (!(refs = reallocarray(refs, refcount + 1, sizeof(git_reference *))))
       +                        err(1, "realloc");
       +                refs[refcount] = ref;
       +        }
       +        git_reference_iterator_free(it);
       +
       +        /* sort by type then shorthand name */
       +        qsort(refs, refcount, sizeof(git_reference *), refs_cmp);
       +
       +        for (j = 0; j < 2; j++) {
       +                for (i = 0, count = 0; i < refcount; i++) {
       +                        if (git_reference_is_branch(refs[i]) && j == 0)
       +                                ;
       +                        else if (git_reference_is_tag(refs[i]) && j == 1)
       +                                ;
       +                        else
       +                                continue;
       +
       +                        id = NULL;
       +                        r = NULL;
       +                        switch (git_reference_type(refs[i])) {
       +                        case GIT_REF_SYMBOLIC:
       +                                if (git_reference_resolve(&dref, refs[i]))
       +                                        goto err;
       +                                r = dref;
       +                                break;
       +                        case GIT_REF_OID:
       +                                r = refs[i];
       +                                break;
       +                        default:
       +                                continue;
       +                        }
       +                        if (!(id = git_reference_target(r)))
       +                                goto err;
       +                        if (git_reference_peel(&obj, r, GIT_OBJ_ANY))
       +                                goto err;
       +                        if (!(id = git_object_id(obj)))
       +                                goto err;
       +                        if (!(ci = commitinfo_getbyoid(id)))
                                        break;
       -                        git_tag_free(tag);
       -                        tag = NULL;
       -                        id = git_object_id(obj);
       -                }
       -
       -                if (!(ci = commitinfo_getbyoid(id)))
       -                        break;
        
       -                relpath = "";
       +                        /* print header if it has an entry (first). */
       +                        if (++count == 1) {
       +                                fprintf(fp, "<h2>%s</h2><table id=\"%s\"><thead>\n<tr><td>%s</td>"
       +                                      "<td>Age</td><td>Commit message</td>"
       +                                      "<td>Author</td><td>Files</td><td class=\"num\">+</td>"
       +                                      "<td class=\"num\">-</td></tr>\n</thead><tbody>\n",
       +                                      titles[j], ids[j], cols[j]);
       +                        }
        
       -                fputs("<tr><td>", fp);
       -                xmlencode(fp, tagnames.strings[i], strlen(tagnames.strings[i]));
       -                fputs("</td><td>", fp);
       -                if (ci->author)
       -                        printtimeshort(fp, &(ci->author->when));
       -                fputs("</td><td>", fp);
       -                if (ci->summary) {
       -                        fprintf(fp, "<a href=\"%scommit/%s.html\">", relpath, ci->oid);
       -                        if ((len = strlen(ci->summary)) > summarylen) {
       -                                xmlencode(fp, ci->summary, summarylen - 1);
       -                                fputs("…", fp);
       -                        } else {
       -                                xmlencode(fp, ci->summary, len);
       +                        relpath = "";
       +                        name = git_reference_shorthand(r);
       +
       +                        fputs("<tr><td>", fp);
       +                        xmlencode(fp, name, strlen(name));
       +                        fputs("</td><td>", fp);
       +                        if (ci->author)
       +                                printtimeshort(fp, &(ci->author->when));
       +                        fputs("</td><td>", fp);
       +                        if (ci->summary) {
       +                                fprintf(fp, "<a href=\"%scommit/%s.html\">", relpath, ci->oid);
       +                                if ((len = strlen(ci->summary)) > summarylen) {
       +                                        xmlencode(fp, ci->summary, summarylen - 1);
       +                                        fputs("…", fp);
       +                                } else {
       +                                        xmlencode(fp, ci->summary, len);
       +                                }
       +                                fputs("</a>", fp);
                                }
       -                        fputs("</a>", fp);
       +                        fputs("</td><td>", fp);
       +                        if (ci->author)
       +                                xmlencode(fp, ci->author->name, strlen(ci->author->name));
       +                        fputs("</td><td class=\"num\">", fp);
       +                        fprintf(fp, "%zu", ci->filecount);
       +                        fputs("</td><td class=\"num\">", fp);
       +                        fprintf(fp, "+%zu", ci->addcount);
       +                        fputs("</td><td class=\"num\">", fp);
       +                        fprintf(fp, "-%zu", ci->delcount);
       +                        fputs("</td></tr>\n", fp);
       +
       +                        relpath = "../";
       +
       +                        commitinfo_free(ci);
       +                        git_reference_free(dref);
       +                        dref = NULL;
                        }
       -                fputs("</td><td>", fp);
       -                if (ci->author)
       -                        xmlencode(fp, ci->author->name, strlen(ci->author->name));
       -                fputs("</td><td class=\"num\">", fp);
       -                fprintf(fp, "%zu", ci->filecount);
       -                fputs("</td><td class=\"num\">", fp);
       -                fprintf(fp, "+%zu", ci->addcount);
       -                fputs("</td><td class=\"num\">", fp);
       -                fprintf(fp, "-%zu", ci->delcount);
       -                fputs("</td></tr>\n", fp);
       -
       -                relpath = "../";
       -
       -                commitinfo_free(ci);
       -                git_object_free(obj);
       -                obj = NULL;
       +                /* table footer */
       +                if (count)
       +                        fputs("</tbody></table>", fp);
                }
       -        fputs("</tbody></table>", fp);
       -        git_strarray_free(&tagnames);
       -        git_tag_free(tag);
       -        git_object_free(obj);
        
       -        return 0;
       -}
       +err:
       +        git_reference_free(dref);
        
       -int
       -writerefs(FILE *fp)
       -{
       -        int ret;
       +        for (i = 0; i < refcount; i++)
       +                git_reference_free(refs[i]);
       +        free(refs);
        
       -        if ((ret = writebranches(fp)))
       -                return ret;
       -        fputs("<br/>", fp);
       -        return writetags(fp);
       +        return 0;
        }
        
        int