/* 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(struct cgit_context *ctx) { struct string_list authors; 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(fmt("Unknown statistics type: %c", code)); return; } if (i > ctx->repo->max_stats) { cgit_print_error(fmt("Statistics type disabled: %s", period->name)); return; } authors = collect_stats(ctx, period); qsort(authors.items, authors.nr, sizeof(struct string_list_item), cmp_total_commits); top = ctx->qry.ofs; if (!top) top = 10; htmlf("<h2>Commits per author per %s", period->name); if (ctx->qry.path) { html(" (path '"); html_txt(ctx->qry.path); html("')"); } html("</h2>"); html("<form method='get' action='' style='float: right; text-align: right;'>"); cgit_add_hidden_formfields(1, 0, "stats"); if (ctx->repo->max_stats > 1) { html("Period: "); html("<select name='period' onchange='this.form.submit();'>"); for (i = 0; i < ctx->repo->max_stats; i++) htmlf("<option value='%c'%s>%s</option>", periods[i].code, period == &periods[i] ? " selected" : "", periods[i].name); html("</select><br/><br/>"); } html("Authors: "); html(""); html("<select name='ofs' onchange='this.form.submit();'>"); htmlf("<option value='10'%s>10</option>", top == 10 ? " selected" : ""); htmlf("<option value='25'%s>25</option>", top == 25 ? " selected" : ""); htmlf("<option value='50'%s>50</option>", top == 50 ? " selected" : ""); htmlf("<option value='100'%s>100</option>", top == 100 ? " selected" : ""); htmlf("<option value='-1'%s>All</option>", top == -1 ? " selected" : ""); html("</select>"); html("<noscript> <input type='submit' value='Reload'/></noscript>"); html("</form>"); print_authors(&authors, top, period); }
static int prepare_repo_cmd(struct cgit_context *ctx) { char *tmp; unsigned char sha1[20]; int nongit = 0; int rc; setenv("GIT_DIR", ctx->repo->path, 1); setup_git_directory_gently(&nongit); if (nongit) { rc = errno; ctx->page.title = fmt("%s - %s", ctx->cfg.root_title, "config error"); tmp = fmt("Failed to open %s: %s", ctx->repo->name, rc ? strerror(rc) : "Not a valid git repository"); ctx->repo = NULL; cgit_print_http_headers(ctx); cgit_print_docstart(ctx); cgit_print_pageheader(ctx); cgit_print_error(tmp); cgit_print_docend(); return 1; } ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc); if (!ctx->repo->defbranch) ctx->repo->defbranch = guess_defbranch(); if (!ctx->qry.head) { ctx->qry.nohead = 1; ctx->qry.head = find_default_branch(ctx->repo); } if (!ctx->qry.head) { cgit_print_http_headers(ctx); cgit_print_docstart(ctx); cgit_print_pageheader(ctx); cgit_print_error("Repository seems to be empty"); cgit_print_docend(); return 1; } if (get_sha1(ctx->qry.head, sha1)) { tmp = xstrdup(ctx->qry.head); ctx->qry.head = ctx->repo->defbranch; ctx->page.status = 404; ctx->page.statusmsg = "Not found"; cgit_print_http_headers(ctx); cgit_print_docstart(ctx); cgit_print_pageheader(ctx); cgit_print_error(fmt("Invalid branch: %s", tmp)); cgit_print_docend(); return 1; } sort_string_list(&ctx->repo->submodules); cgit_prepare_repo_env(ctx->repo); return 0; }
static void process_request(void *cbdata) { struct cgit_context *ctx = cbdata; struct cgit_cmd *cmd; cmd = cgit_get_cmd(ctx); if (!cmd) { ctx->page.title = "cgit error"; ctx->page.status = 404; ctx->page.statusmsg = "Not found"; cgit_print_http_headers(ctx); cgit_print_docstart(ctx); cgit_print_pageheader(ctx); cgit_print_error("Invalid request"); cgit_print_docend(); return; } if (!ctx->cfg.enable_http_clone && cmd->is_clone) { html_status(404, "Not found", 0); return; } /* If cmd->want_vpath is set, assume ctx->qry.path contains a "virtual" * in-project path limit to be made available at ctx->qry.vpath. * Otherwise, no path limit is in effect (ctx->qry.vpath = NULL). */ ctx->qry.vpath = cmd->want_vpath ? ctx->qry.path : NULL; if (cmd->want_repo && !ctx->repo) { cgit_print_http_headers(ctx); cgit_print_docstart(ctx); cgit_print_pageheader(ctx); cgit_print_error(fmt("No repository selected")); cgit_print_docend(); return; } if (ctx->repo && prepare_repo_cmd(ctx)) return; if (cmd->want_layout) { cgit_print_http_headers(ctx); cgit_print_docstart(ctx); cgit_print_pageheader(ctx); } cmd->fn(ctx); if (cmd->want_layout) cgit_print_docend(); }
void cgit_print_patch(char *hex, const char *prefix) { struct commit *commit; struct commitinfo *info; unsigned char sha1[20], old_sha1[20]; char *patchname; if (!hex) hex = ctx.qry.head; if (get_sha1(hex, sha1)) { cgit_print_error(fmt("Bad object id: %s", hex)); return; } commit = lookup_commit_reference(sha1); if (!commit) { cgit_print_error(fmt("Bad commit reference: %s", hex)); return; } info = cgit_parse_commit(commit); if (commit->parents && commit->parents->item) hashcpy(old_sha1, commit->parents->item->object.sha1); else hashclr(old_sha1); patchname = fmt("%s.patch", sha1_to_hex(sha1)); ctx.page.mimetype = "text/plain"; ctx.page.filename = patchname; cgit_print_http_headers(&ctx); htmlf("From %s Mon Sep 17 00:00:00 2001\n", sha1_to_hex(sha1)); htmlf("From: %s", info->author); if (!ctx.cfg.noplainemail) { htmlf(" %s", info->author_email); } html("\n"); html("Date: "); cgit_print_date(info->author_date, "%a, %d %b %Y %H:%M:%S %z%n", ctx.cfg.local_time); htmlf("Subject: %s\n\n", info->subject); if (info->msg && *info->msg) { htmlf("%s", info->msg); if (info->msg[strlen(info->msg) - 1] != '\n') html("\n"); } html("---\n"); if (prefix) htmlf("(limited to '%s')\n\n", prefix); cgit_diff_tree(old_sha1, sha1, filepair_cb, prefix, 0); html("--\n"); htmlf("cgit %s\n", CGIT_VERSION); cgit_free_commitinfo(info); }
static int prepare_repo_cmd(struct cgit_context *ctx) { char *tmp; unsigned char sha1[20]; int nongit = 0; setenv("GIT_DIR", ctx->repo->path, 1); setup_git_directory_gently(&nongit); if (nongit) { ctx->page.title = fmt("%s - %s", ctx->cfg.root_title, "config error"); tmp = fmt("Not a git repository: '%s'", ctx->repo->path); ctx->repo = NULL; cgit_print_http_headers(ctx); cgit_print_docstart(ctx); cgit_print_pageheader(ctx); cgit_print_error(tmp); cgit_print_docend(); return 1; } ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc); if (!ctx->qry.head) { ctx->qry.nohead = 1; ctx->qry.head = find_default_branch(ctx->repo); ctx->repo->defbranch = ctx->qry.head; } if (!ctx->qry.head) { cgit_print_http_headers(ctx); cgit_print_docstart(ctx); cgit_print_pageheader(ctx); cgit_print_error("Repository seems to be empty"); cgit_print_docend(); return 1; } if (get_sha1(ctx->qry.head, sha1)) { tmp = xstrdup(ctx->qry.head); ctx->qry.head = ctx->repo->defbranch; ctx->page.status = 404; ctx->page.statusmsg = "not found"; cgit_print_http_headers(ctx); cgit_print_docstart(ctx); cgit_print_pageheader(ctx); cgit_print_error(fmt("Invalid branch: %s", tmp)); cgit_print_docend(); return 1; } return 0; }
void cgit_print_blob(const char *hex, char *path, const char *head) { unsigned char sha1[20]; enum object_type type; unsigned char *buf; unsigned long size; struct commit *commit; const char *paths[] = {path, NULL}; if (hex) { if (get_sha1_hex(hex, sha1)){ cgit_print_error(fmt("Bad hex value: %s", hex)); return; } } else { if (get_sha1(head,sha1)) { cgit_print_error(fmt("Bad ref: %s", head)); return; } } type = sha1_object_info(sha1, &size); if((!hex) && type == OBJ_COMMIT && path) { commit = lookup_commit_reference(sha1); match_path = path; matched_sha1 = sha1; read_tree_recursive(commit->tree, NULL, 0, 0, paths, walk_tree, NULL); type = sha1_object_info(sha1,&size); } if (type == OBJ_BAD) { cgit_print_error(fmt("Bad object name: %s", hex)); return; } buf = read_sha1_file(sha1, &type, &size); if (!buf) { cgit_print_error(fmt("Error reading object %s", hex)); return; } buf[size] = '\0'; ctx.page.mimetype = ctx.qry.mimetype; ctx.page.filename = path; cgit_print_http_headers(&ctx); write(htmlfd, buf, size); }
void cgit_print_tag(char *revname) { unsigned char sha1[20]; struct object *obj; struct tag *tag; struct taginfo *info; if (get_sha1(revname, sha1)) { cgit_print_error(fmt("Bad tag reference: %s", revname)); return; } obj = parse_object(sha1); if (!obj) { cgit_print_error(fmt("Bad object id: %s", sha1_to_hex(sha1))); return; } if (obj->type == OBJ_TAG) { tag = lookup_tag(sha1); if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) { cgit_print_error(fmt("Bad tag object: %s", revname)); return; } html("<table class='commit-info'>\n"); htmlf("<tr><td>Tag name</td><td>%s (%s)</td></tr>\n", revname, 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>"); html_txt(info->tagger); if (info->tagger_email) { html(" "); html_txt(info->tagger_email); } html("</td></tr>\n"); } html("<tr><td>Tagged object</td><td>"); cgit_object_link(tag->tagged); html("</td></tr>\n"); html("</table>\n"); print_tag_content(info->msg); } return; }
int main(int argc, const char **argv) { const char *path; char *qry; int err, ttl; prepare_context(&ctx); cgit_repolist.length = 0; cgit_repolist.count = 0; cgit_repolist.repos = NULL; cgit_parse_args(argc, argv); parse_configfile(expand_macros(ctx.env.cgit_config), config_cb); ctx.repo = NULL; http_parse_querystring(ctx.qry.raw, querystring_cb); /* If virtual-root isn't specified in cgitrc, lets pretend * that virtual-root equals SCRIPT_NAME, minus any possibly * trailing slashes. */ if (!ctx.cfg.virtual_root && ctx.cfg.script_name) { ctx.cfg.virtual_root = trim_end(ctx.cfg.script_name, '/'); if (!ctx.cfg.virtual_root) ctx.cfg.virtual_root = ""; } /* If no url parameter is specified on the querystring, lets * use PATH_INFO as url. This allows cgit to work with virtual * urls without the need for rewriterules in the webserver (as * long as PATH_INFO is included in the cache lookup key). */ path = ctx.env.path_info; if (!ctx.qry.url && path) { if (path[0] == '/') path++; ctx.qry.url = xstrdup(path); if (ctx.qry.raw) { qry = ctx.qry.raw; ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry)); free(qry); } else ctx.qry.raw = xstrdup(ctx.qry.url); cgit_parse_url(ctx.qry.url); } ttl = calc_ttl(); ctx.page.expires += ttl * 60; if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD")) ctx.cfg.nocache = 1; if (ctx.cfg.nocache) ctx.cfg.cache_size = 0; err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root, ctx.qry.raw, ttl, process_request, &ctx); if (err) cgit_print_error(fmt("Error processing page: %s (%d)", strerror(err), err)); return err; }
static void process_request(void *cbdata) { struct cgit_context *ctx = cbdata; struct cgit_cmd *cmd; cmd = cgit_get_cmd(ctx); if (!cmd) { ctx->page.title = "cgit error"; cgit_print_http_headers(ctx); cgit_print_docstart(ctx); cgit_print_pageheader(ctx); cgit_print_error("Invalid request"); cgit_print_docend(); return; } if (cmd->want_repo && !ctx->repo) { cgit_print_http_headers(ctx); cgit_print_docstart(ctx); cgit_print_pageheader(ctx); cgit_print_error(fmt("No repository selected")); cgit_print_docend(); return; } if (ctx->repo && prepare_repo_cmd(ctx)) return; if (cmd->want_layout) { cgit_print_http_headers(ctx); cgit_print_docstart(ctx); cgit_print_pageheader(ctx); } cmd->fn(ctx); if (cmd->want_layout) 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("Bad object id: %s", new_rev); return; } commit = lookup_commit_reference(new_rev_sha1); if (!commit) { cgit_print_error("Bad commit reference: %s", new_rev); return; } if (old_rev) { if (get_sha1(old_rev, old_rev_sha1)) { cgit_print_error("Bad object id: %s", old_rev); return; } if (!lookup_commit_reference(old_rev_sha1)) { cgit_print_error("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(&ctx); 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_PATCH; 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", cgit_version); } }
void cgit_print_commit(char *hex) { struct commit *commit, *parent; struct commitinfo *info; struct commit_list *p; unsigned char sha1[20]; char *tmp; int parents = 0; if (!hex) hex = ctx.qry.head; if (get_sha1(hex, sha1)) { cgit_print_error(fmt("Bad object id: %s", hex)); return; } commit = lookup_commit_reference(sha1); if (!commit) { cgit_print_error(fmt("Bad commit reference: %s", hex)); return; } info = cgit_parse_commit(commit); html("<table summary='commit info' class='commit-info'>\n"); html("<tr><th>author</th><td>"); html_txt(info->author); html(" "); html_txt(info->author_email); html("</td><td class='right'>"); cgit_print_date(info->author_date, FMT_LONGDATE, ctx.cfg.local_time); html("</td></tr>\n"); html("<tr><th>committer</th><td>"); html_txt(info->committer); html(" "); html_txt(info->committer_email); html("</td><td class='right'>"); cgit_print_date(info->committer_date, FMT_LONGDATE, ctx.cfg.local_time); html("</td></tr>\n"); html("<tr><th>commit</th><td colspan='2' class='sha1'>"); tmp = sha1_to_hex(commit->object.sha1); cgit_commit_link(tmp, NULL, NULL, ctx.qry.head, tmp); html(" ("); cgit_patch_link("patch", NULL, NULL, NULL, tmp); html(")</td></tr>\n"); html("<tr><th>tree</th><td colspan='2' class='sha1'>"); tmp = xstrdup(hex); cgit_tree_link(sha1_to_hex(commit->tree->object.sha1), NULL, NULL, ctx.qry.head, tmp, NULL); html("</td></tr>\n"); for (p = commit->parents; p ; p = p->next) { parent = lookup_commit_reference(p->item->object.sha1); 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'>"); cgit_commit_link(sha1_to_hex(p->item->object.sha1), NULL, NULL, ctx.qry.head, sha1_to_hex(p->item->object.sha1)); html(" ("); cgit_diff_link("diff", NULL, NULL, ctx.qry.head, hex, sha1_to_hex(p->item->object.sha1), NULL); 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'>"); html_txt(info->subject); html("</div>"); html("<div class='commit-msg'>"); html_txt(info->msg); html("</div>"); if (parents < 3) { if (parents) tmp = sha1_to_hex(commit->parents->item->object.sha1); else tmp = NULL; cgit_print_diff(ctx.qry.sha1, tmp, NULL); } cgit_free_commitinfo(info); }
/* 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(struct cgit_context *ctx) { struct string_list authors; 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(fmt("Unknown statistics type: %c", code[0])); return; } if (i > ctx->repo->max_stats) { cgit_print_error(fmt("Statistics type disabled: %s", period->name)); return; } authors = collect_stats(ctx, period); qsort(authors.items, authors.nr, sizeof(struct string_list_item), cmp_total_commits); top = ctx->qry.ofs; if (!top) top = 10; 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); }
void cgit_print_repolist() { int i, columns = 4, hits = 0, header = 0; char *last_group = NULL; int sorted = 0; if (ctx.cfg.enable_index_links) columns++; ctx.page.title = ctx.cfg.root_title; cgit_print_http_headers(&ctx); cgit_print_docstart(&ctx); cgit_print_pageheader(&ctx); if (ctx.cfg.index_header) html_include(ctx.cfg.index_header); if(ctx.qry.sort) sorted = sort_repolist(ctx.qry.sort); html("<table summary='repository list' class='list nowrap'>"); for (i=0; i<cgit_repolist.count; i++) { ctx.repo = &cgit_repolist.repos[i]; if (!(is_match(ctx.repo) && is_in_url(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(columns); if (!sorted && ((last_group == NULL && ctx.repo->group != NULL) || (last_group != NULL && ctx.repo->group == NULL) || (last_group != NULL && ctx.repo->group != NULL && strcmp(ctx.repo->group, last_group)))) { htmlf("<tr class='nohover'><td colspan='%d' class='repogroup'>", columns); html_txt(ctx.repo->group); html("</td></tr>"); last_group = ctx.repo->group; } htmlf("<tr><td class='%s'>", !sorted && ctx.repo->group ? "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>"); html_txt(ctx.repo->owner); 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); cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL); html("</td>"); } html("</tr>\n"); } html("</table>"); if (!hits) cgit_print_error("No repositories found"); else if (hits > ctx.cfg.max_repo_count) print_pager(hits, ctx.cfg.max_repo_count, ctx.qry.search); cgit_print_docend(); }
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("Bad tag reference: %s", revname); goto cleanup; } obj = parse_object(sha1); if (!obj) { cgit_print_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("Bad tag object: %s", revname); goto cleanup; } 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); } else { 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"); } cleanup: strbuf_release(&fullref); }
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("Bad object id: %s", hex); return; } commit = lookup_commit_reference(sha1); if (!commit) { cgit_print_error("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_diff_ctrls(); html("<table summary='commit info' class='commit-info'>\n"); html("<tr><th>author</th><td>"); html_txt(info->author); if (!ctx.cfg.noplainemail) { html(" "); html_txt(info->author_email); } html("</td><td class='right'>"); cgit_print_date(info->author_date, FMT_LONGDATE, ctx.cfg.local_time); html("</td></tr>\n"); html("<tr><th>committer</th><td>"); html_txt(info->committer); if (!ctx.cfg.noplainemail) { html(" "); html_txt(info->committer_email); } html("</td><td class='right'>"); cgit_print_date(info->committer_date, FMT_LONGDATE, ctx.cfg.local_time); html("</td></tr>\n"); html("<tr><th>commit</th><td colspan='2' class='sha1'>"); tmp = sha1_to_hex(commit->object.sha1); cgit_commit_link(tmp, NULL, NULL, ctx.qry.head, tmp, prefix, 0); 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(sha1_to_hex(commit->tree->object.sha1), 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.sha1); 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 = sha1_to_hex(p->item->object.sha1); 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, 0); html(" ("); cgit_diff_link("diff", NULL, NULL, ctx.qry.head, hex, sha1_to_hex(p->item->object.sha1), prefix, 0); 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'>"); if (ctx.repo->commit_filter) cgit_open_filter(ctx.repo->commit_filter); html_txt(info->subject); if (ctx.repo->commit_filter) cgit_close_filter(ctx.repo->commit_filter); show_commit_decorations(commit); html("</div>"); html("<div class='commit-msg'>"); if (ctx.repo->commit_filter) cgit_open_filter(ctx.repo->commit_filter); html_txt(info->msg); if (ctx.repo->commit_filter) cgit_close_filter(ctx.repo->commit_filter); html("</div>"); if (notes.len != 0) { html("<div class='notes-header'>Notes</div>"); html("<div class='notes'>"); if (ctx.repo->commit_filter) cgit_open_filter(ctx.repo->commit_filter); html_txt(notes.buf); if (ctx.repo->commit_filter) cgit_close_filter(ctx.repo->commit_filter); html("</div>"); html("<div class='notes-footer'></div>"); } if (parents < 3) { if (parents) tmp = sha1_to_hex(commit->parents->item->object.sha1); else tmp = NULL; cgit_print_diff(ctx.qry.sha1, tmp, prefix, 0); } strbuf_release(¬es); cgit_free_commitinfo(info); }
void cgit_print_repolist(void) { int i, columns = 3, hits = 0, header = 0; char *last_section = NULL; char *section; int sorted = 0; 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 (ctx.repo->hide || ctx.repo->ignore) continue; if (!(is_match(ctx.repo) && is_in_url(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); cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL); html("</td>"); } html("</tr>\n"); } html("</table>"); if (!hits) cgit_print_error("No repositories found"); else if (hits > ctx.cfg.max_repo_count) print_pager(hits, ctx.cfg.max_repo_count, ctx.qry.search, ctx.qry.sort); cgit_print_docend(); }
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 && path) { 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); 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("Bad hex value: %s", hex); return; } } else { if (get_sha1(head, sha1)) { cgit_print_error("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("Bad object name: %s", hex); return; } buf = read_sha1_file(sha1, &type, &size); if (!buf) { cgit_print_error("Error reading object %s", hex); return; } buf[size] = '\0'; ctx.page.mimetype = ctx.qry.mimetype; if (!ctx.page.mimetype) { if (buffer_is_binary(buf, size)) ctx.page.mimetype = "application/octet-stream"; else ctx.page.mimetype = "text/plain"; } ctx.page.filename = path; cgit_print_http_headers(&ctx); html_raw(buf, size); }