12 static git_repository *repo;
14 static const char *relpath = "";
15 static const char *repodir;
17 static char name[255];
18 static char description[255];
19 static int hasreadme, haslicense;
24 fprintf(fp, "<!DOCTYPE HTML>"
25 "<html dir=\"ltr\" lang=\"en\"><head>"
26 "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />"
27 "<meta http-equiv=\"Content-Language\" content=\"en\" />");
28 fprintf(fp, "<title>%s%s%s</title>", name, description[0] ? " - " : "", description);
29 fprintf(fp, "<link rel=\"icon\" type=\"image/png\" href=\"%sfavicon.png\" />", relpath);
30 fprintf(fp, "<link rel=\"alternate\" type=\"application/atom+xml\" title=\"%s Atom Feed\" href=\"%satom.xml\" />",
32 fprintf(fp, "<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />"
33 "</head><body><center>");
34 fprintf(fp, "<h1><img src=\"%slogo.png\" alt=\"\" /> %s</h1>", relpath, name);
35 fprintf(fp, "<span class=\"desc\">%s</span><br/>", description);
36 fprintf(fp, "<a href=\"%slog.html\">Log</a> |", relpath);
37 fprintf(fp, "<a href=\"%sfiles.html\">Files</a>| ", relpath);
38 fprintf(fp, "<a href=\"%sstats.html\">Stats</a>", relpath);
40 fprintf(fp, " | <a href=\"%sreadme.html\">README</a>", relpath);
42 fprintf(fp, " | <a href=\"%slicense.html\">LICENSE</a>", relpath);
43 fprintf(fp, "</center><hr/><pre>");
51 fprintf(fp, "</pre></body></html>");
57 efopen(const char *name, const char *flags)
61 fp = fopen(name, flags);
68 /* Escape characters below as HTML 2.0 / XML 1.0. */
70 xmlencode(FILE *fp, const char *s, size_t len)
74 for (i = 0; *s && i < len; s++, i++) {
76 case '<': fputs("<", fp); break;
77 case '>': fputs(">", fp); break;
78 case '\'': fputs("'", fp); break;
79 case '&': fputs("&", fp); break;
80 case '"': fputs(""", fp); break;
81 default: fputc(*s, fp);
86 /* Some implementations of basename(3) return a pointer to a static
87 * internal buffer (OpenBSD). Others modify the contents of `path` (POSIX).
88 * This is a wrapper function that is compatible with both versions.
89 * The program will error out if basename(3) failed, this can only happen
90 * with the OpenBSD version. */
92 xbasename(const char *path)
96 if (!(p = strdup(path)))
98 if (!(b = basename(p)))
100 if (!(b = strdup(b)))
108 printtime(FILE *fp, const git_time *intime)
112 int offset, hours, minutes;
115 offset = intime->offset;
124 minutes = offset % 60;
126 t = (time_t) intime->time + (intime->offset * 60);
129 strftime(out, sizeof(out), "%a %b %e %T %Y", intm);
131 fprintf(fp, "%s %c%02d%02d\n", out, sign, hours, minutes);
135 printcommit(FILE *fp, git_commit *commit)
137 const git_signature *sig;
138 char buf[GIT_OID_HEXSZ + 1];
140 const char *scan, *eol;
142 git_oid_tostr(buf, sizeof(buf), git_commit_id(commit));
143 fprintf(fp, "commit <a href=\"%scommit/%s.html\">%s</a>\n",
146 if (git_oid_tostr(buf, sizeof(buf), git_commit_parent_id(commit, 0)))
147 fprintf(fp, "parent <a href=\"%scommit/%s.html\">%s</a>\n",
150 if ((count = (int)git_commit_parentcount(commit)) > 1) {
151 fprintf(fp, "Merge:");
152 for (i = 0; i < count; ++i) {
153 git_oid_tostr(buf, 8, git_commit_parent_id(commit, i));
154 fprintf(fp, " <a href=\"%scommit/%s.html\">%s</a>",
159 if ((sig = git_commit_author(commit)) != NULL) {
160 fprintf(fp, "Author: ");
161 xmlencode(fp, sig->name, strlen(sig->name));
162 fprintf(fp, " <");
163 xmlencode(fp, sig->email, strlen(sig->email));
164 fprintf(fp, ">\nDate: ");
165 printtime(fp, &sig->when);
169 for (scan = git_commit_message(commit); scan && *scan;) {
170 for (eol = scan; *eol && *eol != '\n'; ++eol) /* find eol */
173 fprintf(fp, " %.*s\n", (int) (eol - scan), scan);
174 scan = *eol ? eol + 1 : NULL;
180 printshowfile(git_commit *commit)
182 const git_diff_delta *delta = NULL;
183 const git_diff_hunk *hunk = NULL;
184 const git_diff_line *line = NULL;
185 git_commit *parent = NULL;
186 git_tree *commit_tree = NULL, *parent_tree = NULL;
187 git_patch *patch = NULL;
188 git_diff *diff = NULL;
189 size_t i, j, k, ndeltas, nhunks = 0, nhunklines = 0;
190 char buf[GIT_OID_HEXSZ + 1], path[PATH_MAX];
194 git_oid_tostr(buf, sizeof(buf), git_commit_id(commit));
196 snprintf(path, sizeof(path), "commit/%s.html", buf);
197 fp = efopen(path, "w+b");
200 printcommit(fp, commit);
202 error = git_commit_parent(&parent, commit, 0);
206 error = git_commit_tree(&commit_tree, commit);
209 error = git_commit_tree(&parent_tree, parent);
213 error = git_diff_tree_to_tree(&diff, repo, commit_tree, parent_tree, NULL);
217 /* TODO: diff stat (files list and insertions/deletions) */
219 ndeltas = git_diff_num_deltas(diff);
220 for (i = 0; i < ndeltas; i++) {
221 if (git_patch_from_diff(&patch, diff, i)) {
222 git_patch_free(patch);
223 break; /* TODO: handle error */
226 delta = git_patch_get_delta(patch);
227 fprintf(fp, "diff --git a/<a href=\"%s%s\">%s</a> b/<a href=\"%s%s\">%s</a>\n",
228 relpath, delta->old_file.path, delta->old_file.path,
229 relpath, delta->new_file.path, delta->new_file.path);
232 switch (delta->flags) {
233 case GIT_DIFF_FLAG_BINARY: continue; /* TODO: binary data */
234 case GIT_DIFF_FLAG_NOT_BINARY: break;
235 case GIT_DIFF_FLAG_VALID_ID: break; /* TODO: check */
236 case GIT_DIFF_FLAG_EXISTS: break; /* TODO: check */
240 nhunks = git_patch_num_hunks(patch);
241 for (j = 0; j < nhunks; j++) {
242 if (git_patch_get_hunk(&hunk, &nhunklines, patch, j))
243 break; /* TODO: handle error ? */
245 fprintf(fp, "%s\n", hunk->header);
248 if (git_patch_get_line_in_hunk(&line, patch, j, k))
250 if (line->old_lineno == -1)
252 else if (line->new_lineno == -1)
256 xmlencode(fp, line->content, line->content_len);
259 git_patch_free(patch);
270 git_revwalk *w = NULL;
272 git_commit *c = NULL;
275 mkdir("commit", 0755);
277 git_revwalk_new(&w, repo);
278 git_revwalk_push_head(w);
281 while (!git_revwalk_next(&id, w)) {
282 if (git_commit_lookup(&c, repo, &id))
283 return 1; /* TODO: error */
302 git_revwalk *w = NULL;
304 git_commit *c = NULL;
306 git_revwalk_new(&w, repo);
307 git_revwalk_push_head(w);
309 while (!git_revwalk_next(&id, w)) {
310 if (git_commit_lookup(&c, repo, &id))
311 return 1; /* TODO: error */
326 const git_index_entry *entry;
329 git_repository_index(&index, repo);
331 count = git_index_entrycount(index);
332 for (i = 0; i < count; i++) {
333 entry = git_index_get_byindex(index, i);
334 fprintf(fp, "name: %s, size: %lu, mode: %lu\n",
335 entry->path, entry->file_size, entry->mode);
343 writebranches(FILE *fp)
345 git_branch_iterator *branchit = NULL;
346 git_branch_t branchtype;
347 git_reference *branchref;
348 char branchbuf[BUFSIZ] = "";
351 git_branch_iterator_new(&branchit, repo, GIT_BRANCH_LOCAL);
353 while ((status = git_branch_next(&branchref, &branchtype, branchit)) == GIT_ITEROVER) {
354 git_reference_normalize_name(branchbuf, sizeof(branchbuf),
355 git_reference_name(branchref),
356 GIT_REF_FORMAT_ALLOW_ONELEVEL | GIT_REF_FORMAT_REFSPEC_SHORTHAND);
358 /* fprintf(fp, "branch: |%s|\n", branchbuf); */
361 git_branch_iterator_free(branchit);
368 writeblobhtml(FILE *fp, const git_blob *blob)
370 xmlencode(fp, git_blob_rawcontent(blob), (size_t)git_blob_rawsize(blob));
374 main(int argc, char *argv[])
376 git_object *obj = NULL;
377 const git_error *e = NULL;
379 char path[PATH_MAX], *p;
383 fprintf(stderr, "%s <repodir>\n", argv[0]);
390 if ((status = git_repository_open(&repo, repodir)) < 0) {
392 fprintf(stderr, "error %d/%d: %s\n", status, e->klass, e->message);
396 /* use directory name as name */
397 p = xbasename(repodir);
398 snprintf(name, sizeof(name), "%s", p);
401 /* read description or .git/description */
402 snprintf(path, sizeof(path), "%s%s%s",
403 repodir, repodir[strlen(repodir)] == '/' ? "" : "/", "description");
404 if (!(fpread = fopen(path, "r+b"))) {
405 snprintf(path, sizeof(path), "%s%s%s",
406 repodir, repodir[strlen(repodir)] == '/' ? "" : "/", ".git/description");
407 fpread = fopen(path, "r+b");
410 if (!fgets(description, sizeof(description), fpread))
411 description[0] = '\0';
416 if (!git_revparse_single(&obj, repo, "HEAD:LICENSE")) {
417 fp = efopen("license.html", "w+b");
419 writeblobhtml(fp, (git_blob *)obj);
430 if (!git_revparse_single(&obj, repo, "HEAD:README")) {
431 fp = efopen("readme.html", "w+b");
433 writeblobhtml(fp, (git_blob *)obj);
442 fp = efopen("log.html", "w+b");
449 fp = efopen("atom.xml", "w+b");
454 fp = efopen("files.html", "w+b");
461 git_repository_free(repo);
462 git_libgit2_shutdown();