コード例 #1
0
ファイル: ui-plain.c プロジェクト: ifzz/cgit
static void print_dir(const unsigned char *sha1, const char *base,
		      int baselen, const char *path)
{
	char *fullpath, *slash;
	size_t len;

	fullpath = buildpath(base, baselen, path);
	slash = (fullpath[0] == '/' ? "" : "/");
	ctx.page.etag = sha1_to_hex(sha1);
	cgit_print_http_headers();
	htmlf("<html><head><title>%s", slash);
	html_txt(fullpath);
	htmlf("</title></head>\n<body>\n<h2>%s", slash);
	html_txt(fullpath);
	html("</h2>\n<ul>\n");
	len = strlen(fullpath);
	if (len > 1) {
		fullpath[len - 1] = 0;
		slash = strrchr(fullpath, '/');
		if (slash)
			*(slash + 1) = 0;
		else {
			free(fullpath);
			fullpath = NULL;
		}
		html("<li>");
		cgit_plain_link("../", NULL, NULL, ctx.qry.head, ctx.qry.sha1,
				fullpath);
		html("</li>\n");
	}
	free(fullpath);
}
コード例 #2
0
ファイル: ui-log.c プロジェクト: p00ya/cgit
void print_commit(struct commit *commit)
{
	struct commitinfo *info;
	char *tmp;
	int cols = 2;

	info = cgit_parse_commit(commit);
	htmlf("<tr%s><td>",
		ctx.qry.showmsg ? " class='logheader'" : "");
	tmp = fmt("id=%s", sha1_to_hex(commit->object.sha1));
	tmp = cgit_fileurl(ctx.repo->url, "commit", ctx.qry.vpath, tmp);
	html_link_open(tmp, NULL, NULL);
	cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE);
	html_link_close();
	htmlf("</td><td%s>",
		ctx.qry.showmsg ? " class='logsubject'" : "");
	cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head,
			 sha1_to_hex(commit->object.sha1), ctx.qry.vpath, 0);
	show_commit_decorations(commit);
	html("</td><td>");
	html_txt(info->author);
	if (ctx.repo->enable_log_filecount) {
		files = 0;
		add_lines = 0;
		rem_lines = 0;
		cgit_diff_commit(commit, inspect_files);
		html("</td><td>");
		htmlf("%d", files);
		if (ctx.repo->enable_log_linecount) {
			html("</td><td>");
			htmlf("-%d/+%d", rem_lines, add_lines);
		}
	}
	html("</td></tr>\n");
	if (ctx.qry.showmsg) {
		struct strbuf notes = STRBUF_INIT;
		format_note(NULL, commit->object.sha1, &notes, PAGE_ENCODING, 0);

		if (ctx.repo->enable_log_filecount) {
			cols++;
			if (ctx.repo->enable_log_linecount)
				cols++;
		}
		htmlf("<tr class='nohover'><td/><td colspan='%d' class='logmsg'>",
			cols);
		html_txt(info->msg);
		html("</td></tr>\n");
		if (notes.len != 0) {
			html("<tr class='nohover'>");
			html("<td class='lognotes-label'>Notes:</td>");
			htmlf("<td colspan='%d' class='lognotes'>",
				cols);
			html_txt(notes.buf);
			html("</td></tr>\n");
		}
		strbuf_release(&notes);
	}
	cgit_free_commitinfo(info);
}
コード例 #3
0
ファイル: ui-atom.c プロジェクト: certik/cgit
void cgit_print_atom(char *tip, char *path, int max_count)
{
	char *host;
	const char *argv[] = {NULL, tip, NULL, NULL, NULL};
	struct commit *commit;
	struct rev_info rev;
	int argc = 2;

	if (!tip)
		argv[1] = ctx.qry.head;

	if (path) {
		argv[argc++] = "--";
		argv[argc++] = path;
	}

	init_revisions(&rev, NULL);
	rev.abbrev = DEFAULT_ABBREV;
	rev.commit_format = CMIT_FMT_DEFAULT;
	rev.verbose_header = 1;
	rev.show_root_diff = 0;
	rev.max_count = max_count;
	setup_revisions(argc, argv, &rev, NULL);
	prepare_revision_walk(&rev);

	host = cgit_hosturl();
	ctx.page.mimetype = "text/xml";
	ctx.page.charset = "utf-8";
	cgit_print_http_headers(&ctx);
	html("<feed xmlns='http://www.w3.org/2005/Atom'>\n");
	html("<title>");
	html_txt(ctx.repo->name);
	html("</title>\n");
	html("<subtitle>");
	html_txt(ctx.repo->desc);
	html("</subtitle>\n");
	if (host) {
		html("<link rel='alternate' type='text/html' href='http://");
		html_attr(host);
		html_attr(cgit_repourl(ctx.repo->url));
		html("'/>\n");
	}
	while ((commit = get_revision(&rev)) != NULL) {
		add_entry(commit, host);
		free(commit->buffer);
		commit->buffer = NULL;
		free_commit_list(commit->parents);
		commit->parents = NULL;
	}
	html("</feed>\n");
}
コード例 #4
0
ファイル: ui-stats.c プロジェクト: p00ya/cgit
/* 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);
}
コード例 #5
0
static void cgit_print_diffstat(const struct object_id *old_oid,
				const struct object_id *new_oid,
				const char *prefix)
{
	int i;

	html("<div class='diffstat-header'>");
	cgit_diff_link("Diffstat", NULL, NULL, ctx.qry.head, ctx.qry.sha1,
		       ctx.qry.sha2, NULL);
	if (prefix) {
		html(" (limited to '");
		html_txt(prefix);
		html("')");
	}
	html("</div>");
	html("<table summary='diffstat' class='diffstat'>");
	max_changes = 0;
	cgit_diff_tree(old_oid, new_oid, inspect_filepair, prefix,
		       ctx.qry.ignorews);
	for (i = 0; i<files; i++)
		print_fileinfo(&items[i]);
	html("</table>");
	html("<div class='diffstat-summary'>");
	htmlf("%d files changed, %d insertions, %d deletions",
	      files, total_adds, total_rems);
	html("</div>");
}
コード例 #6
0
ファイル: ui-refs.c プロジェクト: certik/cgit
static int print_branch(struct refinfo *ref)
{
	struct commitinfo *info = ref->commit;
	char *name = (char *)ref->refname;

	if (!info)
		return 1;
	html("<tr><td>");
	cgit_log_link(name, NULL, NULL, name, NULL, NULL, 0, NULL, NULL,
		      ctx.qry.showmsg);
	html("</td><td>");

	if (ref->object->type == OBJ_COMMIT) {
		cgit_commit_link(info->subject, NULL, NULL, name, NULL);
		html("</td><td>");
		html_txt(info->author);
		html("</td><td colspan='2'>");
		cgit_print_age(info->commit->date, -1, NULL);
	} else {
		html("</td><td></td><td>");
		cgit_object_link(ref->object);
	}
	html("</td></tr>\n");
	return 0;
}
コード例 #7
0
ファイル: html.c プロジェクト: ifzz/cgit
void html_intoption(int value, const char *text, int selected_value)
{
	htmlf("<option value='%d'%s>", value,
	      value == selected_value ? " selected='selected'" : "");
	html_txt(text);
	html("</option>");
}
コード例 #8
0
ファイル: ui-tag.c プロジェクト: metajack/cgit
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;
}
コード例 #9
0
ファイル: ui-refs.c プロジェクト: Distrotech/cgit
static int print_tag(struct refinfo *ref)
{
	struct tag *tag = NULL;
	struct taginfo *info = NULL;
	char *name = (char *)ref->refname;
	struct object *obj = ref->object;

	if (obj->type == OBJ_TAG) {
		tag = (struct tag *)obj;
		obj = tag->tagged;
		info = ref->tag;
		if (!tag || !info)
			return 1;
	}

	html("<tr><td>");
	cgit_tag_link(name, NULL, NULL, ctx.qry.head, name);
	html("</td><td>");
	if (ctx.repo->snapshots && (obj->type == OBJ_COMMIT))
		print_tag_downloads(ctx.repo, name);
	else
		cgit_object_link(obj);
	html("</td><td>");
	if (info) {
		if (info->tagger) {
			cgit_open_filter(ctx.repo->email_filter, info->tagger_email, "refs");
			html_txt(info->tagger);
			cgit_close_filter(ctx.repo->email_filter);
		}
	} else if (ref->object->type == OBJ_COMMIT) {
		cgit_open_filter(ctx.repo->email_filter, ref->commit->author_email, "refs");
		html_txt(ref->commit->author);
		cgit_close_filter(ctx.repo->email_filter);
	}
	html("</td><td colspan='2'>");
	if (info) {
		if (info->tagger_date > 0)
			cgit_print_age(info->tagger_date, -1, NULL);
	} else if (ref->object->type == OBJ_COMMIT) {
		cgit_print_age(ref->commit->commit->date, -1, NULL);
	}
	html("</td></tr>\n");

	return 0;
}
コード例 #10
0
ファイル: ui-tag.c プロジェクト: metajack/cgit
static void print_tag_content(char *buf)
{
    char *p;

    if (!buf)
        return;

    html("<div class='commit-subject'>");
    p = strchr(buf, '\n');
    if (p)
        *p = '\0';
    html_txt(buf);
    html("</div>");
    if (p) {
        html("<div class='commit-msg'>");
        html_txt(++p);
        html("</div>");
    }
}
コード例 #11
0
ファイル: html.c プロジェクト: ifzz/cgit
void html_vtxtf(const char *format, va_list ap)
{
	va_list cp;
	struct strbuf buf = STRBUF_INIT;

	va_copy(cp, ap);
	strbuf_vaddf(&buf, format, cp);
	va_end(cp);
	html_txt(buf.buf);
	strbuf_release(&buf);
}
コード例 #12
0
ファイル: html.c プロジェクト: rbrito/cgit
void html_option(const char *value, const char *text, const char *selected_value)
{
	html("<option value='");
	html_attr(value);
	html("'");
	if (selected_value && !strcmp(selected_value, value))
		html(" selected='selected'");
	html(">");
	html_txt(text);
	html("</option>\n");
}
コード例 #13
0
ファイル: ui-summary.c プロジェクト: adamrofer/cgit
static void print_url(char *base, char *suffix)
{
	if (!base || !*base)
		return;
	if (urls++ == 0) {
		html("<tr class='nohover'><td colspan='4'>&nbsp;</td></tr>");
		html("<tr><th class='left' colspan='4'>Clone</th></tr>\n");
	}
	if (suffix && *suffix)
		base = fmt("%s/%s", base, suffix);
	html("<tr><td colspan='4'><a href='");
	html_url_path(base);
	html("'>");
	html_txt(base);
	html("</a></td></tr>\n");
}
コード例 #14
0
ファイル: ui-diff.c プロジェクト: MarkLodato/cgit
void cgit_print_diffstat(const unsigned char *old_sha1,
			 const unsigned char *new_sha1, const char *prefix)
{
	int i, save_context = ctx.qry.context;

	html("<div class='diffstat-header'>");
	cgit_diff_link("Diffstat", NULL, NULL, ctx.qry.head, ctx.qry.sha1,
		       ctx.qry.sha2, NULL, 0);
	if (prefix) {
		html(" (limited to '");
		html_txt(prefix);
		html("')");
	}
	html(" (");
	ctx.qry.context = (save_context > 0 ? save_context : 3) << 1;
	cgit_self_link("more", NULL, NULL, &ctx);
	html("/");
	ctx.qry.context = (save_context > 3 ? save_context : 3) >> 1;
	cgit_self_link("less", NULL, NULL, &ctx);
	ctx.qry.context = save_context;
	html(" context)");
	html(" (");
	ctx.qry.ignorews = (ctx.qry.ignorews + 1) % 2;
	cgit_self_link(ctx.qry.ignorews ? "ignore" : "show", NULL, NULL, &ctx);
	ctx.qry.ignorews = (ctx.qry.ignorews + 1) % 2;
	html(" whitespace changes)");
	html("</div>");
	html("<table summary='diffstat' class='diffstat'>");
	max_changes = 0;
	cgit_diff_tree(old_sha1, new_sha1, inspect_filepair, prefix,
		       ctx.qry.ignorews);
	for(i = 0; i<files; i++)
		print_fileinfo(&items[i]);
	html("</table>");
	html("<div class='diffstat-summary'>");
	htmlf("%d files changed, %d insertions, %d deletions",
	      files, total_adds, total_rems);
	html("</div>");
}
コード例 #15
0
ファイル: ui-refs.c プロジェクト: certik/cgit
static int print_tag(struct refinfo *ref)
{
	struct tag *tag;
	struct taginfo *info;
	char *name = (char *)ref->refname;

	if (ref->object->type == OBJ_TAG) {
		tag = (struct tag *)ref->object;
		info = ref->tag;
		if (!tag || !info)
			return 1;
		html("<tr><td>");
		cgit_tag_link(name, NULL, NULL, ctx.qry.head, name);
		html("</td><td>");
		if (ctx.repo->snapshots && (tag->tagged->type == OBJ_COMMIT))
			print_tag_downloads(ctx.repo, name);
		else
			cgit_object_link(tag->tagged);
		html("</td><td>");
		if (info->tagger)
			html(info->tagger);
		html("</td><td colspan='2'>");
		if (info->tagger_date > 0)
			cgit_print_age(info->tagger_date, -1, NULL);
		html("</td></tr>\n");
	} else {
		if (!header)
			print_tag_header();
		html("<tr><td>");
		html_txt(name);
		html("</td><td>");
		if (ctx.repo->snapshots && (tag->tagged->type == OBJ_COMMIT))
			print_tag_downloads(ctx.repo, name);
		else
			cgit_object_link(ref->object);
		html("</td></tr>\n");
	}
	return 0;
}
コード例 #16
0
ファイル: ui-summary.c プロジェクト: rburgstaler/cgit
static void print_url(const char *url)
{
	int columns = 3;

	if (ctx.repo->enable_log_filecount)
		columns++;
	if (ctx.repo->enable_log_linecount)
		columns++;

	if (urls++ == 0) {
		htmlf("<tr class='nohover'><td colspan='%d'>&nbsp;</td></tr>", columns);
		htmlf("<tr><th class='left' colspan='%d'>Clone</th></tr>\n", columns);
	}

	htmlf("<tr><td colspan='%d'><a rel='vcs-git' href='", columns);
	html_url_path(url);
	html("' title='");
	html_attr(ctx.repo->name);
	html(" Git repository'>");
	html_txt(url);
	html("</a></td></tr>\n");
}
コード例 #17
0
ファイル: ui-summary.c プロジェクト: jhuttner/cgit
static void print_url(char *base, char *suffix)
{
	if (!base || !*base)
		return;
	if (urls++ == 0) {
		html("<tr class='nohover'><td colspan='4'>&nbsp;</td></tr>");
		html("<tr><th class='left' colspan='4'>Clone</th></tr>\n");
	}
	if (suffix && *suffix)
		base = fmt("%s/%s", base, suffix);

	/* Chrome messes up SSH urls so use an input field of type=text instead. */

	/*html("<tr><td colspan='4'><a href='");*/
	/*html_url_path(base);*/
	/*html("'>");*/
	/*html_txt(base);*/
	/*html("</a></td></tr>\n");*/

	html("<tr><td colspan='4'><input type='text' size='70' value='");
	html_txt(base);
	html("' />");
	html("</td></tr>\n");
}
コード例 #18
0
ファイル: ui-log.c プロジェクト: Turbo87/cgit
void print_commit(struct commit *commit, struct rev_info *revs)
{
	struct commitinfo *info;
	int cols = revs->graph ? 3 : 2;
	struct strbuf graphbuf = STRBUF_INIT;
	struct strbuf msgbuf = STRBUF_INIT;

	if (ctx.repo->enable_log_filecount)
		cols++;
	if (ctx.repo->enable_log_linecount)
		cols++;

	if (revs->graph) {
		/* Advance graph until current commit */
		while (!graph_next_line(revs->graph, &graphbuf)) {
			/* Print graph segment in otherwise empty table row */
			html("<tr class='nohover'><td class='commitgraph'>");
			html(graphbuf.buf);
			htmlf("</td><td colspan='%d' /></tr>\n", cols);
			strbuf_setlen(&graphbuf, 0);
		}
		/* Current commit's graph segment is now ready in graphbuf */
	}

	info = cgit_parse_commit(commit);
	htmlf("<tr%s>", ctx.qry.showmsg ? " class='logheader'" : "");

	if (revs->graph) {
		/* Print graph segment for current commit */
		html("<td class='commitgraph'>");
		html(graphbuf.buf);
		html("</td>");
		strbuf_setlen(&graphbuf, 0);
	}
	else {
		html("<td>");
		cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE);
		html("</td>");
	}

	htmlf("<td%s>", ctx.qry.showmsg ? " class='logsubject'" : "");
	if (ctx.qry.showmsg) {
		/* line-wrap long commit subjects instead of truncating them */
		size_t subject_len = strlen(info->subject);

		if (subject_len > ctx.cfg.max_msg_len &&
		    ctx.cfg.max_msg_len >= 15) {
			/* symbol for signaling line-wrap (in PAGE_ENCODING) */
			const char wrap_symbol[] = { ' ', 0xE2, 0x86, 0xB5, 0 };
			int i = ctx.cfg.max_msg_len - strlen(wrap_symbol);

			/* Rewind i to preceding space character */
			while (i > 0 && !isspace(info->subject[i]))
				--i;
			if (!i) /* Oops, zero spaces. Reset i */
				i = ctx.cfg.max_msg_len - strlen(wrap_symbol);

			/* add remainder starting at i to msgbuf */
			strbuf_add(&msgbuf, info->subject + i, subject_len - i);
			strbuf_trim(&msgbuf);
			strbuf_add(&msgbuf, "\n\n", 2);

			/* Place wrap_symbol at position i in info->subject */
			strcpy(info->subject + i, wrap_symbol);
		}
	}
	cgit_commit_link(info->subject, NULL, NULL, ctx.qry.head,
			 sha1_to_hex(commit->object.sha1), ctx.qry.vpath, 0);
	show_commit_decorations(commit);
	html("</td><td>");
	html_txt(info->author);

	if (revs->graph) {
		html("</td><td>");
		cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE);
	}

	if (ctx.repo->enable_log_filecount || ctx.repo->enable_log_linecount) {
		files = 0;
		add_lines = 0;
		rem_lines = 0;
		cgit_diff_commit(commit, inspect_files, ctx.qry.vpath);
	}

	if (ctx.repo->enable_log_filecount)
		htmlf("</td><td>%d", files);
	if (ctx.repo->enable_log_linecount)
		htmlf("</td><td>-%d/+%d", rem_lines, add_lines);

	html("</td></tr>\n");

	if (revs->graph || ctx.qry.showmsg) { /* Print a second table row */
		html("<tr class='nohover'>");

		if (ctx.qry.showmsg) {
			/* Concatenate commit message + notes in msgbuf */
			if (info->msg && *(info->msg)) {
				strbuf_addstr(&msgbuf, info->msg);
				strbuf_addch(&msgbuf, '\n');
			}
			format_note(NULL, commit->object.sha1, &msgbuf,
			            PAGE_ENCODING,
			            NOTES_SHOW_HEADER | NOTES_INDENT);
			strbuf_addch(&msgbuf, '\n');
			strbuf_ltrim(&msgbuf);
		}

		if (revs->graph) {
			int lines = 0;

			/* Calculate graph padding */
			if (ctx.qry.showmsg) {
				/* Count #lines in commit message + notes */
				const char *p = msgbuf.buf;
				lines = 1;
				while ((p = strchr(p, '\n'))) {
					p++;
					lines++;
				}
			}

			/* Print graph padding */
			html("<td class='commitgraph'>");
			while (lines > 0 || !graph_is_commit_finished(revs->graph)) {
				if (graphbuf.len)
					html("\n");
				strbuf_setlen(&graphbuf, 0);
				graph_next_line(revs->graph, &graphbuf);
				html(graphbuf.buf);
				lines--;
			}
			html("</td>\n");
		}
		else
			html("<td/>"); /* Empty 'Age' column */

		/* Print msgbuf into remainder of table row */
		htmlf("<td colspan='%d'%s>\n", cols,
			ctx.qry.showmsg ? " class='logmsg'" : "");
		html_txt(msgbuf.buf);
		html("</td></tr>\n");
	}

	strbuf_release(&msgbuf);
	strbuf_release(&graphbuf);
	cgit_free_commitinfo(info);
}
コード例 #19
0
static void print_fileinfo(struct fileinfo *info)
{
	char *class;

	switch (info->status) {
	case DIFF_STATUS_ADDED:
		class = "add";
		break;
	case DIFF_STATUS_COPIED:
		class = "cpy";
		break;
	case DIFF_STATUS_DELETED:
		class = "del";
		break;
	case DIFF_STATUS_MODIFIED:
		class = "upd";
		break;
	case DIFF_STATUS_RENAMED:
		class = "mov";
		break;
	case DIFF_STATUS_TYPE_CHANGED:
		class = "typ";
		break;
	case DIFF_STATUS_UNKNOWN:
		class = "unk";
		break;
	case DIFF_STATUS_UNMERGED:
		class = "stg";
		break;
	default:
		die("bug: unhandled diff status %c", info->status);
	}

	html("<tr>");
	htmlf("<td class='mode'>");
	if (is_null_oid(info->new_oid)) {
		cgit_print_filemode(info->old_mode);
	} else {
		cgit_print_filemode(info->new_mode);
	}

	if (info->old_mode != info->new_mode &&
	    !is_null_oid(info->old_oid) &&
	    !is_null_oid(info->new_oid)) {
		html("<span class='modechange'>[");
		cgit_print_filemode(info->old_mode);
		html("]</span>");
	}
	htmlf("</td><td class='%s'>", class);
	cgit_diff_link(info->new_path, NULL, NULL, ctx.qry.head, ctx.qry.sha1,
		       ctx.qry.sha2, info->new_path);
	if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED) {
		htmlf(" (%s from ",
		      info->status == DIFF_STATUS_COPIED ? "copied" : "renamed");
		html_txt(info->old_path);
		html(")");
	}
	html("</td><td class='right'>");
	if (info->binary) {
		htmlf("bin</td><td class='graph'>%ld -> %ld bytes",
		      info->old_size, info->new_size);
		return;
	}
	htmlf("%d", info->added + info->removed);
	html("</td><td class='graph'>");
	htmlf("<table summary='file diffstat' width='%d%%'><tr>", (max_changes > 100 ? 100 : max_changes));
	htmlf("<td class='add' style='width: %.1f%%;'/>",
	      info->added * 100.0 / max_changes);
	htmlf("<td class='rem' style='width: %.1f%%;'/>",
	      info->removed * 100.0 / max_changes);
	htmlf("<td class='none' style='width: %.1f%%;'/>",
	      (max_changes - info->removed - info->added) * 100.0 / max_changes);
	html("</tr></table></td></tr>\n");
}
コード例 #20
0
ファイル: ui-stats.c プロジェクト: formorer/pkg-cgit
/* 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();
}
コード例 #21
0
ファイル: ui-blame.c プロジェクト: johnkeeping/cgit
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();
}
コード例 #22
0
ファイル: ui-atom.c プロジェクト: qznc/cgit
void add_entry(struct commit *commit, struct commitinfo *info, char *host, int enable_atom_diff)
{
	char delim = '&';
	char *hex;
	char *hex_parent;
	char *mail, *t, *t2;

	hex = sha1_to_hex(commit->object.sha1);
	if (commit->parents) {
		hex_parent = sha1_to_hex(commit->parents->item->object.sha1);
	} else {
		hex_parent = NULL; /* means before initial commit */
	}
	html("<entry>\n");
	html("<title>");
	html_txt(info->subject);
	html("</title>\n");
	html("<updated>");
	cgit_print_date(info->committer_date, FMT_ATOMDATE, 0);
	html("</updated>\n");
	html("<author>\n");
	if (info->author) {
		html("<name>");
		html_txt(info->author);
		html("</name>\n");
	}
	if (info->author_email && !ctx.cfg.noplainemail) {
		mail = xstrdup(info->author_email);
		t = strchr(mail, '<');
		if (t)
			t++;
		else
			t = mail;
		t2 = strchr(t, '>');
		if (t2)
			*t2 = '\0';
		html("<email>");
		html_txt(t);
		html("</email>\n");
		free(mail);
	}
	html("</author>\n");
	html("<published>");
	cgit_print_date(info->author_date, FMT_ATOMDATE, 0);
	html("</published>\n");
	if (host) {
		html("<link rel='alternate' type='text/html' href='");
		html(cgit_httpscheme());
		html_attr(host);
		html_attr(cgit_pageurl(ctx.repo->url, "commit", NULL));
		if (ctx.cfg.virtual_root)
			delim = '?';
		htmlf("%cid=%s", delim, hex);
		html("'/>\n");

		html("<id>");
		html(cgit_httpscheme());
		html_attr(host);
		html_attr(cgit_repourl(ctx.repo->url));
		htmlf("/commit/?id=%s</id>\n", hex);
	} else {
		htmlf("<id>urn:tag:%s</id>\n", hex);
	}
	html("<content type='xhtml'>\n");
	html("<div xmlns='http://www.w3.org/1999/xhtml'>\n");
	html("<pre>\n");
	html_txt(info->msg);
	html("</pre>\n");
	if (enable_atom_diff) {
		html("<pre class='diff'>\n");
		html("<style scoped=\"scoped\">\n"); /* HTML5 with graceful degradation */
		html("table.diff .add, span.add { background-color: #afa; }");
		html("table.diff .del, span.remove { background-color: #faa; }");
		html("</style>\n");
		cgit_print_diff(hex, hex_parent, NULL);
		html("</pre>");
	}
	html("</div>\n");
	html("</content>\n");
	html("</entry>\n");
}
コード例 #23
0
ファイル: ui-tag.c プロジェクト: formorer/pkg-cgit
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);
}
コード例 #24
0
ファイル: ui-repolist.c プロジェクト: Turbo87/cgit
void cgit_print_repolist()
{
	int i, columns = 4, hits = 0, header = 0;
	char *last_section = NULL;
	char *section;
	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);
	else if (ctx.cfg.sort_sections)
		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_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);
		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>");
		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, ctx.qry.sort);
	cgit_print_docend();
}
コード例 #25
0
ファイル: ui-commit.c プロジェクト: BinaryPrison/cgit
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);
}
コード例 #26
0
ファイル: ui-atom.c プロジェクト: qznc/cgit
void cgit_print_atom(char *tip, char *path, int max_count, int enable_atom_diff)
{
	char *host;
	const char *argv[] = {NULL, tip, NULL, NULL, NULL};
	struct commit *commit;
	struct rev_info rev;
	int argc = 2;
	int had_global_updated = 0;

	if (ctx.qry.show_all)
		argv[1] = "--all";
	else if (!tip)
		argv[1] = ctx.qry.head;

	if (path) {
		argv[argc++] = "--";
		argv[argc++] = path;
	}

	init_revisions(&rev, NULL);
	rev.abbrev = DEFAULT_ABBREV;
	rev.commit_format = CMIT_FMT_DEFAULT;
	rev.verbose_header = 1;
	rev.show_root_diff = 0;
	rev.max_count = max_count;
	setup_revisions(argc, argv, &rev, NULL);
	prepare_revision_walk(&rev);

	host = cgit_hosturl();
	ctx.page.mimetype = "text/xml";
	ctx.page.charset = "utf-8";
	cgit_print_http_headers(&ctx);
	html("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
	html("<feed xmlns='http://www.w3.org/2005/Atom'>\n");
	html("<title>");
	html_txt(ctx.repo->name);
	if (path) {
		html("/");
		html_txt(path);
	}
	if (tip && !ctx.qry.show_all) {
		html(", branch ");
		html_txt(tip);
	}
	html("</title>\n");
	html("<subtitle>");
	html_txt(ctx.repo->desc);
	html("</subtitle>\n");
	if (host) {
		html("<link rel='alternate' type='text/html' href='");
		html(cgit_httpscheme());
		html_attr(host);
		html_attr(cgit_repourl(ctx.repo->url));
		html("'/>\n");

		html("<link rel='self' type='application/atom+xml' href='");
		html(cgit_httpscheme());
		html_attr(host);
		html_attr(cgit_repourl(ctx.repo->url));
		html("atom");
		if (tip) {
			html("/?h=");
			html_txt(tip);
		}
		html("'/>\n");

		html("<id>");
		html(cgit_httpscheme());
		html_txt(host);
		html_txt(cgit_repourl(ctx.repo->url));
		html("</id>\n");
	}

	while ((commit = get_revision(&rev)) != NULL) {
		struct commitinfo *info = cgit_parse_commit(commit);
		if (!had_global_updated) {
			html("<updated>");
			cgit_print_date(info->committer_date, FMT_ATOMDATE, 0);
			html("</updated>\n");
			had_global_updated = 1;
		}
		add_entry(commit, info, host, enable_atom_diff);

		cgit_free_commitinfo(info);
		free(commit->buffer);
		commit->buffer = NULL;
		free_commit_list(commit->parents);
		commit->parents = NULL;
	}
	html("</feed>\n");
}
コード例 #27
0
ファイル: ui-commit.c プロジェクト: certik/cgit
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);
}
コード例 #28
0
ファイル: ui-shared.c プロジェクト: certik/cgit
void cgit_print_error(char *msg)
{
	html("<div class='error'>");
	html_txt(msg);
	html("</div>\n");
}
コード例 #29
0
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();
}
コード例 #30
0
ファイル: ui-stats.c プロジェクト: formorer/pkg-cgit
static void print_authors(struct string_list *authors, int top,
			  const struct cgit_period *period)
{
	struct string_list_item *author;
	struct authorstat *authorstat;
	struct string_list *items;
	struct string_list_item *date;
	time_t now;
	long i, j, total;
	struct tm *tm;
	char *tmp;

	time(&now);
	tm = gmtime(&now);
	period->trunc(tm);
	for (i = 1; i < period->count; i++)
		period->dec(tm);

	html("<table class='stats'><tr><th>Author</th>");
	for (j = 0; j < period->count; j++) {
		tmp = period->pretty(tm);
		htmlf("<th>%s</th>", tmp);
		period->inc(tm);
	}
	html("<th>Total</th></tr>\n");

	if (top <= 0 || top > authors->nr)
		top = authors->nr;

	for (i = 0; i < top; i++) {
		author = &authors->items[i];
		html("<tr><td class='left'>");
		html_txt(author->string);
		html("</td>");
		authorstat = author->util;
		items = &authorstat->list;
		total = 0;
		for (j = 0; j < period->count; j++)
			period->dec(tm);
		for (j = 0; j < period->count; j++) {
			tmp = period->pretty(tm);
			period->inc(tm);
			date = string_list_lookup(items, tmp);
			if (!date)
				html("<td>0</td>");
			else {
				htmlf("<td>"SZ_FMT"</td>", (size_t)date->util);
				total += (size_t)date->util;
			}
		}
		htmlf("<td class='sum'>%ld</td></tr>", total);
	}

	if (top < authors->nr)
		print_combined_authorrow(authors, top, authors->nr - 1,
			"Others (%ld)", "left", "", "sum", period);

	print_combined_authorrow(authors, 0, authors->nr - 1, "Total",
		"total", "sum", "sum", period);
	html("</table>");
}