diff --git a/urmoms.c b/urmoms.c index 16096c7..cc7e400 100644 --- a/urmoms.c +++ b/urmoms.c @@ -1,3 +1,5 @@ +#include + #include #include #include @@ -9,13 +11,48 @@ static git_repository *repo; -static const char *relpath; -static const char *repodir = "."; +static const char *relpath = ""; +static const char *repodir; static char name[255]; static char description[255]; static int hasreadme, haslicense; +int +writeheader(FILE *fp) +{ + fprintf(fp, "" + "" + "" + ""); + fprintf(fp, "%s%s%s", name, description[0] ? " - " : "", description); + fprintf(fp, "", relpath); + fprintf(fp, "", + name, relpath); + fprintf(fp, "" + "
"); + fprintf(fp, "

\"\" %s

", relpath, name); + fprintf(fp, "%s
", description); + fprintf(fp, "Log |", relpath); + fprintf(fp, "Files| ", relpath); + fprintf(fp, "Stats", relpath); + if (hasreadme) + fprintf(fp, " | README", relpath); + if (haslicense) + fprintf(fp, " | LICENSE", relpath); + fprintf(fp, "

");
+
+	return 0;
+}
+
+int
+writefooter(FILE *fp)
+{
+	fprintf(fp, "
"); + + return 0; +} + FILE * efopen(const char *name, const char *flags) { @@ -67,8 +104,8 @@ xbasename(const char *path) return b; } -static void -printtime(FILE *fp, const git_time *intime, const char *prefix) +void +printtime(FILE *fp, const git_time *intime) { struct tm *intm; time_t t; @@ -91,10 +128,10 @@ printtime(FILE *fp, const git_time *intime, const char *prefix) 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); + fprintf(fp, "%s %c%02d%02d\n", out, sign, hours, minutes); } -static void +void printcommit(FILE *fp, git_commit *commit) { const git_signature *sig; @@ -103,22 +140,31 @@ printcommit(FILE *fp, git_commit *commit) const char *scan, *eol; git_oid_tostr(buf, sizeof(buf), git_commit_id(commit)); - fprintf(fp, "commit %s\n", buf, buf); + fprintf(fp, "commit %s\n", + relpath, buf, buf); + + if (git_oid_tostr(buf, sizeof(buf), git_commit_parent_id(commit, 0))) + fprintf(fp, "parent %s\n", + relpath, 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, " %s", + relpath, buf, buf); } - fprintf(fp, "\n"); + fputc('\n', fp); } if ((sig = git_commit_author(commit)) != NULL) { - fprintf(fp, "Author: %s <%s>\n", - sig->name, sig->name, sig->email); - printtime(fp, &sig->when, "Date: "); + fprintf(fp, "Author: "); + xmlencode(fp, sig->name, strlen(sig->name)); + fprintf(fp, " <"); + xmlencode(fp, sig->email, strlen(sig->email)); + fprintf(fp, ">\nDate: "); + printtime(fp, &sig->when); } - fprintf(fp, "\n"); + fputc('\n', fp); for (scan = git_commit_message(commit); scan && *scan;) { for (eol = scan; *eol && *eol != '\n'; ++eol) /* find eol */ @@ -127,79 +173,131 @@ printcommit(FILE *fp, git_commit *commit) fprintf(fp, " %.*s\n", (int) (eol - scan), scan); scan = *eol ? eol + 1 : NULL; } - fprintf(fp, "\n"); + fputc('\n', fp); } -static void -printcommitdiff(FILE *fp, git_commit *commit) +void +printshowfile(git_commit *commit) { - const git_signature *sig; - char buf[GIT_OID_HEXSZ + 1]; - int i, count; - const char *scan, *eol; + const git_diff_delta *delta = NULL; + const git_diff_hunk *hunk = NULL; + const git_diff_line *line = NULL; + git_commit *parent = NULL; + git_tree *commit_tree = NULL, *parent_tree = NULL; + git_patch *patch = NULL; + git_diff *diff = NULL; + size_t i, j, k, ndeltas, nhunks = 0, nhunklines = 0; + char buf[GIT_OID_HEXSZ + 1], path[PATH_MAX]; + FILE *fp; + int error; git_oid_tostr(buf, sizeof(buf), git_commit_id(commit)); - fprintf(fp, "commit %s\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); + snprintf(path, sizeof(path), "commit/%s.html", buf); + fp = efopen(path, "w+b"); + + writeheader(fp); + printcommit(fp, commit); + + error = git_commit_parent(&parent, commit, 0); + if (error) + return; + + error = git_commit_tree(&commit_tree, commit); + if (error) + return; + error = git_commit_tree(&parent_tree, parent); + if (error) + return; + + error = git_diff_tree_to_tree(&diff, repo, commit_tree, parent_tree, NULL); + if (error) + return; + + /* TODO: diff stat (files list and insertions/deletions) */ + + ndeltas = git_diff_num_deltas(diff); + for (i = 0; i < ndeltas; i++) { + if (git_patch_from_diff(&patch, diff, i)) { + git_patch_free(patch); + break; /* TODO: handle error */ } - fprintf(fp, "\n"); + + delta = git_patch_get_delta(patch); + fprintf(fp, "diff --git a/%s b/%s\n", + relpath, delta->old_file.path, delta->old_file.path, + relpath, delta->new_file.path, delta->new_file.path); + +#if 0 + switch (delta->flags) { + case GIT_DIFF_FLAG_BINARY: continue; /* TODO: binary data */ + case GIT_DIFF_FLAG_NOT_BINARY: break; + case GIT_DIFF_FLAG_VALID_ID: break; /* TODO: check */ + case GIT_DIFF_FLAG_EXISTS: break; /* TODO: check */ + } +#endif + + nhunks = git_patch_num_hunks(patch); + for (j = 0; j < nhunks; j++) { + if (git_patch_get_hunk(&hunk, &nhunklines, patch, j)) + break; /* TODO: handle error ? */ + + fprintf(fp, "%s\n", hunk->header); + + for (k = 0; ; k++) { + if (git_patch_get_line_in_hunk(&line, patch, j, k)) + break; + if (line->old_lineno == -1) + fputc('+', fp); + else if (line->new_lineno == -1) + fputc('-', fp); + else + fputc(' ', fp); + xmlencode(fp, line->content, line->content_len); + } + } + git_patch_free(patch); } - if ((sig = git_commit_author(commit)) != NULL) { - fprintf(fp, "Author: %s <%s>\n", - sig->name, sig->name, sig->email); - printtime(fp, &sig->when, "Date: "); - } - fprintf(fp, "\n"); + git_diff_free(diff); - 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, "" - "" - "" - ""); - fprintf(fp, "%s%s%s", name, description[0] ? " - " : "", description); - fprintf(fp, "" - "
"); - fprintf(fp, "

\"\" %s

", relpath, name); - fprintf(fp, "%s
", description); - fprintf(fp, "Log |", relpath); - fprintf(fp, "Files| ", relpath); - fprintf(fp, "Stats", relpath); - if (hasreadme) - fprintf(fp, " | README", relpath); - if (haslicense) - fprintf(fp, " | LICENSE", relpath); - fprintf(fp, "

");
-
-	return 0;
-}
-
-int
-writefooter(FILE *fp)
-{
-	fprintf(fp, "
"); - - return 0; + writefooter(fp); + fclose(fp); } int writelog(FILE *fp) +{ + git_revwalk *w = NULL; + git_oid id; + git_commit *c = NULL; + size_t i; + + mkdir("commit", 0755); + + git_revwalk_new(&w, repo); + git_revwalk_push_head(w); + + i = 0; + while (!git_revwalk_next(&id, w)) { + if (git_commit_lookup(&c, repo, &id)) + return 1; /* TODO: error */ + printcommit(fp, c); + printshowfile(c); + git_commit_free(c); + + /* DEBUG */ + i++; + if (i > 100) + break; + } + git_revwalk_free(w); + + return 0; +} + +#if 0 +int +writeatom(FILE *fp) { git_revwalk *w = NULL; git_oid id; @@ -210,14 +308,16 @@ writelog(FILE *fp) while (!git_revwalk_next(&id, w)) { if (git_commit_lookup(&c, repo, &id)) - return 1; + return 1; /* TODO: error */ printcommit(fp, c); + printshowfile(c); git_commit_free(c); } git_revwalk_free(w); return 0; } +#endif int writefiles(FILE *fp) @@ -251,7 +351,9 @@ writebranches(FILE *fp) 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); + 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); */ } @@ -337,12 +439,18 @@ main(int argc, char *argv[]) hasreadme = 1; } - fp = efopen("logs.html", "w+b"); + fp = efopen("log.html", "w+b"); writeheader(fp); writelog(fp); writefooter(fp); fclose(fp); +#if 0 + fp = efopen("atom.xml", "w+b"); + writeatom(fp); + fclose(fp); +#endif + fp = efopen("files.html", "w+b"); writeheader(fp); writefiles(fp);