URI: 
       rewrite in C with libgit2, first version - stagit-gopher - A git gopher frontend. (mirror)
  HTML 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 415e3fdd55b2ecdf2f35680694362a4b35fd1a05
   DIR parent bda4633633a0701bbd2f7861674a8e612d961fb7
  HTML Author: Hiltjo Posthuma <hiltjo@codemadness.org>
       Date:   Sat,  5 Dec 2015 20:22:57 +0100
       
       rewrite in C with libgit2, first version
       
       Diffstat:
         D urmoms                              |     135 -------------------------------
         A urmoms.c                            |     222 ++++++++++++++++++++++++++++++
       
       2 files changed, 222 insertions(+), 135 deletions(-)
       ---
   DIR diff --git a/urmoms b/urmoms
       @@ -1,135 +0,0 @@
       -#!/bin/sh
       -
       -# DEBUG
       -#set -e -x
       -
       -usage() {
       -        printf '%s <repodir> <htmldir>\n' "$0"
       -        exit 1
       -}
       -
       -header() {
       -        cat <<!__EOF__
       -<!DOCTYPE HTML>
       -<html dir="ltr" lang="en">
       -<head>
       -<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
       -<meta http-equiv="Content-Language" content="en" />
       -<title>${name} - ${description}</title>
       -<link rel="stylesheet" type="text/css" href="style.css" />
       -</head>
       -<body>
       -<center>
       -<h1><img src="${relpath}logo.png" alt="" /> ${name}</h1>
       -<span class="desc">${description}</span><br/>
       -<a href="${relpath}log.html">Log</a> |
       -<a href="${relpath}files.html">Files</a> |
       -<a href="${relpath}stats.html">Stats</a> |
       -<a href="${relpath}readme.html">README</a> |
       -<a href="${relpath}license.html">LICENSE</a>
       -</center>
       -<hr/>
       -<pre>
       -!__EOF__
       -}
       -
       -footer() {
       -        cat <<!__EOF__
       -</pre>
       -</body>
       -</html>
       -!__EOF__
       -}
       -
       -# usage: repodir and htmldir must be set.
       -if test x"$1" = x"" || test x"$2" = x""; then
       -        usage
       -fi
       -
       -# make absolute path to htmldir.
       -htmldir="$(readlink -f $2)"
       -mkdir -p "${htmldir}"
       -
       -# repodir must be a directory to go to.
       -cd "$1" || usage
       -
       -# default index page (symlink).
       -indexpage="log.html"
       -
       -# project name, if bare repo remove .git suffix.
       -name=$(basename "$(pwd)" ".git")
       -
       -# read .git/description.
       -description=""
       -test -f ".git/description" && description="$(cat '.git/description')"
       -
       -# make diff for each commit (all files).
       -relpath="../"
       -mkdir -p "${htmldir}/commit"
       -git log --pretty='%H' | while read -r commit; do
       -        test -e "${htmldir}/commit/${commit}.html" && continue
       -
       -        header > "${htmldir}/commit/${commit}.html"
       -        git show --pretty=full "${commit}" | \
       -                sed -E 's@^commit (.*)$@commit <a href="'${relpath}'commit/\1.html">\1</a>@g' >> "${htmldir}/commit/${commit}.html"
       -        footer >> "${htmldir}/commit/${commit}.html"
       -done 
       -
       -# make log with all commits.
       -relpath=""
       -header > "${htmldir}/log.html"
       -printf '<table border="0">' >> "${htmldir}/log.html"
       -git log --pretty='<tr><td align="right">%cr</td><td><a href="'${relpath}'commit/%H.html">%H</a></td><td>%an</td><td>%s</td></tr>' >> "${htmldir}/log.html"
       -printf '</table>' >> "${htmldir}/log.html"
       -footer >> "${htmldir}/log.html"
       -
       -# make index with file links.
       -relpath=""
       -header >> "${htmldir}/files.html"
       -printf '<table><tr><td><b>Mode</b></td><td><b>Name</b></td><td><b>Size</b></td><td></td></tr>' >> "${htmldir}/files.html"
       -git ls-tree -r -l master | while read -r mode type object size file; do
       -        git log -1 --pretty='<tr><td>'${mode}'</td><td><a href="'${relpath}'commit/%H.html#file-'${file}'">'${file}'</a></td><td>'${size}'</td><td><a href="file/'${file}'">[plain]</a></td></tr>' "${file}"
       -done >> "${htmldir}/files.html"
       -printf '</table>' >> "${htmldir}/files.html"
       -footer >> "${htmldir}/files.html"
       -
       -# readme page
       -# find README file.
       -relpath=""
       -readme=""
       -for f in README README.md readme.md; do
       -        test -e "${f}" && readme="${f}"
       -done
       -# make page.
       -header > "${htmldir}/readme.html"
       -if test x"${readme}" != x""; then
       -        cat "${readme}" >> "${htmldir}/readme.html"
       -else
       -        echo "no README file found" >> "${htmldir}/readme.html"
       -fi
       -footer >> "${htmldir}/readme.html"
       -
       -# license page
       -# find LICENSE file.
       -relpath=""
       -license=""
       -for f in LICENSE LICENSE.md; do
       -        test -e "${f}" && license="${f}"
       -done
       -# make page.
       -header > "${htmldir}/license.html"
       -if test x"${readme}" != x""; then
       -        cat "${license}" >> "${htmldir}/license.html"
       -else
       -        echo "unknown license" >> "${htmldir}/license.html"
       -fi
       -footer >> "${htmldir}/license.html"
       -
       -# stats (authors).
       -relpath=""
       -header > "${htmldir}/stats.html"
       -git shortlog -n -s >> "${htmldir}/stats.html"
       -footer >> "${htmldir}/stats.html"
       -
       -# symlink to index page.
       -ln -sf "$indexpage" "${htmldir}/index.html"
   DIR diff --git a/urmoms.c b/urmoms.c
       @@ -0,0 +1,222 @@
       +#include <err.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +
       +#include "git2.h"
       +
       +static const char *relpath = "";
       +static const char *name = "";
       +static const char *description = "";
       +
       +static const char *repodir = ".";
       +
       +static git_repository *repo;
       +
       +FILE *
       +efopen(const char *name, const char *flags)
       +{
       +        FILE *fp;
       +
       +        fp = fopen(name, flags);
       +        if (!fp)
       +                err(1, "fopen");
       +
       +        return fp;
       +}
       +
       +static void
       +printtime(FILE *fp, const git_time * intime, const char *prefix)
       +{
       +        struct tm *intm;
       +        time_t t;
       +        int offset, hours, minutes;
       +        char sign, out[32];
       +
       +        offset = intime->offset;
       +        if (offset < 0) {
       +                sign = '-';
       +                offset = -offset;
       +        } else {
       +                sign = '+';
       +        }
       +
       +        hours = offset / 60;
       +        minutes = offset % 60;
       +
       +        t = (time_t) intime->time + (intime->offset * 60);
       +
       +        intm = gmtime(&t);
       +        strftime(out, sizeof(out), "%a %b %e %T %Y", intm);
       +
       +        fprintf(fp, "%s%s %c%02d%02d\n", prefix, out, sign, hours, minutes);
       +}
       +
       +static void
       +printcommit(FILE *fp, git_commit * commit)
       +{
       +        const git_signature *sig;
       +        char buf[GIT_OID_HEXSZ + 1];
       +        int i, count;
       +        const char *scan, *eol;
       +
       +        git_oid_tostr(buf, sizeof(buf), git_commit_id(commit));
       +        fprintf(fp, "commit <a href=\"commit/%s.html\">%s</a>\n", buf, buf);
       +
       +        if ((count = (int)git_commit_parentcount(commit)) > 1) {
       +                fprintf(fp, "Merge:");
       +                for (i = 0; i < count; ++i) {
       +                        git_oid_tostr(buf, 8, git_commit_parent_id(commit, i));
       +                        fprintf(fp, " %s", buf);
       +                }
       +                fprintf(fp, "\n");
       +        }
       +        if ((sig = git_commit_author(commit)) != NULL) {
       +                fprintf(fp, "Author: <a href=\"author/%s.html\">%s</a> <%s>\n",
       +                        sig->name, sig->name, sig->email);
       +                printtime(fp, &sig->when, "Date:   ");
       +        }
       +        fprintf(fp, "\n");
       +
       +        for (scan = git_commit_message(commit); scan && *scan;) {
       +                for (eol = scan; *eol && *eol != '\n'; ++eol)        /* find eol */
       +                        ;
       +
       +                fprintf(fp, "    %.*s\n", (int) (eol - scan), scan);
       +                scan = *eol ? eol + 1 : NULL;
       +        }
       +        fprintf(fp, "\n");
       +}
       +
       +int
       +writeheader(FILE *fp)
       +{
       +        fprintf(fp, "<!DOCTYPE HTML>"
       +                "<html dir=\"ltr\" lang=\"en\"><head>"
       +                "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />"
       +                "<meta http-equiv=\"Content-Language\" content=\"en\" />");
       +        fprintf(fp, "<title>%s - %s</title>", name, description);
       +        fprintf(fp, "<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />"
       +                "</head><body><center>");
       +        fprintf(fp, "<h1><img src=\"%slogo.png\" alt=\"\" /> %s</h1>", relpath, name);
       +        fprintf(fp, "<span class=\"desc\">%s</span><br/>", description);
       +        fprintf(fp, "<a href=\"%slog.html\">Log</a> |", relpath);
       +        fprintf(fp, "<a href=\"%sfiles.html\">Files</a>| ", relpath);
       +        fprintf(fp, "<a href=\"%sstats.html\">Stats</a> | ", relpath);
       +        fprintf(fp, "<a href=\"%sreadme.html\">README</a> | ", relpath);
       +        fprintf(fp, "<a href=\"%slicense.html\">LICENSE</a>", relpath);
       +        fprintf(fp, "</center><hr/><pre>");
       +
       +        return 0;
       +}
       +
       +int
       +writefooter(FILE *fp)
       +{
       +        fprintf(fp, "</pre></body></html>");
       +
       +        return 0;
       +}
       +
       +int
       +writelog(FILE *fp)
       +{
       +        git_revwalk *w = NULL;
       +        git_oid id;
       +        git_commit *c = NULL;
       +
       +        git_revwalk_new(&w, repo);
       +        git_revwalk_push_head(w);
       +
       +        while (!git_revwalk_next(&id, w)) {
       +                if (git_commit_lookup(&c, repo, &id))
       +                        return 1;
       +                printcommit(fp, c);
       +                git_commit_free(c);
       +        }
       +        git_revwalk_free(w);
       +
       +        return 0;
       +}
       +
       +int
       +writefiles(FILE *fp)
       +{
       +        git_index *index;
       +        const git_index_entry *entry;
       +        size_t count, i;
       +
       +        git_repository_index(&index, repo);
       +
       +        count = git_index_entrycount(index);
       +        for (i = 0; i < count; i++) {
       +                entry = git_index_get_byindex(index, i);
       +                fprintf(fp, "name: %s, size: %lu, mode: %lu\n",
       +                        entry->path, entry->file_size, entry->mode);
       +        }
       +
       +        return 0;
       +}
       +
       +#if 0
       +int
       +writebranches(FILE *fp)
       +{
       +        git_branch_iterator *branchit = NULL;
       +        git_branch_t branchtype;
       +        git_reference *branchref;
       +        char branchbuf[BUFSIZ] = "";
       +        int status;
       +
       +        git_branch_iterator_new(&branchit, repo, GIT_BRANCH_LOCAL);
       +
       +        while ((status = git_branch_next(&branchref, &branchtype, branchit)) == GIT_ITEROVER) {
       +                git_reference_normalize_name(branchbuf, sizeof(branchbuf), git_reference_name(branchref), GIT_REF_FORMAT_ALLOW_ONELEVEL | GIT_REF_FORMAT_REFSPEC_SHORTHAND);
       +
       +                /* fprintf(fp, "branch: |%s|\n", branchbuf); */
       +        }
       +
       +        git_branch_iterator_free(branchit);
       +
       +        return 0;
       +}
       +#endif
       +
       +int
       +main(int argc, char *argv[])
       +{
       +        int status;
       +        const git_error *e = NULL;
       +        FILE *fp;
       +
       +        if (argc != 2) {
       +                fprintf(stderr, "%s <repodir>\n", argv[0]);
       +                return 1;
       +        }
       +        repodir = argv[1];
       +
       +        git_libgit2_init();
       +
       +        if ((status = git_repository_open(&repo, repodir)) < 0) {
       +                e = giterr_last();
       +                fprintf(stderr, "error %d/%d: %s\n", status, e->klass, e->message);
       +                exit(status);
       +        }
       +
       +        fp = efopen("logs.html", "w+b");
       +        writeheader(fp);
       +        writelog(fp);
       +        writefooter(fp);
       +        fclose(fp);
       +
       +        fp = efopen("files.html", "w+b");
       +        writeheader(fp);
       +        writefiles(fp);
       +        writefooter(fp);
       +        fclose(fp);
       +
       +        /* cleanup */
       +        git_repository_free(repo);
       +        git_libgit2_shutdown();
       +
       +        return 0;
       +}