10 static git_repository *repo;
12 static const char *relpath;
13 static const char *repodir = ".";
15 static char name[255];
16 static char description[255];
17 static int hasreadme, haslicense;
20 efopen(const char *name, const char *flags)
24 fp = fopen(name, flags);
31 /* Escape characters below as HTML 2.0 / XML 1.0. */
33 xmlencode(FILE *fp, const char *s, size_t len)
37 for (i = 0; *s && i < len; s++, i++) {
39 case '<': fputs("<", fp); break;
40 case '>': fputs(">", fp); break;
41 case '\'': fputs("'", fp); break;
42 case '&': fputs("&", fp); break;
43 case '"': fputs(""", fp); break;
44 default: fputc(*s, fp);
49 /* Some implementations of basename(3) return a pointer to a static
50 * internal buffer (OpenBSD). Others modify the contents of `path` (POSIX).
51 * This is a wrapper function that is compatible with both versions.
52 * The program will error out if basename(3) failed, this can only happen
53 * with the OpenBSD version. */
55 xbasename(const char *path)
59 if (!(p = strdup(path)))
61 if (!(b = basename(p)))
71 printtime(FILE *fp, const git_time *intime, const char *prefix)
75 int offset, hours, minutes;
78 offset = intime->offset;
87 minutes = offset % 60;
89 t = (time_t) intime->time + (intime->offset * 60);
92 strftime(out, sizeof(out), "%a %b %e %T %Y", intm);
94 fprintf(fp, "%s%s %c%02d%02d\n", prefix, out, sign, hours, minutes);
98 printcommit(FILE *fp, git_commit *commit)
100 const git_signature *sig;
101 char buf[GIT_OID_HEXSZ + 1];
103 const char *scan, *eol;
105 git_oid_tostr(buf, sizeof(buf), git_commit_id(commit));
106 fprintf(fp, "commit <a href=\"commit/%s.html\">%s</a>\n", buf, buf);
108 if ((count = (int)git_commit_parentcount(commit)) > 1) {
109 fprintf(fp, "Merge:");
110 for (i = 0; i < count; ++i) {
111 git_oid_tostr(buf, 8, git_commit_parent_id(commit, i));
112 fprintf(fp, " %s", buf);
116 if ((sig = git_commit_author(commit)) != NULL) {
117 fprintf(fp, "Author: <a href=\"author/%s.html\">%s</a> <%s>\n",
118 sig->name, sig->name, sig->email);
119 printtime(fp, &sig->when, "Date: ");
123 for (scan = git_commit_message(commit); scan && *scan;) {
124 for (eol = scan; *eol && *eol != '\n'; ++eol) /* find eol */
127 fprintf(fp, " %.*s\n", (int) (eol - scan), scan);
128 scan = *eol ? eol + 1 : NULL;
134 printcommitdiff(FILE *fp, git_commit *commit)
136 const git_signature *sig;
137 char buf[GIT_OID_HEXSZ + 1];
139 const char *scan, *eol;
141 git_oid_tostr(buf, sizeof(buf), git_commit_id(commit));
142 fprintf(fp, "commit <a href=\"commit/%s.html\">%s</a>\n", buf, buf);
144 if ((count = (int)git_commit_parentcount(commit)) > 1) {
145 fprintf(fp, "Merge:");
146 for (i = 0; i < count; ++i) {
147 git_oid_tostr(buf, 8, git_commit_parent_id(commit, i));
148 fprintf(fp, " %s", buf);
152 if ((sig = git_commit_author(commit)) != NULL) {
153 fprintf(fp, "Author: <a href=\"author/%s.html\">%s</a> <%s>\n",
154 sig->name, sig->name, sig->email);
155 printtime(fp, &sig->when, "Date: ");
159 for (scan = git_commit_message(commit); scan && *scan;) {
160 for (eol = scan; *eol && *eol != '\n'; ++eol) /* find eol */
163 fprintf(fp, " %.*s\n", (int) (eol - scan), scan);
164 scan = *eol ? eol + 1 : NULL;
170 writeheader(FILE *fp)
172 fprintf(fp, "<!DOCTYPE HTML>"
173 "<html dir=\"ltr\" lang=\"en\"><head>"
174 "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />"
175 "<meta http-equiv=\"Content-Language\" content=\"en\" />");
176 fprintf(fp, "<title>%s%s%s</title>", name, description[0] ? " - " : "", description);
177 fprintf(fp, "<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />"
178 "</head><body><center>");
179 fprintf(fp, "<h1><img src=\"%slogo.png\" alt=\"\" /> %s</h1>", relpath, name);
180 fprintf(fp, "<span class=\"desc\">%s</span><br/>", description);
181 fprintf(fp, "<a href=\"%slog.html\">Log</a> |", relpath);
182 fprintf(fp, "<a href=\"%sfiles.html\">Files</a>| ", relpath);
183 fprintf(fp, "<a href=\"%sstats.html\">Stats</a>", relpath);
185 fprintf(fp, " | <a href=\"%sreadme.html\">README</a>", relpath);
187 fprintf(fp, " | <a href=\"%slicense.html\">LICENSE</a>", relpath);
188 fprintf(fp, "</center><hr/><pre>");
194 writefooter(FILE *fp)
196 fprintf(fp, "</pre></body></html>");
204 git_revwalk *w = NULL;
206 git_commit *c = NULL;
208 git_revwalk_new(&w, repo);
209 git_revwalk_push_head(w);
211 while (!git_revwalk_next(&id, w)) {
212 if (git_commit_lookup(&c, repo, &id))
226 const git_index_entry *entry;
229 git_repository_index(&index, repo);
231 count = git_index_entrycount(index);
232 for (i = 0; i < count; i++) {
233 entry = git_index_get_byindex(index, i);
234 fprintf(fp, "name: %s, size: %lu, mode: %lu\n",
235 entry->path, entry->file_size, entry->mode);
243 writebranches(FILE *fp)
245 git_branch_iterator *branchit = NULL;
246 git_branch_t branchtype;
247 git_reference *branchref;
248 char branchbuf[BUFSIZ] = "";
251 git_branch_iterator_new(&branchit, repo, GIT_BRANCH_LOCAL);
253 while ((status = git_branch_next(&branchref, &branchtype, branchit)) == GIT_ITEROVER) {
254 git_reference_normalize_name(branchbuf, sizeof(branchbuf), git_reference_name(branchref), GIT_REF_FORMAT_ALLOW_ONELEVEL | GIT_REF_FORMAT_REFSPEC_SHORTHAND);
256 /* fprintf(fp, "branch: |%s|\n", branchbuf); */
259 git_branch_iterator_free(branchit);
266 writeblobhtml(FILE *fp, const git_blob *blob)
268 xmlencode(fp, git_blob_rawcontent(blob), (size_t)git_blob_rawsize(blob));
272 main(int argc, char *argv[])
274 git_object *obj = NULL;
275 const git_error *e = NULL;
277 char path[PATH_MAX], *p;
281 fprintf(stderr, "%s <repodir>\n", argv[0]);
288 if ((status = git_repository_open(&repo, repodir)) < 0) {
290 fprintf(stderr, "error %d/%d: %s\n", status, e->klass, e->message);
294 /* use directory name as name */
295 p = xbasename(repodir);
296 snprintf(name, sizeof(name), "%s", p);
299 /* read description or .git/description */
300 snprintf(path, sizeof(path), "%s%s%s",
301 repodir, repodir[strlen(repodir)] == '/' ? "" : "/", "description");
302 if (!(fpread = fopen(path, "r+b"))) {
303 snprintf(path, sizeof(path), "%s%s%s",
304 repodir, repodir[strlen(repodir)] == '/' ? "" : "/", ".git/description");
305 fpread = fopen(path, "r+b");
308 if (!fgets(description, sizeof(description), fpread))
309 description[0] = '\0';
314 if (!git_revparse_single(&obj, repo, "HEAD:LICENSE")) {
315 fp = efopen("license.html", "w+b");
317 writeblobhtml(fp, (git_blob *)obj);
328 if (!git_revparse_single(&obj, repo, "HEAD:README")) {
329 fp = efopen("readme.html", "w+b");
331 writeblobhtml(fp, (git_blob *)obj);
340 fp = efopen("logs.html", "w+b");
346 fp = efopen("files.html", "w+b");
353 git_repository_free(repo);
354 git_libgit2_shutdown();