author | Johan Herland <johan@herland.net> | 2010-06-09 23:09:26 (UTC) |
---|---|---|
committer | Lars Hjemli <hjemli@gmail.com> | 2010-06-19 08:40:22 (UTC) |
commit | 0ff143df7043b7dd87c31c50fa875bc96d1a7779 (patch) (unidiff) | |
tree | d1625ba2aafed1ddfebc429921abdbb0d692042f /cgit.c | |
parent | 0e34c6d1ef32ea8f69019272fe72dbf2aeaba392 (diff) | |
download | cgit-0ff143df7043b7dd87c31c50fa875bc96d1a7779.zip cgit-0ff143df7043b7dd87c31c50fa875bc96d1a7779.tar.gz cgit-0ff143df7043b7dd87c31c50fa875bc96d1a7779.tar.bz2 |
struct cgit_cmd: Differentiate between various usages of ctx.qry.path
For many commands/pages (e.g. 'tree', 'diff', 'plain', etc.), the
ctx.qry.path argument is interpreted as a path within the "virtual" project
directory structure. However, for some other commands (notably 'refs', and
the clone-related commands) ctx.qry.path is used in a different context (as
a more or less "real" path within the '.git' directory).
This patch differentiates between these two usages of ctx.qry.path, by
introducing a new variable - ctx.qry.vpath - which is equal to ctx.qry.path
in the former case, and NULL in the latter.
This will become useful in future patches when we want various pages and the
links between them to preserve existing in-project paths.
Signed-off-by: Johan Herland <johan@herland.net>
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
-rw-r--r-- | cgit.c | 6 |
1 files changed, 6 insertions, 0 deletions
@@ -235,384 +235,390 @@ static void querystring_cb(const char *name, const char *value) | |||
235 | ctx.qry.sha2 = xstrdup(value); | 235 | ctx.qry.sha2 = xstrdup(value); |
236 | ctx.qry.has_sha1 = 1; | 236 | ctx.qry.has_sha1 = 1; |
237 | } else if (!strcmp(name, "ofs")) { | 237 | } else if (!strcmp(name, "ofs")) { |
238 | ctx.qry.ofs = atoi(value); | 238 | ctx.qry.ofs = atoi(value); |
239 | } else if (!strcmp(name, "path")) { | 239 | } else if (!strcmp(name, "path")) { |
240 | ctx.qry.path = trim_end(value, '/'); | 240 | ctx.qry.path = trim_end(value, '/'); |
241 | } else if (!strcmp(name, "name")) { | 241 | } else if (!strcmp(name, "name")) { |
242 | ctx.qry.name = xstrdup(value); | 242 | ctx.qry.name = xstrdup(value); |
243 | } else if (!strcmp(name, "mimetype")) { | 243 | } else if (!strcmp(name, "mimetype")) { |
244 | ctx.qry.mimetype = xstrdup(value); | 244 | ctx.qry.mimetype = xstrdup(value); |
245 | } else if (!strcmp(name, "s")){ | 245 | } else if (!strcmp(name, "s")){ |
246 | ctx.qry.sort = xstrdup(value); | 246 | ctx.qry.sort = xstrdup(value); |
247 | } else if (!strcmp(name, "showmsg")) { | 247 | } else if (!strcmp(name, "showmsg")) { |
248 | ctx.qry.showmsg = atoi(value); | 248 | ctx.qry.showmsg = atoi(value); |
249 | } else if (!strcmp(name, "period")) { | 249 | } else if (!strcmp(name, "period")) { |
250 | ctx.qry.period = xstrdup(value); | 250 | ctx.qry.period = xstrdup(value); |
251 | } else if (!strcmp(name, "ss")) { | 251 | } else if (!strcmp(name, "ss")) { |
252 | ctx.qry.ssdiff = atoi(value); | 252 | ctx.qry.ssdiff = atoi(value); |
253 | } | 253 | } |
254 | } | 254 | } |
255 | 255 | ||
256 | char *xstrdupn(const char *str) | 256 | char *xstrdupn(const char *str) |
257 | { | 257 | { |
258 | return (str ? xstrdup(str) : NULL); | 258 | return (str ? xstrdup(str) : NULL); |
259 | } | 259 | } |
260 | 260 | ||
261 | static void prepare_context(struct cgit_context *ctx) | 261 | static void prepare_context(struct cgit_context *ctx) |
262 | { | 262 | { |
263 | memset(ctx, 0, sizeof(*ctx)); | 263 | memset(ctx, 0, sizeof(*ctx)); |
264 | ctx->cfg.agefile = "info/web/last-modified"; | 264 | ctx->cfg.agefile = "info/web/last-modified"; |
265 | ctx->cfg.nocache = 0; | 265 | ctx->cfg.nocache = 0; |
266 | ctx->cfg.cache_size = 0; | 266 | ctx->cfg.cache_size = 0; |
267 | ctx->cfg.cache_dynamic_ttl = 5; | 267 | ctx->cfg.cache_dynamic_ttl = 5; |
268 | ctx->cfg.cache_max_create_time = 5; | 268 | ctx->cfg.cache_max_create_time = 5; |
269 | ctx->cfg.cache_repo_ttl = 5; | 269 | ctx->cfg.cache_repo_ttl = 5; |
270 | ctx->cfg.cache_root = CGIT_CACHE_ROOT; | 270 | ctx->cfg.cache_root = CGIT_CACHE_ROOT; |
271 | ctx->cfg.cache_root_ttl = 5; | 271 | ctx->cfg.cache_root_ttl = 5; |
272 | ctx->cfg.cache_scanrc_ttl = 15; | 272 | ctx->cfg.cache_scanrc_ttl = 15; |
273 | ctx->cfg.cache_static_ttl = -1; | 273 | ctx->cfg.cache_static_ttl = -1; |
274 | ctx->cfg.css = "/cgit.css"; | 274 | ctx->cfg.css = "/cgit.css"; |
275 | ctx->cfg.logo = "/cgit.png"; | 275 | ctx->cfg.logo = "/cgit.png"; |
276 | ctx->cfg.local_time = 0; | 276 | ctx->cfg.local_time = 0; |
277 | ctx->cfg.enable_tree_linenumbers = 1; | 277 | ctx->cfg.enable_tree_linenumbers = 1; |
278 | ctx->cfg.max_repo_count = 50; | 278 | ctx->cfg.max_repo_count = 50; |
279 | ctx->cfg.max_commit_count = 50; | 279 | ctx->cfg.max_commit_count = 50; |
280 | ctx->cfg.max_lock_attempts = 5; | 280 | ctx->cfg.max_lock_attempts = 5; |
281 | ctx->cfg.max_msg_len = 80; | 281 | ctx->cfg.max_msg_len = 80; |
282 | ctx->cfg.max_repodesc_len = 80; | 282 | ctx->cfg.max_repodesc_len = 80; |
283 | ctx->cfg.max_blob_size = 0; | 283 | ctx->cfg.max_blob_size = 0; |
284 | ctx->cfg.max_stats = 0; | 284 | ctx->cfg.max_stats = 0; |
285 | ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; | 285 | ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; |
286 | ctx->cfg.renamelimit = -1; | 286 | ctx->cfg.renamelimit = -1; |
287 | ctx->cfg.robots = "index, nofollow"; | 287 | ctx->cfg.robots = "index, nofollow"; |
288 | ctx->cfg.root_title = "Git repository browser"; | 288 | ctx->cfg.root_title = "Git repository browser"; |
289 | ctx->cfg.root_desc = "a fast webinterface for the git dscm"; | 289 | ctx->cfg.root_desc = "a fast webinterface for the git dscm"; |
290 | ctx->cfg.script_name = CGIT_SCRIPT_NAME; | 290 | ctx->cfg.script_name = CGIT_SCRIPT_NAME; |
291 | ctx->cfg.section = ""; | 291 | ctx->cfg.section = ""; |
292 | ctx->cfg.summary_branches = 10; | 292 | ctx->cfg.summary_branches = 10; |
293 | ctx->cfg.summary_log = 10; | 293 | ctx->cfg.summary_log = 10; |
294 | ctx->cfg.summary_tags = 10; | 294 | ctx->cfg.summary_tags = 10; |
295 | ctx->cfg.ssdiff = 0; | 295 | ctx->cfg.ssdiff = 0; |
296 | ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG")); | 296 | ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG")); |
297 | ctx->env.http_host = xstrdupn(getenv("HTTP_HOST")); | 297 | ctx->env.http_host = xstrdupn(getenv("HTTP_HOST")); |
298 | ctx->env.https = xstrdupn(getenv("HTTPS")); | 298 | ctx->env.https = xstrdupn(getenv("HTTPS")); |
299 | ctx->env.no_http = xstrdupn(getenv("NO_HTTP")); | 299 | ctx->env.no_http = xstrdupn(getenv("NO_HTTP")); |
300 | ctx->env.path_info = xstrdupn(getenv("PATH_INFO")); | 300 | ctx->env.path_info = xstrdupn(getenv("PATH_INFO")); |
301 | ctx->env.query_string = xstrdupn(getenv("QUERY_STRING")); | 301 | ctx->env.query_string = xstrdupn(getenv("QUERY_STRING")); |
302 | ctx->env.request_method = xstrdupn(getenv("REQUEST_METHOD")); | 302 | ctx->env.request_method = xstrdupn(getenv("REQUEST_METHOD")); |
303 | ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME")); | 303 | ctx->env.script_name = xstrdupn(getenv("SCRIPT_NAME")); |
304 | ctx->env.server_name = xstrdupn(getenv("SERVER_NAME")); | 304 | ctx->env.server_name = xstrdupn(getenv("SERVER_NAME")); |
305 | ctx->env.server_port = xstrdupn(getenv("SERVER_PORT")); | 305 | ctx->env.server_port = xstrdupn(getenv("SERVER_PORT")); |
306 | ctx->page.mimetype = "text/html"; | 306 | ctx->page.mimetype = "text/html"; |
307 | ctx->page.charset = PAGE_ENCODING; | 307 | ctx->page.charset = PAGE_ENCODING; |
308 | ctx->page.filename = NULL; | 308 | ctx->page.filename = NULL; |
309 | ctx->page.size = 0; | 309 | ctx->page.size = 0; |
310 | ctx->page.modified = time(NULL); | 310 | ctx->page.modified = time(NULL); |
311 | ctx->page.expires = ctx->page.modified; | 311 | ctx->page.expires = ctx->page.modified; |
312 | ctx->page.etag = NULL; | 312 | ctx->page.etag = NULL; |
313 | memset(&ctx->cfg.mimetypes, 0, sizeof(struct string_list)); | 313 | memset(&ctx->cfg.mimetypes, 0, sizeof(struct string_list)); |
314 | if (ctx->env.script_name) | 314 | if (ctx->env.script_name) |
315 | ctx->cfg.script_name = ctx->env.script_name; | 315 | ctx->cfg.script_name = ctx->env.script_name; |
316 | if (ctx->env.query_string) | 316 | if (ctx->env.query_string) |
317 | ctx->qry.raw = ctx->env.query_string; | 317 | ctx->qry.raw = ctx->env.query_string; |
318 | if (!ctx->env.cgit_config) | 318 | if (!ctx->env.cgit_config) |
319 | ctx->env.cgit_config = CGIT_CONFIG; | 319 | ctx->env.cgit_config = CGIT_CONFIG; |
320 | } | 320 | } |
321 | 321 | ||
322 | struct refmatch { | 322 | struct refmatch { |
323 | char *req_ref; | 323 | char *req_ref; |
324 | char *first_ref; | 324 | char *first_ref; |
325 | int match; | 325 | int match; |
326 | }; | 326 | }; |
327 | 327 | ||
328 | int find_current_ref(const char *refname, const unsigned char *sha1, | 328 | int find_current_ref(const char *refname, const unsigned char *sha1, |
329 | int flags, void *cb_data) | 329 | int flags, void *cb_data) |
330 | { | 330 | { |
331 | struct refmatch *info; | 331 | struct refmatch *info; |
332 | 332 | ||
333 | info = (struct refmatch *)cb_data; | 333 | info = (struct refmatch *)cb_data; |
334 | if (!strcmp(refname, info->req_ref)) | 334 | if (!strcmp(refname, info->req_ref)) |
335 | info->match = 1; | 335 | info->match = 1; |
336 | if (!info->first_ref) | 336 | if (!info->first_ref) |
337 | info->first_ref = xstrdup(refname); | 337 | info->first_ref = xstrdup(refname); |
338 | return info->match; | 338 | return info->match; |
339 | } | 339 | } |
340 | 340 | ||
341 | char *find_default_branch(struct cgit_repo *repo) | 341 | char *find_default_branch(struct cgit_repo *repo) |
342 | { | 342 | { |
343 | struct refmatch info; | 343 | struct refmatch info; |
344 | char *ref; | 344 | char *ref; |
345 | 345 | ||
346 | info.req_ref = repo->defbranch; | 346 | info.req_ref = repo->defbranch; |
347 | info.first_ref = NULL; | 347 | info.first_ref = NULL; |
348 | info.match = 0; | 348 | info.match = 0; |
349 | for_each_branch_ref(find_current_ref, &info); | 349 | for_each_branch_ref(find_current_ref, &info); |
350 | if (info.match) | 350 | if (info.match) |
351 | ref = info.req_ref; | 351 | ref = info.req_ref; |
352 | else | 352 | else |
353 | ref = info.first_ref; | 353 | ref = info.first_ref; |
354 | if (ref) | 354 | if (ref) |
355 | ref = xstrdup(ref); | 355 | ref = xstrdup(ref); |
356 | return ref; | 356 | return ref; |
357 | } | 357 | } |
358 | 358 | ||
359 | static int prepare_repo_cmd(struct cgit_context *ctx) | 359 | static int prepare_repo_cmd(struct cgit_context *ctx) |
360 | { | 360 | { |
361 | char *tmp; | 361 | char *tmp; |
362 | unsigned char sha1[20]; | 362 | unsigned char sha1[20]; |
363 | int nongit = 0; | 363 | int nongit = 0; |
364 | 364 | ||
365 | setenv("GIT_DIR", ctx->repo->path, 1); | 365 | setenv("GIT_DIR", ctx->repo->path, 1); |
366 | setup_git_directory_gently(&nongit); | 366 | setup_git_directory_gently(&nongit); |
367 | if (nongit) { | 367 | if (nongit) { |
368 | ctx->page.title = fmt("%s - %s", ctx->cfg.root_title, | 368 | ctx->page.title = fmt("%s - %s", ctx->cfg.root_title, |
369 | "config error"); | 369 | "config error"); |
370 | tmp = fmt("Not a git repository: '%s'", ctx->repo->path); | 370 | tmp = fmt("Not a git repository: '%s'", ctx->repo->path); |
371 | ctx->repo = NULL; | 371 | ctx->repo = NULL; |
372 | cgit_print_http_headers(ctx); | 372 | cgit_print_http_headers(ctx); |
373 | cgit_print_docstart(ctx); | 373 | cgit_print_docstart(ctx); |
374 | cgit_print_pageheader(ctx); | 374 | cgit_print_pageheader(ctx); |
375 | cgit_print_error(tmp); | 375 | cgit_print_error(tmp); |
376 | cgit_print_docend(); | 376 | cgit_print_docend(); |
377 | return 1; | 377 | return 1; |
378 | } | 378 | } |
379 | ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc); | 379 | ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc); |
380 | 380 | ||
381 | if (!ctx->qry.head) { | 381 | if (!ctx->qry.head) { |
382 | ctx->qry.nohead = 1; | 382 | ctx->qry.nohead = 1; |
383 | ctx->qry.head = find_default_branch(ctx->repo); | 383 | ctx->qry.head = find_default_branch(ctx->repo); |
384 | ctx->repo->defbranch = ctx->qry.head; | 384 | ctx->repo->defbranch = ctx->qry.head; |
385 | } | 385 | } |
386 | 386 | ||
387 | if (!ctx->qry.head) { | 387 | if (!ctx->qry.head) { |
388 | cgit_print_http_headers(ctx); | 388 | cgit_print_http_headers(ctx); |
389 | cgit_print_docstart(ctx); | 389 | cgit_print_docstart(ctx); |
390 | cgit_print_pageheader(ctx); | 390 | cgit_print_pageheader(ctx); |
391 | cgit_print_error("Repository seems to be empty"); | 391 | cgit_print_error("Repository seems to be empty"); |
392 | cgit_print_docend(); | 392 | cgit_print_docend(); |
393 | return 1; | 393 | return 1; |
394 | } | 394 | } |
395 | 395 | ||
396 | if (get_sha1(ctx->qry.head, sha1)) { | 396 | if (get_sha1(ctx->qry.head, sha1)) { |
397 | tmp = xstrdup(ctx->qry.head); | 397 | tmp = xstrdup(ctx->qry.head); |
398 | ctx->qry.head = ctx->repo->defbranch; | 398 | ctx->qry.head = ctx->repo->defbranch; |
399 | ctx->page.status = 404; | 399 | ctx->page.status = 404; |
400 | ctx->page.statusmsg = "not found"; | 400 | ctx->page.statusmsg = "not found"; |
401 | cgit_print_http_headers(ctx); | 401 | cgit_print_http_headers(ctx); |
402 | cgit_print_docstart(ctx); | 402 | cgit_print_docstart(ctx); |
403 | cgit_print_pageheader(ctx); | 403 | cgit_print_pageheader(ctx); |
404 | cgit_print_error(fmt("Invalid branch: %s", tmp)); | 404 | cgit_print_error(fmt("Invalid branch: %s", tmp)); |
405 | cgit_print_docend(); | 405 | cgit_print_docend(); |
406 | return 1; | 406 | return 1; |
407 | } | 407 | } |
408 | return 0; | 408 | return 0; |
409 | } | 409 | } |
410 | 410 | ||
411 | static void process_request(void *cbdata) | 411 | static void process_request(void *cbdata) |
412 | { | 412 | { |
413 | struct cgit_context *ctx = cbdata; | 413 | struct cgit_context *ctx = cbdata; |
414 | struct cgit_cmd *cmd; | 414 | struct cgit_cmd *cmd; |
415 | 415 | ||
416 | cmd = cgit_get_cmd(ctx); | 416 | cmd = cgit_get_cmd(ctx); |
417 | if (!cmd) { | 417 | if (!cmd) { |
418 | ctx->page.title = "cgit error"; | 418 | ctx->page.title = "cgit error"; |
419 | cgit_print_http_headers(ctx); | 419 | cgit_print_http_headers(ctx); |
420 | cgit_print_docstart(ctx); | 420 | cgit_print_docstart(ctx); |
421 | cgit_print_pageheader(ctx); | 421 | cgit_print_pageheader(ctx); |
422 | cgit_print_error("Invalid request"); | 422 | cgit_print_error("Invalid request"); |
423 | cgit_print_docend(); | 423 | cgit_print_docend(); |
424 | return; | 424 | return; |
425 | } | 425 | } |
426 | 426 | ||
427 | /* If cmd->want_vpath is set, assume ctx->qry.path contains a "virtual" | ||
428 | * in-project path limit to be made available at ctx->qry.vpath. | ||
429 | * Otherwise, no path limit is in effect (ctx->qry.vpath = NULL). | ||
430 | */ | ||
431 | ctx->qry.vpath = cmd->want_vpath ? ctx->qry.path : NULL; | ||
432 | |||
427 | if (cmd->want_repo && !ctx->repo) { | 433 | if (cmd->want_repo && !ctx->repo) { |
428 | cgit_print_http_headers(ctx); | 434 | cgit_print_http_headers(ctx); |
429 | cgit_print_docstart(ctx); | 435 | cgit_print_docstart(ctx); |
430 | cgit_print_pageheader(ctx); | 436 | cgit_print_pageheader(ctx); |
431 | cgit_print_error(fmt("No repository selected")); | 437 | cgit_print_error(fmt("No repository selected")); |
432 | cgit_print_docend(); | 438 | cgit_print_docend(); |
433 | return; | 439 | return; |
434 | } | 440 | } |
435 | 441 | ||
436 | if (ctx->repo && prepare_repo_cmd(ctx)) | 442 | if (ctx->repo && prepare_repo_cmd(ctx)) |
437 | return; | 443 | return; |
438 | 444 | ||
439 | if (cmd->want_layout) { | 445 | if (cmd->want_layout) { |
440 | cgit_print_http_headers(ctx); | 446 | cgit_print_http_headers(ctx); |
441 | cgit_print_docstart(ctx); | 447 | cgit_print_docstart(ctx); |
442 | cgit_print_pageheader(ctx); | 448 | cgit_print_pageheader(ctx); |
443 | } | 449 | } |
444 | 450 | ||
445 | cmd->fn(ctx); | 451 | cmd->fn(ctx); |
446 | 452 | ||
447 | if (cmd->want_layout) | 453 | if (cmd->want_layout) |
448 | cgit_print_docend(); | 454 | cgit_print_docend(); |
449 | } | 455 | } |
450 | 456 | ||
451 | int cmp_repos(const void *a, const void *b) | 457 | int cmp_repos(const void *a, const void *b) |
452 | { | 458 | { |
453 | const struct cgit_repo *ra = a, *rb = b; | 459 | const struct cgit_repo *ra = a, *rb = b; |
454 | return strcmp(ra->url, rb->url); | 460 | return strcmp(ra->url, rb->url); |
455 | } | 461 | } |
456 | 462 | ||
457 | char *build_snapshot_setting(int bitmap) | 463 | char *build_snapshot_setting(int bitmap) |
458 | { | 464 | { |
459 | const struct cgit_snapshot_format *f; | 465 | const struct cgit_snapshot_format *f; |
460 | char *result = xstrdup(""); | 466 | char *result = xstrdup(""); |
461 | char *tmp; | 467 | char *tmp; |
462 | int len; | 468 | int len; |
463 | 469 | ||
464 | for (f = cgit_snapshot_formats; f->suffix; f++) { | 470 | for (f = cgit_snapshot_formats; f->suffix; f++) { |
465 | if (f->bit & bitmap) { | 471 | if (f->bit & bitmap) { |
466 | tmp = result; | 472 | tmp = result; |
467 | result = xstrdup(fmt("%s%s ", tmp, f->suffix)); | 473 | result = xstrdup(fmt("%s%s ", tmp, f->suffix)); |
468 | free(tmp); | 474 | free(tmp); |
469 | } | 475 | } |
470 | } | 476 | } |
471 | len = strlen(result); | 477 | len = strlen(result); |
472 | if (len) | 478 | if (len) |
473 | result[len - 1] = '\0'; | 479 | result[len - 1] = '\0'; |
474 | return result; | 480 | return result; |
475 | } | 481 | } |
476 | 482 | ||
477 | char *get_first_line(char *txt) | 483 | char *get_first_line(char *txt) |
478 | { | 484 | { |
479 | char *t = xstrdup(txt); | 485 | char *t = xstrdup(txt); |
480 | char *p = strchr(t, '\n'); | 486 | char *p = strchr(t, '\n'); |
481 | if (p) | 487 | if (p) |
482 | *p = '\0'; | 488 | *p = '\0'; |
483 | return t; | 489 | return t; |
484 | } | 490 | } |
485 | 491 | ||
486 | void print_repo(FILE *f, struct cgit_repo *repo) | 492 | void print_repo(FILE *f, struct cgit_repo *repo) |
487 | { | 493 | { |
488 | fprintf(f, "repo.url=%s\n", repo->url); | 494 | fprintf(f, "repo.url=%s\n", repo->url); |
489 | fprintf(f, "repo.name=%s\n", repo->name); | 495 | fprintf(f, "repo.name=%s\n", repo->name); |
490 | fprintf(f, "repo.path=%s\n", repo->path); | 496 | fprintf(f, "repo.path=%s\n", repo->path); |
491 | if (repo->owner) | 497 | if (repo->owner) |
492 | fprintf(f, "repo.owner=%s\n", repo->owner); | 498 | fprintf(f, "repo.owner=%s\n", repo->owner); |
493 | if (repo->desc) { | 499 | if (repo->desc) { |
494 | char *tmp = get_first_line(repo->desc); | 500 | char *tmp = get_first_line(repo->desc); |
495 | fprintf(f, "repo.desc=%s\n", tmp); | 501 | fprintf(f, "repo.desc=%s\n", tmp); |
496 | free(tmp); | 502 | free(tmp); |
497 | } | 503 | } |
498 | if (repo->readme) | 504 | if (repo->readme) |
499 | fprintf(f, "repo.readme=%s\n", repo->readme); | 505 | fprintf(f, "repo.readme=%s\n", repo->readme); |
500 | if (repo->defbranch) | 506 | if (repo->defbranch) |
501 | fprintf(f, "repo.defbranch=%s\n", repo->defbranch); | 507 | fprintf(f, "repo.defbranch=%s\n", repo->defbranch); |
502 | if (repo->module_link) | 508 | if (repo->module_link) |
503 | fprintf(f, "repo.module-link=%s\n", repo->module_link); | 509 | fprintf(f, "repo.module-link=%s\n", repo->module_link); |
504 | if (repo->section) | 510 | if (repo->section) |
505 | fprintf(f, "repo.section=%s\n", repo->section); | 511 | fprintf(f, "repo.section=%s\n", repo->section); |
506 | if (repo->clone_url) | 512 | if (repo->clone_url) |
507 | fprintf(f, "repo.clone-url=%s\n", repo->clone_url); | 513 | fprintf(f, "repo.clone-url=%s\n", repo->clone_url); |
508 | fprintf(f, "repo.enable-log-filecount=%d\n", | 514 | fprintf(f, "repo.enable-log-filecount=%d\n", |
509 | repo->enable_log_filecount); | 515 | repo->enable_log_filecount); |
510 | fprintf(f, "repo.enable-log-linecount=%d\n", | 516 | fprintf(f, "repo.enable-log-linecount=%d\n", |
511 | repo->enable_log_linecount); | 517 | repo->enable_log_linecount); |
512 | if (repo->about_filter && repo->about_filter != ctx.cfg.about_filter) | 518 | if (repo->about_filter && repo->about_filter != ctx.cfg.about_filter) |
513 | fprintf(f, "repo.about-filter=%s\n", repo->about_filter->cmd); | 519 | fprintf(f, "repo.about-filter=%s\n", repo->about_filter->cmd); |
514 | if (repo->commit_filter && repo->commit_filter != ctx.cfg.commit_filter) | 520 | if (repo->commit_filter && repo->commit_filter != ctx.cfg.commit_filter) |
515 | fprintf(f, "repo.commit-filter=%s\n", repo->commit_filter->cmd); | 521 | fprintf(f, "repo.commit-filter=%s\n", repo->commit_filter->cmd); |
516 | if (repo->source_filter && repo->source_filter != ctx.cfg.source_filter) | 522 | if (repo->source_filter && repo->source_filter != ctx.cfg.source_filter) |
517 | fprintf(f, "repo.source-filter=%s\n", repo->source_filter->cmd); | 523 | fprintf(f, "repo.source-filter=%s\n", repo->source_filter->cmd); |
518 | if (repo->snapshots != ctx.cfg.snapshots) { | 524 | if (repo->snapshots != ctx.cfg.snapshots) { |
519 | char *tmp = build_snapshot_setting(repo->snapshots); | 525 | char *tmp = build_snapshot_setting(repo->snapshots); |
520 | fprintf(f, "repo.snapshots=%s\n", tmp); | 526 | fprintf(f, "repo.snapshots=%s\n", tmp); |
521 | free(tmp); | 527 | free(tmp); |
522 | } | 528 | } |
523 | if (repo->max_stats != ctx.cfg.max_stats) | 529 | if (repo->max_stats != ctx.cfg.max_stats) |
524 | fprintf(f, "repo.max-stats=%s\n", | 530 | fprintf(f, "repo.max-stats=%s\n", |
525 | cgit_find_stats_periodname(repo->max_stats)); | 531 | cgit_find_stats_periodname(repo->max_stats)); |
526 | fprintf(f, "\n"); | 532 | fprintf(f, "\n"); |
527 | } | 533 | } |
528 | 534 | ||
529 | void print_repolist(FILE *f, struct cgit_repolist *list, int start) | 535 | void print_repolist(FILE *f, struct cgit_repolist *list, int start) |
530 | { | 536 | { |
531 | int i; | 537 | int i; |
532 | 538 | ||
533 | for(i = start; i < list->count; i++) | 539 | for(i = start; i < list->count; i++) |
534 | print_repo(f, &list->repos[i]); | 540 | print_repo(f, &list->repos[i]); |
535 | } | 541 | } |
536 | 542 | ||
537 | /* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc' | 543 | /* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc' |
538 | * and return 0 on success. | 544 | * and return 0 on success. |
539 | */ | 545 | */ |
540 | static int generate_cached_repolist(const char *path, const char *cached_rc) | 546 | static int generate_cached_repolist(const char *path, const char *cached_rc) |
541 | { | 547 | { |
542 | char *locked_rc; | 548 | char *locked_rc; |
543 | int idx; | 549 | int idx; |
544 | FILE *f; | 550 | FILE *f; |
545 | 551 | ||
546 | locked_rc = xstrdup(fmt("%s.lock", cached_rc)); | 552 | locked_rc = xstrdup(fmt("%s.lock", cached_rc)); |
547 | f = fopen(locked_rc, "wx"); | 553 | f = fopen(locked_rc, "wx"); |
548 | if (!f) { | 554 | if (!f) { |
549 | /* Inform about the error unless the lockfile already existed, | 555 | /* Inform about the error unless the lockfile already existed, |
550 | * since that only means we've got concurrent requests. | 556 | * since that only means we've got concurrent requests. |
551 | */ | 557 | */ |
552 | if (errno != EEXIST) | 558 | if (errno != EEXIST) |
553 | fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n", | 559 | fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n", |
554 | locked_rc, strerror(errno), errno); | 560 | locked_rc, strerror(errno), errno); |
555 | return errno; | 561 | return errno; |
556 | } | 562 | } |
557 | idx = cgit_repolist.count; | 563 | idx = cgit_repolist.count; |
558 | scan_tree(path, repo_config); | 564 | scan_tree(path, repo_config); |
559 | print_repolist(f, &cgit_repolist, idx); | 565 | print_repolist(f, &cgit_repolist, idx); |
560 | if (rename(locked_rc, cached_rc)) | 566 | if (rename(locked_rc, cached_rc)) |
561 | fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", | 567 | fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", |
562 | locked_rc, cached_rc, strerror(errno), errno); | 568 | locked_rc, cached_rc, strerror(errno), errno); |
563 | fclose(f); | 569 | fclose(f); |
564 | return 0; | 570 | return 0; |
565 | } | 571 | } |
566 | 572 | ||
567 | static void process_cached_repolist(const char *path) | 573 | static void process_cached_repolist(const char *path) |
568 | { | 574 | { |
569 | struct stat st; | 575 | struct stat st; |
570 | char *cached_rc; | 576 | char *cached_rc; |
571 | time_t age; | 577 | time_t age; |
572 | 578 | ||
573 | cached_rc = xstrdup(fmt("%s/rc-%8x", ctx.cfg.cache_root, | 579 | cached_rc = xstrdup(fmt("%s/rc-%8x", ctx.cfg.cache_root, |
574 | hash_str(path))); | 580 | hash_str(path))); |
575 | 581 | ||
576 | if (stat(cached_rc, &st)) { | 582 | if (stat(cached_rc, &st)) { |
577 | /* Nothing is cached, we need to scan without forking. And | 583 | /* Nothing is cached, we need to scan without forking. And |
578 | * if we fail to generate a cached repolist, we need to | 584 | * if we fail to generate a cached repolist, we need to |
579 | * invoke scan_tree manually. | 585 | * invoke scan_tree manually. |
580 | */ | 586 | */ |
581 | if (generate_cached_repolist(path, cached_rc)) | 587 | if (generate_cached_repolist(path, cached_rc)) |
582 | scan_tree(path, repo_config); | 588 | scan_tree(path, repo_config); |
583 | return; | 589 | return; |
584 | } | 590 | } |
585 | 591 | ||
586 | parse_configfile(cached_rc, config_cb); | 592 | parse_configfile(cached_rc, config_cb); |
587 | 593 | ||
588 | /* If the cached configfile hasn't expired, lets exit now */ | 594 | /* If the cached configfile hasn't expired, lets exit now */ |
589 | age = time(NULL) - st.st_mtime; | 595 | age = time(NULL) - st.st_mtime; |
590 | if (age <= (ctx.cfg.cache_scanrc_ttl * 60)) | 596 | if (age <= (ctx.cfg.cache_scanrc_ttl * 60)) |
591 | return; | 597 | return; |
592 | 598 | ||
593 | /* The cached repolist has been parsed, but it was old. So lets | 599 | /* The cached repolist has been parsed, but it was old. So lets |
594 | * rescan the specified path and generate a new cached repolist | 600 | * rescan the specified path and generate a new cached repolist |
595 | * in a child-process to avoid latency for the current request. | 601 | * in a child-process to avoid latency for the current request. |
596 | */ | 602 | */ |
597 | if (fork()) | 603 | if (fork()) |
598 | return; | 604 | return; |
599 | 605 | ||
600 | exit(generate_cached_repolist(path, cached_rc)); | 606 | exit(generate_cached_repolist(path, cached_rc)); |
601 | } | 607 | } |
602 | 608 | ||
603 | static void cgit_parse_args(int argc, const char **argv) | 609 | static void cgit_parse_args(int argc, const char **argv) |
604 | { | 610 | { |
605 | int i; | 611 | int i; |
606 | int scan = 0; | 612 | int scan = 0; |
607 | 613 | ||
608 | for (i = 1; i < argc; i++) { | 614 | for (i = 1; i < argc; i++) { |
609 | if (!strncmp(argv[i], "--cache=", 8)) { | 615 | if (!strncmp(argv[i], "--cache=", 8)) { |
610 | ctx.cfg.cache_root = xstrdup(argv[i]+8); | 616 | ctx.cfg.cache_root = xstrdup(argv[i]+8); |
611 | } | 617 | } |
612 | if (!strcmp(argv[i], "--nocache")) { | 618 | if (!strcmp(argv[i], "--nocache")) { |
613 | ctx.cfg.nocache = 1; | 619 | ctx.cfg.nocache = 1; |
614 | } | 620 | } |
615 | if (!strcmp(argv[i], "--nohttp")) { | 621 | if (!strcmp(argv[i], "--nohttp")) { |
616 | ctx.env.no_http = "1"; | 622 | ctx.env.no_http = "1"; |
617 | } | 623 | } |
618 | if (!strncmp(argv[i], "--query=", 8)) { | 624 | if (!strncmp(argv[i], "--query=", 8)) { |