summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c3
-rw-r--r--cgit.h1
-rw-r--r--cgitrc.5.txt8
-rw-r--r--scan-tree.c20
4 files changed, 23 insertions, 9 deletions
diff --git a/cgit.c b/cgit.c
index 53ab68d..71f3fc8 100644
--- a/cgit.c
+++ b/cgit.c
@@ -178,48 +178,50 @@ void config_cb(const char *name, const char *value)
178 else if (!strcmp(name, "embedded")) 178 else if (!strcmp(name, "embedded"))
179 ctx.cfg.embedded = atoi(value); 179 ctx.cfg.embedded = atoi(value);
180 else if (!strcmp(name, "max-atom-items")) 180 else if (!strcmp(name, "max-atom-items"))
181 ctx.cfg.max_atom_items = atoi(value); 181 ctx.cfg.max_atom_items = atoi(value);
182 else if (!strcmp(name, "max-message-length")) 182 else if (!strcmp(name, "max-message-length"))
183 ctx.cfg.max_msg_len = atoi(value); 183 ctx.cfg.max_msg_len = atoi(value);
184 else if (!strcmp(name, "max-repodesc-length")) 184 else if (!strcmp(name, "max-repodesc-length"))
185 ctx.cfg.max_repodesc_len = atoi(value); 185 ctx.cfg.max_repodesc_len = atoi(value);
186 else if (!strcmp(name, "max-blob-size")) 186 else if (!strcmp(name, "max-blob-size"))
187 ctx.cfg.max_blob_size = atoi(value); 187 ctx.cfg.max_blob_size = atoi(value);
188 else if (!strcmp(name, "max-repo-count")) 188 else if (!strcmp(name, "max-repo-count"))
189 ctx.cfg.max_repo_count = atoi(value); 189 ctx.cfg.max_repo_count = atoi(value);
190 else if (!strcmp(name, "max-commit-count")) 190 else if (!strcmp(name, "max-commit-count"))
191 ctx.cfg.max_commit_count = atoi(value); 191 ctx.cfg.max_commit_count = atoi(value);
192 else if (!strcmp(name, "project-list")) 192 else if (!strcmp(name, "project-list"))
193 ctx.cfg.project_list = xstrdup(expand_macros(value)); 193 ctx.cfg.project_list = xstrdup(expand_macros(value));
194 else if (!strcmp(name, "scan-path")) 194 else if (!strcmp(name, "scan-path"))
195 if (!ctx.cfg.nocache && ctx.cfg.cache_size) 195 if (!ctx.cfg.nocache && ctx.cfg.cache_size)
196 process_cached_repolist(expand_macros(value)); 196 process_cached_repolist(expand_macros(value));
197 else if (ctx.cfg.project_list) 197 else if (ctx.cfg.project_list)
198 scan_projects(expand_macros(value), 198 scan_projects(expand_macros(value),
199 ctx.cfg.project_list, repo_config); 199 ctx.cfg.project_list, repo_config);
200 else 200 else
201 scan_tree(expand_macros(value), repo_config); 201 scan_tree(expand_macros(value), repo_config);
202 else if (!strcmp(name, "scan-hidden-path"))
203 ctx.cfg.scan_hidden_path = atoi(value);
202 else if (!strcmp(name, "section-from-path")) 204 else if (!strcmp(name, "section-from-path"))
203 ctx.cfg.section_from_path = atoi(value); 205 ctx.cfg.section_from_path = atoi(value);
204 else if (!strcmp(name, "source-filter")) 206 else if (!strcmp(name, "source-filter"))
205 ctx.cfg.source_filter = new_filter(value, 1); 207 ctx.cfg.source_filter = new_filter(value, 1);
206 else if (!strcmp(name, "summary-log")) 208 else if (!strcmp(name, "summary-log"))
207 ctx.cfg.summary_log = atoi(value); 209 ctx.cfg.summary_log = atoi(value);
208 else if (!strcmp(name, "summary-branches")) 210 else if (!strcmp(name, "summary-branches"))
209 ctx.cfg.summary_branches = atoi(value); 211 ctx.cfg.summary_branches = atoi(value);
210 else if (!strcmp(name, "summary-tags")) 212 else if (!strcmp(name, "summary-tags"))
211 ctx.cfg.summary_tags = atoi(value); 213 ctx.cfg.summary_tags = atoi(value);
212 else if (!strcmp(name, "side-by-side-diffs")) 214 else if (!strcmp(name, "side-by-side-diffs"))
213 ctx.cfg.ssdiff = atoi(value); 215 ctx.cfg.ssdiff = atoi(value);
214 else if (!strcmp(name, "agefile")) 216 else if (!strcmp(name, "agefile"))
215 ctx.cfg.agefile = xstrdup(value); 217 ctx.cfg.agefile = xstrdup(value);
216 else if (!strcmp(name, "renamelimit")) 218 else if (!strcmp(name, "renamelimit"))
217 ctx.cfg.renamelimit = atoi(value); 219 ctx.cfg.renamelimit = atoi(value);
218 else if (!strcmp(name, "remove-suffix")) 220 else if (!strcmp(name, "remove-suffix"))
219 ctx.cfg.remove_suffix = atoi(value); 221 ctx.cfg.remove_suffix = atoi(value);
220 else if (!strcmp(name, "robots")) 222 else if (!strcmp(name, "robots"))
221 ctx.cfg.robots = xstrdup(value); 223 ctx.cfg.robots = xstrdup(value);
222 else if (!strcmp(name, "clone-prefix")) 224 else if (!strcmp(name, "clone-prefix"))
223 ctx.cfg.clone_prefix = xstrdup(value); 225 ctx.cfg.clone_prefix = xstrdup(value);
224 else if (!strcmp(name, "local-time")) 226 else if (!strcmp(name, "local-time"))
225 ctx.cfg.local_time = atoi(value); 227 ctx.cfg.local_time = atoi(value);
@@ -298,48 +300,49 @@ static void prepare_context(struct cgit_context *ctx)
298 ctx->cfg.cache_repo_ttl = 5; 300 ctx->cfg.cache_repo_ttl = 5;
299 ctx->cfg.cache_root = CGIT_CACHE_ROOT; 301 ctx->cfg.cache_root = CGIT_CACHE_ROOT;
300 ctx->cfg.cache_root_ttl = 5; 302 ctx->cfg.cache_root_ttl = 5;
301 ctx->cfg.cache_scanrc_ttl = 15; 303 ctx->cfg.cache_scanrc_ttl = 15;
302 ctx->cfg.cache_static_ttl = -1; 304 ctx->cfg.cache_static_ttl = -1;
303 ctx->cfg.css = "/cgit.css"; 305 ctx->cfg.css = "/cgit.css";
304 ctx->cfg.logo = "/cgit.png"; 306 ctx->cfg.logo = "/cgit.png";
305 ctx->cfg.local_time = 0; 307 ctx->cfg.local_time = 0;
306 ctx->cfg.enable_gitweb_owner = 1; 308 ctx->cfg.enable_gitweb_owner = 1;
307 ctx->cfg.enable_tree_linenumbers = 1; 309 ctx->cfg.enable_tree_linenumbers = 1;
308 ctx->cfg.max_repo_count = 50; 310 ctx->cfg.max_repo_count = 50;
309 ctx->cfg.max_commit_count = 50; 311 ctx->cfg.max_commit_count = 50;
310 ctx->cfg.max_lock_attempts = 5; 312 ctx->cfg.max_lock_attempts = 5;
311 ctx->cfg.max_msg_len = 80; 313 ctx->cfg.max_msg_len = 80;
312 ctx->cfg.max_repodesc_len = 80; 314 ctx->cfg.max_repodesc_len = 80;
313 ctx->cfg.max_blob_size = 0; 315 ctx->cfg.max_blob_size = 0;
314 ctx->cfg.max_stats = 0; 316 ctx->cfg.max_stats = 0;
315 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; 317 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s";
316 ctx->cfg.project_list = NULL; 318 ctx->cfg.project_list = NULL;
317 ctx->cfg.renamelimit = -1; 319 ctx->cfg.renamelimit = -1;
318 ctx->cfg.remove_suffix = 0; 320 ctx->cfg.remove_suffix = 0;
319 ctx->cfg.robots = "index, nofollow"; 321 ctx->cfg.robots = "index, nofollow";
320 ctx->cfg.root_title = "Git repository browser"; 322 ctx->cfg.root_title = "Git repository browser";
321 ctx->cfg.root_desc = "a fast webinterface for the git dscm"; 323 ctx->cfg.root_desc = "a fast webinterface for the git dscm";
324 ctx->cfg.scan_hidden_path = 0;
322 ctx->cfg.script_name = CGIT_SCRIPT_NAME; 325 ctx->cfg.script_name = CGIT_SCRIPT_NAME;
323 ctx->cfg.section = ""; 326 ctx->cfg.section = "";
324 ctx->cfg.summary_branches = 10; 327 ctx->cfg.summary_branches = 10;
325 ctx->cfg.summary_log = 10; 328 ctx->cfg.summary_log = 10;
326 ctx->cfg.summary_tags = 10; 329 ctx->cfg.summary_tags = 10;
327 ctx->cfg.max_atom_items = 10; 330 ctx->cfg.max_atom_items = 10;
328 ctx->cfg.ssdiff = 0; 331 ctx->cfg.ssdiff = 0;
329 ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG")); 332 ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG"));
330 ctx->env.http_host = xstrdupn(getenv("HTTP_HOST")); 333 ctx->env.http_host = xstrdupn(getenv("HTTP_HOST"));
331 ctx->env.https = xstrdupn(getenv("HTTPS")); 334 ctx->env.https = xstrdupn(getenv("HTTPS"));
332 ctx->env.no_http = xstrdupn(getenv("NO_HTTP")); 335 ctx->env.no_http = xstrdupn(getenv("NO_HTTP"));
333 ctx->env.path_info = xstrdupn(getenv("PATH_INFO")); 336 ctx->env.path_info = xstrdupn(getenv("PATH_INFO"));
334 ctx->env.query_string = xstrdupn(getenv("QUERY_STRING")); 337 ctx->env.query_string = xstrdupn(getenv("QUERY_STRING"));
335 ctx->env.request_method = xstrdupn(getenv("REQUEST_METHOD")); 338 ctx->env.request_method = xstrdupn(getenv("REQUEST_METHOD"));
336 ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME")); 339 ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME"));
337 ctx->env.server_name = xstrdupn(getenv("SERVER_NAME")); 340 ctx->env.server_name = xstrdupn(getenv("SERVER_NAME"));
338 ctx->env.server_port = xstrdupn(getenv("SERVER_PORT")); 341 ctx->env.server_port = xstrdupn(getenv("SERVER_PORT"));
339 ctx->page.mimetype = "text/html"; 342 ctx->page.mimetype = "text/html";
340 ctx->page.charset = PAGE_ENCODING; 343 ctx->page.charset = PAGE_ENCODING;
341 ctx->page.filename = NULL; 344 ctx->page.filename = NULL;
342 ctx->page.size = 0; 345 ctx->page.size = 0;
343 ctx->page.modified = time(NULL); 346 ctx->page.modified = time(NULL);
344 ctx->page.expires = ctx->page.modified; 347 ctx->page.expires = ctx->page.modified;
345 ctx->page.etag = NULL; 348 ctx->page.etag = NULL;
diff --git a/cgit.h b/cgit.h
index bed770b..74aa340 100644
--- a/cgit.h
+++ b/cgit.h
@@ -189,48 +189,49 @@ struct cgit_config {
189 int embedded; 189 int embedded;
190 int enable_filter_overrides; 190 int enable_filter_overrides;
191 int enable_gitweb_owner; 191 int enable_gitweb_owner;
192 int enable_index_links; 192 int enable_index_links;
193 int enable_commit_graph; 193 int enable_commit_graph;
194 int enable_log_filecount; 194 int enable_log_filecount;
195 int enable_log_linecount; 195 int enable_log_linecount;
196 int enable_remote_branches; 196 int enable_remote_branches;
197 int enable_subject_links; 197 int enable_subject_links;
198 int enable_tree_linenumbers; 198 int enable_tree_linenumbers;
199 int local_time; 199 int local_time;
200 int max_atom_items; 200 int max_atom_items;
201 int max_repo_count; 201 int max_repo_count;
202 int max_commit_count; 202 int max_commit_count;
203 int max_lock_attempts; 203 int max_lock_attempts;
204 int max_msg_len; 204 int max_msg_len;
205 int max_repodesc_len; 205 int max_repodesc_len;
206 int max_blob_size; 206 int max_blob_size;
207 int max_stats; 207 int max_stats;
208 int nocache; 208 int nocache;
209 int noplainemail; 209 int noplainemail;
210 int noheader; 210 int noheader;
211 int renamelimit; 211 int renamelimit;
212 int remove_suffix; 212 int remove_suffix;
213 int scan_hidden_path;
213 int section_from_path; 214 int section_from_path;
214 int snapshots; 215 int snapshots;
215 int summary_branches; 216 int summary_branches;
216 int summary_log; 217 int summary_log;
217 int summary_tags; 218 int summary_tags;
218 int ssdiff; 219 int ssdiff;
219 struct string_list mimetypes; 220 struct string_list mimetypes;
220 struct cgit_filter *about_filter; 221 struct cgit_filter *about_filter;
221 struct cgit_filter *commit_filter; 222 struct cgit_filter *commit_filter;
222 struct cgit_filter *source_filter; 223 struct cgit_filter *source_filter;
223}; 224};
224 225
225struct cgit_page { 226struct cgit_page {
226 time_t modified; 227 time_t modified;
227 time_t expires; 228 time_t expires;
228 size_t size; 229 size_t size;
229 char *mimetype; 230 char *mimetype;
230 char *charset; 231 char *charset;
231 char *filename; 232 char *filename;
232 char *etag; 233 char *etag;
233 char *title; 234 char *title;
234 int status; 235 int status;
235 char *statusmsg; 236 char *statusmsg;
236}; 237};
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index 3c20fe1..a832830 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -253,48 +253,56 @@ renamelimit::
253 "-1" uses the compiletime value in git (for further info, look at 253 "-1" uses the compiletime value in git (for further info, look at
254 `man git-diff`). Default value: "-1". 254 `man git-diff`). Default value: "-1".
255 255
256repo.group:: 256repo.group::
257 Legacy alias for "section". This option is deprecated and will not be 257 Legacy alias for "section". This option is deprecated and will not be
258 supported in cgit-1.0. 258 supported in cgit-1.0.
259 259
260robots:: 260robots::
261 Text used as content for the "robots" meta-tag. Default value: 261 Text used as content for the "robots" meta-tag. Default value:
262 "index, nofollow". 262 "index, nofollow".
263 263
264root-desc:: 264root-desc::
265 Text printed below the heading on the repository index page. Default 265 Text printed below the heading on the repository index page. Default
266 value: "a fast webinterface for the git dscm". 266 value: "a fast webinterface for the git dscm".
267 267
268root-readme:: 268root-readme::
269 The content of the file specified with this option will be included 269 The content of the file specified with this option will be included
270 verbatim below the "about" link on the repository index page. Default 270 verbatim below the "about" link on the repository index page. Default
271 value: none. 271 value: none.
272 272
273root-title:: 273root-title::
274 Text printed as heading on the repository index page. Default value: 274 Text printed as heading on the repository index page. Default value:
275 "Git Repository Browser". 275 "Git Repository Browser".
276 276
277scan-hidden-path::
278 If set to "1" and scan-path is enabled, scan-path will recurse into
279 directories whose name starts with a period ('.'). Otherwise,
280 scan-path will stay away from such directories (considered as
281 "hidden"). Note that this does not apply to the ".git" directory in
282 non-bare repos. This must be defined prior to scan-path.
283 Default value: 0. See also: scan-path.
284
277scan-path:: 285scan-path::
278 A path which will be scanned for repositories. If caching is enabled, 286 A path which will be scanned for repositories. If caching is enabled,
279 the result will be cached as a cgitrc include-file in the cache 287 the result will be cached as a cgitrc include-file in the cache
280 directory. If project-list has been defined prior to scan-path, 288 directory. If project-list has been defined prior to scan-path,
281 scan-path loads only the directories listed in the file pointed to by 289 scan-path loads only the directories listed in the file pointed to by
282 project-list. Default value: none. See also: cache-scanrc-ttl, 290 project-list. Default value: none. See also: cache-scanrc-ttl,
283 project-list. 291 project-list.
284 292
285section:: 293section::
286 The name of the current repository section - all repositories defined 294 The name of the current repository section - all repositories defined
287 after this option will inherit the current section name. Default value: 295 after this option will inherit the current section name. Default value:
288 none. 296 none.
289 297
290section-from-path:: 298section-from-path::
291 A number which, if specified before scan-path, specifies how many 299 A number which, if specified before scan-path, specifies how many
292 path elements from each repo path to use as a default section name. 300 path elements from each repo path to use as a default section name.
293 If negative, cgit will discard the specified number of path elements 301 If negative, cgit will discard the specified number of path elements
294 above the repo directory. Default value: 0. 302 above the repo directory. Default value: 0.
295 303
296side-by-side-diffs:: 304side-by-side-diffs::
297 If set to "1" shows side-by-side diffs instead of unidiffs per 305 If set to "1" shows side-by-side diffs instead of unidiffs per
298 default. Default value: "0". 306 default. Default value: "0".
299 307
300snapshots:: 308snapshots::
diff --git a/scan-tree.c b/scan-tree.c
index a0e09ce..627af1b 100644
--- a/scan-tree.c
+++ b/scan-tree.c
@@ -138,91 +138,93 @@ static void add_repo(const char *base, const char *path, repo_config_fn fn)
138 while (slash && n && (slash = xstrrchr(rel, slash, '/'))) 138 while (slash && n && (slash = xstrrchr(rel, slash, '/')))
139 n++; 139 n++;
140 } 140 }
141 if (slash && !n) { 141 if (slash && !n) {
142 *slash = '\0'; 142 *slash = '\0';
143 repo->section = xstrdup(rel); 143 repo->section = xstrdup(rel);
144 *slash = '/'; 144 *slash = '/';
145 if (!prefixcmp(repo->name, repo->section)) { 145 if (!prefixcmp(repo->name, repo->section)) {
146 repo->name += strlen(repo->section); 146 repo->name += strlen(repo->section);
147 if (*repo->name == '/') 147 if (*repo->name == '/')
148 repo->name++; 148 repo->name++;
149 } 149 }
150 } 150 }
151 } 151 }
152 152
153 p = fmt("%s/cgitrc", path); 153 p = fmt("%s/cgitrc", path);
154 if (!stat(p, &st)) { 154 if (!stat(p, &st)) {
155 config_fn = fn; 155 config_fn = fn;
156 parse_configfile(xstrdup(p), &repo_config); 156 parse_configfile(xstrdup(p), &repo_config);
157 } 157 }
158} 158}
159 159
160static void scan_path(const char *base, const char *path, repo_config_fn fn) 160static void scan_path(const char *base, const char *path, repo_config_fn fn)
161{ 161{
162 DIR *dir; 162 DIR *dir = opendir(path);
163 struct dirent *ent; 163 struct dirent *ent;
164 char *buf; 164 char *buf;
165 struct stat st; 165 struct stat st;
166 166
167 if (!dir) {
168 fprintf(stderr, "Error opening directory %s: %s (%d)\n",
169 path, strerror(errno), errno);
170 return;
171 }
167 if (is_git_dir(path)) { 172 if (is_git_dir(path)) {
168 add_repo(base, path, fn); 173 add_repo(base, path, fn);
169 return; 174 goto end;
170 } 175 }
171 if (is_git_dir(fmt("%s/.git", path))) { 176 if (is_git_dir(fmt("%s/.git", path))) {
172 add_repo(base, fmt("%s/.git", path), fn); 177 add_repo(base, fmt("%s/.git", path), fn);
173 return; 178 goto end;
174 }
175 dir = opendir(path);
176 if (!dir) {
177 fprintf(stderr, "Error opening directory %s: %s (%d)\n",
178 path, strerror(errno), errno);
179 return;
180 } 179 }
181 while((ent = readdir(dir)) != NULL) { 180 while((ent = readdir(dir)) != NULL) {
182 if (ent->d_name[0] == '.') { 181 if (ent->d_name[0] == '.') {
183 if (ent->d_name[1] == '\0') 182 if (ent->d_name[1] == '\0')
184 continue; 183 continue;
185 if (ent->d_name[1] == '.' && ent->d_name[2] == '\0') 184 if (ent->d_name[1] == '.' && ent->d_name[2] == '\0')
186 continue; 185 continue;
186 if (!ctx.cfg.scan_hidden_path)
187 continue;
187 } 188 }
188 buf = malloc(strlen(path) + strlen(ent->d_name) + 2); 189 buf = malloc(strlen(path) + strlen(ent->d_name) + 2);
189 if (!buf) { 190 if (!buf) {
190 fprintf(stderr, "Alloc error on %s: %s (%d)\n", 191 fprintf(stderr, "Alloc error on %s: %s (%d)\n",
191 path, strerror(errno), errno); 192 path, strerror(errno), errno);
192 exit(1); 193 exit(1);
193 } 194 }
194 sprintf(buf, "%s/%s", path, ent->d_name); 195 sprintf(buf, "%s/%s", path, ent->d_name);
195 if (stat(buf, &st)) { 196 if (stat(buf, &st)) {
196 fprintf(stderr, "Error checking path %s: %s (%d)\n", 197 fprintf(stderr, "Error checking path %s: %s (%d)\n",
197 buf, strerror(errno), errno); 198 buf, strerror(errno), errno);
198 free(buf); 199 free(buf);
199 continue; 200 continue;
200 } 201 }
201 if (S_ISDIR(st.st_mode)) 202 if (S_ISDIR(st.st_mode))
202 scan_path(base, buf, fn); 203 scan_path(base, buf, fn);
203 free(buf); 204 free(buf);
204 } 205 }
206end:
205 closedir(dir); 207 closedir(dir);
206} 208}
207 209
208#define lastc(s) s[strlen(s) - 1] 210#define lastc(s) s[strlen(s) - 1]
209 211
210void scan_projects(const char *path, const char *projectsfile, repo_config_fn fn) 212void scan_projects(const char *path, const char *projectsfile, repo_config_fn fn)
211{ 213{
212 char line[MAX_PATH * 2], *z; 214 char line[MAX_PATH * 2], *z;
213 FILE *projects; 215 FILE *projects;
214 int err; 216 int err;
215 217
216 projects = fopen(projectsfile, "r"); 218 projects = fopen(projectsfile, "r");
217 if (!projects) { 219 if (!projects) {
218 fprintf(stderr, "Error opening projectsfile %s: %s (%d)\n", 220 fprintf(stderr, "Error opening projectsfile %s: %s (%d)\n",
219 projectsfile, strerror(errno), errno); 221 projectsfile, strerror(errno), errno);
220 } 222 }
221 while (fgets(line, sizeof(line), projects) != NULL) { 223 while (fgets(line, sizeof(line), projects) != NULL) {
222 for (z = &lastc(line); 224 for (z = &lastc(line);
223 strlen(line) && strchr("\n\r", *z); 225 strlen(line) && strchr("\n\r", *z);
224 z = &lastc(line)) 226 z = &lastc(line))
225 *z = '\0'; 227 *z = '\0';
226 if (strlen(line)) 228 if (strlen(line))
227 scan_path(path, fmt("%s/%s", path, line), fn); 229 scan_path(path, fmt("%s/%s", path, line), fn);
228 } 230 }