Diff options
| -rw-r--r-- | MANUAL.txt | 8 | |
| -rw-r--r-- | source/cgit.c | 62 | |
| -rw-r--r-- | source/shared.c | 2 | |
| -rwxr-xr-x | tests/t0003-cache.sh | 22 |
4 files changed, 83 insertions, 11 deletions
@@ -466,9 +466,11 @@ scan-hidden-path:: scan-path:: A path which is scanned for repositories. If caching is enabled, the - result is cached as a cgitrc include-file in the cache directory. If - project-list has been defined prior to scan-path, scan-path loads only - the directories listed in the file pointed to by project-list. A + result is cached as a cgitrc include-file in the cache directory, under + a name drawn from the path and every setting the scan depends on, so + configs that would scan differently never share one. If project-list + has been defined prior to scan-path, scan-path loads only the + directories listed in the file pointed to by project-list. A repository containing a file named "noweb" is skipped, the reverse of what "strict-export" checks. Only the global settings taken before the scan-path directive apply to each repository. That holds for every diff --git a/source/cgit.c b/source/cgit.c index f8795d7..3571bc4 100644 --- a/source/cgit.c +++ b/source/cgit.c @@ -376,18 +376,70 @@ out: */ static void apply_config(const char *name, const char *value); +/* + * The cached list is read back as trusted config, so it is kept under a name + * drawn from every setting that changes what the scan writes, from the scan + * itself to the defaults cgit_add_repo hands each repository. Two sites + * sharing a cache-root, or one that changed a setting, would otherwise read + * a list scanned under other settings until it expired. + */ +static void build_scan_key(struct strbuf *key, const char *path) +{ + const char *texts[] = { + path, + ctx.cfg.project_list, + ctx.cfg.strict_export, + ctx.cfg.section, + ctx.cfg.module_link, + ctx.cfg.clone_url, + }; + const int numbers[] = { + ctx.cfg.scan_hidden_path, + ctx.cfg.remove_suffix, + ctx.cfg.section_from_path, + ctx.cfg.enable_git_config, + ctx.cfg.trust_scan_config, + ctx.cfg.snapshots, + ctx.cfg.max_stats, + ctx.cfg.branch_sort, + ctx.cfg.commit_sort, + ctx.cfg.enable_blame, + ctx.cfg.enable_commit_graph, + ctx.cfg.enable_commit_trailers, + ctx.cfg.enable_follow_links, + ctx.cfg.enable_gitmodules_links, + ctx.cfg.enable_html_serving, + ctx.cfg.enable_log_filecount, + ctx.cfg.enable_log_linecount, + ctx.cfg.enable_mailmap, + ctx.cfg.enable_remote_branches, + ctx.cfg.enable_subject_links, + }; + size_t i; + + // Each text goes behind its length so no value can run into the next, + // and an unset one is told apart from an empty one. + for (i = 0; i < ARRAY_SIZE(texts); i++) { + if (texts[i]) + strbuf_addf(key, "%zu|%s", strlen(texts[i]), texts[i]); + else + strbuf_addch(key, '-'); + } + for (i = 0; i < ARRAY_SIZE(numbers); i++) + strbuf_addf(key, "%d|", numbers[i]); +} + static void process_cached_repolist(const char *path) { struct stat st; + struct strbuf key = STRBUF_INIT; struct strbuf cached_rc = STRBUF_INIT; time_t age; - unsigned long hash; int devnull; - hash = cache_hash_str(path); - if (ctx.cfg.project_list) - hash += cache_hash_str(ctx.cfg.project_list); - strbuf_addf(&cached_rc, "%s/rc-%8lx", ctx.cfg.cache_root, hash); + build_scan_key(&key, path); + strbuf_addf(&cached_rc, "%s/rc-%8lx", ctx.cfg.cache_root, cache_hash_str(key.buf)); + strbuf_release(&key); if (stat(cached_rc.buf, &st)) { // Nothing is cached yet, so this request scans in its own diff --git a/source/shared.c b/source/shared.c index 1e1bb26..1cfe4b0 100644 --- a/source/shared.c +++ b/source/shared.c @@ -37,6 +37,8 @@ struct cgit_repo *cgit_add_repo(const char *url) } repo->name = repo->url; repo->desc = cgit_default_repo_desc; + // A cached scan keeps these copies, so build_scan_key in cgit.c has to + // name every setting copied here. repo->section = ctx.cfg.section; repo->snapshots = ctx.cfg.snapshots; repo->enable_blame = ctx.cfg.enable_blame; diff --git a/tests/t0003-cache.sh b/tests/t0003-cache.sh index d247ae4..e63efa0 100755 --- a/tests/t0003-cache.sh +++ b/tests/t0003-cache.sh @@ -355,9 +355,9 @@ test_expect_success 'a slot lock that cannot take its key is let go' ' test_dir_is_empty cache3 ' -# A scan is cached in a file named after the hash of its path, so a first -# scan finds out what that name is. The index page is left uncached, which -# makes each request read the list afresh. +# A scan is cached in a file named after a hash of its path and settings, so +# a first scan finds out what that name is. The index page is left uncached, +# which makes each request read the list afresh. test_expect_success 'set up a cached scan of two repositories' ' mkrepo scanned/one 1 && mkrepo scanned/two 1 && @@ -418,4 +418,20 @@ test_expect_success 'a stale lock file reaches neither the scan nor a slot' ' ! grep "STALE-TAIL" replay.out ' +# The cached list is read back as trusted config, so a config that would +# scan differently keeps a list of its own in the same cache-root, here one +# that takes only the repositories carrying an export marker. +test_expect_success 'a config that scans differently keeps its own list' ' + touch scanned/one/.git/export-ok && + { + echo "strict-export=export-ok" && + cat scanrc + } >strictrc && + cgit_rc scanrc "url=" >all.out && + cgit_rc strictrc "url=" >strict.out && + grep ">two</a>" all.out && + grep ">one</a>" strict.out && + ! grep ">two</a>" strict.out +' + test_done |
