summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c8
-rw-r--r--cgit.h3
-rw-r--r--cgitrc.5.txt9
-rw-r--r--scan-tree.c30
-rw-r--r--scan-tree.h2
5 files changed, 39 insertions, 13 deletions
diff --git a/cgit.c b/cgit.c
index 90ae124..e281aa9 100644
--- a/cgit.c
+++ b/cgit.c
@@ -159,25 +159,25 @@ void config_cb(const char *name, const char *value)
159 else if (!strcmp(name, "max-message-length")) 159 else if (!strcmp(name, "max-message-length"))
160 ctx.cfg.max_msg_len = atoi(value); 160 ctx.cfg.max_msg_len = atoi(value);
161 else if (!strcmp(name, "max-repodesc-length")) 161 else if (!strcmp(name, "max-repodesc-length"))
162 ctx.cfg.max_repodesc_len = atoi(value); 162 ctx.cfg.max_repodesc_len = atoi(value);
163 else if (!strcmp(name, "max-repo-count")) 163 else if (!strcmp(name, "max-repo-count"))
164 ctx.cfg.max_repo_count = atoi(value); 164 ctx.cfg.max_repo_count = atoi(value);
165 else if (!strcmp(name, "max-commit-count")) 165 else if (!strcmp(name, "max-commit-count"))
166 ctx.cfg.max_commit_count = atoi(value); 166 ctx.cfg.max_commit_count = atoi(value);
167 else if (!strcmp(name, "scan-path")) 167 else if (!strcmp(name, "scan-path"))
168 if (!ctx.cfg.nocache && ctx.cfg.cache_size) 168 if (!ctx.cfg.nocache && ctx.cfg.cache_size)
169 process_cached_repolist(value); 169 process_cached_repolist(value);
170 else 170 else
171 scan_tree(value); 171 scan_tree(value, repo_config);
172 else if (!strcmp(name, "source-filter")) 172 else if (!strcmp(name, "source-filter"))
173 ctx.cfg.source_filter = new_filter(value, 1); 173 ctx.cfg.source_filter = new_filter(value, 1);
174 else if (!strcmp(name, "summary-log")) 174 else if (!strcmp(name, "summary-log"))
175 ctx.cfg.summary_log = atoi(value); 175 ctx.cfg.summary_log = atoi(value);
176 else if (!strcmp(name, "summary-branches")) 176 else if (!strcmp(name, "summary-branches"))
177 ctx.cfg.summary_branches = atoi(value); 177 ctx.cfg.summary_branches = atoi(value);
178 else if (!strcmp(name, "summary-tags")) 178 else if (!strcmp(name, "summary-tags"))
179 ctx.cfg.summary_tags = atoi(value); 179 ctx.cfg.summary_tags = atoi(value);
180 else if (!strcmp(name, "agefile")) 180 else if (!strcmp(name, "agefile"))
181 ctx.cfg.agefile = xstrdup(value); 181 ctx.cfg.agefile = xstrdup(value);
182 else if (!strcmp(name, "renamelimit")) 182 else if (!strcmp(name, "renamelimit"))
183 ctx.cfg.renamelimit = atoi(value); 183 ctx.cfg.renamelimit = atoi(value);
@@ -467,49 +467,49 @@ static int generate_cached_repolist(const char *path, const char *cached_rc)
467 locked_rc = xstrdup(fmt("%s.lock", cached_rc)); 467 locked_rc = xstrdup(fmt("%s.lock", cached_rc));
468 f = fopen(locked_rc, "wx"); 468 f = fopen(locked_rc, "wx");
469 if (!f) { 469 if (!f) {
470 /* Inform about the error unless the lockfile already existed, 470 /* Inform about the error unless the lockfile already existed,
471 * since that only means we've got concurrent requests. 471 * since that only means we've got concurrent requests.
472 */ 472 */
473 if (errno != EEXIST) 473 if (errno != EEXIST)
474 fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n", 474 fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n",
475 locked_rc, strerror(errno), errno); 475 locked_rc, strerror(errno), errno);
476 return errno; 476 return errno;
477 } 477 }
478 idx = cgit_repolist.count; 478 idx = cgit_repolist.count;
479 scan_tree(path); 479 scan_tree(path, repo_config);
480 print_repolist(f, &cgit_repolist, idx); 480 print_repolist(f, &cgit_repolist, idx);
481 if (rename(locked_rc, cached_rc)) 481 if (rename(locked_rc, cached_rc))
482 fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", 482 fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n",
483 locked_rc, cached_rc, strerror(errno), errno); 483 locked_rc, cached_rc, strerror(errno), errno);
484 fclose(f); 484 fclose(f);
485 return 0; 485 return 0;
486} 486}
487 487
488static void process_cached_repolist(const char *path) 488static void process_cached_repolist(const char *path)
489{ 489{
490 struct stat st; 490 struct stat st;
491 char *cached_rc; 491 char *cached_rc;
492 time_t age; 492 time_t age;
493 493
494 cached_rc = xstrdup(fmt("%s/rc-%8x", ctx.cfg.cache_root, 494 cached_rc = xstrdup(fmt("%s/rc-%8x", ctx.cfg.cache_root,
495 hash_str(path))); 495 hash_str(path)));
496 496
497 if (stat(cached_rc, &st)) { 497 if (stat(cached_rc, &st)) {
498 /* Nothing is cached, we need to scan without forking. And 498 /* Nothing is cached, we need to scan without forking. And
499 * if we fail to generate a cached repolist, we need to 499 * if we fail to generate a cached repolist, we need to
500 * invoke scan_tree manually. 500 * invoke scan_tree manually.
501 */ 501 */
502 if (generate_cached_repolist(path, cached_rc)) 502 if (generate_cached_repolist(path, cached_rc))
503 scan_tree(path); 503 scan_tree(path, repo_config);
504 return; 504 return;
505 } 505 }
506 506
507 parse_configfile(cached_rc, config_cb); 507 parse_configfile(cached_rc, config_cb);
508 508
509 /* If the cached configfile hasn't expired, lets exit now */ 509 /* If the cached configfile hasn't expired, lets exit now */
510 age = time(NULL) - st.st_mtime; 510 age = time(NULL) - st.st_mtime;
511 if (age <= (ctx.cfg.cache_scanrc_ttl * 60)) 511 if (age <= (ctx.cfg.cache_scanrc_ttl * 60))
512 return; 512 return;
513 513
514 /* The cached repolist has been parsed, but it was old. So lets 514 /* The cached repolist has been parsed, but it was old. So lets
515 * rescan the specified path and generate a new cached repolist 515 * rescan the specified path and generate a new cached repolist
@@ -550,25 +550,25 @@ static void cgit_parse_args(int argc, const char **argv)
550 ctx.qry.has_symref = 1; 550 ctx.qry.has_symref = 1;
551 } 551 }
552 if (!strncmp(argv[i], "--sha1=", 7)) { 552 if (!strncmp(argv[i], "--sha1=", 7)) {
553 ctx.qry.sha1 = xstrdup(argv[i]+7); 553 ctx.qry.sha1 = xstrdup(argv[i]+7);
554 ctx.qry.has_sha1 = 1; 554 ctx.qry.has_sha1 = 1;
555 } 555 }
556 if (!strncmp(argv[i], "--ofs=", 6)) { 556 if (!strncmp(argv[i], "--ofs=", 6)) {
557 ctx.qry.ofs = atoi(argv[i]+6); 557 ctx.qry.ofs = atoi(argv[i]+6);
558 } 558 }
559 if (!strncmp(argv[i], "--scan-tree=", 12) || 559 if (!strncmp(argv[i], "--scan-tree=", 12) ||
560 !strncmp(argv[i], "--scan-path=", 12)) { 560 !strncmp(argv[i], "--scan-path=", 12)) {
561 scan++; 561 scan++;
562 scan_tree(argv[i] + 12); 562 scan_tree(argv[i] + 12, repo_config);
563 } 563 }
564 } 564 }
565 if (scan) { 565 if (scan) {
566 qsort(cgit_repolist.repos, cgit_repolist.count, 566 qsort(cgit_repolist.repos, cgit_repolist.count,
567 sizeof(struct cgit_repo), cmp_repos); 567 sizeof(struct cgit_repo), cmp_repos);
568 print_repolist(stdout, &cgit_repolist, 0); 568 print_repolist(stdout, &cgit_repolist, 0);
569 exit(0); 569 exit(0);
570 } 570 }
571} 571}
572 572
573static int calc_ttl() 573static int calc_ttl()
574{ 574{
diff --git a/cgit.h b/cgit.h
index fc7c7d5..3359be9 100644
--- a/cgit.h
+++ b/cgit.h
@@ -70,24 +70,27 @@ struct cgit_repo {
70 char *section; 70 char *section;
71 char *clone_url; 71 char *clone_url;
72 int snapshots; 72 int snapshots;
73 int enable_log_filecount; 73 int enable_log_filecount;
74 int enable_log_linecount; 74 int enable_log_linecount;
75 int max_stats; 75 int max_stats;
76 time_t mtime; 76 time_t mtime;
77 struct cgit_filter *about_filter; 77 struct cgit_filter *about_filter;
78 struct cgit_filter *commit_filter; 78 struct cgit_filter *commit_filter;
79 struct cgit_filter *source_filter; 79 struct cgit_filter *source_filter;
80}; 80};
81 81
82typedef void (*repo_config_fn)(struct cgit_repo *repo, const char *name,
83 const char *value);
84
82struct cgit_repolist { 85struct cgit_repolist {
83 int length; 86 int length;
84 int count; 87 int count;
85 struct cgit_repo *repos; 88 struct cgit_repo *repos;
86}; 89};
87 90
88struct commitinfo { 91struct commitinfo {
89 struct commit *commit; 92 struct commit *commit;
90 char *author; 93 char *author;
91 char *author_email; 94 char *author_email;
92 unsigned long author_date; 95 unsigned long author_date;
93 char *committer; 96 char *committer;
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index e99c9f7..df494aa 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -317,24 +317,33 @@ repo.snapshots::
317 317
318repo.section:: 318repo.section::
319 Override the current section for this repository. Default value: none. 319 Override the current section for this repository. Default value: none.
320 320
321repo.source-filter:: 321repo.source-filter::
322 Override the default source-filter. Default value: <source-filter>. 322 Override the default source-filter. Default value: <source-filter>.
323 323
324repo.url:: 324repo.url::
325 The relative url used to access the repository. This must be the first 325 The relative url used to access the repository. This must be the first
326 setting specified for each repo. Default value: none. 326 setting specified for each repo. Default value: none.
327 327
328 328
329REPOSITORY-SPECIFIC CGITRC FILE
330-------------------------------
331When the option 'scan-path' is used to auto-discover git repositories, cgit
332will try to parse the file 'cgitrc' within any found repository. Such a repo-
333specific config file may contain any of the repo-specific options described
334above, except 'repo.url' and 'repo.path'. Also, in a repo-specific config
335file, the 'repo.' prefix is dropped from the config option names.
336
337
329EXAMPLE CGITRC FILE 338EXAMPLE CGITRC FILE
330------------------- 339-------------------
331 340
332.... 341....
333# Enable caching of up to 1000 output entriess 342# Enable caching of up to 1000 output entriess
334cache-size=1000 343cache-size=1000
335 344
336 345
337# Specify some default clone prefixes 346# Specify some default clone prefixes
338clone-prefix=git://foobar.com ssh://foobar.com/pub/git http://foobar.com/git 347clone-prefix=git://foobar.com ssh://foobar.com/pub/git http://foobar.com/git
339 348
340# Specify the css url 349# Specify the css url
diff --git a/scan-tree.c b/scan-tree.c
index 67f4550..dbca797 100644
--- a/scan-tree.c
+++ b/scan-tree.c
@@ -1,13 +1,14 @@
1#include "cgit.h" 1#include "cgit.h"
2#include "configfile.h"
2#include "html.h" 3#include "html.h"
3 4
4#define MAX_PATH 4096 5#define MAX_PATH 4096
5 6
6/* return 1 if path contains a objects/ directory and a HEAD file */ 7/* return 1 if path contains a objects/ directory and a HEAD file */
7static int is_git_dir(const char *path) 8static int is_git_dir(const char *path)
8{ 9{
9 struct stat st; 10 struct stat st;
10 static char buf[MAX_PATH]; 11 static char buf[MAX_PATH];
11 12
12 if (snprintf(buf, MAX_PATH, "%s/objects", path) >= MAX_PATH) { 13 if (snprintf(buf, MAX_PATH, "%s/objects", path) >= MAX_PATH) {
13 fprintf(stderr, "Insanely long path: %s\n", path); 14 fprintf(stderr, "Insanely long path: %s\n", path);
@@ -26,27 +27,34 @@ static int is_git_dir(const char *path)
26 if (stat(buf, &st)) { 27 if (stat(buf, &st)) {
27 if (errno != ENOENT) 28 if (errno != ENOENT)
28 fprintf(stderr, "Error checking path %s: %s (%d)\n", 29 fprintf(stderr, "Error checking path %s: %s (%d)\n",
29 path, strerror(errno), errno); 30 path, strerror(errno), errno);
30 return 0; 31 return 0;
31 } 32 }
32 if (!S_ISREG(st.st_mode)) 33 if (!S_ISREG(st.st_mode))
33 return 0; 34 return 0;
34 35
35 return 1; 36 return 1;
36} 37}
37 38
38static void add_repo(const char *base, const char *path) 39struct cgit_repo *repo;
40repo_config_fn config_fn;
41
42static void repo_config(const char *name, const char *value)
43{
44 config_fn(repo, name, value);
45}
46
47static void add_repo(const char *base, const char *path, repo_config_fn fn)
39{ 48{
40 struct cgit_repo *repo;
41 struct stat st; 49 struct stat st;
42 struct passwd *pwd; 50 struct passwd *pwd;
43 char *p; 51 char *p;
44 size_t size; 52 size_t size;
45 53
46 if (stat(path, &st)) { 54 if (stat(path, &st)) {
47 fprintf(stderr, "Error accessing %s: %s (%d)\n", 55 fprintf(stderr, "Error accessing %s: %s (%d)\n",
48 path, strerror(errno), errno); 56 path, strerror(errno), errno);
49 return; 57 return;
50 } 58 }
51 if ((pwd = getpwuid(st.st_uid)) == NULL) { 59 if ((pwd = getpwuid(st.st_uid)) == NULL) {
52 fprintf(stderr, "Error reading owner-info for %s: %s (%d)\n", 60 fprintf(stderr, "Error reading owner-info for %s: %s (%d)\n",
@@ -67,39 +75,45 @@ static void add_repo(const char *base, const char *path)
67 p = (pwd && pwd->pw_gecos) ? strchr(pwd->pw_gecos, ',') : NULL; 75 p = (pwd && pwd->pw_gecos) ? strchr(pwd->pw_gecos, ',') : NULL;
68 if (p) 76 if (p)
69 *p = '\0'; 77 *p = '\0';
70 repo->owner = (pwd ? xstrdup(pwd->pw_gecos ? pwd->pw_gecos : pwd->pw_name) : ""); 78 repo->owner = (pwd ? xstrdup(pwd->pw_gecos ? pwd->pw_gecos : pwd->pw_name) : "");
71 79
72 p = fmt("%s/description", path); 80 p = fmt("%s/description", path);
73 if (!stat(p, &st)) 81 if (!stat(p, &st))
74 readfile(p, &repo->desc, &size); 82 readfile(p, &repo->desc, &size);
75 83
76 p = fmt("%s/README.html", path); 84 p = fmt("%s/README.html", path);
77 if (!stat(p, &st)) 85 if (!stat(p, &st))
78 repo->readme = "README.html"; 86 repo->readme = "README.html";
87
88 p = fmt("%s/cgitrc", path);
89 if (!stat(p, &st)) {
90 config_fn = fn;
91 parse_configfile(xstrdup(p), &repo_config);
92 }
79} 93}
80 94
81static void scan_path(const char *base, const char *path) 95static void scan_path(const char *base, const char *path, repo_config_fn fn)
82{ 96{
83 DIR *dir; 97 DIR *dir;
84 struct dirent *ent; 98 struct dirent *ent;
85 char *buf; 99 char *buf;
86 struct stat st; 100 struct stat st;
87 101
88 if (is_git_dir(path)) { 102 if (is_git_dir(path)) {
89 add_repo(base, path); 103 add_repo(base, path, fn);
90 return; 104 return;
91 } 105 }
92 if (is_git_dir(fmt("%s/.git", path))) { 106 if (is_git_dir(fmt("%s/.git", path))) {
93 add_repo(base, fmt("%s/.git", path)); 107 add_repo(base, fmt("%s/.git", path), fn);
94 return; 108 return;
95 } 109 }
96 dir = opendir(path); 110 dir = opendir(path);
97 if (!dir) { 111 if (!dir) {
98 fprintf(stderr, "Error opening directory %s: %s (%d)\n", 112 fprintf(stderr, "Error opening directory %s: %s (%d)\n",
99 path, strerror(errno), errno); 113 path, strerror(errno), errno);
100 return; 114 return;
101 } 115 }
102 while((ent = readdir(dir)) != NULL) { 116 while((ent = readdir(dir)) != NULL) {
103 if (ent->d_name[0] == '.') { 117 if (ent->d_name[0] == '.') {
104 if (ent->d_name[1] == '\0') 118 if (ent->d_name[1] == '\0')
105 continue; 119 continue;
@@ -111,22 +125,22 @@ static void scan_path(const char *base, const char *path)
111 fprintf(stderr, "Alloc error on %s: %s (%d)\n", 125 fprintf(stderr, "Alloc error on %s: %s (%d)\n",
112 path, strerror(errno), errno); 126 path, strerror(errno), errno);
113 exit(1); 127 exit(1);
114 } 128 }
115 sprintf(buf, "%s/%s", path, ent->d_name); 129 sprintf(buf, "%s/%s", path, ent->d_name);
116 if (stat(buf, &st)) { 130 if (stat(buf, &st)) {
117 fprintf(stderr, "Error checking path %s: %s (%d)\n", 131 fprintf(stderr, "Error checking path %s: %s (%d)\n",
118 buf, strerror(errno), errno); 132 buf, strerror(errno), errno);
119 free(buf); 133 free(buf);
120 continue; 134 continue;
121 } 135 }
122 if (S_ISDIR(st.st_mode)) 136 if (S_ISDIR(st.st_mode))
123 scan_path(base, buf); 137 scan_path(base, buf, fn);
124 free(buf); 138 free(buf);
125 } 139 }
126 closedir(dir); 140 closedir(dir);
127} 141}
128 142
129void scan_tree(const char *path) 143void scan_tree(const char *path, repo_config_fn fn)
130{ 144{
131 scan_path(path, path); 145 scan_path(path, path, fn);
132} 146}
diff --git a/scan-tree.h b/scan-tree.h
index b103b16..11539f4 100644
--- a/scan-tree.h
+++ b/scan-tree.h
@@ -1,3 +1,3 @@
1 1
2 2
3extern void scan_tree(const char *path); 3extern void scan_tree(const char *path, repo_config_fn fn);