void cgit_print_blame(void) { const char *rev = ctx.qry.sha1; struct object_id oid; struct commit *commit; struct pathspec_item path_items = { .match = ctx.qry.path, .len = ctx.qry.path ? strlen(ctx.qry.path) : 0 }; struct pathspec paths = { .nr = 1, .items = &path_items }; struct walk_tree_context walk_tree_ctx = { .state = 0 }; if (!rev) rev = ctx.qry.head; if (get_oid(rev, &oid)) { cgit_print_error_page(404, "Not found", "Invalid revision name: %s", rev); return; } commit = lookup_commit_reference(&oid); if (!commit || parse_commit(commit)) { cgit_print_error_page(404, "Not found", "Invalid commit reference: %s", rev); return; } walk_tree_ctx.curr_rev = xstrdup(rev); walk_tree_ctx.match_baselen = (path_items.match) ? basedir_len(path_items.match) : -1; read_tree_recursive(commit->tree, "", 0, 0, &paths, walk_tree, &walk_tree_ctx); if (!walk_tree_ctx.state) cgit_print_error_page(404, "Not found", "Not found"); else if (walk_tree_ctx.state == 2) cgit_print_error_page(404, "No blame for folders", "Blame is not available for folders."); free(walk_tree_ctx.curr_rev); }
void cgit_print_plain(void) { const char *rev = ctx.qry.sha1; unsigned char sha1[20]; struct commit *commit; struct pathspec_item path_items = { .match = ctx.qry.path, .len = ctx.qry.path ? strlen(ctx.qry.path) : 0 }; struct pathspec paths = { .nr = 1, .items = &path_items }; struct walk_tree_context walk_tree_ctx = { .match = 0 }; if (!rev) rev = ctx.qry.head; if (get_sha1(rev, sha1)) { cgit_print_error_page(404, "Not found", "Not found"); return; } commit = lookup_commit_reference(sha1); if (!commit || parse_commit(commit)) { cgit_print_error_page(404, "Not found", "Not found"); return; } if (!path_items.match) { path_items.match = ""; walk_tree_ctx.match_baselen = -1; print_dir(commit->tree->object.sha1, "", 0, ""); walk_tree_ctx.match = 2; } else walk_tree_ctx.match_baselen = basedir_len(path_items.match); read_tree_recursive(commit->tree, "", 0, 0, &paths, walk_tree, &walk_tree_ctx); if (!walk_tree_ctx.match) cgit_print_error_page(404, "Not found", "Not found"); else if (walk_tree_ctx.match == 2) print_dir_tail(); }
void cgit_clone_info(void) { if (!ctx.qry.path || strcmp(ctx.qry.path, "refs")) { cgit_print_error_page(400, "Bad request", "Bad request"); return; } ctx.page.mimetype = "text/plain"; ctx.page.filename = "info/refs"; cgit_print_http_headers(); for_each_ref(print_ref_info, NULL); }
static int print_object(const unsigned char *sha1, const char *path) { enum object_type type; char *buf, *mimetype; unsigned long size; type = sha1_object_info(sha1, &size); if (type == OBJ_BAD) { cgit_print_error_page(404, "Not found", "Not found"); return 0; } buf = read_sha1_file(sha1, &type, &size); if (!buf) { cgit_print_error_page(404, "Not found", "Not found"); return 0; } mimetype = get_mimetype_for_filename(path); ctx.page.mimetype = mimetype; if (!ctx.page.mimetype) { if (buffer_is_binary(buf, size)) { ctx.page.mimetype = "application/octet-stream"; ctx.page.charset = NULL; } else { ctx.page.mimetype = "text/plain"; } } ctx.page.filename = path; ctx.page.size = size; ctx.page.etag = sha1_to_hex(sha1); cgit_print_http_headers(); html_raw(buf, size); free(mimetype); free(buf); return 1; }
void cgit_clone_objects(void) { if (!ctx.qry.path) { cgit_print_error_page(400, "Bad request", "Bad request"); return; } if (!strcmp(ctx.qry.path, "info/packs")) { print_pack_info(); return; } send_file(git_path("objects/%s", ctx.qry.path)); }
static void send_file(const char *path) { struct stat st; if (stat(path, &st)) { switch (errno) { case ENOENT: cgit_print_error_page(404, "Not found", "Not found"); break; case EACCES: cgit_print_error_page(403, "Forbidden", "Forbidden"); break; default: cgit_print_error_page(400, "Bad request", "Bad request"); } return; } ctx.page.mimetype = "application/octet-stream"; ctx.page.filename = path; skip_prefix(path, ctx.repo->path, &ctx.page.filename); skip_prefix(ctx.page.filename, "/", &ctx.page.filename); cgit_print_http_headers(); html_include(path); }
void cgit_print_repolist(void) { int i, columns = 3, hits = 0, header = 0; char *last_section = NULL; char *section; int sorted = 0; if (!any_repos_visible()) { cgit_print_error_page(404, "Not found", "No repositories found"); return; } if (ctx.cfg.enable_index_links) ++columns; if (ctx.cfg.enable_index_owner) ++columns; ctx.page.title = ctx.cfg.root_title; cgit_print_http_headers(); cgit_print_docstart(); cgit_print_pageheader(); if (ctx.cfg.index_header) html_include(ctx.cfg.index_header); if (ctx.qry.sort) sorted = sort_repolist(ctx.qry.sort); else if (ctx.cfg.section_sort) sort_repolist("section"); html("<table summary='repository list' class='list nowrap'>"); for (i = 0; i < cgit_repolist.count; i++) { ctx.repo = &cgit_repolist.repos[i]; if (!is_visible(ctx.repo)) continue; hits++; if (hits <= ctx.qry.ofs) continue; if (hits > ctx.qry.ofs + ctx.cfg.max_repo_count) continue; if (!header++) print_header(); section = ctx.repo->section; if (section && !strcmp(section, "")) section = NULL; if (!sorted && ((last_section == NULL && section != NULL) || (last_section != NULL && section == NULL) || (last_section != NULL && section != NULL && strcmp(section, last_section)))) { htmlf("<tr class='nohover'><td colspan='%d' class='reposection'>", columns); html_txt(section); html("</td></tr>"); last_section = section; } htmlf("<tr><td class='%s'>", !sorted && section ? "sublevel-repo" : "toplevel-repo"); cgit_summary_link(ctx.repo->name, ctx.repo->name, NULL, NULL); html("</td><td>"); html_link_open(cgit_repourl(ctx.repo->url), NULL, NULL); html_ntxt(ctx.cfg.max_repodesc_len, ctx.repo->desc); html_link_close(); html("</td><td>"); if (ctx.cfg.enable_index_owner) { if (ctx.repo->owner_filter) { cgit_open_filter(ctx.repo->owner_filter); html_txt(ctx.repo->owner); cgit_close_filter(ctx.repo->owner_filter); } else { html("<a href='"); html_attr(cgit_currenturl()); html("?q="); html_url_arg(ctx.repo->owner); html("'>"); html_txt(ctx.repo->owner); html("</a>"); } html("</td><td>"); } print_modtime(ctx.repo); html("</td>"); if (ctx.cfg.enable_index_links) { html("<td>"); cgit_summary_link("summary", NULL, "button", NULL); cgit_log_link("log", NULL, "button", NULL, NULL, NULL, 0, NULL, NULL, ctx.qry.showmsg, 0); cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL); html("</td>"); } html("</tr>\n"); } html("</table>"); if (hits > ctx.cfg.max_repo_count) print_pager(hits, ctx.cfg.max_repo_count, ctx.qry.search, ctx.qry.sort); cgit_print_docend(); }
void cgit_print_patch(const char *new_rev, const char *old_rev, const char *prefix) { struct rev_info rev; struct commit *commit; unsigned char new_rev_sha1[20], old_rev_sha1[20]; char rev_range[2 * 40 + 3]; char *rev_argv[] = { NULL, "--reverse", "--format=email", rev_range }; char *patchname; if (!new_rev) new_rev = ctx.qry.head; if (get_sha1(new_rev, new_rev_sha1)) { cgit_print_error_page(404, "Not found", "Bad object id: %s", new_rev); return; } commit = lookup_commit_reference(new_rev_sha1); if (!commit) { cgit_print_error_page(404, "Not found", "Bad commit reference: %s", new_rev); return; } if (old_rev) { if (get_sha1(old_rev, old_rev_sha1)) { cgit_print_error_page(404, "Not found", "Bad object id: %s", old_rev); return; } if (!lookup_commit_reference(old_rev_sha1)) { cgit_print_error_page(404, "Not found", "Bad commit reference: %s", old_rev); return; } } else if (commit->parents && commit->parents->item) { hashcpy(old_rev_sha1, commit->parents->item->object.sha1); } else { hashclr(old_rev_sha1); } if (is_null_sha1(old_rev_sha1)) { memcpy(rev_range, sha1_to_hex(new_rev_sha1), 41); } else { sprintf(rev_range, "%s..%s", sha1_to_hex(old_rev_sha1), sha1_to_hex(new_rev_sha1)); } patchname = fmt("%s.patch", rev_range); ctx.page.mimetype = "text/plain"; ctx.page.filename = patchname; cgit_print_http_headers(); if (ctx.cfg.noplainemail) { rev_argv[2] = "--format=format:From %H Mon Sep 17 00:00:00 " "2001%nFrom: %an%nDate: %aD%n%w(78,0,1)Subject: " "%s%n%n%w(0)%b"; } init_revisions(&rev, NULL); rev.abbrev = DEFAULT_ABBREV; rev.verbose_header = 1; rev.diff = 1; rev.show_root_diff = 1; rev.max_parents = 1; rev.diffopt.output_format |= DIFF_FORMAT_DIFFSTAT | DIFF_FORMAT_PATCH | DIFF_FORMAT_SUMMARY; setup_revisions(ARRAY_SIZE(rev_argv), (const char **)rev_argv, &rev, NULL); prepare_revision_walk(&rev); while ((commit = get_revision(&rev)) != NULL) { log_tree_commit(&rev, commit); printf("-- \ncgit %s\n\n", cgit_version); } fflush(stdout); }
/* Create a sorted string_list with one entry per author. The util-field * for each author is another string_list which is used to calculate the * number of commits per time-interval. */ void cgit_show_stats(void) { struct string_list authors; const struct cgit_period *period; int top, i; const char *code = "w"; if (ctx.qry.period) code = ctx.qry.period; i = cgit_find_stats_period(code, &period); if (!i) { cgit_print_error_page(404, "Not found", "Unknown statistics type: %c", code[0]); return; } if (i > ctx.repo->max_stats) { cgit_print_error_page(400, "Bad request", "Statistics type disabled: %s", period->name); return; } authors = collect_stats(period); qsort(authors.items, authors.nr, sizeof(struct string_list_item), cmp_total_commits); top = ctx.qry.ofs; if (!top) top = 10; cgit_print_layout_start(); html("<div class='cgit-panel'>"); html("<b>stat options</b>"); html("<form method='get' action=''>"); cgit_add_hidden_formfields(1, 0, "stats"); html("<table><tr><td colspan='2'/></tr>"); if (ctx.repo->max_stats > 1) { html("<tr><td class='label'>Period:</td>"); html("<td class='ctrl'><select name='period' onchange='this.form.submit();'>"); for (i = 0; i < ctx.repo->max_stats; i++) html_option(fmt("%c", periods[i].code), periods[i].name, fmt("%c", period->code)); html("</select></td></tr>"); } html("<tr><td class='label'>Authors:</td>"); html("<td class='ctrl'><select name='ofs' onchange='this.form.submit();'>"); html_intoption(10, "10", top); html_intoption(25, "25", top); html_intoption(50, "50", top); html_intoption(100, "100", top); html_intoption(-1, "all", top); html("</select></td></tr>"); html("<tr><td/><td class='ctrl'>"); html("<noscript><input type='submit' value='Reload'/></noscript>"); html("</td></tr></table>"); html("</form>"); html("</div>"); htmlf("<h2>Commits per author per %s", period->name); if (ctx.qry.path) { html(" (path '"); html_txt(ctx.qry.path); html("')"); } html("</h2>"); print_authors(&authors, top, period); cgit_print_layout_end(); }
int cgit_ref_path_exists(const char *path, const char *ref, int file_only) { unsigned char sha1[20]; unsigned long size; struct pathspec_item path_items = { .match = path, .len = strlen(path) }; struct pathspec paths = { .nr = 1, .items = &path_items }; struct walk_tree_context walk_tree_ctx = { .match_path = path, .matched_sha1 = sha1, .found_path = 0, .file_only = file_only }; if (get_sha1(ref, sha1)) return 0; if (sha1_object_info(sha1, &size) != OBJ_COMMIT) return 0; read_tree_recursive(lookup_commit_reference(sha1)->tree, "", 0, 0, &paths, walk_tree, &walk_tree_ctx); return walk_tree_ctx.found_path; } int cgit_print_file(char *path, const char *head, int file_only) { unsigned char sha1[20]; enum object_type type; char *buf; unsigned long size; struct commit *commit; struct pathspec_item path_items = { .match = path, .len = strlen(path) }; struct pathspec paths = { .nr = 1, .items = &path_items }; struct walk_tree_context walk_tree_ctx = { .match_path = path, .matched_sha1 = sha1, .found_path = 0, .file_only = file_only }; if (get_sha1(head, sha1)) return -1; type = sha1_object_info(sha1, &size); if (type == OBJ_COMMIT) { commit = lookup_commit_reference(sha1); read_tree_recursive(commit->tree, "", 0, 0, &paths, walk_tree, &walk_tree_ctx); if (!walk_tree_ctx.found_path) return -1; type = sha1_object_info(sha1, &size); } if (type == OBJ_BAD) return -1; buf = read_sha1_file(sha1, &type, &size); if (!buf) return -1; buf[size] = '\0'; html_raw(buf, size); free(buf); return 0; } void cgit_print_blob(const char *hex, char *path, const char *head, int file_only) { unsigned char sha1[20]; enum object_type type; char *buf; unsigned long size; struct commit *commit; struct pathspec_item path_items = { .match = path, .len = path ? strlen(path) : 0 }; struct pathspec paths = { .nr = 1, .items = &path_items }; struct walk_tree_context walk_tree_ctx = { .match_path = path, .matched_sha1 = sha1, .found_path = 0, .file_only = file_only }; if (hex) { if (get_sha1_hex(hex, sha1)) { cgit_print_error_page(400, "Bad request", "Bad hex value: %s", hex); return; } } else { if (get_sha1(head, sha1)) { cgit_print_error_page(404, "Not found", "Bad ref: %s", head); return; } } type = sha1_object_info(sha1, &size); if ((!hex) && type == OBJ_COMMIT && path) { commit = lookup_commit_reference(sha1); read_tree_recursive(commit->tree, "", 0, 0, &paths, walk_tree, &walk_tree_ctx); type = sha1_object_info(sha1,&size); } if (type == OBJ_BAD) { cgit_print_error_page(404, "Not found", "Bad object name: %s", hex); return; } buf = read_sha1_file(sha1, &type, &size); if (!buf) { cgit_print_error_page(500, "Internal server error", "Error reading object %s", hex); return; } buf[size] = '\0'; if (buffer_is_binary(buf, size)) ctx.page.mimetype = "application/octet-stream"; else ctx.page.mimetype = "text/plain"; ctx.page.filename = path; html("X-Content-Type-Options: nosniff\n"); html("Content-Security-Policy: default-src 'none'\n"); cgit_print_http_headers(); html_raw(buf, size); free(buf); }
void cgit_print_tag(char *revname) { struct strbuf fullref = STRBUF_INIT; unsigned char sha1[20]; struct object *obj; struct tag *tag; struct taginfo *info; if (!revname) revname = ctx.qry.head; strbuf_addf(&fullref, "refs/tags/%s", revname); if (get_sha1(fullref.buf, sha1)) { cgit_print_error_page(404, "Not found", "Bad tag reference: %s", revname); goto cleanup; } obj = parse_object(sha1); if (!obj) { cgit_print_error_page(500, "Internal server error", "Bad object id: %s", sha1_to_hex(sha1)); goto cleanup; } if (obj->type == OBJ_TAG) { tag = lookup_tag(sha1); if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) { cgit_print_error_page(500, "Internal server error", "Bad tag object: %s", revname); goto cleanup; } cgit_print_layout_start(); html("<table class='commit-info'>\n"); htmlf("<tr><td>tag name</td><td>"); html_txt(revname); htmlf(" (%s)</td></tr>\n", sha1_to_hex(sha1)); if (info->tagger_date > 0) { html("<tr><td>tag date</td><td>"); cgit_print_date(info->tagger_date, FMT_LONGDATE, ctx.cfg.local_time); html("</td></tr>\n"); } if (info->tagger) { html("<tr><td>tagged by</td><td>"); cgit_open_filter(ctx.repo->email_filter, info->tagger_email, "tag"); html_txt(info->tagger); if (info->tagger_email && !ctx.cfg.noplainemail) { html(" "); html_txt(info->tagger_email); } cgit_close_filter(ctx.repo->email_filter); html("</td></tr>\n"); } html("<tr><td>tagged object</td><td class='sha1'>"); cgit_object_link(tag->tagged); html("</td></tr>\n"); if (ctx.repo->snapshots) print_download_links(revname); html("</table>\n"); print_tag_content(info->msg); cgit_print_layout_end(); } else { cgit_print_layout_start(); html("<table class='commit-info'>\n"); htmlf("<tr><td>tag name</td><td>"); html_txt(revname); html("</td></tr>\n"); html("<tr><td>Tagged object</td><td class='sha1'>"); cgit_object_link(obj); html("</td></tr>\n"); if (ctx.repo->snapshots) print_download_links(revname); html("</table>\n"); cgit_print_layout_end(); } cleanup: strbuf_release(&fullref); }
static void print_object(const unsigned char *sha1, const char *path, const char *basename, const char *rev) { enum object_type type; char *buf; unsigned long size; struct argv_array rev_argv = ARGV_ARRAY_INIT; struct rev_info revs; struct blame_scoreboard sb; struct blame_origin *o; struct blame_entry *ent = NULL; type = sha1_object_info(sha1, &size); if (type == OBJ_BAD) { cgit_print_error_page(404, "Not found", "Bad object name: %s", sha1_to_hex(sha1)); return; } buf = read_sha1_file(sha1, &type, &size); if (!buf) { cgit_print_error_page(500, "Internal server error", "Error reading object %s", sha1_to_hex(sha1)); return; } argv_array_push(&rev_argv, "blame"); argv_array_push(&rev_argv, rev); init_revisions(&revs, NULL); revs.diffopt.flags.allow_textconv = 1; setup_revisions(rev_argv.argc, rev_argv.argv, &revs, NULL); init_scoreboard(&sb); sb.revs = &revs; setup_scoreboard(&sb, path, &o); o->suspects = blame_entry_prepend(NULL, 0, sb.num_lines, o); prio_queue_put(&sb.commits, o->commit); blame_origin_decref(o); sb.ent = NULL; sb.path = path; assign_blame(&sb, 0); blame_sort_final(&sb); blame_coalesce(&sb); cgit_set_title_from_path(path); cgit_print_layout_start(); htmlf("blob: %s (", sha1_to_hex(sha1)); cgit_plain_link("plain", NULL, NULL, ctx.qry.head, rev, path); html(") ("); cgit_tree_link("tree", NULL, NULL, ctx.qry.head, rev, path); html(")\n"); if (ctx.cfg.max_blob_size && size / 1024 > ctx.cfg.max_blob_size) { htmlf("<div class='error'>blob size (%ldKB)" " exceeds display size limit (%dKB).</div>", size / 1024, ctx.cfg.max_blob_size); return; } html("<table class='blame blob'>\n<tr>\n"); /* Commit hashes */ html("<td class='hashes'>"); for (ent = sb.ent; ent; ent = ent->next) { html("<div class='alt'><pre>"); emit_blame_entry_hash(ent); html("</pre></div>"); } html("</td>\n"); /* Line numbers */ if (ctx.cfg.enable_tree_linenumbers) { html("<td class='linenumbers'>"); for (ent = sb.ent; ent; ent = ent->next) { html("<div class='alt'><pre>"); emit_blame_entry_linenumber(ent); html("</pre></div>"); } html("</td>\n"); } html("<td class='lines'><div>"); /* Colored bars behind lines */ html("<div>"); for (ent = sb.ent; ent; ) { struct blame_entry *e = ent->next; html("<div class='alt'><pre>"); emit_blame_entry_line_background(&sb, ent); html("</pre></div>"); free(ent); ent = e; } html("</div>"); free((void *)sb.final_buf); /* Lines */ html("<pre><code>"); if (ctx.repo->source_filter) { char *filter_arg = xstrdup(basename); cgit_open_filter(ctx.repo->source_filter, filter_arg); html_raw(buf, size); cgit_close_filter(ctx.repo->source_filter); free(filter_arg); } else { html_txt(buf); } html("</code></pre>"); html("</div></td>\n"); html("</tr>\n</table>\n"); cgit_print_layout_end(); }
void cgit_print_commit(char *hex, const char *prefix) { struct commit *commit, *parent; struct commitinfo *info, *parent_info; struct commit_list *p; struct strbuf notes = STRBUF_INIT; unsigned char sha1[20]; char *tmp, *tmp2; int parents = 0; if (!hex) hex = ctx.qry.head; if (get_sha1(hex, sha1)) { cgit_print_error_page(400, "Bad request", "Bad object id: %s", hex); return; } commit = lookup_commit_reference(sha1); if (!commit) { cgit_print_error_page(404, "Not found", "Bad commit reference: %s", hex); return; } info = cgit_parse_commit(commit); format_display_notes(sha1, ¬es, PAGE_ENCODING, 0); load_ref_decorations(DECORATE_FULL_REFS); cgit_print_layout_start(); cgit_print_diff_ctrls(); html("<table summary='commit info' class='commit-info'>\n"); html("<tr><th>author</th><td>"); cgit_open_filter(ctx.repo->email_filter, info->author_email, "commit"); html_txt(info->author); if (!ctx.cfg.noplainemail) { html(" "); html_txt(info->author_email); } cgit_close_filter(ctx.repo->email_filter); html("</td><td class='right'>"); html_txt(show_date(info->author_date, info->author_tz, cgit_date_mode(DATE_ISO8601))); html("</td></tr>\n"); html("<tr><th>committer</th><td>"); cgit_open_filter(ctx.repo->email_filter, info->committer_email, "commit"); html_txt(info->committer); if (!ctx.cfg.noplainemail) { html(" "); html_txt(info->committer_email); } cgit_close_filter(ctx.repo->email_filter); html("</td><td class='right'>"); html_txt(show_date(info->committer_date, info->committer_tz, cgit_date_mode(DATE_ISO8601))); html("</td></tr>\n"); html("<tr><th>commit</th><td colspan='2' class='sha1'>"); tmp = oid_to_hex(&commit->object.oid); cgit_commit_link(tmp, NULL, NULL, ctx.qry.head, tmp, prefix); html(" ("); cgit_patch_link("patch", NULL, NULL, NULL, tmp, prefix); html(")</td></tr>\n"); html("<tr><th>tree</th><td colspan='2' class='sha1'>"); tmp = xstrdup(hex); cgit_tree_link(oid_to_hex(&commit->tree->object.oid), NULL, NULL, ctx.qry.head, tmp, NULL); if (prefix) { html(" /"); cgit_tree_link(prefix, NULL, NULL, ctx.qry.head, tmp, prefix); } free(tmp); html("</td></tr>\n"); for (p = commit->parents; p; p = p->next) { parent = lookup_commit_reference(p->item->object.oid.hash); if (!parent) { html("<tr><td colspan='3'>"); cgit_print_error("Error reading parent commit"); html("</td></tr>"); continue; } html("<tr><th>parent</th>" "<td colspan='2' class='sha1'>"); tmp = tmp2 = oid_to_hex(&p->item->object.oid); if (ctx.repo->enable_subject_links) { parent_info = cgit_parse_commit(parent); tmp2 = parent_info->subject; } cgit_commit_link(tmp2, NULL, NULL, ctx.qry.head, tmp, prefix); html(" ("); cgit_diff_link("diff", NULL, NULL, ctx.qry.head, hex, oid_to_hex(&p->item->object.oid), prefix); html(")</td></tr>"); parents++; } if (ctx.repo->snapshots) { html("<tr><th>download</th><td colspan='2' class='sha1'>"); cgit_print_snapshot_links(ctx.qry.repo, ctx.qry.head, hex, ctx.repo->snapshots); html("</td></tr>"); } html("</table>\n"); html("<div class='commit-subject'>"); cgit_open_filter(ctx.repo->commit_filter); html_txt(info->subject); cgit_close_filter(ctx.repo->commit_filter); show_commit_decorations(commit); html("</div>"); html("<div class='commit-msg'>"); cgit_open_filter(ctx.repo->commit_filter); html_txt(info->msg); cgit_close_filter(ctx.repo->commit_filter); html("</div>"); if (notes.len != 0) { html("<div class='notes-header'>Notes</div>"); html("<div class='notes'>"); cgit_open_filter(ctx.repo->commit_filter); html_txt(notes.buf); cgit_close_filter(ctx.repo->commit_filter); html("</div>"); html("<div class='notes-footer'></div>"); } if (parents < 3) { if (parents) tmp = oid_to_hex(&commit->parents->item->object.oid); else tmp = NULL; cgit_print_diff(ctx.qry.sha1, tmp, prefix, 0, 0); } strbuf_release(¬es); cgit_free_commitinfo(info); cgit_print_layout_end(); }