stagit

rewrite in C with libgit2, first version

Hiltjo Posthuma contact@arjunchoudhary.com

commit: d5c477c parent: 0db9ba6
2 files changed, 222 insertions(+), 135 deletions(-)
Durmoms+0-135
Aurmoms.c+222-0
D · urmoms +0, -135
  1@@ -1,135 +0,0 @@
  2-#!/bin/sh
  3-
  4-# DEBUG
  5-#set -e -x
  6-
  7-usage() {
  8-	printf '%s <repodir> <htmldir>\n' "$0"
  9-	exit 1
 10-}
 11-
 12-header() {
 13-	cat <<!__EOF__
 14-<!DOCTYPE HTML>
 15-<html dir="ltr" lang="en">
 16-<head>
 17-<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 18-<meta http-equiv="Content-Language" content="en" />
 19-<title>${name} - ${description}</title>
 20-<link rel="stylesheet" type="text/css" href="style.css" />
 21-</head>
 22-<body>
 23-<center>
 24-<h1><img src="${relpath}logo.png" alt="" /> ${name}</h1>
 25-<span class="desc">${description}</span><br/>
 26-<a href="${relpath}log.html">Log</a> |
 27-<a href="${relpath}files.html">Files</a> |
 28-<a href="${relpath}stats.html">Stats</a> |
 29-<a href="${relpath}readme.html">README</a> |
 30-<a href="${relpath}license.html">LICENSE</a>
 31-</center>
 32-<hr/>
 33-<pre>
 34-!__EOF__
 35-}
 36-
 37-footer() {
 38-	cat <<!__EOF__
 39-</pre>
 40-</body>
 41-</html>
 42-!__EOF__
 43-}
 44-
 45-# usage: repodir and htmldir must be set.
 46-if test x"$1" = x"" || test x"$2" = x""; then
 47-	usage
 48-fi
 49-
 50-# make absolute path to htmldir.
 51-htmldir="$(readlink -f $2)"
 52-mkdir -p "${htmldir}"
 53-
 54-# repodir must be a directory to go to.
 55-cd "$1" || usage
 56-
 57-# default index page (symlink).
 58-indexpage="log.html"
 59-
 60-# project name, if bare repo remove .git suffix.
 61-name=$(basename "$(pwd)" ".git")
 62-
 63-# read .git/description.
 64-description=""
 65-test -f ".git/description" && description="$(cat '.git/description')"
 66-
 67-# make diff for each commit (all files).
 68-relpath="../"
 69-mkdir -p "${htmldir}/commit"
 70-git log --pretty='%H' | while read -r commit; do
 71-	test -e "${htmldir}/commit/${commit}.html" && continue
 72-
 73-	header > "${htmldir}/commit/${commit}.html"
 74-	git show --pretty=full "${commit}" | \
 75-		sed -E 's@^commit (.*)$@commit <a href="'${relpath}'commit/\1.html">\1</a>@g' >> "${htmldir}/commit/${commit}.html"
 76-	footer >> "${htmldir}/commit/${commit}.html"
 77-done 
 78-
 79-# make log with all commits.
 80-relpath=""
 81-header > "${htmldir}/log.html"
 82-printf '<table border="0">' >> "${htmldir}/log.html"
 83-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"
 84-printf '</table>' >> "${htmldir}/log.html"
 85-footer >> "${htmldir}/log.html"
 86-
 87-# make index with file links.
 88-relpath=""
 89-header >> "${htmldir}/files.html"
 90-printf '<table><tr><td><b>Mode</b></td><td><b>Name</b></td><td><b>Size</b></td><td></td></tr>' >> "${htmldir}/files.html"
 91-git ls-tree -r -l master | while read -r mode type object size file; do
 92-	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}"
 93-done >> "${htmldir}/files.html"
 94-printf '</table>' >> "${htmldir}/files.html"
 95-footer >> "${htmldir}/files.html"
 96-
 97-# readme page
 98-# find README file.
 99-relpath=""
100-readme=""
101-for f in README README.md readme.md; do
102-	test -e "${f}" && readme="${f}"
103-done
104-# make page.
105-header > "${htmldir}/readme.html"
106-if test x"${readme}" != x""; then
107-	cat "${readme}" >> "${htmldir}/readme.html"
108-else
109-	echo "no README file found" >> "${htmldir}/readme.html"
110-fi
111-footer >> "${htmldir}/readme.html"
112-
113-# license page
114-# find LICENSE file.
115-relpath=""
116-license=""
117-for f in LICENSE LICENSE.md; do
118-	test -e "${f}" && license="${f}"
119-done
120-# make page.
121-header > "${htmldir}/license.html"
122-if test x"${readme}" != x""; then
123-	cat "${license}" >> "${htmldir}/license.html"
124-else
125-	echo "unknown license" >> "${htmldir}/license.html"
126-fi
127-footer >> "${htmldir}/license.html"
128-
129-# stats (authors).
130-relpath=""
131-header > "${htmldir}/stats.html"
132-git shortlog -n -s >> "${htmldir}/stats.html"
133-footer >> "${htmldir}/stats.html"
134-
135-# symlink to index page.
136-ln -sf "$indexpage" "${htmldir}/index.html"
A · urmoms.c +222, -0
  1@@ -0,0 +1,222 @@
  2+#include <err.h>
  3+#include <stdio.h>
  4+#include <stdlib.h>
  5+
  6+#include "git2.h"
  7+
  8+static const char *relpath = "";
  9+static const char *name = "";
 10+static const char *description = "";
 11+
 12+static const char *repodir = ".";
 13+
 14+static git_repository *repo;
 15+
 16+FILE *
 17+efopen(const char *name, const char *flags)
 18+{
 19+	FILE *fp;
 20+
 21+	fp = fopen(name, flags);
 22+	if (!fp)
 23+		err(1, "fopen");
 24+
 25+	return fp;
 26+}
 27+
 28+static void
 29+printtime(FILE *fp, const git_time * intime, const char *prefix)
 30+{
 31+	struct tm *intm;
 32+	time_t t;
 33+	int offset, hours, minutes;
 34+	char sign, out[32];
 35+
 36+	offset = intime->offset;
 37+	if (offset < 0) {
 38+		sign = '-';
 39+		offset = -offset;
 40+	} else {
 41+		sign = '+';
 42+	}
 43+
 44+	hours = offset / 60;
 45+	minutes = offset % 60;
 46+
 47+	t = (time_t) intime->time + (intime->offset * 60);
 48+
 49+	intm = gmtime(&t);
 50+	strftime(out, sizeof(out), "%a %b %e %T %Y", intm);
 51+
 52+	fprintf(fp, "%s%s %c%02d%02d\n", prefix, out, sign, hours, minutes);
 53+}
 54+
 55+static void
 56+printcommit(FILE *fp, git_commit * commit)
 57+{
 58+	const git_signature *sig;
 59+	char buf[GIT_OID_HEXSZ + 1];
 60+	int i, count;
 61+	const char *scan, *eol;
 62+
 63+	git_oid_tostr(buf, sizeof(buf), git_commit_id(commit));
 64+	fprintf(fp, "commit <a href=\"commit/%s.html\">%s</a>\n", buf, buf);
 65+
 66+	if ((count = (int)git_commit_parentcount(commit)) > 1) {
 67+		fprintf(fp, "Merge:");
 68+		for (i = 0; i < count; ++i) {
 69+			git_oid_tostr(buf, 8, git_commit_parent_id(commit, i));
 70+			fprintf(fp, " %s", buf);
 71+		}
 72+		fprintf(fp, "\n");
 73+	}
 74+	if ((sig = git_commit_author(commit)) != NULL) {
 75+		fprintf(fp, "Author: <a href=\"author/%s.html\">%s</a> <%s>\n",
 76+			sig->name, sig->name, sig->email);
 77+		printtime(fp, &sig->when, "Date:   ");
 78+	}
 79+	fprintf(fp, "\n");
 80+
 81+	for (scan = git_commit_message(commit); scan && *scan;) {
 82+		for (eol = scan; *eol && *eol != '\n'; ++eol)	/* find eol */
 83+			;
 84+
 85+		fprintf(fp, "    %.*s\n", (int) (eol - scan), scan);
 86+		scan = *eol ? eol + 1 : NULL;
 87+	}
 88+	fprintf(fp, "\n");
 89+}
 90+
 91+int
 92+writeheader(FILE *fp)
 93+{
 94+	fprintf(fp, "<!DOCTYPE HTML>"
 95+		"<html dir=\"ltr\" lang=\"en\"><head>"
 96+		"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />"
 97+		"<meta http-equiv=\"Content-Language\" content=\"en\" />");
 98+	fprintf(fp, "<title>%s - %s</title>", name, description);
 99+	fprintf(fp, "<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />"
100+		"</head><body><center>");
101+	fprintf(fp, "<h1><img src=\"%slogo.png\" alt=\"\" /> %s</h1>", relpath, name);
102+	fprintf(fp, "<span class=\"desc\">%s</span><br/>", description);
103+	fprintf(fp, "<a href=\"%slog.html\">Log</a> |", relpath);
104+	fprintf(fp, "<a href=\"%sfiles.html\">Files</a>| ", relpath);
105+	fprintf(fp, "<a href=\"%sstats.html\">Stats</a> | ", relpath);
106+	fprintf(fp, "<a href=\"%sreadme.html\">README</a> | ", relpath);
107+	fprintf(fp, "<a href=\"%slicense.html\">LICENSE</a>", relpath);
108+	fprintf(fp, "</center><hr/><pre>");
109+
110+	return 0;
111+}
112+
113+int
114+writefooter(FILE *fp)
115+{
116+	fprintf(fp, "</pre></body></html>");
117+
118+	return 0;
119+}
120+
121+int
122+writelog(FILE *fp)
123+{
124+	git_revwalk *w = NULL;
125+	git_oid id;
126+	git_commit *c = NULL;
127+
128+	git_revwalk_new(&w, repo);
129+	git_revwalk_push_head(w);
130+
131+	while (!git_revwalk_next(&id, w)) {
132+		if (git_commit_lookup(&c, repo, &id))
133+			return 1;
134+		printcommit(fp, c);
135+		git_commit_free(c);
136+	}
137+	git_revwalk_free(w);
138+
139+	return 0;
140+}
141+
142+int
143+writefiles(FILE *fp)
144+{
145+	git_index *index;
146+	const git_index_entry *entry;
147+	size_t count, i;
148+
149+	git_repository_index(&index, repo);
150+
151+	count = git_index_entrycount(index);
152+	for (i = 0; i < count; i++) {
153+		entry = git_index_get_byindex(index, i);
154+		fprintf(fp, "name: %s, size: %lu, mode: %lu\n",
155+			entry->path, entry->file_size, entry->mode);
156+	}
157+
158+	return 0;
159+}
160+
161+#if 0
162+int
163+writebranches(FILE *fp)
164+{
165+	git_branch_iterator *branchit = NULL;
166+	git_branch_t branchtype;
167+	git_reference *branchref;
168+	char branchbuf[BUFSIZ] = "";
169+	int status;
170+
171+	git_branch_iterator_new(&branchit, repo, GIT_BRANCH_LOCAL);
172+
173+	while ((status = git_branch_next(&branchref, &branchtype, branchit)) == GIT_ITEROVER) {
174+		git_reference_normalize_name(branchbuf, sizeof(branchbuf), git_reference_name(branchref), GIT_REF_FORMAT_ALLOW_ONELEVEL | GIT_REF_FORMAT_REFSPEC_SHORTHAND);
175+
176+		/* fprintf(fp, "branch: |%s|\n", branchbuf); */
177+	}
178+
179+	git_branch_iterator_free(branchit);
180+
181+	return 0;
182+}
183+#endif
184+
185+int
186+main(int argc, char *argv[])
187+{
188+	int status;
189+	const git_error *e = NULL;
190+	FILE *fp;
191+
192+	if (argc != 2) {
193+		fprintf(stderr, "%s <repodir>\n", argv[0]);
194+		return 1;
195+	}
196+	repodir = argv[1];
197+
198+	git_libgit2_init();
199+
200+	if ((status = git_repository_open(&repo, repodir)) < 0) {
201+		e = giterr_last();
202+		fprintf(stderr, "error %d/%d: %s\n", status, e->klass, e->message);
203+		exit(status);
204+	}
205+
206+	fp = efopen("logs.html", "w+b");
207+	writeheader(fp);
208+	writelog(fp);
209+	writefooter(fp);
210+	fclose(fp);
211+
212+	fp = efopen("files.html", "w+b");
213+	writeheader(fp);
214+	writefiles(fp);
215+	writefooter(fp);
216+	fclose(fp);
217+
218+	/* cleanup */
219+	git_repository_free(repo);
220+	git_libgit2_shutdown();
221+
222+	return 0;
223+}