diff options
| author | Bryce Kwon <bryce@brycekwon.com> | |
|---|---|---|
| committer | Bryce Kwon <bryce@brycekwon.com> | |
| commit | ||
| parent | ||
| tree | ||
| download | ||
Stat oversized diffs instead of inlining them
| -rw-r--r-- | assets/cgit.css | 10 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | cgitrc.5.txt | 12 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | examples/cgitrc | 10 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | source/cgit.c | 6 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | source/cgit.h | 2 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | source/ui-diff.c | 48 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rwxr-xr-x | tests/t0201-limits.sh | 45 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7 files changed, 130 insertions, 3 deletions
diff --git a/assets/cgit.css b/assets/cgit.css index b55f002..7f7535d 100644 --- a/assets/cgit.css +++ b/assets/cgit.css @@ -1013,6 +1013,16 @@ div#cgit table.diff td div.del { color: var(--del); } +/* Notice shown in place of a diff that exceeds max-diff-lines or + * max-diff-files, pointing at the page that renders it in full. */ +div#cgit div.truncated, +div#cgit table.ssdiff td.truncated { + color: var(--muted); + font-family: var(--font-sans); + white-space: normal; + padding: 0.4em 0; +} + div#cgit .oid { font-family: var(--font-mono); font-size: 90%; diff --git a/cgitrc.5.txt b/cgitrc.5.txt index 18916f9..e56cbae 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt @@ -298,6 +298,18 @@ max-commit-count:: Specifies the number of entries to list per page in "log" view. Default value: "50". +max-diff-files:: + If a commit changes more files than this, the "commit" and "diff" + views show only the diffstat, where each file links to its own diff + page. The "rawdiff" and "patch" views are never limited. Default + value: "200". Set to "0" to always render every file inline. + +max-diff-lines:: + If a single file's diff spans more lines than this, the whole-commit + views print a note in its place linking to the file's own diff page, + which always renders in full. Default value: "1000". Set to "0" to + always render oversized files inline. + max-message-length:: Specifies the maximum number of commit message characters to display in "log" view. Default value: "80". diff --git a/examples/cgitrc b/examples/cgitrc index e86f43c..62b10b5 100644 --- a/examples/cgitrc +++ b/examples/cgitrc @@ -341,6 +341,16 @@ max-repo-count=50 # Default is 50. max-commit-count=50 +# Commits changing more files than this render as a diffstat, where each file +# links to its own diff page. A value of 0 always renders everything inline. +# Value is an integer. Default is 200. +max-diff-files=200 + +# A file whose diff spans more lines than this is replaced by a link to its +# own diff page in whole-commit views. A value of 0 always renders it inline. +# Value is an integer. Default is 1000. +max-diff-lines=1000 + # Branches and tags listed per section on the refs page, and per page on the # dedicated branch and tag pages. A value of 0 lists everything on one page. # Value is an integer. Default is 200. 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) diff --git a/tests/t0201-limits.sh b/tests/t0201-limits.sh index e7f74c6..b7d82de 100755 --- a/tests/t0201-limits.sh +++ b/tests/t0201-limits.sh @@ -1,9 +1,10 @@ #!/bin/sh -test_description='Check the ref listing limits' +test_description='Check the ref listing and diff size limits' . ./setup.sh -# A repo with several branches and tags, and a config that pins a tiny limit. +# A repo with several branches and tags, one commit with an oversized file +# diff beside a small one, and configs that pin tiny limits. test_expect_success 'set up limit fixtures' ' mkrepo repos/limits 1 && ( @@ -22,9 +23,18 @@ test_expect_success 'set up limit fixtures' ' echo "virtual-root=/" && echo "cache-size=0" && echo "max-ref-count=2" && + echo "max-diff-lines=20" && + echo "max-diff-files=0" && echo "repo.url=limits" && echo "repo.path=$PWD/repos/limits/.git" - } >limitrc + } >limitrc && + { + echo "virtual-root=/" && + echo "cache-size=0" && + echo "max-diff-files=1" && + echo "repo.url=limits" && + echo "repo.path=$PWD/repos/limits/.git" + } >limitfilesrc ' limitq() { CGIT_CONFIG="$PWD/limitrc" QUERY_STRING="$1" cgit; } @@ -57,4 +67,33 @@ test_expect_success 'tag page paginates independently' ' ! grep "log/?h=" tmp ' +# --- Oversized file diffs link out instead of rendering inline -------------- +test_expect_success 'oversized file diff is replaced by a link' ' + limitq "url=limits/commit/" >tmp && + grep "too large to be rendered inline" tmp && + grep "View it on its own page" tmp +' + +test_expect_success 'small file in the same commit still renders inline' ' + grep "class=.add.>+int y;" tmp +' + +test_expect_success 'the single-file diff page always renders in full' ' + limitq "url=limits/diff/big.c" >tmp && + grep "class=.hunk." tmp && + ! grep "too large to be rendered inline" tmp +' + +# --- Commits over max-diff-files fall back to the diffstat ------------------ +test_expect_success 'a commit changing too many files shows stat only' ' + CGIT_CONFIG="$PWD/limitfilesrc" QUERY_STRING="url=limits/commit/" cgit >tmp && + grep "too large to be rendered inline" tmp && + ! grep "class=.hunk." tmp +' + +test_expect_success 'the single-file page is not limited by max-diff-files' ' + CGIT_CONFIG="$PWD/limitfilesrc" QUERY_STRING="url=limits/diff/small.c" cgit >tmp && + grep "class=.hunk." tmp +' + test_done |
