diff options
context:
space:
mode:
authorBryce Kwon <bryce@brycekwon.com>
committerBryce Kwon <bryce@brycekwon.com>
commit
parent
tree
download
Stat oversized diffs instead of inlining them
Diffstat (limited to 'source')
-rw-r--r--source/cgit.c6
-rw-r--r--source/cgit.h2
-rw-r--r--source/ui-diff.c48
3 files changed, 56 insertions, 0 deletions
diff --git a/source/cgit.c b/source/cgit.c
index 5fcd17f..d0d454d 100644
--- a/source/cgit.c
+++ b/source/cgit.c
@@ -257,6 +257,10 @@ static void config_cb(const char *name, const char *value)
ctx.cfg.max_repodesc_len = atoi(value);
else if (!strcmp(name, "max-blob-size"))
ctx.cfg.max_blob_size = atoi(value);
+ else if (!strcmp(name, "max-diff-files"))
+ ctx.cfg.max_diff_files = atoi(value);
+ else if (!strcmp(name, "max-diff-lines"))
+ ctx.cfg.max_diff_lines = atoi(value);
else if (!strcmp(name, "max-ref-count"))
ctx.cfg.max_ref_count = atoi(value);
else if (!strcmp(name, "max-repo-count")) {
@@ -418,6 +422,8 @@ static void prepare_context(void)
ctx.cfg.enable_git_config = 0;
ctx.cfg.max_repo_count = 50;
ctx.cfg.max_commit_count = 50;
+ ctx.cfg.max_diff_files = 200; /* larger commits render stat only */
+ ctx.cfg.max_diff_lines = 1000; /* larger file diffs link out */
ctx.cfg.max_msg_len = 80;
ctx.cfg.max_ref_count = 200; /* refs beyond this paginate */
ctx.cfg.max_repodesc_len = 80;
diff --git a/source/cgit.h b/source/cgit.h
index 1b28023..727067a 100644
--- a/source/cgit.h
+++ b/source/cgit.h
@@ -249,6 +249,8 @@ struct cgit_config {
int max_atom_items;
int max_repo_count;
int max_commit_count;
+ int max_diff_files;
+ int max_diff_lines;
int max_msg_len;
int max_ref_count;
int max_repodesc_len;
diff --git a/source/ui-diff.c b/source/ui-diff.c
index baaa1f8..b34f7b3 100644
--- a/source/ui-diff.c
+++ b/source/ui-diff.c
@@ -40,6 +40,11 @@ static int use_ssdiff = 0;
static struct diff_filepair *current_filepair;
static const char *current_prefix;
+/* Caps apply only to whole-commit views. A single-file diff page must
+ * always render fully, since it is where the capped views link to. */
+static int cap_diffs;
+static int item_idx;
+
struct diff_filespec *cgit_get_current_old_file(void)
{
return current_filepair->one;
@@ -299,11 +304,13 @@ static void filepair_cb(struct diff_filepair *pair)
unsigned long old_size = 0;
unsigned long new_size = 0;
int binary = 0;
+ int idx;
linediff_fn print_line_fn = print_line;
if (!show_filepair(pair))
return;
+ idx = item_idx++;
current_filepair = pair;
if (use_ssdiff) {
cgit_ssdiff_header_begin();
@@ -313,6 +320,29 @@ static void filepair_cb(struct diff_filepair *pair)
&pair->two->oid, pair->two->path, pair->two->mode);
if (use_ssdiff)
cgit_ssdiff_header_end();
+
+ /* The diffstat pass counted this file's lines. Over the budget,
+ * print the header and hand off to the single-file diff page
+ * instead of rendering the whole thing inline. */
+ if (cap_diffs && ctx.cfg.max_diff_lines > 0 && idx < files &&
+ !items[idx].binary && items[idx].added + items[idx].removed >
+ (unsigned int)ctx.cfg.max_diff_lines) {
+ if (use_ssdiff)
+ html("<tr><td colspan='4' class='truncated'>");
+ else
+ html("<div class='truncated'>");
+ html("This diff is too large to be rendered inline. ");
+ cgit_diff_link("View it on its own page", NULL, NULL,
+ ctx.qry.head, ctx.qry.oid, ctx.qry.oid2,
+ items[idx].new_path);
+ html(".");
+ if (use_ssdiff) {
+ html("</td></tr>");
+ cgit_ssdiff_footer();
+ } else
+ html("</div>");
+ return;
+ }
if (S_ISGITLINK(pair->one->mode) || S_ISGITLINK(pair->two->mode)) {
if (S_ISGITLINK(pair->one->mode)) {
char *l = fmt("-Subproject %s", oid_to_hex(&pair->one->oid));
@@ -406,6 +436,8 @@ void cgit_print_diff(const char *new_rev, const char *old_rev,
current_prefix = NULL;
}
+ cap_diffs = !prefix && !current_prefix;
+
if (!new_rev)
new_rev = ctx.qry.head;
if (repo_get_oid(the_repository, new_rev, new_rev_oid)) {
@@ -493,12 +525,28 @@ void cgit_print_diff(const char *new_rev, const char *old_rev,
return;
}
+ /* A commit touching more files than max-diff-files stops at the
+ * stat above, where every file links to its own diff page. */
+ if (cap_diffs && ctx.cfg.max_diff_files > 0 &&
+ files > ctx.cfg.max_diff_files) {
+ html("<div class='truncated'>");
+ html("This diff is too large to be rendered inline. "
+ "Follow a file above, or the ");
+ cgit_patch_link("patch", NULL, NULL, NULL, ctx.qry.oid, NULL);
+ html(" link for the whole commit.");
+ html("</div>");
+ if (show_ctrls)
+ cgit_print_layout_end();
+ return;
+ }
+
if (use_ssdiff) {
html("<table summary='ssdiff' class='ssdiff'>");
} else {
html("<table summary='diff' class='diff'>");
html("<tr><td>");
}
+ item_idx = 0;
cgit_diff_tree(old_rev_oid, new_rev_oid, filepair_cb, prefix,
ctx.qry.ignorews);
if (!use_ssdiff)