summaryrefslogtreecommitdiffstatshomepage
path: root/ui-diff.c
diff options
context:
space:
mode:
Diffstat (limited to 'ui-diff.c')
-rw-r--r--ui-diff.c5
1 files changed, 4 insertions, 1 deletions
diff --git a/ui-diff.c b/ui-diff.c
index 7ec5701..999b6f3 100644
--- a/ui-diff.c
+++ b/ui-diff.c
@@ -35,7 +35,10 @@ static void header(unsigned char *sha1, char *path1,
unsigned char *sha2, char *path2)
{
char *abbrev1, *abbrev2;
-
+ if (is_null_sha1(sha1))
+ path1 = "dev/null";
+ if (is_null_sha1(sha2))
+ path2 = "dev/null";
html("<tr><td>");
html("<div class='head'>");
html("diff --git a/");
98'>98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
/* ui-commit.c: generate commit view
 *
 * Copyright (C) 2006 Lars Hjemli
 *
 * Licensed under GNU General Public License v2
 *   (see COPYING for full license text)
 */

#include "cgit.h"

int files = 0;

void print_filepair(struct diff_filepair *pair)
{
	char *query;
	char *class;
	
	switch (pair->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", pair->status);
	}

	html("<tr>");
	htmlf("<td class='mode'>");
	if (is_null_sha1(pair->two->sha1)) {
		html_filemode(pair->one->mode);
	} else {
		html_filemode(pair->two->mode);
	}

	if (pair->one->mode != pair->two->mode && 
	    !is_null_sha1(pair->one->sha1) && 
	    !is_null_sha1(pair->two->sha1)) {
		html("<span class='modechange'>[");
		html_filemode(pair->one->mode);
		html("]</span>");
	}
	htmlf("</td><td class='%s'>", class);
	query = fmt("id=%s&id2=%s", sha1_to_hex(pair->one->sha1), 
		    sha1_to_hex(pair->two->sha1));	
	html_link_open(cgit_pageurl(cgit_query_repo, "diff", query), 
		       NULL, NULL);
	if (pair->status == DIFF_STATUS_COPIED || 
	    pair->status == DIFF_STATUS_RENAMED) {
		html_txt(pair->two->path);
		htmlf("</a> (%s from ", pair->status == DIFF_STATUS_COPIED ? 
		      "copied" : "renamed");
		query = fmt("id=%s", sha1_to_hex(pair->one->sha1));	
		html_link_open(cgit_pageurl(cgit_query_repo, "view", query), 
			       NULL, NULL);
		html_txt(pair->one->path);
		html("</a>)");
	} else {
		html_txt(pair->two->path);
		html("</a>");
	}
	html("<td>");

	//TODO: diffstat graph
	
	html("</td></tr>\n");
	files++;	
}

void diff_format_cb(struct diff_queue_struct *q,
		    struct diff_options *options, void *data)
{
	int i;

	for (i = 0; i < q->nr; i++) {
		if (q->queue[i]->status == 'U')
			continue;
		print_filepair(q->queue[i]);
	}
}

void cgit_diffstat(struct commit *commit)
{
	struct diff_options opt;
	int ret;

	diff_setup(&opt);
	opt.output_format = DIFF_FORMAT_CALLBACK;
	opt.detect_rename = 1;
	opt.recursive = 1;
	opt.format_callback = diff_format_cb;
	diff_setup_done(&opt);
	
	if (commit->parents)
		ret = diff_tree_sha1(commit->parents->item->object.sha1,
				     commit->object.sha1,
				     "", &opt);
	else
		ret = diff_root_tree_sha1(commit->object.sha1, "", &opt);

	diffcore_std(&opt);
	diff_flush(&opt);
}

void cgit_print_commit(const char *hex)
{
	struct commit *commit;
	struct commitinfo *info;
	struct commit_list *p;
	unsigned char sha1[20];
	char *query;

	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 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);
	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);
	html("</td></tr>\n");
	html("<tr><th>tree</th><td colspan='2' class='sha1'><a href='");
	query = fmt("id=%s", sha1_to_hex(commit->tree->object.sha1));
	html_attr(cgit_pageurl(cgit_query_repo, "tree", query));
	htmlf("'>%s</a></td></tr>\n", sha1_to_hex(commit->tree->object.sha1));
      	for (p = commit->parents; p ; p = p->next) {
		html("<tr><th>parent</th>"
		     "<td colspan='2' class='sha1'>"
		     "<a href='");
		query = fmt("id=%s", sha1_to_hex(p->item->object.sha1));
		html_attr(cgit_pageurl(cgit_query_repo, "commit", query));
		htmlf("'>%s</a></td></tr>\n", 
		      sha1_to_hex(p->item->object.sha1));
	}
	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>");
	html("<table class='diffstat'>");
	html("<tr><th colspan='3'>Affected files</tr>\n");
	cgit_diffstat(commit);
	htmlf("<tr><td colspan='3' class='summary'>"
	      "%d file%s changed</td></tr>\n", files, files > 1 ? "s" : "");
	html("</table>");
	cgit_free_commitinfo(info);
}