- commit
- 0b28d0832592ca51a81730779b917f63b42a1642
- parent
- b24cdfc14a898af0cca18bfb1be1fe825ae480aa
- Author
- Tobias Bengfort <tobias.bengfort@posteo.de>
- Date
- 2020-03-26 16:54
major refactoring
Diffstat
M | stagit.c | 922 | ++++++++++++++++++++++++++++--------------------------------- |
1 files changed, 417 insertions, 505 deletions
diff --git a/stagit.c b/stagit.c
@@ -28,28 +28,22 @@ struct deltainfo { 28 28 }; 29 29 30 30 struct commitinfo {31 -1 const git_oid *id;-1 31 git_commit *commit; 32 32 33 33 char oid[GIT_OID_HEXSZ + 1]; 34 34 char parentoid[GIT_OID_HEXSZ + 1]; 35 35 36 36 const git_signature *author; 37 37 const git_signature *committer;38 -1 const char *summary;39 -1 const char *msg;40 -141 -1 git_diff *diff;42 -1 git_commit *commit;43 -1 git_commit *parent;44 -1 git_tree *commit_tree;45 -1 git_tree *parent_tree;-1 38 const char *summary; -1 39 const char *msg; -1 40 }; 46 41 -1 42 struct commitstats { 47 43 size_t addcount; 48 44 size_t delcount;49 -1 size_t filecount;50 -151 -1 struct deltainfo **deltas;52 45 size_t ndeltas; -1 46 struct deltainfo **deltas; 53 47 }; 54 48 55 49 static git_repository *repo; @@ -57,19 +51,13 @@ static git_repository *repo; 57 51 static const char *relpath = ""; 58 52 static const char *repodir; 59 5360 -1 static char *name = "";61 -1 static char *strippedname = "";-1 54 /* reponame is a pointer into repodirabs */ -1 55 char repodirabs[PATH_MAX + 1]; -1 56 static char *reponame = ""; 62 57 static char description[255];63 -1 static char cloneurl[1024];-1 58 static char *cloneurl = "git@git.example.com:"; 64 59 static char *readmefiles[] = { "HEAD:README", "HEAD:README.md", "HEAD:README.rst" };65 -1 static char *readme;66 -1 static long long nlogcommits = -1; /* < 0 indicates not used */67 -168 -1 /* cache */69 -1 static git_oid lastoid;70 -1 static char lastoidstr[GIT_OID_HEXSZ + 2]; /* id + newline + NUL byte */71 -1 static FILE *rcachefp, *wcachefp;72 -1 static const char *cachefile;-1 60 static int force = 1; 73 61 74 62 void 75 63 joinpath(char *buf, size_t bufsiz, const char *path, const char *path2) @@ -125,22 +113,24 @@ deltainfo_free(struct deltainfo *di) 125 113 } 126 114 127 115 void128 -1 commitinfo_free(struct commitinfo *ci)-1 116 commitstats_free(struct commitstats *cs) 129 117 { 130 118 size_t i; -1 119 if (!cs) -1 120 return; -1 121 for (i = 0; i < cs->ndeltas; i++) -1 122 deltainfo_free(cs->deltas[i]); -1 123 free(cs->deltas); -1 124 memset(cs, 0, sizeof(*cs)); -1 125 free(cs); -1 126 } 131 127 -1 128 void -1 129 commitinfo_free(struct commitinfo *ci) -1 130 { 132 131 if (!ci) 133 132 return;134 -1 if (ci->deltas)135 -1 for (i = 0; i < ci->ndeltas; i++)136 -1 deltainfo_free(ci->deltas[i]);137 -1138 -1 free(ci->deltas);139 -1 git_diff_free(ci->diff);140 -1 git_tree_free(ci->commit_tree);141 -1 git_tree_free(ci->parent_tree);142 133 git_commit_free(ci->commit);143 -1 git_commit_free(ci->parent);144 134 memset(ci, 0, sizeof(*ci)); 145 135 free(ci); 146 136 } @@ -155,7 +145,6 @@ commitinfo_getbyoid(const git_oid *id) 155 145 156 146 if (git_commit_lookup(&(ci->commit), repo, id)) 157 147 goto err;158 -1 ci->id = id;159 148 160 149 git_oid_tostr(ci->oid, sizeof(ci->oid), git_commit_id(ci->commit)); 161 150 git_oid_tostr(ci->parentoid, sizeof(ci->parentoid), git_commit_parent_id(ci->commit, 0)); @@ -169,56 +158,84 @@ commitinfo_getbyoid(const git_oid *id) 169 158 170 159 err: 171 160 commitinfo_free(ci);172 -1173 161 return NULL; 174 162 } 175 163 176 164 int177 -1 commitinfo_getstats(struct commitinfo *ci)-1 165 git_commit_get_diff(git_diff **diff, git_commit *commit) 178 166 {179 -1 struct deltainfo *di;-1 167 git_commit *parent; -1 168 git_tree *commit_tree; -1 169 git_tree *parent_tree; 180 170 git_diff_options opts; 181 171 git_diff_find_options fopts;182 -1 const git_diff_delta *delta;183 -1 const git_diff_hunk *hunk;184 -1 const git_diff_line *line;185 -1 git_patch *patch = NULL;186 -1 size_t ndeltas, nhunks, nhunklines;187 -1 size_t i, j, k;188 172189 -1 if (git_tree_lookup(&(ci->commit_tree), repo, git_commit_tree_id(ci->commit)))-1 173 if (git_tree_lookup(&commit_tree, repo, git_commit_tree_id(commit))) 190 174 goto err;191 -1 if (!git_commit_parent(&(ci->parent), ci->commit, 0)) {192 -1 if (git_tree_lookup(&(ci->parent_tree), repo, git_commit_tree_id(ci->parent))) {193 -1 ci->parent = NULL;194 -1 ci->parent_tree = NULL;-1 175 if (!git_commit_parent(&parent, commit, 0)) { -1 176 if (git_tree_lookup(&parent_tree, repo, git_commit_tree_id(parent))) { -1 177 parent = NULL; -1 178 parent_tree = NULL; 195 179 } 196 180 } 197 181198 -1 git_diff_init_options(&opts, GIT_DIFF_OPTIONS_VERSION);199 -1 opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH |200 -1 GIT_DIFF_INCLUDE_TYPECHANGE;201 -1 if (git_diff_tree_to_tree(&(ci->diff), repo, ci->parent_tree, ci->commit_tree, &opts))-1 182 if (git_diff_init_options(&opts, GIT_DIFF_OPTIONS_VERSION)) 202 183 goto err; -1 184 opts.flags |= GIT_DIFF_DISABLE_PATHSPEC_MATCH | GIT_DIFF_INCLUDE_TYPECHANGE; -1 185 if (git_diff_tree_to_tree(diff, repo, parent_tree, commit_tree, &opts)) -1 186 goto err; -1 187 -1 188 git_tree_free(commit_tree); -1 189 git_tree_free(parent_tree); -1 190 git_commit_free(parent); 203 191 204 192 if (git_diff_find_init_options(&fopts, GIT_DIFF_FIND_OPTIONS_VERSION)) 205 193 goto err; 206 194 fopts.flags |= GIT_DIFF_FIND_RENAMES | GIT_DIFF_FIND_COPIES;207 -1 if (git_diff_find_similar(ci->diff, &fopts))-1 195 if (git_diff_find_similar(*diff, &fopts)) { -1 196 git_diff_free(*diff); 208 197 goto err; -1 198 } -1 199 -1 200 return 0; 209 201210 -1 ndeltas = git_diff_num_deltas(ci->diff);211 -1 if (ndeltas && !(ci->deltas = calloc(ndeltas, sizeof(struct deltainfo *))))-1 202 err: -1 203 git_tree_free(commit_tree); -1 204 git_tree_free(parent_tree); -1 205 git_commit_free(parent); -1 206 return -1; -1 207 } -1 208 -1 209 struct commitstats * -1 210 commitinfo_getstats(struct commitinfo *ci) -1 211 { -1 212 struct commitstats *cs; -1 213 struct deltainfo *di; -1 214 const git_diff_delta *delta; -1 215 const git_diff_hunk *hunk; -1 216 const git_diff_line *line; -1 217 git_diff *diff; -1 218 git_patch *patch = NULL; -1 219 size_t ndeltas, nhunks, nhunklines, i, j, k; -1 220 -1 221 if (!(cs = calloc(1, sizeof(struct commitstats)))) -1 222 err(1, "calloc"); -1 223 -1 224 if (git_commit_get_diff(&diff, ci->commit)) -1 225 goto err; -1 226 -1 227 ndeltas = git_diff_num_deltas(diff); -1 228 if (ndeltas && !(cs->deltas = calloc(ndeltas, sizeof(struct deltainfo *)))) 212 229 err(1, "calloc"); 213 230 214 231 for (i = 0; i < ndeltas; i++) {215 -1 if (git_patch_from_diff(&patch, ci->diff, i))216 -1 goto err;-1 232 if (git_patch_from_diff(&patch, diff, i)) -1 233 break; 217 234 218 235 if (!(di = calloc(1, sizeof(struct deltainfo)))) 219 236 err(1, "calloc"); 220 237 di->patch = patch;221 -1 ci->deltas[i] = di;-1 238 cs->deltas[i] = di; 222 239 223 240 delta = git_patch_get_delta(patch); 224 241 @@ -235,43 +252,22 @@ commitinfo_getstats(struct commitinfo *ci) 235 252 break; 236 253 if (line->old_lineno == -1) { 237 254 di->addcount++;238 -1 ci->addcount++;-1 255 cs->addcount++; 239 256 } else if (line->new_lineno == -1) { 240 257 di->delcount++;241 -1 ci->delcount++;-1 258 cs->delcount++; 242 259 } 243 260 } 244 261 } 245 262 }246 -1 ci->ndeltas = i;247 -1 ci->filecount = i;-1 263 cs->ndeltas = i; 248 264249 -1 return 0;-1 265 git_diff_free(diff); 250 266 251 267 err:252 -1 git_diff_free(ci->diff);253 -1 ci->diff = NULL;254 -1 git_tree_free(ci->commit_tree);255 -1 ci->commit_tree = NULL;256 -1 git_tree_free(ci->parent_tree);257 -1 ci->parent_tree = NULL;258 -1 git_commit_free(ci->parent);259 -1 ci->parent = NULL;260 -1261 -1 if (ci->deltas)262 -1 for (i = 0; i < ci->ndeltas; i++)263 -1 deltainfo_free(ci->deltas[i]);264 -1 free(ci->deltas);265 -1 ci->deltas = NULL;266 -1 ci->ndeltas = 0;267 -1 ci->addcount = 0;268 -1 ci->delcount = 0;269 -1 ci->filecount = 0;270 -1271 -1 return -1;-1 268 return cs; 272 269 } 273 270274 -1 /* Escape characters below as HTML 2.0 / XML 1.0. */275 271 void 276 272 xmlencode(FILE *fp, const char *s, size_t len) 277 273 { @@ -325,21 +321,21 @@ write_header(FILE *fp, const char *title) 325 321 "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n" 326 322 "<title>", fp); 327 323 xmlencode(fp, title, strlen(title));328 -1 if (title[0] && strippedname[0])-1 324 if (title[0] && reponame[0]) 329 325 fputs(" - ", fp);330 -1 xmlencode(fp, strippedname, strlen(strippedname));-1 326 xmlencode(fp, reponame, strlen(reponame)); 331 327 if (description[0]) 332 328 fputs(" - ", fp); 333 329 xmlencode(fp, description, strlen(description)); 334 330 fprintf(fp, "</title>\n<link rel=\"icon\" type=\"image/png\" href=\"%sfavicon.png\" />\n", relpath); 335 331 fprintf(fp, "<link rel=\"alternate\" type=\"application/atom+xml\" title=\"%s Atom Feed\" href=\"%satom.xml\" />\n",336 -1 name, relpath);-1 332 reponame, relpath); 337 333 fprintf(fp, "<link rel=\"stylesheet\" type=\"text/css\" href=\"%sstyle.css\" />\n", relpath); 338 334 fputs("</head>\n<body>\n<table><tr><td>", fp); 339 335 fprintf(fp, "<a href=\"../%s\"><img src=\"%slogo.png\" alt=\"\" width=\"32\" height=\"32\" /></a>", 340 336 relpath, relpath); 341 337 fputs("</td><td><h1>", fp);342 -1 xmlencode(fp, strippedname, strlen(strippedname));-1 338 xmlencode(fp, reponame, strlen(reponame)); 343 339 fputs("</h1><span class=\"desc\">", fp); 344 340 xmlencode(fp, description, strlen(description)); 345 341 fputs("</span></td></tr>", fp); @@ -382,8 +378,107 @@ write_readme(FILE *fp, const git_blob *blob) 382 378 } 383 379 384 380 void -1 381 write_commit_statline(FILE *fp, struct deltainfo *di, size_t i) -1 382 { -1 383 char c; -1 384 int total; -1 385 size_t j; -1 386 const git_diff_delta *delta; -1 387 -1 388 delta = git_patch_get_delta(di->patch); -1 389 -1 390 switch (delta->status) { -1 391 case GIT_DELTA_ADDED: c = 'A'; break; -1 392 case GIT_DELTA_COPIED: c = 'C'; break; -1 393 case GIT_DELTA_DELETED: c = 'D'; break; -1 394 case GIT_DELTA_MODIFIED: c = 'M'; break; -1 395 case GIT_DELTA_RENAMED: c = 'R'; break; -1 396 case GIT_DELTA_TYPECHANGE: c = 'T'; break; -1 397 default: c = ' '; break; -1 398 } -1 399 -1 400 fputs("<tr>\n", fp); -1 401 fprintf(fp, "<td class=\"%c\">%c</td>\n", c, c); -1 402 fprintf(fp, "<td><a href=\"#h%zu\">", i); -1 403 xmlencode(fp, delta->old_file.path, strlen(delta->old_file.path)); -1 404 if (strcmp(delta->old_file.path, delta->new_file.path)) { -1 405 fputs(" -> ", fp); -1 406 xmlencode(fp, delta->new_file.path, strlen(delta->new_file.path)); -1 407 } -1 408 fputs("</a></td>\n", fp); -1 409 -1 410 total = di->addcount + di->delcount; -1 411 fprintf(fp, "<td class=\"num\">%i</td>\n", total); -1 412 fputs("<td><span class=\"i\">", fp); -1 413 for (j = 0; j < di->addcount && j * total < di->addcount * 60; j++) -1 414 fputc('+', fp); -1 415 fputs("</span><span class=\"d\">", fp); -1 416 for (j = 0; j < di->delcount && j * total < di->delcount * 60; j++) -1 417 fputc('-', fp); -1 418 -1 419 fputs("</tr>\n", fp); -1 420 } -1 421 -1 422 void -1 423 write_commit_file(FILE *fp, struct deltainfo *di, size_t i) -1 424 { -1 425 const git_diff_delta *delta; -1 426 const git_diff_hunk *hunk; -1 427 const git_diff_line *line; -1 428 size_t nhunks, nhunklines, j, k; -1 429 -1 430 delta = git_patch_get_delta(di->patch); -1 431 nhunks = git_patch_num_hunks(di->patch); -1 432 -1 433 fprintf(fp, "<h2 id=\"h%zu\">\n", i); -1 434 fprintf(fp, "<b>diff --git a/<a id=\"h%zu\" href=\"%sfile/", i, relpath); -1 435 xmlencode(fp, delta->old_file.path, strlen(delta->old_file.path)); -1 436 fputs(".html\">", fp); -1 437 xmlencode(fp, delta->old_file.path, strlen(delta->old_file.path)); -1 438 fprintf(fp, "</a> b/<a href=\"%sfile/", relpath); -1 439 xmlencode(fp, delta->new_file.path, strlen(delta->new_file.path)); -1 440 fprintf(fp, ".html\">"); -1 441 xmlencode(fp, delta->new_file.path, strlen(delta->new_file.path)); -1 442 fprintf(fp, "</a></b>\n"); -1 443 -1 444 if (delta->flags & GIT_DIFF_FLAG_BINARY) { -1 445 fputs("Binary files differ.\n", fp); -1 446 return; -1 447 } -1 448 -1 449 if (nhunks == 0) -1 450 return; -1 451 -1 452 for (j = 0; j < nhunks; j++) { -1 453 if (git_patch_get_hunk(&hunk, &nhunklines, di->patch, j)) -1 454 break; -1 455 fprintf(fp, "<a href=\"#h%zu-%zu\" id=\"h%zu-%zu\" class=\"h\">", i, j, i, j); -1 456 xmlencode(fp, hunk->header, hunk->header_len - 1); -1 457 fputs("</a>\n", fp); -1 458 for (k = 0; k < nhunklines; k++) { -1 459 if (git_patch_get_line_in_hunk(&line, di->patch, j, k)) -1 460 break; -1 461 if (line->old_lineno == -1) -1 462 fprintf(fp, "<a href=\"#h%zu-%zu-%zu\" id=\"h%zu-%zu-%zu\" class=\"i\">+", -1 463 i, j, k, i, j, k); -1 464 else if (line->new_lineno == -1) -1 465 fprintf(fp, "<a href=\"#h%zu-%zu-%zu\" id=\"h%zu-%zu-%zu\" class=\"d\">-", -1 466 i, j, k, i, j, k); -1 467 else -1 468 fputc(' ', fp); -1 469 xmlencode(fp, line->content, line->content_len); -1 470 if (line->old_lineno == -1 || line->new_lineno == -1) -1 471 fputs("</a>", fp); -1 472 } -1 473 } -1 474 } -1 475 -1 476 void 385 477 write_commit(FILE *fp, struct commitinfo *ci) 386 478 { -1 479 size_t i; -1 480 struct commitstats *cs = commitinfo_getstats(ci); -1 481 387 482 fprintf(fp, "<b>commit</b> <a href=\"%scommit/%s.html\">%s</a>\n", 388 483 relpath, ci->oid, ci->oid); 389 484 @@ -407,130 +502,51 @@ write_commit(FILE *fp, struct commitinfo *ci) 407 502 xmlencode(fp, ci->msg, strlen(ci->msg)); 408 503 fputc('\n', fp); 409 504 }410 -1 }411 -1412 -1 void413 -1 write_commit_file(FILE *fp, struct commitinfo *ci)414 -1 {415 -1 const git_diff_delta *delta;416 -1 const git_diff_hunk *hunk;417 -1 const git_diff_line *line;418 -1 git_patch *patch;419 -1 size_t nhunks, nhunklines, changed, add, del, total, i, j, k;420 -1 char linestr[80];421 -1 int c;422 -1423 -1 write_commit(fp, ci);424 505425 -1 if (!ci->deltas)426 -1 return;-1 506 if (!cs->deltas) -1 507 goto err; 427 508428 -1 if (ci->filecount > 1000 ||429 -1 ci->ndeltas > 1000 ||430 -1 ci->addcount > 100000 ||431 -1 ci->delcount > 100000) {-1 509 if ( -1 510 cs->ndeltas > 1000 || -1 511 cs->addcount > 100000 || -1 512 cs->delcount > 100000 -1 513 ) { 432 514 fputs("Diff is too large, output suppressed.\n", fp);433 -1 return;-1 515 goto err; 434 516 } 435 517436 -1 /* diff stat */437 -1 fputs("<b>Diffstat:</b>\n<table>", fp);438 -1 for (i = 0; i < ci->ndeltas; i++) {439 -1 delta = git_patch_get_delta(ci->deltas[i]->patch);440 -1441 -1 switch (delta->status) {442 -1 case GIT_DELTA_ADDED: c = 'A'; break;443 -1 case GIT_DELTA_COPIED: c = 'C'; break;444 -1 case GIT_DELTA_DELETED: c = 'D'; break;445 -1 case GIT_DELTA_MODIFIED: c = 'M'; break;446 -1 case GIT_DELTA_RENAMED: c = 'R'; break;447 -1 case GIT_DELTA_TYPECHANGE: c = 'T'; break;448 -1 default: c = ' '; break;449 -1 }450 -1 if (c == ' ')451 -1 fprintf(fp, "<tr><td>%c", c);452 -1 else453 -1 fprintf(fp, "<tr><td class=\"%c\">%c", c, c);454 -1455 -1 fprintf(fp, "</td><td><a href=\"#h%zu\">", i);456 -1 xmlencode(fp, delta->old_file.path, strlen(delta->old_file.path));457 -1 if (strcmp(delta->old_file.path, delta->new_file.path)) {458 -1 fputs(" -> ", fp);459 -1 xmlencode(fp, delta->new_file.path, strlen(delta->new_file.path));460 -1 }-1 518 fputs("<h2>Diffstat</h2>\n", fp); -1 519 fputs("<table>\n", fp); 461 520462 -1 add = ci->deltas[i]->addcount;463 -1 del = ci->deltas[i]->delcount;464 -1 changed = add + del;465 -1 total = sizeof(linestr) - 2;466 -1 if (changed > total) {467 -1 if (add)468 -1 add = ((float)total / changed * add) + 1;469 -1 if (del)470 -1 del = ((float)total / changed * del) + 1;471 -1 }472 -1 memset(&linestr, '+', add);473 -1 memset(&linestr[add], '-', del);474 -1475 -1 fprintf(fp, "</a></td><td> | </td><td class=\"num\">%zu</td><td><span class=\"i\">",476 -1 ci->deltas[i]->addcount + ci->deltas[i]->delcount);477 -1 fwrite(&linestr, 1, add, fp);478 -1 fputs("</span><span class=\"d\">", fp);479 -1 fwrite(&linestr[add], 1, del, fp);480 -1 fputs("</span></td></tr>\n", fp);-1 521 for (i = 0; i < cs->ndeltas; i++) { -1 522 write_commit_statline(fp, cs->deltas[i], i); 481 523 } 482 524 fprintf(fp, "</table></pre><pre>%zu file%s changed, %zu insertion%s(+), %zu deletion%s(-)\n",483 -1 ci->filecount, ci->filecount == 1 ? "" : "s",484 -1 ci->addcount, ci->addcount == 1 ? "" : "s",485 -1 ci->delcount, ci->delcount == 1 ? "" : "s");-1 525 cs->ndeltas, cs->ndeltas == 1 ? "" : "s", -1 526 cs->addcount, cs->addcount == 1 ? "" : "s", -1 527 cs->delcount, cs->delcount == 1 ? "" : "s"); 486 528 -1 529 fputs("</table>\n", fp); -1 530 fputs("<p>", fp); -1 531 fputs("</p>\n", fp); 487 532 fputs("<hr/>", fp); 488 533489 -1 for (i = 0; i < ci->ndeltas; i++) {490 -1 patch = ci->deltas[i]->patch;491 -1 delta = git_patch_get_delta(patch);492 -1 fprintf(fp, "<b>diff --git a/<a id=\"h%zu\" href=\"%sfile/", i, relpath);493 -1 xmlencode(fp, delta->old_file.path, strlen(delta->old_file.path));494 -1 fputs(".html\">", fp);495 -1 xmlencode(fp, delta->old_file.path, strlen(delta->old_file.path));496 -1 fprintf(fp, "</a> b/<a href=\"%sfile/", relpath);497 -1 xmlencode(fp, delta->new_file.path, strlen(delta->new_file.path));498 -1 fprintf(fp, ".html\">");499 -1 xmlencode(fp, delta->new_file.path, strlen(delta->new_file.path));500 -1 fprintf(fp, "</a></b>\n");501 -1502 -1 /* check binary data */503 -1 if (delta->flags & GIT_DIFF_FLAG_BINARY) {504 -1 fputs("Binary files differ.\n", fp);505 -1 continue;506 -1 }507 -1508 -1 nhunks = git_patch_num_hunks(patch);509 -1 for (j = 0; j < nhunks; j++) {510 -1 if (git_patch_get_hunk(&hunk, &nhunklines, patch, j))511 -1 break;-1 534 for (i = 0; i < cs->ndeltas; i++) { -1 535 write_commit_file(fp, cs->deltas[i], i); -1 536 } 512 537513 -1 fprintf(fp, "<a href=\"#h%zu-%zu\" id=\"h%zu-%zu\" class=\"h\">", i, j, i, j);514 -1 xmlencode(fp, hunk->header, hunk->header_len);515 -1 fputs("</a>", fp);-1 538 err: -1 539 commitstats_free(cs); -1 540 } 516 541517 -1 for (k = 0; ; k++) {518 -1 if (git_patch_get_line_in_hunk(&line, patch, j, k))519 -1 break;520 -1 if (line->old_lineno == -1)521 -1 fprintf(fp, "<a href=\"#h%zu-%zu-%zu\" id=\"h%zu-%zu-%zu\" class=\"i\">+",522 -1 i, j, k, i, j, k);523 -1 else if (line->new_lineno == -1)524 -1 fprintf(fp, "<a href=\"#h%zu-%zu-%zu\" id=\"h%zu-%zu-%zu\" class=\"d\">-",525 -1 i, j, k, i, j, k);526 -1 else527 -1 fputc(' ', fp);528 -1 xmlencode(fp, line->content, line->content_len);529 -1 if (line->old_lineno == -1 || line->new_lineno == -1)530 -1 fputs("</a>", fp);531 -1 }532 -1 }533 -1 }-1 542 void -1 543 write_log_header(FILE *fp) -1 544 { -1 545 fputs("<table id=\"log\">\n", fp); -1 546 fputs("<thead>\n", fp); -1 547 fputs("<tr><th>Date</th><th class=\"text\">Commit message</th><th>Author</th></tr>\n", fp); -1 548 fputs("</thead>\n", fp); -1 549 fputs("<tbody>\n", fp); 534 550 } 535 551 536 552 void @@ -548,85 +564,26 @@ write_log_line(FILE *fp, struct commitinfo *ci) 548 564 fputs("</td><td>", fp); 549 565 if (ci->author) 550 566 xmlencode(fp, ci->author->name, strlen(ci->author->name));551 -1 fputs("</td><td class=\"num\" align=\"right\">", fp);552 -1 fprintf(fp, "%zu", ci->filecount);553 -1 fputs("</td><td class=\"num\" align=\"right\">", fp);554 -1 fprintf(fp, "+%zu", ci->addcount);555 -1 fputs("</td><td class=\"num\" align=\"right\">", fp);556 -1 fprintf(fp, "-%zu", ci->delcount);557 567 fputs("</td></tr>\n", fp); 558 568 } 559 569560 -1 int561 -1 write_log(FILE *fp, const git_oid *oid)-1 570 void -1 571 write_log_footer(FILE *fp) 562 572 {563 -1 struct commitinfo *ci;564 -1 git_revwalk *w = NULL;565 -1 git_oid id;566 -1 char path[PATH_MAX], oidstr[GIT_OID_HEXSZ + 1];567 -1 FILE *fpfile;568 -1 int r;569 -1570 -1 git_revwalk_new(&w, repo);571 -1 git_revwalk_push(w, oid);572 -1 git_revwalk_simplify_first_parent(w);573 -1574 -1 while (!git_revwalk_next(&id, w)) {575 -1 relpath = "";576 -1577 -1 if (cachefile && !memcmp(&id, &lastoid, sizeof(id)))578 -1 break;579 -1580 -1 git_oid_tostr(oidstr, sizeof(oidstr), &id);581 -1 r = snprintf(path, sizeof(path), "commit/%s.html", oidstr);582 -1 if (r < 0 || (size_t)r >= sizeof(path))583 -1 errx(1, "path truncated: 'commit/%s.html'", oidstr);584 -1 r = access(path, F_OK);585 -1586 -1 /* optimization: if there are no log lines to write and587 -1 the commit file already exists: skip the diffstat */588 -1 if (!nlogcommits && !r)589 -1 continue;590 -1591 -1 if (!(ci = commitinfo_getbyoid(&id)))592 -1 break;593 -1 /* diffstat: for stagit HTML required for the log.html line */594 -1 if (commitinfo_getstats(ci) == -1)595 -1 goto err;596 -1597 -1 if (nlogcommits < 0) {598 -1 write_log_line(fp, ci);599 -1 } else if (nlogcommits > 0) {600 -1 write_log_line(fp, ci);601 -1 nlogcommits--;602 -1 if (!nlogcommits && ci->parentoid[0])603 -1 fputs("<tr><td></td><td colspan=\"5\">"604 -1 "More commits remaining [...]</td>"605 -1 "</tr>\n", fp);606 -1 }607 -1608 -1 if (cachefile)609 -1 write_log_line(wcachefp, ci);610 -1611 -1 /* check if file exists if so skip it */612 -1 if (r) {613 -1 relpath = "../";614 -1 fpfile = efopen(path, "w");615 -1 write_header(fpfile, ci->summary);616 -1 fputs("<pre>", fpfile);617 -1 write_commit_file(fpfile, ci);618 -1 fputs("</pre>\n", fpfile);619 -1 write_footer(fpfile);620 -1 fclose(fpfile);621 -1 }622 -1 err:623 -1 commitinfo_free(ci);624 -1 }625 -1 git_revwalk_free(w);626 -1627 -1 relpath = "";-1 573 fputs("</tbody>\n", fp); -1 574 fputs("</table>\n", fp); -1 575 } 628 576629 -1 return 0;-1 577 void -1 578 write_atom_header(FILE *fp) -1 579 { -1 580 fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", fp); -1 581 fputs("<feed xmlns=\"http://www.w3.org/2005/Atom\">\n", fp); -1 582 fputs("<title>", fp); -1 583 xmlencode(fp, reponame, strlen(reponame)); -1 584 fputs(", branch HEAD</title>\n<subtitle>", fp); -1 585 xmlencode(fp, description, strlen(description)); -1 586 fputs("</subtitle>\n", fp); 630 587 } 631 588 632 589 void @@ -650,8 +607,7 @@ write_atom_entry(FILE *fp, struct commitinfo *ci) 650 607 xmlencode(fp, ci->summary, strlen(ci->summary)); 651 608 fputs("</title>\n", fp); 652 609 }653 -1 fprintf(fp, "<link rel=\"alternate\" type=\"text/html\" href=\"commit/%s.html\" />\n",654 -1 ci->oid);-1 610 fprintf(fp, "<link rel=\"alternate\" type=\"text/html\" href=\"commit/%s.html\" />\n", ci->oid); 655 611 656 612 if (ci->author) { 657 613 fputs("<author>\n<name>", fp); @@ -669,65 +625,84 @@ write_atom_entry(FILE *fp, struct commitinfo *ci) 669 625 fputs("</entry>\n", fp); 670 626 } 671 627672 -1 int673 -1 write_atom(FILE *fp)-1 628 void -1 629 write_atom_footer(FILE *fp) 674 630 {675 -1 struct commitinfo *ci;676 -1 git_revwalk *w = NULL;677 -1 git_oid id;678 -1 size_t i, m = 100; /* last 'm' commits */679 -1680 -1 fputs("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"681 -1 "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n<title>", fp);682 -1 xmlencode(fp, strippedname, strlen(strippedname));683 -1 fputs(", branch HEAD</title>\n<subtitle>", fp);684 -1 xmlencode(fp, description, strlen(description));685 -1 fputs("</subtitle>\n", fp);686 -1687 -1 git_revwalk_new(&w, repo);688 -1 git_revwalk_push_head(w);689 -1 git_revwalk_simplify_first_parent(w);690 -1691 -1 for (i = 0; i < m && !git_revwalk_next(&id, w); i++) {692 -1 if (!(ci = commitinfo_getbyoid(&id)))693 -1 break;694 -1 write_atom_entry(fp, ci);695 -1 commitinfo_free(ci);696 -1 }697 -1 git_revwalk_free(w);698 -1699 631 fputs("</feed>\n", fp);700 -1701 -1 return 0;702 632 } 703 633704 -1 int705 -1 copy_blob(git_object *obj, const char *fpath, const char *filename, git_off_t filesize)-1 634 void -1 635 copy_blob(git_object *obj, const char *fpath) 706 636 {707 -1 char tmp[PATH_MAX] = "", *d;708 -1 int lc = 0;-1 637 char tmp[PATH_MAX] = ""; -1 638 char *d; 709 639 git_off_t len; 710 640 const void *raw; 711 641 FILE *fp; 712 642 713 643 if (strlcpy(tmp, fpath, sizeof(tmp)) >= sizeof(tmp)) 714 644 errx(1, "path truncated: '%s'", fpath); -1 645 715 646 if (!(d = dirname(tmp))) 716 647 err(1, "dirname"); 717 648 if (mkdirp(d))718 -1 return -1;-1 649 return; 719 650 720 651 fp = efopen(fpath, "w"); 721 652 len = git_blob_rawsize((git_blob *)obj); 722 653 raw = git_blob_rawcontent((git_blob *)obj); 723 654 fwrite(raw, 1, len, fp); 724 655 fclose(fp); -1 656 } -1 657 -1 658 void -1 659 write_files_header(FILE *fp) -1 660 { -1 661 fputs("<table id=\"files\"><thead>\n<tr>" -1 662 "<td><b>Name</b></td>" -1 663 "<td class=\"num\" align=\"right\"><b>Size</b></td>" -1 664 "</tr>\n</thead><tbody>\n", fp); -1 665 } -1 666 -1 667 void -1 668 write_files_line(FILE *fp, char *entrypath, char *filepath, uintmax_t size) -1 669 { -1 670 fprintf(fp, "<tr><td><a href=\"%s", relpath); -1 671 xmlencode(fp, filepath, strlen(filepath)); -1 672 fputs("\">", fp); -1 673 xmlencode(fp, entrypath, strlen(entrypath)); -1 674 fputs("</a></td><td class=\"num\" align=\"right\">", fp); -1 675 fprintf(fp, "%juB", (uintmax_t)size); -1 676 fputs("</td></tr>\n", fp); -1 677 } -1 678 -1 679 void -1 680 write_files_footer(FILE *fp) -1 681 { -1 682 fputs("</tbody>\n", fp); -1 683 fputs("</table>\n", fp); -1 684 } -1 685 -1 686 void -1 687 process_readme(FILE *fp) -1 688 { -1 689 int i; -1 690 git_object *obj = NULL; 725 691726 -1 return lc;-1 692 for (i = 0; i < sizeof(readmefiles) / sizeof(*readmefiles); i++) { -1 693 if ( -1 694 !git_revparse_single(&obj, repo, readmefiles[i]) && -1 695 git_object_type(obj) == GIT_OBJ_BLOB -1 696 ) { -1 697 write_readme(fp, (git_blob *)obj); -1 698 break; -1 699 } -1 700 git_object_free(obj); -1 701 } 727 702 } 728 703 729 704 int730 -1 writefilestree(FILE *fp, git_tree *tree, const char *path)-1 705 _process_files(FILE *fp, git_tree *tree, const char *path) 731 706 { 732 707 const git_tree_entry *entry = NULL; 733 708 git_object *obj = NULL; @@ -735,19 +710,17 @@ writefilestree(FILE *fp, git_tree *tree, const char *path) 735 710 const char *entryname; 736 711 char filepath[PATH_MAX], entrypath[PATH_MAX]; 737 712 size_t count, i;738 -1 int lc, r, ret;-1 713 int ret; 739 714 740 715 count = git_tree_entrycount(tree); 741 716 for (i = 0; i < count; i++) {742 -1 if (!(entry = git_tree_entry_byindex(tree, i)) ||743 -1 !(entryname = git_tree_entry_name(entry)))-1 717 if ( -1 718 !(entry = git_tree_entry_byindex(tree, i)) || -1 719 !(entryname = git_tree_entry_name(entry)) -1 720 ) 744 721 return -1; 745 722 joinpath(entrypath, sizeof(entrypath), path, entryname);746 -1747 -1 r = snprintf(filepath, sizeof(filepath), "file/%s",748 -1 entrypath);749 -1 if (r < 0 || (size_t)r >= sizeof(filepath))750 -1 errx(1, "path truncated: 'file/%s.html'", entrypath);-1 723 joinpath(filepath, sizeof(filepath), "blob", entrypath); 751 724 752 725 if (!git_tree_entry_to_object(&obj, repo, entry)) { 753 726 switch (git_object_type(obj)) { @@ -755,8 +728,7 @@ writefilestree(FILE *fp, git_tree *tree, const char *path) 755 728 break; 756 729 case GIT_OBJ_TREE: 757 730 /* NOTE: recurses */758 -1 ret = writefilestree(fp, (git_tree *)obj,759 -1 entrypath);-1 731 ret = _process_files(fp, (git_tree *)obj, entrypath); 760 732 git_object_free(obj); 761 733 if (ret) 762 734 return ret; @@ -766,19 +738,11 @@ writefilestree(FILE *fp, git_tree *tree, const char *path) 766 738 continue; 767 739 } 768 740 -1 741 copy_blob(obj, filepath); -1 742 769 743 filesize = git_blob_rawsize((git_blob *)obj);770 -1 lc = copy_blob(obj, filepath, entryname, filesize);771 -1772 -1 fprintf(fp, "<tr><td><a href=\"%s", relpath);773 -1 xmlencode(fp, filepath, strlen(filepath));774 -1 fputs("\">", fp);775 -1 xmlencode(fp, entrypath, strlen(entrypath));776 -1 fputs("</a></td><td class=\"num\" align=\"right\">", fp);777 -1 if (lc > 0)778 -1 fprintf(fp, "%dL", lc);779 -1 else780 -1 fprintf(fp, "%juB", (uintmax_t)filesize);781 -1 fputs("</td></tr>\n", fp);-1 744 write_files_line(fp, entrypath, filepath, filesize); -1 745 782 746 git_object_free(obj); 783 747 } 784 748 } @@ -787,22 +751,25 @@ writefilestree(FILE *fp, git_tree *tree, const char *path) 787 751 } 788 752 789 753 int790 -1 write_files(FILE *fp, const git_oid *id)-1 754 process_files(FILE *fp) 791 755 { 792 756 git_tree *tree = NULL; 793 757 git_commit *commit = NULL; -1 758 git_object *obj = NULL; -1 759 const git_oid *head = NULL; 794 760 int ret = -1; 795 761796 -1 fputs("<table id=\"files\"><thead>\n<tr>"797 -1 "<td><b>Name</b></td>"798 -1 "<td class=\"num\" align=\"right\"><b>Size</b></td>"799 -1 "</tr>\n</thead><tbody>\n", fp);800 -1801 -1 if (!git_commit_lookup(&commit, repo, id) &&802 -1 !git_commit_tree(&tree, commit))803 -1 ret = writefilestree(fp, tree, "");-1 762 /* find HEAD */ -1 763 if (!git_revparse_single(&obj, repo, "HEAD")) -1 764 head = git_object_id(obj); -1 765 git_object_free(obj); -1 766 if (!head) { -1 767 fprintf(stderr, "no HEAD found\n"); -1 768 return 1; -1 769 } 804 770805 -1 fputs("</tbody></table>", fp);-1 771 if (!git_commit_lookup(&commit, repo, head) && !git_commit_tree(&tree, commit)) -1 772 ret = _process_files(fp, tree, ""); 806 773 807 774 git_commit_free(commit); 808 775 git_tree_free(tree); @@ -811,49 +778,97 @@ write_files(FILE *fp, const git_oid *id) 811 778 } 812 779 813 780 void -1 781 process_commits(FILE *fp_log, FILE *fp_atom, size_t m) -1 782 { -1 783 struct commitinfo *ci; -1 784 git_revwalk *w = NULL; -1 785 git_oid id; -1 786 FILE *fp_commit; -1 787 char path[PATH_MAX], oidstr[GIT_OID_HEXSZ + 1]; -1 788 -1 789 git_revwalk_new(&w, repo); -1 790 git_revwalk_push_head(w); -1 791 -1 792 while (!git_revwalk_next(&id, w)) { -1 793 if (m == 0) { -1 794 fputs("<tr><td colspan=\"3\">More commits remaining…</td></tr>\n", fp_log); -1 795 break; -1 796 } -1 797 if (!(ci = commitinfo_getbyoid(&id))) -1 798 break; -1 799 -1 800 write_log_line(fp_log, ci); -1 801 write_atom_entry(fp_atom, ci); -1 802 -1 803 git_oid_tostr(oidstr, sizeof(oidstr), &id); -1 804 snprintf(path, sizeof(path), "commit/%s.html", oidstr); -1 805 -1 806 if (force || access(path, F_OK)) { -1 807 relpath = "../"; -1 808 mkdirp("commit"); -1 809 fp_commit = efopen(path, "w"); -1 810 write_header(fp_commit, ci->summary); -1 811 write_commit(fp_commit, ci); -1 812 write_footer(fp_commit); -1 813 fclose(fp_commit); -1 814 relpath = ""; -1 815 } -1 816 -1 817 m -= 1; -1 818 commitinfo_free(ci); -1 819 } -1 820 git_revwalk_free(w); -1 821 } -1 822 -1 823 void 814 824 usage(char *argv0) 815 825 {816 -1 fprintf(stderr, "%s [-c cachefile | -l commits] repodir\n", argv0);-1 826 fprintf(stderr, "%s repodir\n", argv0); 817 827 exit(1); 818 828 } 819 829820 -1 int821 -1 main(int argc, char *argv[])-1 830 void -1 831 get_repo_name(const char *path) 822 832 {823 -1 git_object *obj = NULL;824 -1 const git_oid *head = NULL;825 -1 mode_t mask;826 -1 FILE *fp, *fpread;827 -1 char path[PATH_MAX], repodirabs[PATH_MAX + 1], *p;828 -1 char tmppath[64] = "cache.XXXXXXXXXXXX", buf[BUFSIZ];829 -1 size_t n;830 -1 int i, fd;831 -1832 -1 for (i = 1; i < argc; i++) {833 -1 if (argv[i][0] != '-') {834 -1 if (repodir)835 -1 usage(argv[0]);836 -1 repodir = argv[i];837 -1 } else if (argv[i][1] == 'c') {838 -1 if (nlogcommits > 0 || i + 1 >= argc)839 -1 usage(argv[0]);840 -1 cachefile = argv[++i];841 -1 } else if (argv[i][1] == 'l') {842 -1 if (cachefile || i + 1 >= argc)843 -1 usage(argv[0]);844 -1 errno = 0;845 -1 nlogcommits = strtoll(argv[++i], &p, 10);846 -1 if (argv[i][0] == '\0' || *p != '\0' ||847 -1 nlogcommits <= 0 || errno)848 -1 usage(argv[0]);849 -1 }850 -1 }851 -1 if (!repodir)852 -1 usage(argv[0]);-1 833 char *p; 853 834 854 835 if (!realpath(repodir, repodirabs)) 855 836 err(1, "realpath"); 856 837 -1 838 if (!(reponame = strrchr(repodirabs, '/'))) { -1 839 fprintf(stderr, "could not use directory name\n"); -1 840 return; -1 841 } -1 842 reponame++; -1 843 if ((p = strrchr(reponame, '.'))) -1 844 if (!strcmp(p, ".git")) -1 845 *p = '\0'; -1 846 } -1 847 -1 848 void -1 849 get_metadata(void) -1 850 { -1 851 char path[PATH_MAX]; -1 852 FILE *fpread; -1 853 -1 854 joinpath(path, sizeof(path), repodir, "description"); -1 855 if ((fpread = fopen(path, "r"))) { -1 856 if (!fgets(description, sizeof(description), fpread)) -1 857 description[0] = '\0'; -1 858 fclose(fpread); -1 859 } -1 860 } -1 861 -1 862 int -1 863 main(int argc, char *argv[]) -1 864 { -1 865 static FILE *fp_index, *fp_log, *fp_atom; -1 866 -1 867 if (argc == 2) -1 868 repodir = argv[1]; -1 869 else -1 870 usage(argv[0]); -1 871 857 872 git_libgit2_init(); 858 873 859 874 #ifdef __OpenBSD__ @@ -861,152 +876,49 @@ main(int argc, char *argv[]) 861 876 err(1, "unveil: %s", repodir); 862 877 if (unveil(".", "rwc") == -1) 863 878 err(1, "unveil: .");864 -1 if (cachefile && unveil(cachefile, "rwc") == -1)865 -1 err(1, "unveil: %s", cachefile);866 -1867 -1 if (cachefile) {868 -1 if (pledge("stdio rpath wpath cpath fattr", NULL) == -1)869 -1 err(1, "pledge");870 -1 } else {871 -1 if (pledge("stdio rpath wpath cpath", NULL) == -1)872 -1 err(1, "pledge");873 -1 }-1 879 -1 880 if (pledge("stdio rpath wpath cpath", NULL) == -1) -1 881 err(1, "pledge"); 874 882 #endif 875 883876 -1 if (git_repository_open_ext(&repo, repodir,877 -1 GIT_REPOSITORY_OPEN_NO_SEARCH, NULL) < 0) {-1 884 if (git_repository_open_ext( -1 885 &repo, repodir, GIT_REPOSITORY_OPEN_NO_SEARCH, NULL -1 886 ) < 0) { 878 887 fprintf(stderr, "%s: cannot open repository\n", argv[0]); 879 888 return 1; 880 889 } 881 890882 -1 /* find HEAD */883 -1 if (!git_revparse_single(&obj, repo, "HEAD"))884 -1 head = git_object_id(obj);885 -1 git_object_free(obj);-1 891 get_repo_name(repodir); -1 892 get_metadata(); 886 893887 -1 /* use directory name as name */888 -1 if ((name = strrchr(repodirabs, '/')))889 -1 name++;890 -1 else891 -1 name = "";-1 894 fp_index = efopen("index.html", "w"); -1 895 fp_log = efopen("log.html", "w"); -1 896 fp_atom = efopen("atom.xml", "w"); 892 897893 -1 /* strip .git suffix */894 -1 if (!(strippedname = strdup(name)))895 -1 err(1, "strdup");896 -1 if ((p = strrchr(strippedname, '.')))897 -1 if (!strcmp(p, ".git"))898 -1 *p = '\0';899 -1900 -1 /* read description or .git/description */901 -1 joinpath(path, sizeof(path), repodir, "description");902 -1 if (!(fpread = fopen(path, "r"))) {903 -1 joinpath(path, sizeof(path), repodir, ".git/description");904 -1 fpread = fopen(path, "r");905 -1 }906 -1 if (fpread) {907 -1 if (!fgets(description, sizeof(description), fpread))908 -1 description[0] = '\0';909 -1 fclose(fpread);910 -1 }-1 898 write_header(fp_index, "Files"); -1 899 write_files_header(fp_index); 911 900912 -1 /* read url or .git/url */913 -1 joinpath(path, sizeof(path), repodir, "url");914 -1 if (!(fpread = fopen(path, "r"))) {915 -1 joinpath(path, sizeof(path), repodir, ".git/url");916 -1 fpread = fopen(path, "r");917 -1 }918 -1 if (fpread) {919 -1 if (!fgets(cloneurl, sizeof(cloneurl), fpread))920 -1 cloneurl[0] = '\0';921 -1 cloneurl[strcspn(cloneurl, "\n")] = '\0';922 -1 fclose(fpread);923 -1 }-1 901 write_header(fp_log, "Log"); -1 902 write_log_header(fp_log); 924 903925 -1 /* log for HEAD */926 -1 fp = efopen("log.html", "w");927 -1 relpath = "";928 -1 mkdir("commit", S_IRWXU | S_IRWXG | S_IRWXO);929 -1 write_header(fp, "Log");930 -1 fputs("<table id=\"log\"><thead>\n<tr><td><b>Date</b></td>"931 -1 "<td><b>Commit message</b></td>"932 -1 "<td><b>Author</b></td><td class=\"num\" align=\"right\"><b>Files</b></td>"933 -1 "<td class=\"num\" align=\"right\"><b>+</b></td>"934 -1 "<td class=\"num\" align=\"right\"><b>-</b></td></tr>\n</thead><tbody>\n", fp);935 -1936 -1 if (cachefile && head) {937 -1 /* read from cache file (does not need to exist) */938 -1 if ((rcachefp = fopen(cachefile, "r"))) {939 -1 if (!fgets(lastoidstr, sizeof(lastoidstr), rcachefp))940 -1 errx(1, "%s: no object id", cachefile);941 -1 if (git_oid_fromstr(&lastoid, lastoidstr))942 -1 errx(1, "%s: invalid object id", cachefile);943 -1 }-1 904 write_atom_header(fp_atom); 944 905945 -1 /* write log to (temporary) cache */946 -1 if ((fd = mkstemp(tmppath)) == -1)947 -1 err(1, "mkstemp");948 -1 if (!(wcachefp = fdopen(fd, "w")))949 -1 err(1, "fdopen: '%s'", tmppath);950 -1 /* write last commit id (HEAD) */951 -1 git_oid_tostr(buf, sizeof(buf), head);952 -1 fprintf(wcachefp, "%s\n", buf);953 -1954 -1 write_log(fp, head);955 -1956 -1 if (rcachefp) {957 -1 /* append previous log to log.html and the new cache */958 -1 while (!feof(rcachefp)) {959 -1 n = fread(buf, 1, sizeof(buf), rcachefp);960 -1 if (ferror(rcachefp))961 -1 err(1, "fread");962 -1 if (fwrite(buf, 1, n, fp) != n ||963 -1 fwrite(buf, 1, n, wcachefp) != n)964 -1 err(1, "fwrite");965 -1 }966 -1 fclose(rcachefp);967 -1 }968 -1 fclose(wcachefp);969 -1 } else {970 -1 if (head)971 -1 write_log(fp, head);972 -1 }-1 906 process_files(fp_index); -1 907 write_files_footer(fp_index); -1 908 process_readme(fp_index); -1 909 process_commits(fp_log, fp_atom, 100); 973 910974 -1 fputs("</tbody></table>", fp);975 -1 write_footer(fp);976 -1 fclose(fp);-1 911 write_atom_footer(fp_atom); 977 912978 -1 /* files for HEAD */979 -1 fp = efopen("files.html", "w");980 -1 write_header(fp, "Files");981 -1 if (head)982 -1 write_files(fp, head);983 -1 for (i = 0; i < sizeof(readmefiles) / sizeof(*readmefiles) && !readme; i++) {984 -1 if (!git_revparse_single(&obj, repo, readmefiles[i]) &&985 -1 git_object_type(obj) == GIT_OBJ_BLOB) {986 -1 readme = readmefiles[i];987 -1 write_readme(fp, (git_blob *)obj);988 -1 }989 -1 git_object_free(obj);990 -1 }991 -1 write_footer(fp);992 -1 fclose(fp);-1 913 write_log_footer(fp_log); -1 914 write_footer(fp_log); 993 915994 -1 /* Atom feed */995 -1 fp = efopen("atom.xml", "w");996 -1 write_atom(fp);997 -1 fclose(fp);-1 916 write_footer(fp_index); 998 917999 -1 /* rename new cache file on success */1000 -1 if (cachefile && head) {1001 -1 if (rename(tmppath, cachefile))1002 -1 err(1, "rename: '%s' to '%s'", tmppath, cachefile);1003 -1 umask((mask = umask(0)));1004 -1 if (chmod(cachefile,1005 -1 (S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH) & ~mask))1006 -1 err(1, "chmod: '%s'", cachefile);1007 -1 }-1 918 fclose(fp_index); -1 919 fclose(fp_log); -1 920 fclose(fp_atom); 1008 9211009 -1 /* cleanup */1010 922 git_repository_free(repo); 1011 923 git_libgit2_shutdown(); 1012 924