From 32cb4f35c92ba2602b5e65d05239158c5e32f56b Mon Sep 17 00:00:00 2001 From: Bryce Kwon Date: Sat, 31 Oct 2026 18:07:09 -1000 Subject: List scanned repositories in path order readdir hands entries back in whatever order the filesystem keeps them, so proj111 could come before proj105 and a section could start twice. section-sort is off by default to keep the order written in cgitrc, and a scan has none to keep. --- MANUAL.txt | 12 ++++++++---- source/cgit.c | 1 + source/scan-tree.c | 17 +++++++++++++---- tests/t0101-index.sh | 27 +++++++++++++++++++++++++++ 4 files changed, 49 insertions(+), 8 deletions(-) diff --git a/MANUAL.txt b/MANUAL.txt index 1fd3fcf..473a6e5 100644 --- a/MANUAL.txt +++ b/MANUAL.txt @@ -478,7 +478,10 @@ scan-path:: filters and the enable flags, not only the entries that say so explicitly. The readme list is the exception, since a repository with none of its own follows the global list as the whole cgitrc leaves it. - Default value: none. See also: "cache-scan-ttl", "project-list", + The scan adds repositories in path order, comparing names as a + "case-sensitive-sort" defined prior to scan-path says, and takes those + a project-list names in the order it lists them. Default value: none. + See also: "cache-scan-ttl", "case-sensitive-sort", "project-list", "strict-export", "Macro expansion". section:: @@ -496,9 +499,10 @@ section-from-path:: section-sort:: Flag which, when set to "1", sorts the sections on the repository listing by name, along with the repositories within each section. Set - this flag to "0" to preserve the order in the cgitrc file. Default - value: "0". See also: "section", "case-sensitive-sort", - "repository-sort". + this flag to "0" to preserve the order in the cgitrc file, where the + repositories a scan-path finds come in path order. Default value: "0". + See also: "section", "case-sensitive-sort", "repository-sort", + "scan-path". side-by-side-diffs:: If set to "1" shows side-by-side diffs instead of unidiffs by default. diff --git a/source/cgit.c b/source/cgit.c index 3571bc4..254062f 100644 --- a/source/cgit.c +++ b/source/cgit.c @@ -395,6 +395,7 @@ static void build_scan_key(struct strbuf *key, const char *path) }; const int numbers[] = { ctx.cfg.scan_hidden_path, + ctx.cfg.case_sensitive_sort, ctx.cfg.remove_suffix, ctx.cfg.section_from_path, ctx.cfg.enable_git_config, diff --git a/source/scan-tree.c b/source/scan-tree.c index ec991e0..91db419 100644 --- a/source/scan-tree.c +++ b/source/scan-tree.c @@ -296,6 +296,8 @@ static void scan_path(const char *base, const char *path) { DIR *dir; struct dirent *ent; + struct string_list entries = STRING_LIST_INIT_DUP; + struct string_list_item *entry; struct strbuf pathbuf = STRBUF_INIT; size_t pathlen = strlen(path); struct stat st; @@ -321,11 +323,17 @@ static void scan_path(const char *base, const char *path) // Take in the '/' that "/.git" left in the buffer, since the loop below // truncates to this length and then appends an entry name straight on. pathlen++; - while ((ent = readdir(dir))) { - if (!should_scan(ent)) - continue; + while ((ent = readdir(dir))) + if (should_scan(ent)) + string_list_append(&entries, ent->d_name); + // A scan has no cgitrc order for the index to keep, and readdir hands + // entries back in whatever order the filesystem stores them, so they + // are taken by name, compared the way the index compares names. + entries.cmp = ctx.cfg.case_sensitive_sort ? strcmp : strcasecmp; + string_list_sort(&entries); + for_each_string_list_item(entry, &entries) { strbuf_setlen(&pathbuf, pathlen); - strbuf_addstr(&pathbuf, ent->d_name); + strbuf_addstr(&pathbuf, entry->string); if (stat(pathbuf.buf, &st)) { fprintf(stderr, "[cgit] Unable to stat %s: %s (%d)\n", pathbuf.buf, strerror(errno), errno); @@ -335,6 +343,7 @@ static void scan_path(const char *base, const char *path) scan_path(base, pathbuf.buf); } end: + string_list_clear(&entries, 0); strbuf_release(&pathbuf); closedir(dir); } diff --git a/tests/t0101-index.sh b/tests/t0101-index.sh index 2e49ed8..9b02a18 100755 --- a/tests/t0101-index.sh +++ b/tests/t0101-index.sh @@ -66,4 +66,31 @@ test_expect_success 'the index sorts by a column on request' ' done ' +# A scan has no cgitrc order for the index to keep, so it lists what it finds +# by path whatever order the directory hands back, comparing names the way +# case-sensitive-sort tells the index to. +test_expect_success 'a scan lists repositories in path order' ' + for name in proj9 Proj3 proj7 proj1 Proj5 proj8 proj2 proj6 proj4 + do + git init -q --bare "sorted/$name.git" || return 1 + done && + { + echo "virtual-root=/" && + echo "cache-size=0" && + echo "scan-path=$PWD/sorted" + } >sortrc && + { + echo "case-sensitive-sort=0" && + cat sortrc + } >foldrc && + cgit_rc sortrc "url=" >tmp && + sed -n "s/.*>\([Pp]roj[0-9]\)\.git<\/a>.*/\1/p" tmp >order && + printf "%s\n" Proj3 Proj5 proj1 proj2 proj4 proj6 proj7 proj8 proj9 >expect && + test_cmp expect order && + cgit_rc foldrc "url=" >tmp && + sed -n "s/.*>\([Pp]roj[0-9]\)\.git<\/a>.*/\1/p" tmp >order && + printf "%s\n" proj1 proj2 Proj3 proj4 Proj5 proj6 proj7 proj8 proj9 >expect && + test_cmp expect order +' + test_done -- cgit 2.12.1