Пример #1
0
/* 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>&nbsp;&nbsp;<input type='submit' value='Reload'/></noscript>");
	html("</form>");
	print_authors(&authors, top, period);
}
Пример #2
0
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;
}
Пример #3
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();
}
Пример #4
0
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);
}
Пример #5
0
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;
}
Пример #6
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);
}
Пример #7
0
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;
}
Пример #8
0
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;
}
Пример #9
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";
		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();
}
Пример #10
0
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);
	}
}
Пример #11
0
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);
}
Пример #12
0
/* 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);
}
Пример #13
0
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();
}
Пример #14
0
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);
}
Пример #15
0
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, &notes, 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(&notes);
	cgit_free_commitinfo(info);
}
Пример #16
0
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();
}
Пример #17
0
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);
}