");
+ html("");
+ htmlf("%d files changed, %d insertions, %d deletions",
+ files, total_adds, total_rems);
+ html("
");
+}
/*
@@ -35,97 +216,199 @@ static void print_line(char *line, int len)
line[len-1] = c;
}
-/*
- * Receive diff-buffers from xdiff and concatenate them as
- * needed across multiple callbacks.
- *
- * This is basically a copy of xdiff-interface.c/xdiff_outf(),
- * ripped from git and modified to use globals instead of
- * a special callback-struct.
- */
-int diff_cb(void *priv_, mmbuffer_t *mb, int nbuf)
+static void header(unsigned char *sha1, char *path1, int mode1,
+ unsigned char *sha2, char *path2, int mode2)
{
- int i;
+ char *abbrev1, *abbrev2;
+ int subproject;
- for (i = 0; i < nbuf; i++) {
- if (mb[i].ptr[mb[i].size-1] != '\n') {
- /* Incomplete line */
- diff_buffer = xrealloc(diff_buffer,
- diff_buffer_size + mb[i].size);
- memcpy(diff_buffer + diff_buffer_size,
- mb[i].ptr, mb[i].size);
- diff_buffer_size += mb[i].size;
- continue;
- }
+ subproject = (S_ISGITLINK(mode1) || S_ISGITLINK(mode2));
+ html("");
+ html("diff --git a/");
+ html_txt(path1);
+ html(" b/");
+ html_txt(path2);
- /* we have a complete line */
- if (!diff_buffer) {
- print_line(mb[i].ptr, mb[i].size);
- continue;
- }
- diff_buffer = xrealloc(diff_buffer,
- diff_buffer_size + mb[i].size);
- memcpy(diff_buffer + diff_buffer_size, mb[i].ptr, mb[i].size);
- print_line(diff_buffer, diff_buffer_size + mb[i].size);
- free(diff_buffer);
- diff_buffer = NULL;
- diff_buffer_size = 0;
- }
- if (diff_buffer) {
- print_line(diff_buffer, diff_buffer_size);
- free(diff_buffer);
- diff_buffer = NULL;
- diff_buffer_size = 0;
- }
- return 0;
-}
+ if (is_null_sha1(sha1))
+ path1 = "dev/null";
+ if (is_null_sha1(sha2))
+ path2 = "dev/null";
-static int load_mmfile(mmfile_t *file, const unsigned char *sha1)
-{
- char type[20];
+ if (mode1 == 0)
+ htmlf("
new file mode %.6o", mode2);
- if (is_null_sha1(sha1)) {
- file->ptr = (char *)"";
- file->size = 0;
- } else {
- file->ptr = read_sha1_file(sha1, type, &file->size);
+ if (mode2 == 0)
+ htmlf("
deleted file mode %.6o", mode1);
+
+ if (!subproject) {
+ abbrev1 = xstrdup(find_unique_abbrev(sha1, DEFAULT_ABBREV));
+ abbrev2 = xstrdup(find_unique_abbrev(sha2, DEFAULT_ABBREV));
+ htmlf("
index %s..%s", abbrev1, abbrev2);
+ free(abbrev1);
+ free(abbrev2);
+ if (mode1 != 0 && mode2 != 0) {
+ htmlf(" %.6o", mode1);
+ if (mode2 != mode1)
+ htmlf("..%.6o", mode2);
+ }
+ html("
--- a/");
+ if (mode1 != 0)
+ cgit_tree_link(path1, NULL, NULL, ctx.qry.head,
+ sha1_to_hex(old_rev_sha1), path1);
+ else
+ html_txt(path1);
+ html("
+++ b/");
+ if (mode2 != 0)
+ cgit_tree_link(path2, NULL, NULL, ctx.qry.head,
+ sha1_to_hex(new_rev_sha1), path2);
+ else
+ html_txt(path2);
}
- return 1;
+ html("
");
}
-static void run_diff(const unsigned char *sha1, const unsigned char *sha2)
+static void filepair_cb(struct diff_filepair *pair)
{
- mmfile_t file1, file2;
- xpparam_t diff_params;
- xdemitconf_t emit_params;
- xdemitcb_t emit_cb;
+ unsigned long old_size = 0;
+ unsigned long new_size = 0;
+ int binary = 0;
+ linediff_fn print_line_fn = print_line;
- if (!load_mmfile(&file1, sha1) || !load_mmfile(&file2, sha2)) {
- cgit_print_error("Unable to load files for diff");
+ current_filepair = pair;
+ if (use_ssdiff) {
+ cgit_ssdiff_header_begin();
+ print_line_fn = cgit_ssdiff_line_cb;
+ }
+ header(pair->one->sha1, pair->one->path, pair->one->mode,
+ pair->two->sha1, pair->two->path, pair->two->mode);
+ if (use_ssdiff)
+ cgit_ssdiff_header_end();
+ if (S_ISGITLINK(pair->one->mode) || S_ISGITLINK(pair->two->mode)) {
+ if (S_ISGITLINK(pair->one->mode))
+ print_line_fn(fmt("-Subproject %s", sha1_to_hex(pair->one->sha1)), 52);
+ if (S_ISGITLINK(pair->two->mode))
+ print_line_fn(fmt("+Subproject %s", sha1_to_hex(pair->two->sha1)), 52);
+ if (use_ssdiff)
+ cgit_ssdiff_footer();
return;
}
+ if (cgit_diff_files(pair->one->sha1, pair->two->sha1, &old_size,
+ &new_size, &binary, ctx.qry.context,
+ ctx.qry.ignorews, print_line_fn))
+ cgit_print_error("Error running diff");
+ if (binary) {
+ if (use_ssdiff)
+ html("| Binary files differ |
");
+ else
+ html("Binary files differ");
+ }
+ if (use_ssdiff)
+ cgit_ssdiff_footer();
+}
- diff_params.flags = XDF_NEED_MINIMAL;
+void cgit_print_diff_ctrls()
+{
+ int i, curr;
- emit_params.ctxlen = 3;
- emit_params.flags = XDL_EMIT_FUNCNAMES;
+ html("");
+ html("
diff options");
+ html("
");
+ html("
");
+}
- emit_cb.outf = diff_cb;
+void cgit_print_diff(const char *new_rev, const char *old_rev,
+ const char *prefix, int show_ctrls)
+{
+ enum object_type type;
+ unsigned long size;
+ struct commit *commit, *commit2;
- xdl_diff(&file1, &file2, &diff_params, &emit_params, &emit_cb);
-}
+ if (!new_rev)
+ new_rev = ctx.qry.head;
+ get_sha1(new_rev, new_rev_sha1);
+ type = sha1_object_info(new_rev_sha1, &size);
+ if (type == OBJ_BAD) {
+ cgit_print_error(fmt("Bad object name: %s", new_rev));
+ return;
+ }
+ commit = lookup_commit_reference(new_rev_sha1);
+ if (!commit || parse_commit(commit)) {
+ cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(new_rev_sha1)));
+ return;
+ }
+ if (old_rev)
+ get_sha1(old_rev, old_rev_sha1);
+ 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)) {
+ type = sha1_object_info(old_rev_sha1, &size);
+ if (type == OBJ_BAD) {
+ cgit_print_error(fmt("Bad object name: %s", sha1_to_hex(old_rev_sha1)));
+ return;
+ }
+ commit2 = lookup_commit_reference(old_rev_sha1);
+ if (!commit2 || parse_commit(commit2)) {
+ cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(old_rev_sha1)));
+ return;
+ }
+ }
-void cgit_print_diff(const char *old_hex, const char *new_hex)
-{
- unsigned char sha1[20], sha2[20];
+ use_ssdiff = ctx.qry.has_ssdiff ? ctx.qry.ssdiff : ctx.cfg.ssdiff;
- get_sha1(old_hex, sha1);
- get_sha1(new_hex, sha2);
+ if (show_ctrls)
+ cgit_print_diff_ctrls();
- html("diff
\n");
- html("| ");
- run_diff(sha1, sha2);
- html(" |
");
+ cgit_print_diffstat(old_rev_sha1, new_rev_sha1, prefix);
+
+ if (use_ssdiff) {
+ html("");
+ } else {
+ html("");
+ html("| ");
+ }
+ cgit_diff_tree(old_rev_sha1, new_rev_sha1, filepair_cb, prefix,
+ ctx.qry.ignorews);
+ if (!use_ssdiff)
+ html(" |
");
+ html("
");
}