summaryrefslogtreecommitdiffabout
authorLars Hjemli <hjemli@gmail.com>2009-08-24 11:31:49 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2009-08-24 11:31:49 (UTC)
commitee554849ac7209fa8f7486327ec9f3b370e4c876 (patch) (unidiff)
tree63c284ebf72ea401067dd5d4d59ae8ede8f8743c
parent588fb8efc69778b85062e8fc2f482a8de43bad75 (diff)
downloadcgit-ee554849ac7209fa8f7486327ec9f3b370e4c876.zip
cgit-ee554849ac7209fa8f7486327ec9f3b370e4c876.tar.gz
cgit-ee554849ac7209fa8f7486327ec9f3b370e4c876.tar.bz2
cgit.c: respect repo-local 'snapshots' option for --scan-path
The repo-specific 'snapshots' option is bitwise AND'ed with the global 'snapshots' option during parsing, and since the global cgitrc hasn't been parsed when --scan-path is processed the global 'snapshots' will always be 0 (i.e. no repo-specific 'snapshots' setting will have any effect). This patch fixes the issue by setting the global 'snapshots' mask to 0xFF (hence relying on later parsing of the generated cgitrc repolist to do the right thing). Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/cgit.c b/cgit.c
index 8381630..3fcca2a 100644
--- a/cgit.c
+++ b/cgit.c
@@ -431,275 +431,285 @@ static void process_request(void *cbdata)
431 cgit_print_docend(); 431 cgit_print_docend();
432} 432}
433 433
434int cmp_repos(const void *a, const void *b) 434int cmp_repos(const void *a, const void *b)
435{ 435{
436 const struct cgit_repo *ra = a, *rb = b; 436 const struct cgit_repo *ra = a, *rb = b;
437 return strcmp(ra->url, rb->url); 437 return strcmp(ra->url, rb->url);
438} 438}
439 439
440char *build_snapshot_setting(int bitmap) 440char *build_snapshot_setting(int bitmap)
441{ 441{
442 const struct cgit_snapshot_format *f; 442 const struct cgit_snapshot_format *f;
443 char *result = xstrdup(""); 443 char *result = xstrdup("");
444 char *tmp; 444 char *tmp;
445 int len; 445 int len;
446 446
447 for (f = cgit_snapshot_formats; f->suffix; f++) { 447 for (f = cgit_snapshot_formats; f->suffix; f++) {
448 if (f->bit & bitmap) { 448 if (f->bit & bitmap) {
449 tmp = result; 449 tmp = result;
450 result = xstrdup(fmt("%s%s ", tmp, f->suffix)); 450 result = xstrdup(fmt("%s%s ", tmp, f->suffix));
451 free(tmp); 451 free(tmp);
452 } 452 }
453 } 453 }
454 len = strlen(result); 454 len = strlen(result);
455 if (len) 455 if (len)
456 result[len - 1] = '\0'; 456 result[len - 1] = '\0';
457 return result; 457 return result;
458} 458}
459 459
460char *get_first_line(char *txt) 460char *get_first_line(char *txt)
461{ 461{
462 char *t = xstrdup(txt); 462 char *t = xstrdup(txt);
463 char *p = strchr(t, '\n'); 463 char *p = strchr(t, '\n');
464 if (p) 464 if (p)
465 *p = '\0'; 465 *p = '\0';
466 return t; 466 return t;
467} 467}
468 468
469void print_repo(FILE *f, struct cgit_repo *repo) 469void print_repo(FILE *f, struct cgit_repo *repo)
470{ 470{
471 fprintf(f, "repo.url=%s\n", repo->url); 471 fprintf(f, "repo.url=%s\n", repo->url);
472 fprintf(f, "repo.name=%s\n", repo->name); 472 fprintf(f, "repo.name=%s\n", repo->name);
473 fprintf(f, "repo.path=%s\n", repo->path); 473 fprintf(f, "repo.path=%s\n", repo->path);
474 if (repo->owner) 474 if (repo->owner)
475 fprintf(f, "repo.owner=%s\n", repo->owner); 475 fprintf(f, "repo.owner=%s\n", repo->owner);
476 if (repo->desc) { 476 if (repo->desc) {
477 char *tmp = get_first_line(repo->desc); 477 char *tmp = get_first_line(repo->desc);
478 fprintf(f, "repo.desc=%s\n", tmp); 478 fprintf(f, "repo.desc=%s\n", tmp);
479 free(tmp); 479 free(tmp);
480 } 480 }
481 if (repo->readme) 481 if (repo->readme)
482 fprintf(f, "repo.readme=%s\n", repo->readme); 482 fprintf(f, "repo.readme=%s\n", repo->readme);
483 if (repo->defbranch) 483 if (repo->defbranch)
484 fprintf(f, "repo.defbranch=%s\n", repo->defbranch); 484 fprintf(f, "repo.defbranch=%s\n", repo->defbranch);
485 if (repo->module_link) 485 if (repo->module_link)
486 fprintf(f, "repo.module-link=%s\n", repo->module_link); 486 fprintf(f, "repo.module-link=%s\n", repo->module_link);
487 if (repo->section) 487 if (repo->section)
488 fprintf(f, "repo.section=%s\n", repo->section); 488 fprintf(f, "repo.section=%s\n", repo->section);
489 if (repo->clone_url) 489 if (repo->clone_url)
490 fprintf(f, "repo.clone-url=%s\n", repo->clone_url); 490 fprintf(f, "repo.clone-url=%s\n", repo->clone_url);
491 fprintf(f, "repo.enable-log-filecount=%d\n", 491 fprintf(f, "repo.enable-log-filecount=%d\n",
492 repo->enable_log_filecount); 492 repo->enable_log_filecount);
493 fprintf(f, "repo.enable-log-linecount=%d\n", 493 fprintf(f, "repo.enable-log-linecount=%d\n",
494 repo->enable_log_linecount); 494 repo->enable_log_linecount);
495 if (repo->about_filter && repo->about_filter != ctx.cfg.about_filter) 495 if (repo->about_filter && repo->about_filter != ctx.cfg.about_filter)
496 fprintf(f, "repo.about-filter=%s\n", repo->about_filter->cmd); 496 fprintf(f, "repo.about-filter=%s\n", repo->about_filter->cmd);
497 if (repo->commit_filter && repo->commit_filter != ctx.cfg.commit_filter) 497 if (repo->commit_filter && repo->commit_filter != ctx.cfg.commit_filter)
498 fprintf(f, "repo.commit-filter=%s\n", repo->commit_filter->cmd); 498 fprintf(f, "repo.commit-filter=%s\n", repo->commit_filter->cmd);
499 if (repo->source_filter && repo->source_filter != ctx.cfg.source_filter) 499 if (repo->source_filter && repo->source_filter != ctx.cfg.source_filter)
500 fprintf(f, "repo.source-filter=%s\n", repo->source_filter->cmd); 500 fprintf(f, "repo.source-filter=%s\n", repo->source_filter->cmd);
501 if (repo->snapshots != ctx.cfg.snapshots) { 501 if (repo->snapshots != ctx.cfg.snapshots) {
502 char *tmp = build_snapshot_setting(repo->snapshots); 502 char *tmp = build_snapshot_setting(repo->snapshots);
503 fprintf(f, "repo.snapshots=%s\n", tmp); 503 fprintf(f, "repo.snapshots=%s\n", tmp);
504 free(tmp); 504 free(tmp);
505 } 505 }
506 if (repo->max_stats != ctx.cfg.max_stats) 506 if (repo->max_stats != ctx.cfg.max_stats)
507 fprintf(f, "repo.max-stats=%s\n", 507 fprintf(f, "repo.max-stats=%s\n",
508 cgit_find_stats_periodname(repo->max_stats)); 508 cgit_find_stats_periodname(repo->max_stats));
509 fprintf(f, "\n"); 509 fprintf(f, "\n");
510} 510}
511 511
512void print_repolist(FILE *f, struct cgit_repolist *list, int start) 512void print_repolist(FILE *f, struct cgit_repolist *list, int start)
513{ 513{
514 int i; 514 int i;
515 515
516 for(i = start; i < list->count; i++) 516 for(i = start; i < list->count; i++)
517 print_repo(f, &list->repos[i]); 517 print_repo(f, &list->repos[i]);
518} 518}
519 519
520/* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc' 520/* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc'
521 * and return 0 on success. 521 * and return 0 on success.
522 */ 522 */
523static int generate_cached_repolist(const char *path, const char *cached_rc) 523static int generate_cached_repolist(const char *path, const char *cached_rc)
524{ 524{
525 char *locked_rc; 525 char *locked_rc;
526 int idx; 526 int idx;
527 FILE *f; 527 FILE *f;
528 528
529 locked_rc = xstrdup(fmt("%s.lock", cached_rc)); 529 locked_rc = xstrdup(fmt("%s.lock", cached_rc));
530 f = fopen(locked_rc, "wx"); 530 f = fopen(locked_rc, "wx");
531 if (!f) { 531 if (!f) {
532 /* Inform about the error unless the lockfile already existed, 532 /* Inform about the error unless the lockfile already existed,
533 * since that only means we've got concurrent requests. 533 * since that only means we've got concurrent requests.
534 */ 534 */
535 if (errno != EEXIST) 535 if (errno != EEXIST)
536 fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n", 536 fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n",
537 locked_rc, strerror(errno), errno); 537 locked_rc, strerror(errno), errno);
538 return errno; 538 return errno;
539 } 539 }
540 idx = cgit_repolist.count; 540 idx = cgit_repolist.count;
541 scan_tree(path, repo_config); 541 scan_tree(path, repo_config);
542 print_repolist(f, &cgit_repolist, idx); 542 print_repolist(f, &cgit_repolist, idx);
543 if (rename(locked_rc, cached_rc)) 543 if (rename(locked_rc, cached_rc))
544 fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", 544 fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n",
545 locked_rc, cached_rc, strerror(errno), errno); 545 locked_rc, cached_rc, strerror(errno), errno);
546 fclose(f); 546 fclose(f);
547 return 0; 547 return 0;
548} 548}
549 549
550static void process_cached_repolist(const char *path) 550static void process_cached_repolist(const char *path)
551{ 551{
552 struct stat st; 552 struct stat st;
553 char *cached_rc; 553 char *cached_rc;
554 time_t age; 554 time_t age;
555 555
556 cached_rc = xstrdup(fmt("%s/rc-%8x", ctx.cfg.cache_root, 556 cached_rc = xstrdup(fmt("%s/rc-%8x", ctx.cfg.cache_root,
557 hash_str(path))); 557 hash_str(path)));
558 558
559 if (stat(cached_rc, &st)) { 559 if (stat(cached_rc, &st)) {
560 /* Nothing is cached, we need to scan without forking. And 560 /* Nothing is cached, we need to scan without forking. And
561 * if we fail to generate a cached repolist, we need to 561 * if we fail to generate a cached repolist, we need to
562 * invoke scan_tree manually. 562 * invoke scan_tree manually.
563 */ 563 */
564 if (generate_cached_repolist(path, cached_rc)) 564 if (generate_cached_repolist(path, cached_rc))
565 scan_tree(path, repo_config); 565 scan_tree(path, repo_config);
566 return; 566 return;
567 } 567 }
568 568
569 parse_configfile(cached_rc, config_cb); 569 parse_configfile(cached_rc, config_cb);
570 570
571 /* If the cached configfile hasn't expired, lets exit now */ 571 /* If the cached configfile hasn't expired, lets exit now */
572 age = time(NULL) - st.st_mtime; 572 age = time(NULL) - st.st_mtime;
573 if (age <= (ctx.cfg.cache_scanrc_ttl * 60)) 573 if (age <= (ctx.cfg.cache_scanrc_ttl * 60))
574 return; 574 return;
575 575
576 /* The cached repolist has been parsed, but it was old. So lets 576 /* The cached repolist has been parsed, but it was old. So lets
577 * rescan the specified path and generate a new cached repolist 577 * rescan the specified path and generate a new cached repolist
578 * in a child-process to avoid latency for the current request. 578 * in a child-process to avoid latency for the current request.
579 */ 579 */
580 if (fork()) 580 if (fork())
581 return; 581 return;
582 582
583 exit(generate_cached_repolist(path, cached_rc)); 583 exit(generate_cached_repolist(path, cached_rc));
584} 584}
585 585
586static void cgit_parse_args(int argc, const char **argv) 586static void cgit_parse_args(int argc, const char **argv)
587{ 587{
588 int i; 588 int i;
589 int scan = 0; 589 int scan = 0;
590 590
591 for (i = 1; i < argc; i++) { 591 for (i = 1; i < argc; i++) {
592 if (!strncmp(argv[i], "--cache=", 8)) { 592 if (!strncmp(argv[i], "--cache=", 8)) {
593 ctx.cfg.cache_root = xstrdup(argv[i]+8); 593 ctx.cfg.cache_root = xstrdup(argv[i]+8);
594 } 594 }
595 if (!strcmp(argv[i], "--nocache")) { 595 if (!strcmp(argv[i], "--nocache")) {
596 ctx.cfg.nocache = 1; 596 ctx.cfg.nocache = 1;
597 } 597 }
598 if (!strcmp(argv[i], "--nohttp")) { 598 if (!strcmp(argv[i], "--nohttp")) {
599 ctx.env.no_http = "1"; 599 ctx.env.no_http = "1";
600 } 600 }
601 if (!strncmp(argv[i], "--query=", 8)) { 601 if (!strncmp(argv[i], "--query=", 8)) {
602 ctx.qry.raw = xstrdup(argv[i]+8); 602 ctx.qry.raw = xstrdup(argv[i]+8);
603 } 603 }
604 if (!strncmp(argv[i], "--repo=", 7)) { 604 if (!strncmp(argv[i], "--repo=", 7)) {
605 ctx.qry.repo = xstrdup(argv[i]+7); 605 ctx.qry.repo = xstrdup(argv[i]+7);
606 } 606 }
607 if (!strncmp(argv[i], "--page=", 7)) { 607 if (!strncmp(argv[i], "--page=", 7)) {
608 ctx.qry.page = xstrdup(argv[i]+7); 608 ctx.qry.page = xstrdup(argv[i]+7);
609 } 609 }
610 if (!strncmp(argv[i], "--head=", 7)) { 610 if (!strncmp(argv[i], "--head=", 7)) {
611 ctx.qry.head = xstrdup(argv[i]+7); 611 ctx.qry.head = xstrdup(argv[i]+7);
612 ctx.qry.has_symref = 1; 612 ctx.qry.has_symref = 1;
613 } 613 }
614 if (!strncmp(argv[i], "--sha1=", 7)) { 614 if (!strncmp(argv[i], "--sha1=", 7)) {
615 ctx.qry.sha1 = xstrdup(argv[i]+7); 615 ctx.qry.sha1 = xstrdup(argv[i]+7);
616 ctx.qry.has_sha1 = 1; 616 ctx.qry.has_sha1 = 1;
617 } 617 }
618 if (!strncmp(argv[i], "--ofs=", 6)) { 618 if (!strncmp(argv[i], "--ofs=", 6)) {
619 ctx.qry.ofs = atoi(argv[i]+6); 619 ctx.qry.ofs = atoi(argv[i]+6);
620 } 620 }
621 if (!strncmp(argv[i], "--scan-tree=", 12) || 621 if (!strncmp(argv[i], "--scan-tree=", 12) ||
622 !strncmp(argv[i], "--scan-path=", 12)) { 622 !strncmp(argv[i], "--scan-path=", 12)) {
623 /* HACK: the global snapshot bitmask defines the
624 * set of allowed snapshot formats, but the config
625 * file hasn't been parsed yet so the mask is
626 * currently 0. By setting all bits high before
627 * scanning we make sure that any in-repo cgitrc
628 * snapshot setting is respected by scan_tree().
629 * BTW: we assume that there'll never be more than
630 * 255 different snapshot formats supported by cgit...
631 */
632 ctx.cfg.snapshots = 0xFF;
623 scan++; 633 scan++;
624 scan_tree(argv[i] + 12, repo_config); 634 scan_tree(argv[i] + 12, repo_config);
625 } 635 }
626 } 636 }
627 if (scan) { 637 if (scan) {
628 qsort(cgit_repolist.repos, cgit_repolist.count, 638 qsort(cgit_repolist.repos, cgit_repolist.count,
629 sizeof(struct cgit_repo), cmp_repos); 639 sizeof(struct cgit_repo), cmp_repos);
630 print_repolist(stdout, &cgit_repolist, 0); 640 print_repolist(stdout, &cgit_repolist, 0);
631 exit(0); 641 exit(0);
632 } 642 }
633} 643}
634 644
635static int calc_ttl() 645static int calc_ttl()
636{ 646{
637 if (!ctx.repo) 647 if (!ctx.repo)
638 return ctx.cfg.cache_root_ttl; 648 return ctx.cfg.cache_root_ttl;
639 649
640 if (!ctx.qry.page) 650 if (!ctx.qry.page)
641 return ctx.cfg.cache_repo_ttl; 651 return ctx.cfg.cache_repo_ttl;
642 652
643 if (ctx.qry.has_symref) 653 if (ctx.qry.has_symref)
644 return ctx.cfg.cache_dynamic_ttl; 654 return ctx.cfg.cache_dynamic_ttl;
645 655
646 if (ctx.qry.has_sha1) 656 if (ctx.qry.has_sha1)
647 return ctx.cfg.cache_static_ttl; 657 return ctx.cfg.cache_static_ttl;
648 658
649 return ctx.cfg.cache_repo_ttl; 659 return ctx.cfg.cache_repo_ttl;
650} 660}
651 661
652int main(int argc, const char **argv) 662int main(int argc, const char **argv)
653{ 663{
654 const char *path; 664 const char *path;
655 char *qry; 665 char *qry;
656 int err, ttl; 666 int err, ttl;
657 667
658 prepare_context(&ctx); 668 prepare_context(&ctx);
659 cgit_repolist.length = 0; 669 cgit_repolist.length = 0;
660 cgit_repolist.count = 0; 670 cgit_repolist.count = 0;
661 cgit_repolist.repos = NULL; 671 cgit_repolist.repos = NULL;
662 672
663 cgit_parse_args(argc, argv); 673 cgit_parse_args(argc, argv);
664 parse_configfile(ctx.env.cgit_config, config_cb); 674 parse_configfile(ctx.env.cgit_config, config_cb);
665 ctx.repo = NULL; 675 ctx.repo = NULL;
666 http_parse_querystring(ctx.qry.raw, querystring_cb); 676 http_parse_querystring(ctx.qry.raw, querystring_cb);
667 677
668 /* If virtual-root isn't specified in cgitrc, lets pretend 678 /* If virtual-root isn't specified in cgitrc, lets pretend
669 * that virtual-root equals SCRIPT_NAME. 679 * that virtual-root equals SCRIPT_NAME.
670 */ 680 */
671 if (!ctx.cfg.virtual_root) 681 if (!ctx.cfg.virtual_root)
672 ctx.cfg.virtual_root = ctx.cfg.script_name; 682 ctx.cfg.virtual_root = ctx.cfg.script_name;
673 683
674 /* If no url parameter is specified on the querystring, lets 684 /* If no url parameter is specified on the querystring, lets
675 * use PATH_INFO as url. This allows cgit to work with virtual 685 * use PATH_INFO as url. This allows cgit to work with virtual
676 * urls without the need for rewriterules in the webserver (as 686 * urls without the need for rewriterules in the webserver (as
677 * long as PATH_INFO is included in the cache lookup key). 687 * long as PATH_INFO is included in the cache lookup key).
678 */ 688 */
679 path = ctx.env.path_info; 689 path = ctx.env.path_info;
680 if (!ctx.qry.url && path) { 690 if (!ctx.qry.url && path) {
681 if (path[0] == '/') 691 if (path[0] == '/')
682 path++; 692 path++;
683 ctx.qry.url = xstrdup(path); 693 ctx.qry.url = xstrdup(path);
684 if (ctx.qry.raw) { 694 if (ctx.qry.raw) {
685 qry = ctx.qry.raw; 695 qry = ctx.qry.raw;
686 ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry)); 696 ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry));
687 free(qry); 697 free(qry);
688 } else 698 } else
689 ctx.qry.raw = xstrdup(ctx.qry.url); 699 ctx.qry.raw = xstrdup(ctx.qry.url);
690 cgit_parse_url(ctx.qry.url); 700 cgit_parse_url(ctx.qry.url);
691 } 701 }
692 702
693 ttl = calc_ttl(); 703 ttl = calc_ttl();
694 ctx.page.expires += ttl*60; 704 ctx.page.expires += ttl*60;
695 if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD")) 705 if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD"))
696 ctx.cfg.nocache = 1; 706 ctx.cfg.nocache = 1;
697 if (ctx.cfg.nocache) 707 if (ctx.cfg.nocache)
698 ctx.cfg.cache_size = 0; 708 ctx.cfg.cache_size = 0;
699 err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root, 709 err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root,
700 ctx.qry.raw, ttl, process_request, &ctx); 710 ctx.qry.raw, ttl, process_request, &ctx);
701 if (err) 711 if (err)
702 cgit_print_error(fmt("Error processing page: %s (%d)", 712 cgit_print_error(fmt("Error processing page: %s (%d)",
703 strerror(err), err)); 713 strerror(err), err));
704 return err; 714 return err;
705} 715}