diff options
| author | Bryce Kwon <bryce@brycekwon.com> | |
|---|---|---|
| committer | Bryce Kwon <bryce@brycekwon.com> | |
| commit | ||
| parent | ||
| tree | ||
| download | ||
Cap and paginate the ref listings
Diffstat (limited to '')
| -rw-r--r-- | cgitrc.5.txt | 6 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | examples/cgitrc | 5 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | source/cgit.c | 3 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | source/cgit.h | 1 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | source/ui-refs.c | 128 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rwxr-xr-x | tests/t0201-limits.sh | 60 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
6 files changed, 189 insertions, 14 deletions
diff --git a/cgitrc.5.txt b/cgitrc.5.txt index a07d190..18916f9 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt @@ -302,6 +302,12 @@ max-message-length:: Specifies the maximum number of commit message characters to display in "log" view. Default value: "80". +max-ref-count:: + Specifies the number of branches and tags to list per section on the + "refs" view, and per page on the dedicated branch and tag pages that + its overflow links lead to. Default value: "200". Set to "0" to list + every ref on one page. + max-repo-count:: Specifies the number of entries to list per page on the repository index page. The value "0" shows all repositories without limitation. diff --git a/examples/cgitrc b/examples/cgitrc index c035742..e86f43c 100644 --- a/examples/cgitrc +++ b/examples/cgitrc @@ -341,6 +341,11 @@ max-repo-count=50 # Default is 50. max-commit-count=50 +# 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. +max-ref-count=200 + # Max files considered when detecting renames. A value of -1 uses the git # compile-time value. Value is an integer. Default is -1. renamelimit=-1 diff --git a/source/cgit.c b/source/cgit.c index ce8b340..5fcd17f 100644 --- a/source/cgit.c +++ b/source/cgit.c @@ -257,6 +257,8 @@ 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-ref-count")) + ctx.cfg.max_ref_count = atoi(value); else if (!strcmp(name, "max-repo-count")) { ctx.cfg.max_repo_count = atoi(value); if (ctx.cfg.max_repo_count <= 0) @@ -417,6 +419,7 @@ static void prepare_context(void) ctx.cfg.max_repo_count = 50; ctx.cfg.max_commit_count = 50; ctx.cfg.max_msg_len = 80; + ctx.cfg.max_ref_count = 200; /* refs beyond this paginate */ ctx.cfg.max_repodesc_len = 80; ctx.cfg.max_blob_size = 10 * 1024; /* 10 MB; bounds per-request memory */ ctx.cfg.max_stats = 0; diff --git a/source/cgit.h b/source/cgit.h index d921e76..1b28023 100644 --- a/source/cgit.h +++ b/source/cgit.h @@ -250,6 +250,7 @@ struct cgit_config { int max_repo_count; int max_commit_count; int max_msg_len; + int max_ref_count; int max_repodesc_len; int max_blob_size; int max_stats; diff --git a/source/ui-refs.c b/source/ui-refs.c index 500adfd..a38bfc4 100644 --- a/source/ui-refs.c +++ b/source/ui-refs.c @@ -145,23 +145,60 @@ static void print_refs_link(const char *path) html("</td></tr>"); } -void cgit_print_branches(int maxcount) +/* Prev/next links for the dedicated branch and tag pages, so each + * category pages independently instead of sharing one endless page. */ +static void print_ref_pager(int ofs, int pagesize, int count, const char *path) { - struct reflist list; - int i; + char *url; + + html("<tr class='nohover'><td colspan='5' class='refs-pager'>"); + if (ofs > 0) { + url = cgit_pageurl(ctx.qry.repo, fmt("refs/%s", path), + fmt("ofs=%d", ofs > pagesize ? ofs - pagesize : 0)); + html("<a href='"); + html_attr(url); + html("'>[prev]</a> "); + free(url); + } + htmlf("%d - %d of %d", ofs + 1, + ofs + pagesize < count ? ofs + pagesize : count, count); + if (ofs + pagesize < count) { + url = cgit_pageurl(ctx.qry.repo, fmt("refs/%s", path), + fmt("ofs=%d", ofs + pagesize)); + html(" <a href='"); + html_attr(url); + html("'>[next]</a>"); + free(url); + } + html("</td></tr>"); +} +static void collect_branches(struct reflist *list) +{ + list->refs = NULL; + list->alloc = list->count = 0; + refs_for_each_branch_ref(get_main_ref_store(the_repository), + cgit_refs_cb, list); + if (ctx.repo->enable_remote_branches) + refs_for_each_remote_ref(get_main_ref_store(the_repository), + cgit_refs_cb, list); +} + +static void print_branch_header(void) +{ html("<tr class='nohover'><th class='left'>Branch</th>" "<th class='left'>Commit message</th>" "<th class='left'>Author</th>" "<th class='left' colspan='2'>Age</th></tr>\n"); +} - list.refs = NULL; - list.alloc = list.count = 0; - refs_for_each_branch_ref(get_main_ref_store(the_repository), - cgit_refs_cb, &list); - if (ctx.repo->enable_remote_branches) - refs_for_each_remote_ref(get_main_ref_store(the_repository), - cgit_refs_cb, &list); +void cgit_print_branches(int maxcount) +{ + struct reflist list; + int i; + + print_branch_header(); + collect_branches(&list); if (maxcount == 0 || maxcount > list.count) maxcount = list.count; @@ -205,19 +242,82 @@ void cgit_print_tags(int maxcount) cgit_free_reflist_inner(&list); } +/* The dedicated branch page lists everything, a page at a time. The + * whole list is name-sorted (or age-sorted per branch-sort) so the + * order is stable across pages. */ +static void print_branches_page(int pagesize) +{ + struct reflist list; + int i, ofs, end; + + print_branch_header(); + collect_branches(&list); + + qsort(list.refs, list.count, sizeof(*list.refs), cmp_branch_age); + if (ctx.repo->branch_sort == 0) + qsort(list.refs, list.count, sizeof(*list.refs), cmp_ref_name); + + if (pagesize <= 0 || pagesize > list.count) + pagesize = list.count; + ofs = ctx.qry.ofs > 0 ? ctx.qry.ofs : 0; + if (ofs > list.count) + ofs = list.count; + end = ofs + pagesize < list.count ? ofs + pagesize : list.count; + + for (i = ofs; i < end; i++) + print_branch(list.refs[i]); + + if (pagesize < list.count) + print_ref_pager(ofs, pagesize, list.count, "heads"); + + cgit_free_reflist_inner(&list); +} + +static void print_tags_page(int pagesize) +{ + struct reflist list; + int i, ofs, end; + + list.refs = NULL; + list.alloc = list.count = 0; + refs_for_each_tag_ref(get_main_ref_store(the_repository), + cgit_refs_cb, &list); + if (list.count == 0) + return; + qsort(list.refs, list.count, sizeof(*list.refs), cmp_tag_age); + + if (pagesize <= 0 || pagesize > list.count) + pagesize = list.count; + ofs = ctx.qry.ofs > 0 ? ctx.qry.ofs : 0; + if (ofs > list.count) + ofs = list.count; + end = ofs + pagesize < list.count ? ofs + pagesize : list.count; + + print_tag_header(); + for (i = ofs; i < end; i++) + print_tag(list.refs[i]); + + if (pagesize < list.count) + print_ref_pager(ofs, pagesize, list.count, "tags"); + + cgit_free_reflist_inner(&list); +} + void cgit_print_refs(void) { cgit_print_layout_start(); html("<table class='list nowrap'>"); if (ctx.qry.path && starts_with(ctx.qry.path, "heads")) - cgit_print_branches(0); + print_branches_page(ctx.cfg.max_ref_count); else if (ctx.qry.path && starts_with(ctx.qry.path, "tags")) - cgit_print_tags(0); + print_tags_page(ctx.cfg.max_ref_count); else { - cgit_print_branches(0); + /* The combined page caps each section, with the [...] rows + * leading to the dedicated pages above. */ + cgit_print_branches(ctx.cfg.max_ref_count); html("<tr class='nohover'><td colspan='5'> </td></tr>"); - cgit_print_tags(0); + cgit_print_tags(ctx.cfg.max_ref_count); } html("</table>"); cgit_print_layout_end(); diff --git a/tests/t0201-limits.sh b/tests/t0201-limits.sh new file mode 100755 index 0000000..e7f74c6 --- /dev/null +++ b/tests/t0201-limits.sh @@ -0,0 +1,60 @@ +#!/bin/sh + +test_description='Check the ref listing limits' +. ./setup.sh + +# A repo with several branches and tags, and a config that pins a tiny limit. +test_expect_success 'set up limit fixtures' ' + mkrepo repos/limits 1 && + ( + cd repos/limits && + seq 1 60 >big.c && + printf "int x;\n" >small.c && + git add -A && + git commit -m sources && + seq 301 360 >big.c && + printf "int y;\n" >small.c && + git commit -am change && + for i in 1 2 3; do git branch branch-$i || exit 1; done && + for i in 1 2 3; do git tag tag-$i || exit 1; done + ) && + { + echo "virtual-root=/" && + echo "cache-size=0" && + echo "max-ref-count=2" && + echo "repo.url=limits" && + echo "repo.path=$PWD/repos/limits/.git" + } >limitrc +' + +limitq() { CGIT_CONFIG="$PWD/limitrc" QUERY_STRING="$1" cgit; } + +# --- The refs page caps each section and links to the category pages -------- +test_expect_success 'refs page lists max-ref-count branches and tags' ' + limitq "url=limits/refs/" >tmp && + test $(grep -c "log/?h=" tmp) -eq 2 && + test $(grep -c "/tag/?h=tag-" tmp) -eq 2 +' + +test_expect_success 'refs page links each overflow to its own category' ' + grep "refs/heads" tmp && + grep "refs/tags" tmp +' + +test_expect_success 'branch page paginates independently' ' + limitq "url=limits/refs/heads/" >tmp && + test $(grep -c "log/?h=" tmp) -eq 2 && + grep "\[next\]" tmp && + limitq "url=limits/refs/heads/&ofs=2" >tmp && + grep "\[prev\]" tmp && + ! grep "/tag/?h=tag-" tmp +' + +test_expect_success 'tag page paginates independently' ' + limitq "url=limits/refs/tags/&ofs=2" >tmp && + grep "/tag/?h=tag-" tmp && + grep "\[prev\]" tmp && + ! grep "log/?h=" tmp +' + +test_done |
