stagit

static git page generator
git clone git://git.2f30.org/stagit.git
Log | Files | Refs | README | LICENSE

commit 415e3fdd55b2ecdf2f35680694362a4b35fd1a05
parent bda4633633a0701bbd2f7861674a8e612d961fb7
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date:   Sat Dec  5 20:22:57 +0100

rewrite in C with libgit2, first version

Diffstat:
urmoms | 135-------------------------------------------------------------------------------
urmoms.c | 222+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 222 insertions(+), 135 deletions(-)
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" 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; +}