summaryrefslogtreecommitdiffabout
authorLars Hjemli <hjemli@gmail.com>2009-08-23 17:36:45 (UTC)
committer Lars Hjemli <hjemli@gmail.com>2009-08-24 08:22:58 (UTC)
commit50d5af3adcdd90424b70e9472af24356ed50aa9b (patch) (unidiff)
tree758484a13b8226f64da1e7bde04bb5333beb1e0b
parent00466376922e2f7db02b3c335d46af5eb8991c49 (diff)
downloadcgit-50d5af3adcdd90424b70e9472af24356ed50aa9b.zip
cgit-50d5af3adcdd90424b70e9472af24356ed50aa9b.tar.gz
cgit-50d5af3adcdd90424b70e9472af24356ed50aa9b.tar.bz2
Add support for --scan-path command line option
This is an alias for --scan-tree (which might be deprecated in the future). Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c3
1 files changed, 2 insertions, 1 deletions
diff --git a/cgit.c b/cgit.c
index 6ece411..a792fe4 100644
--- a/cgit.c
+++ b/cgit.c
@@ -294,340 +294,341 @@ struct refmatch {
294 char *first_ref; 294 char *first_ref;
295 int match; 295 int match;
296}; 296};
297 297
298int find_current_ref(const char *refname, const unsigned char *sha1, 298int find_current_ref(const char *refname, const unsigned char *sha1,
299 int flags, void *cb_data) 299 int flags, void *cb_data)
300{ 300{
301 struct refmatch *info; 301 struct refmatch *info;
302 302
303 info = (struct refmatch *)cb_data; 303 info = (struct refmatch *)cb_data;
304 if (!strcmp(refname, info->req_ref)) 304 if (!strcmp(refname, info->req_ref))
305 info->match = 1; 305 info->match = 1;
306 if (!info->first_ref) 306 if (!info->first_ref)
307 info->first_ref = xstrdup(refname); 307 info->first_ref = xstrdup(refname);
308 return info->match; 308 return info->match;
309} 309}
310 310
311char *find_default_branch(struct cgit_repo *repo) 311char *find_default_branch(struct cgit_repo *repo)
312{ 312{
313 struct refmatch info; 313 struct refmatch info;
314 char *ref; 314 char *ref;
315 315
316 info.req_ref = repo->defbranch; 316 info.req_ref = repo->defbranch;
317 info.first_ref = NULL; 317 info.first_ref = NULL;
318 info.match = 0; 318 info.match = 0;
319 for_each_branch_ref(find_current_ref, &info); 319 for_each_branch_ref(find_current_ref, &info);
320 if (info.match) 320 if (info.match)
321 ref = info.req_ref; 321 ref = info.req_ref;
322 else 322 else
323 ref = info.first_ref; 323 ref = info.first_ref;
324 if (ref) 324 if (ref)
325 ref = xstrdup(ref); 325 ref = xstrdup(ref);
326 return ref; 326 return ref;
327} 327}
328 328
329static int prepare_repo_cmd(struct cgit_context *ctx) 329static int prepare_repo_cmd(struct cgit_context *ctx)
330{ 330{
331 char *tmp; 331 char *tmp;
332 unsigned char sha1[20]; 332 unsigned char sha1[20];
333 int nongit = 0; 333 int nongit = 0;
334 334
335 setenv("GIT_DIR", ctx->repo->path, 1); 335 setenv("GIT_DIR", ctx->repo->path, 1);
336 setup_git_directory_gently(&nongit); 336 setup_git_directory_gently(&nongit);
337 if (nongit) { 337 if (nongit) {
338 ctx->page.title = fmt("%s - %s", ctx->cfg.root_title, 338 ctx->page.title = fmt("%s - %s", ctx->cfg.root_title,
339 "config error"); 339 "config error");
340 tmp = fmt("Not a git repository: '%s'", ctx->repo->path); 340 tmp = fmt("Not a git repository: '%s'", ctx->repo->path);
341 ctx->repo = NULL; 341 ctx->repo = NULL;
342 cgit_print_http_headers(ctx); 342 cgit_print_http_headers(ctx);
343 cgit_print_docstart(ctx); 343 cgit_print_docstart(ctx);
344 cgit_print_pageheader(ctx); 344 cgit_print_pageheader(ctx);
345 cgit_print_error(tmp); 345 cgit_print_error(tmp);
346 cgit_print_docend(); 346 cgit_print_docend();
347 return 1; 347 return 1;
348 } 348 }
349 ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc); 349 ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc);
350 350
351 if (!ctx->qry.head) { 351 if (!ctx->qry.head) {
352 ctx->qry.nohead = 1; 352 ctx->qry.nohead = 1;
353 ctx->qry.head = find_default_branch(ctx->repo); 353 ctx->qry.head = find_default_branch(ctx->repo);
354 ctx->repo->defbranch = ctx->qry.head; 354 ctx->repo->defbranch = ctx->qry.head;
355 } 355 }
356 356
357 if (!ctx->qry.head) { 357 if (!ctx->qry.head) {
358 cgit_print_http_headers(ctx); 358 cgit_print_http_headers(ctx);
359 cgit_print_docstart(ctx); 359 cgit_print_docstart(ctx);
360 cgit_print_pageheader(ctx); 360 cgit_print_pageheader(ctx);
361 cgit_print_error("Repository seems to be empty"); 361 cgit_print_error("Repository seems to be empty");
362 cgit_print_docend(); 362 cgit_print_docend();
363 return 1; 363 return 1;
364 } 364 }
365 365
366 if (get_sha1(ctx->qry.head, sha1)) { 366 if (get_sha1(ctx->qry.head, sha1)) {
367 tmp = xstrdup(ctx->qry.head); 367 tmp = xstrdup(ctx->qry.head);
368 ctx->qry.head = ctx->repo->defbranch; 368 ctx->qry.head = ctx->repo->defbranch;
369 ctx->page.status = 404; 369 ctx->page.status = 404;
370 ctx->page.statusmsg = "not found"; 370 ctx->page.statusmsg = "not found";
371 cgit_print_http_headers(ctx); 371 cgit_print_http_headers(ctx);
372 cgit_print_docstart(ctx); 372 cgit_print_docstart(ctx);
373 cgit_print_pageheader(ctx); 373 cgit_print_pageheader(ctx);
374 cgit_print_error(fmt("Invalid branch: %s", tmp)); 374 cgit_print_error(fmt("Invalid branch: %s", tmp));
375 cgit_print_docend(); 375 cgit_print_docend();
376 return 1; 376 return 1;
377 } 377 }
378 return 0; 378 return 0;
379} 379}
380 380
381static void process_request(void *cbdata) 381static void process_request(void *cbdata)
382{ 382{
383 struct cgit_context *ctx = cbdata; 383 struct cgit_context *ctx = cbdata;
384 struct cgit_cmd *cmd; 384 struct cgit_cmd *cmd;
385 385
386 cmd = cgit_get_cmd(ctx); 386 cmd = cgit_get_cmd(ctx);
387 if (!cmd) { 387 if (!cmd) {
388 ctx->page.title = "cgit error"; 388 ctx->page.title = "cgit error";
389 cgit_print_http_headers(ctx); 389 cgit_print_http_headers(ctx);
390 cgit_print_docstart(ctx); 390 cgit_print_docstart(ctx);
391 cgit_print_pageheader(ctx); 391 cgit_print_pageheader(ctx);
392 cgit_print_error("Invalid request"); 392 cgit_print_error("Invalid request");
393 cgit_print_docend(); 393 cgit_print_docend();
394 return; 394 return;
395 } 395 }
396 396
397 if (cmd->want_repo && !ctx->repo) { 397 if (cmd->want_repo && !ctx->repo) {
398 cgit_print_http_headers(ctx); 398 cgit_print_http_headers(ctx);
399 cgit_print_docstart(ctx); 399 cgit_print_docstart(ctx);
400 cgit_print_pageheader(ctx); 400 cgit_print_pageheader(ctx);
401 cgit_print_error(fmt("No repository selected")); 401 cgit_print_error(fmt("No repository selected"));
402 cgit_print_docend(); 402 cgit_print_docend();
403 return; 403 return;
404 } 404 }
405 405
406 if (ctx->repo && prepare_repo_cmd(ctx)) 406 if (ctx->repo && prepare_repo_cmd(ctx))
407 return; 407 return;
408 408
409 if (cmd->want_layout) { 409 if (cmd->want_layout) {
410 cgit_print_http_headers(ctx); 410 cgit_print_http_headers(ctx);
411 cgit_print_docstart(ctx); 411 cgit_print_docstart(ctx);
412 cgit_print_pageheader(ctx); 412 cgit_print_pageheader(ctx);
413 } 413 }
414 414
415 cmd->fn(ctx); 415 cmd->fn(ctx);
416 416
417 if (cmd->want_layout) 417 if (cmd->want_layout)
418 cgit_print_docend(); 418 cgit_print_docend();
419} 419}
420 420
421int cmp_repos(const void *a, const void *b) 421int cmp_repos(const void *a, const void *b)
422{ 422{
423 const struct cgit_repo *ra = a, *rb = b; 423 const struct cgit_repo *ra = a, *rb = b;
424 return strcmp(ra->url, rb->url); 424 return strcmp(ra->url, rb->url);
425} 425}
426 426
427void print_repo(FILE *f, struct cgit_repo *repo) 427void print_repo(FILE *f, struct cgit_repo *repo)
428{ 428{
429 fprintf(f, "repo.url=%s\n", repo->url); 429 fprintf(f, "repo.url=%s\n", repo->url);
430 fprintf(f, "repo.name=%s\n", repo->name); 430 fprintf(f, "repo.name=%s\n", repo->name);
431 fprintf(f, "repo.path=%s\n", repo->path); 431 fprintf(f, "repo.path=%s\n", repo->path);
432 if (repo->owner) 432 if (repo->owner)
433 fprintf(f, "repo.owner=%s\n", repo->owner); 433 fprintf(f, "repo.owner=%s\n", repo->owner);
434 if (repo->desc) 434 if (repo->desc)
435 fprintf(f, "repo.desc=%s\n", repo->desc); 435 fprintf(f, "repo.desc=%s\n", repo->desc);
436 if (repo->readme) 436 if (repo->readme)
437 fprintf(f, "repo.readme=%s\n", repo->readme); 437 fprintf(f, "repo.readme=%s\n", repo->readme);
438 fprintf(f, "\n"); 438 fprintf(f, "\n");
439} 439}
440 440
441void print_repolist(FILE *f, struct cgit_repolist *list, int start) 441void print_repolist(FILE *f, struct cgit_repolist *list, int start)
442{ 442{
443 int i; 443 int i;
444 444
445 for(i = start; i < list->count; i++) 445 for(i = start; i < list->count; i++)
446 print_repo(f, &list->repos[i]); 446 print_repo(f, &list->repos[i]);
447} 447}
448 448
449/* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc' 449/* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc'
450 * and return 0 on success. 450 * and return 0 on success.
451 */ 451 */
452static int generate_cached_repolist(const char *path, const char *cached_rc) 452static int generate_cached_repolist(const char *path, const char *cached_rc)
453{ 453{
454 char *locked_rc; 454 char *locked_rc;
455 int idx; 455 int idx;
456 FILE *f; 456 FILE *f;
457 457
458 locked_rc = xstrdup(fmt("%s.lock", cached_rc)); 458 locked_rc = xstrdup(fmt("%s.lock", cached_rc));
459 f = fopen(locked_rc, "wx"); 459 f = fopen(locked_rc, "wx");
460 if (!f) { 460 if (!f) {
461 /* Inform about the error unless the lockfile already existed, 461 /* Inform about the error unless the lockfile already existed,
462 * since that only means we've got concurrent requests. 462 * since that only means we've got concurrent requests.
463 */ 463 */
464 if (errno != EEXIST) 464 if (errno != EEXIST)
465 fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n", 465 fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n",
466 locked_rc, strerror(errno), errno); 466 locked_rc, strerror(errno), errno);
467 return errno; 467 return errno;
468 } 468 }
469 idx = cgit_repolist.count; 469 idx = cgit_repolist.count;
470 scan_tree(path); 470 scan_tree(path);
471 print_repolist(f, &cgit_repolist, idx); 471 print_repolist(f, &cgit_repolist, idx);
472 if (rename(locked_rc, cached_rc)) 472 if (rename(locked_rc, cached_rc))
473 fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", 473 fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n",
474 locked_rc, cached_rc, strerror(errno), errno); 474 locked_rc, cached_rc, strerror(errno), errno);
475 fclose(f); 475 fclose(f);
476 return 0; 476 return 0;
477} 477}
478 478
479static void process_cached_repolist(const char *path) 479static void process_cached_repolist(const char *path)
480{ 480{
481 struct stat st; 481 struct stat st;
482 char *cached_rc; 482 char *cached_rc;
483 time_t age; 483 time_t age;
484 484
485 cached_rc = xstrdup(fmt("%s/rc-%8x", ctx.cfg.cache_root, 485 cached_rc = xstrdup(fmt("%s/rc-%8x", ctx.cfg.cache_root,
486 hash_str(path))); 486 hash_str(path)));
487 487
488 if (stat(cached_rc, &st)) { 488 if (stat(cached_rc, &st)) {
489 /* Nothing is cached, we need to scan without forking. And 489 /* Nothing is cached, we need to scan without forking. And
490 * if we fail to generate a cached repolist, we need to 490 * if we fail to generate a cached repolist, we need to
491 * invoke scan_tree manually. 491 * invoke scan_tree manually.
492 */ 492 */
493 if (generate_cached_repolist(path, cached_rc)) 493 if (generate_cached_repolist(path, cached_rc))
494 scan_tree(path); 494 scan_tree(path);
495 return; 495 return;
496 } 496 }
497 497
498 parse_configfile(cached_rc, config_cb); 498 parse_configfile(cached_rc, config_cb);
499 499
500 /* If the cached configfile hasn't expired, lets exit now */ 500 /* If the cached configfile hasn't expired, lets exit now */
501 age = time(NULL) - st.st_mtime; 501 age = time(NULL) - st.st_mtime;
502 if (age <= (ctx.cfg.cache_scanrc_ttl * 60)) 502 if (age <= (ctx.cfg.cache_scanrc_ttl * 60))
503 return; 503 return;
504 504
505 /* The cached repolist has been parsed, but it was old. So lets 505 /* The cached repolist has been parsed, but it was old. So lets
506 * rescan the specified path and generate a new cached repolist 506 * rescan the specified path and generate a new cached repolist
507 * in a child-process to avoid latency for the current request. 507 * in a child-process to avoid latency for the current request.
508 */ 508 */
509 if (fork()) 509 if (fork())
510 return; 510 return;
511 511
512 exit(generate_cached_repolist(path, cached_rc)); 512 exit(generate_cached_repolist(path, cached_rc));
513} 513}
514 514
515static void cgit_parse_args(int argc, const char **argv) 515static void cgit_parse_args(int argc, const char **argv)
516{ 516{
517 int i; 517 int i;
518 int scan = 0; 518 int scan = 0;
519 519
520 for (i = 1; i < argc; i++) { 520 for (i = 1; i < argc; i++) {
521 if (!strncmp(argv[i], "--cache=", 8)) { 521 if (!strncmp(argv[i], "--cache=", 8)) {
522 ctx.cfg.cache_root = xstrdup(argv[i]+8); 522 ctx.cfg.cache_root = xstrdup(argv[i]+8);
523 } 523 }
524 if (!strcmp(argv[i], "--nocache")) { 524 if (!strcmp(argv[i], "--nocache")) {
525 ctx.cfg.nocache = 1; 525 ctx.cfg.nocache = 1;
526 } 526 }
527 if (!strcmp(argv[i], "--nohttp")) { 527 if (!strcmp(argv[i], "--nohttp")) {
528 ctx.env.no_http = "1"; 528 ctx.env.no_http = "1";
529 } 529 }
530 if (!strncmp(argv[i], "--query=", 8)) { 530 if (!strncmp(argv[i], "--query=", 8)) {
531 ctx.qry.raw = xstrdup(argv[i]+8); 531 ctx.qry.raw = xstrdup(argv[i]+8);
532 } 532 }
533 if (!strncmp(argv[i], "--repo=", 7)) { 533 if (!strncmp(argv[i], "--repo=", 7)) {
534 ctx.qry.repo = xstrdup(argv[i]+7); 534 ctx.qry.repo = xstrdup(argv[i]+7);
535 } 535 }
536 if (!strncmp(argv[i], "--page=", 7)) { 536 if (!strncmp(argv[i], "--page=", 7)) {
537 ctx.qry.page = xstrdup(argv[i]+7); 537 ctx.qry.page = xstrdup(argv[i]+7);
538 } 538 }
539 if (!strncmp(argv[i], "--head=", 7)) { 539 if (!strncmp(argv[i], "--head=", 7)) {
540 ctx.qry.head = xstrdup(argv[i]+7); 540 ctx.qry.head = xstrdup(argv[i]+7);
541 ctx.qry.has_symref = 1; 541 ctx.qry.has_symref = 1;
542 } 542 }
543 if (!strncmp(argv[i], "--sha1=", 7)) { 543 if (!strncmp(argv[i], "--sha1=", 7)) {
544 ctx.qry.sha1 = xstrdup(argv[i]+7); 544 ctx.qry.sha1 = xstrdup(argv[i]+7);
545 ctx.qry.has_sha1 = 1; 545 ctx.qry.has_sha1 = 1;
546 } 546 }
547 if (!strncmp(argv[i], "--ofs=", 6)) { 547 if (!strncmp(argv[i], "--ofs=", 6)) {
548 ctx.qry.ofs = atoi(argv[i]+6); 548 ctx.qry.ofs = atoi(argv[i]+6);
549 } 549 }
550 if (!strncmp(argv[i], "--scan-tree=", 12)) { 550 if (!strncmp(argv[i], "--scan-tree=", 12) ||
551 !strncmp(argv[i], "--scan-path=", 12)) {
551 scan++; 552 scan++;
552 scan_tree(argv[i] + 12); 553 scan_tree(argv[i] + 12);
553 } 554 }
554 } 555 }
555 if (scan) { 556 if (scan) {
556 qsort(cgit_repolist.repos, cgit_repolist.count, 557 qsort(cgit_repolist.repos, cgit_repolist.count,
557 sizeof(struct cgit_repo), cmp_repos); 558 sizeof(struct cgit_repo), cmp_repos);
558 print_repolist(stdout, &cgit_repolist, 0); 559 print_repolist(stdout, &cgit_repolist, 0);
559 exit(0); 560 exit(0);
560 } 561 }
561} 562}
562 563
563static int calc_ttl() 564static int calc_ttl()
564{ 565{
565 if (!ctx.repo) 566 if (!ctx.repo)
566 return ctx.cfg.cache_root_ttl; 567 return ctx.cfg.cache_root_ttl;
567 568
568 if (!ctx.qry.page) 569 if (!ctx.qry.page)
569 return ctx.cfg.cache_repo_ttl; 570 return ctx.cfg.cache_repo_ttl;
570 571
571 if (ctx.qry.has_symref) 572 if (ctx.qry.has_symref)
572 return ctx.cfg.cache_dynamic_ttl; 573 return ctx.cfg.cache_dynamic_ttl;
573 574
574 if (ctx.qry.has_sha1) 575 if (ctx.qry.has_sha1)
575 return ctx.cfg.cache_static_ttl; 576 return ctx.cfg.cache_static_ttl;
576 577
577 return ctx.cfg.cache_repo_ttl; 578 return ctx.cfg.cache_repo_ttl;
578} 579}
579 580
580int main(int argc, const char **argv) 581int main(int argc, const char **argv)
581{ 582{
582 const char *path; 583 const char *path;
583 char *qry; 584 char *qry;
584 int err, ttl; 585 int err, ttl;
585 586
586 prepare_context(&ctx); 587 prepare_context(&ctx);
587 cgit_repolist.length = 0; 588 cgit_repolist.length = 0;
588 cgit_repolist.count = 0; 589 cgit_repolist.count = 0;
589 cgit_repolist.repos = NULL; 590 cgit_repolist.repos = NULL;
590 591
591 cgit_parse_args(argc, argv); 592 cgit_parse_args(argc, argv);
592 parse_configfile(ctx.env.cgit_config, config_cb); 593 parse_configfile(ctx.env.cgit_config, config_cb);
593 ctx.repo = NULL; 594 ctx.repo = NULL;
594 http_parse_querystring(ctx.qry.raw, querystring_cb); 595 http_parse_querystring(ctx.qry.raw, querystring_cb);
595 596
596 /* If virtual-root isn't specified in cgitrc, lets pretend 597 /* If virtual-root isn't specified in cgitrc, lets pretend
597 * that virtual-root equals SCRIPT_NAME. 598 * that virtual-root equals SCRIPT_NAME.
598 */ 599 */
599 if (!ctx.cfg.virtual_root) 600 if (!ctx.cfg.virtual_root)
600 ctx.cfg.virtual_root = ctx.cfg.script_name; 601 ctx.cfg.virtual_root = ctx.cfg.script_name;
601 602
602 /* If no url parameter is specified on the querystring, lets 603 /* If no url parameter is specified on the querystring, lets
603 * use PATH_INFO as url. This allows cgit to work with virtual 604 * use PATH_INFO as url. This allows cgit to work with virtual
604 * urls without the need for rewriterules in the webserver (as 605 * urls without the need for rewriterules in the webserver (as
605 * long as PATH_INFO is included in the cache lookup key). 606 * long as PATH_INFO is included in the cache lookup key).
606 */ 607 */
607 path = ctx.env.path_info; 608 path = ctx.env.path_info;
608 if (!ctx.qry.url && path) { 609 if (!ctx.qry.url && path) {
609 if (path[0] == '/') 610 if (path[0] == '/')
610 path++; 611 path++;
611 ctx.qry.url = xstrdup(path); 612 ctx.qry.url = xstrdup(path);
612 if (ctx.qry.raw) { 613 if (ctx.qry.raw) {
613 qry = ctx.qry.raw; 614 qry = ctx.qry.raw;
614 ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry)); 615 ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry));
615 free(qry); 616 free(qry);
616 } else 617 } else
617 ctx.qry.raw = xstrdup(ctx.qry.url); 618 ctx.qry.raw = xstrdup(ctx.qry.url);
618 cgit_parse_url(ctx.qry.url); 619 cgit_parse_url(ctx.qry.url);
619 } 620 }
620 621
621 ttl = calc_ttl(); 622 ttl = calc_ttl();
622 ctx.page.expires += ttl*60; 623 ctx.page.expires += ttl*60;
623 if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD")) 624 if (ctx.env.request_method && !strcmp(ctx.env.request_method, "HEAD"))
624 ctx.cfg.nocache = 1; 625 ctx.cfg.nocache = 1;
625 if (ctx.cfg.nocache) 626 if (ctx.cfg.nocache)
626 ctx.cfg.cache_size = 0; 627 ctx.cfg.cache_size = 0;
627 err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root, 628 err = cache_process(ctx.cfg.cache_size, ctx.cfg.cache_root,
628 ctx.qry.raw, ttl, process_request, &ctx); 629 ctx.qry.raw, ttl, process_request, &ctx);
629 if (err) 630 if (err)
630 cgit_print_error(fmt("Error processing page: %s (%d)", 631 cgit_print_error(fmt("Error processing page: %s (%d)",
631 strerror(err), err)); 632 strerror(err), err));
632 return err; 633 return err;
633} 634}