diff options
-rw-r--r-- | cgit.c | 75 | ||||
-rw-r--r-- | cgit.h | 1 |
2 files changed, 75 insertions, 1 deletions
@@ -40,6 +40,8 @@ struct cgit_filter *new_filter(const char *cmd, int extra_args) | |||
40 | return f; | 40 | return f; |
41 | } | 41 | } |
42 | 42 | ||
43 | static void process_cached_repolist(const char *path); | ||
44 | |||
43 | void config_cb(const char *name, const char *value) | 45 | void config_cb(const char *name, const char *value) |
44 | { | 46 | { |
45 | if (!strcmp(name, "root-title")) | 47 | if (!strcmp(name, "root-title")) |
@@ -96,6 +98,8 @@ void config_cb(const char *name, const char *value) | |||
96 | ctx.cfg.cache_root_ttl = atoi(value); | 98 | ctx.cfg.cache_root_ttl = atoi(value); |
97 | else if (!strcmp(name, "cache-repo-ttl")) | 99 | else if (!strcmp(name, "cache-repo-ttl")) |
98 | ctx.cfg.cache_repo_ttl = atoi(value); | 100 | ctx.cfg.cache_repo_ttl = atoi(value); |
101 | else if (!strcmp(name, "cache-scanrc-ttl")) | ||
102 | ctx.cfg.cache_scanrc_ttl = atoi(value); | ||
99 | else if (!strcmp(name, "cache-static-ttl")) | 103 | else if (!strcmp(name, "cache-static-ttl")) |
100 | ctx.cfg.cache_static_ttl = atoi(value); | 104 | ctx.cfg.cache_static_ttl = atoi(value); |
101 | else if (!strcmp(name, "cache-dynamic-ttl")) | 105 | else if (!strcmp(name, "cache-dynamic-ttl")) |
@@ -137,7 +141,10 @@ void config_cb(const char *name, const char *value) | |||
137 | else if (!strcmp(name, "repo.group")) | 141 | else if (!strcmp(name, "repo.group")) |
138 | ctx.cfg.repo_group = xstrdup(value); | 142 | ctx.cfg.repo_group = xstrdup(value); |
139 | else if (!strcmp(name, "repo.scan")) | 143 | else if (!strcmp(name, "repo.scan")) |
140 | scan_tree(value); | 144 | if (!ctx.cfg.nocache && ctx.cfg.cache_size) |
145 | process_cached_repolist(value); | ||
146 | else | ||
147 | scan_tree(value); | ||
141 | else if (!strcmp(name, "repo.url")) | 148 | else if (!strcmp(name, "repo.url")) |
142 | ctx.repo = cgit_add_repo(value); | 149 | ctx.repo = cgit_add_repo(value); |
143 | else if (!strcmp(name, "repo.name")) | 150 | else if (!strcmp(name, "repo.name")) |
@@ -236,6 +243,7 @@ static void prepare_context(struct cgit_context *ctx) | |||
236 | ctx->cfg.cache_repo_ttl = 5; | 243 | ctx->cfg.cache_repo_ttl = 5; |
237 | ctx->cfg.cache_root = CGIT_CACHE_ROOT; | 244 | ctx->cfg.cache_root = CGIT_CACHE_ROOT; |
238 | ctx->cfg.cache_root_ttl = 5; | 245 | ctx->cfg.cache_root_ttl = 5; |
246 | ctx->cfg.cache_scanrc_ttl = 15; | ||
239 | ctx->cfg.cache_static_ttl = -1; | 247 | ctx->cfg.cache_static_ttl = -1; |
240 | ctx->cfg.css = "/cgit.css"; | 248 | ctx->cfg.css = "/cgit.css"; |
241 | ctx->cfg.logo = "/cgit.png"; | 249 | ctx->cfg.logo = "/cgit.png"; |
@@ -438,6 +446,71 @@ void print_repolist(FILE *f, struct cgit_repolist *list, int start) | |||
438 | print_repo(f, &list->repos[i]); | 446 | print_repo(f, &list->repos[i]); |
439 | } | 447 | } |
440 | 448 | ||
449 | /* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc' | ||
450 | * and return 0 on success. | ||
451 | */ | ||
452 | static int generate_cached_repolist(const char *path, const char *cached_rc) | ||
453 | { | ||
454 | char *locked_rc; | ||
455 | int idx; | ||
456 | FILE *f; | ||
457 | |||
458 | locked_rc = xstrdup(fmt("%s.lock", cached_rc)); | ||
459 | f = fopen(locked_rc, "wx"); | ||
460 | if (!f) { | ||
461 | /* Inform about the error unless the lockfile already existed, | ||
462 | * since that only means we've got concurrent requests. | ||
463 | */ | ||
464 | if (errno != EEXIST) | ||
465 | fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n", | ||
466 | locked_rc, strerror(errno), errno); | ||
467 | return errno; | ||
468 | } | ||
469 | idx = cgit_repolist.count; | ||
470 | scan_tree(path); | ||
471 | print_repolist(f, &cgit_repolist, idx); | ||
472 | if (rename(locked_rc, cached_rc)) | ||
473 | fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", | ||
474 | locked_rc, cached_rc, strerror(errno), errno); | ||
475 | fclose(f); | ||
476 | return 0; | ||
477 | } | ||
478 | |||
479 | static void process_cached_repolist(const char *path) | ||
480 | { | ||
481 | struct stat st; | ||
482 | char *cached_rc; | ||
483 | time_t age; | ||
484 | |||
485 | cached_rc = xstrdup(fmt("%s/rc-%8x", ctx.cfg.cache_root, | ||
486 | hash_str(path))); | ||
487 | |||
488 | if (stat(cached_rc, &st)) { | ||
489 | /* Nothing is cached, we need to scan without forking. And | ||
490 | * if we fail to generate a cached repolist, we need to | ||
491 | * invoke scan_tree manually. | ||
492 | */ | ||
493 | if (generate_cached_repolist(path, cached_rc)) | ||
494 | scan_tree(path); | ||
495 | return; | ||
496 | } | ||
497 | |||
498 | parse_configfile(cached_rc, config_cb); | ||
499 | |||
500 | /* If the cached configfile hasn't expired, lets exit now */ | ||
501 | age = time(NULL) - st.st_mtime; | ||
502 | if (age <= (ctx.cfg.cache_scanrc_ttl * 60)) | ||
503 | return; | ||
504 | |||
505 | /* The cached repolist has been parsed, but it was old. So lets | ||
506 | * rescan the specified path and generate a new cached repolist | ||
507 | * in a child-process to avoid latency for the current request. | ||
508 | */ | ||
509 | if (fork()) | ||
510 | return; | ||
511 | |||
512 | exit(generate_cached_repolist(path, cached_rc)); | ||
513 | } | ||
441 | 514 | ||
442 | static void cgit_parse_args(int argc, const char **argv) | 515 | static void cgit_parse_args(int argc, const char **argv) |
443 | { | 516 | { |
@@ -168,6 +168,7 @@ struct cgit_config { | |||
168 | int cache_max_create_time; | 168 | int cache_max_create_time; |
169 | int cache_repo_ttl; | 169 | int cache_repo_ttl; |
170 | int cache_root_ttl; | 170 | int cache_root_ttl; |
171 | int cache_scanrc_ttl; | ||
171 | int cache_static_ttl; | 172 | int cache_static_ttl; |
172 | int embedded; | 173 | int embedded; |
173 | int enable_index_links; | 174 | int enable_index_links; |