From 6f3bf1ae1eb1d4114a1df0194b2236665a13bdac Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Tue, 11 Aug 2009 10:09:06 +0200 Subject: cgit.c: add support for cgitrc option 'repo.scan' When specified, the specified path will be scanned for repositories. Signed-off-by: Lars Hjemli --- cgit.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'cgit.c') diff --git a/cgit.c b/cgit.c index b0e1c44..97f5e08 100644 --- a/cgit.c +++ b/cgit.c @@ -136,6 +136,8 @@ void config_cb(const char *name, const char *value) add_mimetype(name + 9, value); else if (!strcmp(name, "repo.group")) ctx.cfg.repo_group = xstrdup(value); + else if (!strcmp(name, "repo.scan")) + scan_tree(value); else if (!strcmp(name, "repo.url")) ctx.repo = cgit_add_repo(value); else if (!strcmp(name, "repo.name")) -- cgit v1.2.3-70-g09d2 From 302a3efa261b1b6127b2a2189e25ab45019b1b54 Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Wed, 19 Aug 2009 17:47:24 +0200 Subject: cgit.c: make print_repolist() and print_repo() reusable for caching Signed-off-by: Lars Hjemli --- cgit.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'cgit.c') diff --git a/cgit.c b/cgit.c index 97f5e08..db96905 100644 --- a/cgit.c +++ b/cgit.c @@ -416,26 +416,26 @@ int cmp_repos(const void *a, const void *b) return strcmp(ra->url, rb->url); } -void print_repo(struct cgit_repo *repo) +void print_repo(FILE *f, struct cgit_repo *repo) { - printf("repo.url=%s\n", repo->url); - printf("repo.name=%s\n", repo->name); - printf("repo.path=%s\n", repo->path); + fprintf(f, "repo.url=%s\n", repo->url); + fprintf(f, "repo.name=%s\n", repo->name); + fprintf(f, "repo.path=%s\n", repo->path); if (repo->owner) - printf("repo.owner=%s\n", repo->owner); + fprintf(f, "repo.owner=%s\n", repo->owner); if (repo->desc) - printf("repo.desc=%s\n", repo->desc); + fprintf(f, "repo.desc=%s\n", repo->desc); if (repo->readme) - printf("repo.readme=%s\n", repo->readme); - printf("\n"); + fprintf(f, "repo.readme=%s\n", repo->readme); + fprintf(f, "\n"); } -void print_repolist(struct cgit_repolist *list) +void print_repolist(FILE *f, struct cgit_repolist *list, int start) { int i; - for(i = 0; i < list->count; i++) - print_repo(&list->repos[i]); + for(i = start; i < list->count; i++) + print_repo(f, &list->repos[i]); } @@ -482,7 +482,7 @@ static void cgit_parse_args(int argc, const char **argv) if (scan) { qsort(cgit_repolist.repos, cgit_repolist.count, sizeof(struct cgit_repo), cmp_repos); - print_repolist(&cgit_repolist); + print_repolist(stdout, &cgit_repolist, 0); exit(0); } } -- cgit v1.2.3-70-g09d2 From d746827ec43a6dd53bce56ee8d8100a03383329e Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Thu, 20 Aug 2009 17:41:54 +0200 Subject: cgit.c: add support for caching autodetected repositories Signed-off-by: Lars Hjemli --- cgit.c | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- cgit.h | 1 + 2 files changed, 75 insertions(+), 1 deletion(-) (limited to 'cgit.c') diff --git a/cgit.c b/cgit.c index db96905..594b950 100644 --- a/cgit.c +++ b/cgit.c @@ -40,6 +40,8 @@ struct cgit_filter *new_filter(const char *cmd, int extra_args) return f; } +static void process_cached_repolist(const char *path); + void config_cb(const char *name, const char *value) { if (!strcmp(name, "root-title")) @@ -96,6 +98,8 @@ void config_cb(const char *name, const char *value) ctx.cfg.cache_root_ttl = atoi(value); else if (!strcmp(name, "cache-repo-ttl")) ctx.cfg.cache_repo_ttl = atoi(value); + else if (!strcmp(name, "cache-scanrc-ttl")) + ctx.cfg.cache_scanrc_ttl = atoi(value); else if (!strcmp(name, "cache-static-ttl")) ctx.cfg.cache_static_ttl = atoi(value); else if (!strcmp(name, "cache-dynamic-ttl")) @@ -137,7 +141,10 @@ void config_cb(const char *name, const char *value) else if (!strcmp(name, "repo.group")) ctx.cfg.repo_group = xstrdup(value); else if (!strcmp(name, "repo.scan")) - scan_tree(value); + if (!ctx.cfg.nocache && ctx.cfg.cache_size) + process_cached_repolist(value); + else + scan_tree(value); else if (!strcmp(name, "repo.url")) ctx.repo = cgit_add_repo(value); else if (!strcmp(name, "repo.name")) @@ -236,6 +243,7 @@ static void prepare_context(struct cgit_context *ctx) ctx->cfg.cache_repo_ttl = 5; ctx->cfg.cache_root = CGIT_CACHE_ROOT; ctx->cfg.cache_root_ttl = 5; + ctx->cfg.cache_scanrc_ttl = 15; ctx->cfg.cache_static_ttl = -1; ctx->cfg.css = "/cgit.css"; ctx->cfg.logo = "/cgit.png"; @@ -438,6 +446,71 @@ void print_repolist(FILE *f, struct cgit_repolist *list, int start) print_repo(f, &list->repos[i]); } +/* Scan 'path' for git repositories, save the resulting repolist in 'cached_rc' + * and return 0 on success. + */ +static int generate_cached_repolist(const char *path, const char *cached_rc) +{ + char *locked_rc; + int idx; + FILE *f; + + locked_rc = xstrdup(fmt("%s.lock", cached_rc)); + f = fopen(locked_rc, "wx"); + if (!f) { + /* Inform about the error unless the lockfile already existed, + * since that only means we've got concurrent requests. + */ + if (errno != EEXIST) + fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n", + locked_rc, strerror(errno), errno); + return errno; + } + idx = cgit_repolist.count; + scan_tree(path); + print_repolist(f, &cgit_repolist, idx); + if (rename(locked_rc, cached_rc)) + fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", + locked_rc, cached_rc, strerror(errno), errno); + fclose(f); + return 0; +} + +static void process_cached_repolist(const char *path) +{ + struct stat st; + char *cached_rc; + time_t age; + + cached_rc = xstrdup(fmt("%s/rc-%8x", ctx.cfg.cache_root, + hash_str(path))); + + if (stat(cached_rc, &st)) { + /* Nothing is cached, we need to scan without forking. And + * if we fail to generate a cached repolist, we need to + * invoke scan_tree manually. + */ + if (generate_cached_repolist(path, cached_rc)) + scan_tree(path); + return; + } + + parse_configfile(cached_rc, config_cb); + + /* If the cached configfile hasn't expired, lets exit now */ + age = time(NULL) - st.st_mtime; + if (age <= (ctx.cfg.cache_scanrc_ttl * 60)) + return; + + /* The cached repolist has been parsed, but it was old. So lets + * rescan the specified path and generate a new cached repolist + * in a child-process to avoid latency for the current request. + */ + if (fork()) + return; + + exit(generate_cached_repolist(path, cached_rc)); +} static void cgit_parse_args(int argc, const char **argv) { diff --git a/cgit.h b/cgit.h index adb8da4..5659580 100644 --- a/cgit.h +++ b/cgit.h @@ -168,6 +168,7 @@ struct cgit_config { int cache_max_create_time; int cache_repo_ttl; int cache_root_ttl; + int cache_scanrc_ttl; int cache_static_ttl; int embedded; int enable_index_links; -- cgit v1.2.3-70-g09d2 From 00466376922e2f7db02b3c335d46af5eb8991c49 Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Sun, 23 Aug 2009 19:35:56 +0200 Subject: Rename 'repo.scan' to 'scan-path' The 'repo.' prefix will soon be reserved for repo-specific config options. Signed-off-by: Lars Hjemli --- cgit.c | 10 +++++----- cgitrc.5.txt | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'cgit.c') diff --git a/cgit.c b/cgit.c index 594b950..6ece411 100644 --- a/cgit.c +++ b/cgit.c @@ -118,6 +118,11 @@ void config_cb(const char *name, const char *value) ctx.cfg.max_repo_count = atoi(value); else if (!strcmp(name, "max-commit-count")) ctx.cfg.max_commit_count = atoi(value); + else if (!strcmp(name, "scan-path")) + if (!ctx.cfg.nocache && ctx.cfg.cache_size) + process_cached_repolist(value); + else + scan_tree(value); else if (!strcmp(name, "source-filter")) ctx.cfg.source_filter = new_filter(value, 1); else if (!strcmp(name, "summary-log")) @@ -140,11 +145,6 @@ void config_cb(const char *name, const char *value) add_mimetype(name + 9, value); else if (!strcmp(name, "repo.group")) ctx.cfg.repo_group = xstrdup(value); - else if (!strcmp(name, "repo.scan")) - if (!ctx.cfg.nocache && ctx.cfg.cache_size) - process_cached_repolist(value); - else - scan_tree(value); else if (!strcmp(name, "repo.url")) ctx.repo = cgit_add_repo(value); else if (!strcmp(name, "repo.name")) diff --git a/cgitrc.5.txt b/cgitrc.5.txt index 68ae2ed..2abbd41 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt @@ -203,11 +203,6 @@ repo.group:: A value for the current repository group, which all repositories specified after this setting will inherit. Default value: none. -repo.scan:: - A path which will be scanned for repositories. If caching is enabled, - the result will be cached as a cgitrc include-file in the cache - directory. Default value: none. See also: cache-scanrc-ttl. - robots:: Text used as content for the "robots" meta-tag. Default value: "index, nofollow". @@ -225,6 +220,11 @@ root-title:: Text printed as heading on the repository index page. Default value: "Git Repository Browser". +scan-path:: + A path which will be scanned for repositories. If caching is enabled, + the result will be cached as a cgitrc include-file in the cache + directory. Default value: none. See also: cache-scanrc-ttl. + snapshots:: Text which specifies the default set of snapshot formats generated by cgit. The value is a space-separated list of zero or more of the -- cgit v1.2.3-70-g09d2 From 50d5af3adcdd90424b70e9472af24356ed50aa9b Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Sun, 23 Aug 2009 19:36:45 +0200 Subject: 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 --- cgit.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'cgit.c') diff --git a/cgit.c b/cgit.c index 6ece411..a792fe4 100644 --- a/cgit.c +++ b/cgit.c @@ -547,7 +547,8 @@ static void cgit_parse_args(int argc, const char **argv) if (!strncmp(argv[i], "--ofs=", 6)) { ctx.qry.ofs = atoi(argv[i]+6); } - if (!strncmp(argv[i], "--scan-tree=", 12)) { + if (!strncmp(argv[i], "--scan-tree=", 12) || + !strncmp(argv[i], "--scan-path=", 12)) { scan++; scan_tree(argv[i] + 12); } -- cgit v1.2.3-70-g09d2 From e7af002d5c405c82652f739d08ced3908d1f57e7 Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Sun, 23 Aug 2009 22:58:39 +0200 Subject: Introduce 'section' as canonical spelling for 'repo.group' The 'repo.' prefix should be reserved for repo-specific options, but the option 'repo.group' must still be honored to stay backwards compatible. Signed-off-by: Lars Hjemli --- cgit.c | 4 ++-- cgit.css | 2 +- cgit.h | 4 ++-- cgitrc.5.txt | 9 +++++++-- shared.c | 2 +- ui-repolist.c | 18 +++++++++--------- 6 files changed, 22 insertions(+), 17 deletions(-) (limited to 'cgit.c') diff --git a/cgit.c b/cgit.c index a792fe4..013a0fe 100644 --- a/cgit.c +++ b/cgit.c @@ -143,8 +143,8 @@ void config_cb(const char *name, const char *value) ctx.cfg.local_time = atoi(value); else if (!prefixcmp(name, "mimetype.")) add_mimetype(name + 9, value); - else if (!strcmp(name, "repo.group")) - ctx.cfg.repo_group = xstrdup(value); + else if (!strcmp(name, "section") || !strcmp(name, "repo.group")) + ctx.cfg.section = xstrdup(value); else if (!strcmp(name, "repo.url")) ctx.repo = cgit_add_repo(value); else if (!strcmp(name, "repo.name")) diff --git a/cgit.css b/cgit.css index e3b32e7..3c65114 100644 --- a/cgit.css +++ b/cgit.css @@ -429,7 +429,7 @@ table.diff td div.del { text-align: right; } -table.list td.repogroup { +table.list td.reposection { font-style: italic; color: #888; } diff --git a/cgit.h b/cgit.h index 5659580..fc7c7d5 100644 --- a/cgit.h +++ b/cgit.h @@ -65,9 +65,9 @@ struct cgit_repo { char *desc; char *owner; char *defbranch; - char *group; char *module_link; char *readme; + char *section; char *clone_url; int snapshots; int enable_log_filecount; @@ -156,12 +156,12 @@ struct cgit_config { char *logo; char *logo_link; char *module_link; - char *repo_group; char *robots; char *root_title; char *root_desc; char *root_readme; char *script_name; + char *section; char *virtual_root; int cache_size; int cache_dynamic_ttl; diff --git a/cgitrc.5.txt b/cgitrc.5.txt index 2abbd41..4d009f9 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt @@ -200,8 +200,8 @@ renamelimit:: `man git-diff`). Default value: "-1". repo.group:: - A value for the current repository group, which all repositories - specified after this setting will inherit. Default value: none. + Legacy alias for 'section' which will be deprecated starting with + cgit-1.0. robots:: Text used as content for the "robots" meta-tag. Default value: @@ -225,6 +225,11 @@ scan-path:: the result will be cached as a cgitrc include-file in the cache directory. Default value: none. See also: cache-scanrc-ttl. +section: + The name of the current repository section - all repositories defined + after this option will inherit the current section name. Default value: + none. + snapshots:: Text which specifies the default set of snapshot formats generated by cgit. The value is a space-separated list of zero or more of the diff --git a/shared.c b/shared.c index 4cb9573..9475581 100644 --- a/shared.c +++ b/shared.c @@ -53,7 +53,7 @@ struct cgit_repo *cgit_add_repo(const char *url) ret->path = NULL; ret->desc = "[no description]"; ret->owner = NULL; - ret->group = ctx.cfg.repo_group; + ret->section = ctx.cfg.section; ret->defbranch = "master"; ret->snapshots = ctx.cfg.snapshots; ret->enable_log_filecount = ctx.cfg.enable_log_filecount; diff --git a/ui-repolist.c b/ui-repolist.c index 7c7aa9b..4dea3b3 100644 --- a/ui-repolist.c +++ b/ui-repolist.c @@ -203,7 +203,7 @@ int sort_repolist(char *field) void cgit_print_repolist() { int i, columns = 4, hits = 0, header = 0; - char *last_group = NULL; + char *last_section = NULL; int sorted = 0; if (ctx.cfg.enable_index_links) @@ -233,18 +233,18 @@ void cgit_print_repolist() if (!header++) print_header(columns); if (!sorted && - ((last_group == NULL && ctx.repo->group != NULL) || - (last_group != NULL && ctx.repo->group == NULL) || - (last_group != NULL && ctx.repo->group != NULL && - strcmp(ctx.repo->group, last_group)))) { - htmlf("", + ((last_section == NULL && ctx.repo->section != NULL) || + (last_section != NULL && ctx.repo->section == NULL) || + (last_section != NULL && ctx.repo->section != NULL && + strcmp(ctx.repo->section, last_section)))) { + htmlf("", columns); - html_txt(ctx.repo->group); + html_txt(ctx.repo->section); html(""); - last_group = ctx.repo->group; + last_section = ctx.repo->section; } htmlf("", - !sorted && ctx.repo->group ? "sublevel-repo" : "toplevel-repo"); + !sorted && ctx.repo->section ? "sublevel-repo" : "toplevel-repo"); cgit_summary_link(ctx.repo->name, ctx.repo->name, NULL, NULL); html(""); html_link_open(cgit_repourl(ctx.repo->url), NULL, NULL); -- cgit v1.2.3-70-g09d2 From 39398545787179bc8075d64a443f9da3845c4f67 Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Sun, 23 Aug 2009 23:00:28 +0200 Subject: Add config option 'repo.section' This option can be used to specify the section name for the current repository. Signed-off-by: Lars Hjemli --- cgit.c | 2 ++ cgitrc.5.txt | 3 +++ 2 files changed, 5 insertions(+) (limited to 'cgit.c') diff --git a/cgit.c b/cgit.c index 013a0fe..7264b8e 100644 --- a/cgit.c +++ b/cgit.c @@ -169,6 +169,8 @@ void config_cb(const char *name, const char *value) ctx.repo->max_stats = cgit_find_stats_period(value, NULL); else if (ctx.repo && !strcmp(name, "repo.module-link")) ctx.repo->module_link= xstrdup(value); + else if (ctx.repo && !strcmp(name, "repo.section")) + ctx.repo->section = xstrdup(value); else if (ctx.repo && !strcmp(name, "repo.about-filter")) ctx.repo->about_filter = new_filter(value, 0); else if (ctx.repo && !strcmp(name, "repo.commit-filter")) diff --git a/cgitrc.5.txt b/cgitrc.5.txt index 4d009f9..e99c9f7 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt @@ -315,6 +315,9 @@ repo.snapshots:: A mask of allowed snapshot-formats for this repo, restricted by the "snapshots" global setting. Default value: . +repo.section:: + Override the current section for this repository. Default value: none. + repo.source-filter:: Override the default source-filter. Default value: . -- cgit v1.2.3-70-g09d2 From a1b3938f711c9b0e5eedad1678535e5779da82c1 Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Sun, 23 Aug 2009 23:23:20 +0200 Subject: cgit.c: refactor repo_config() from config_cb() The new function repo_config() is used to handle all 'simple' repo options, for the following reasons: * code readability * parser performance * upcoming support for repo-local cgitrc files during scanning Signed-off-by: Lars Hjemli --- cgit.c | 89 ++++++++++++++++++++++++++++++++++++------------------------------ 1 file changed, 48 insertions(+), 41 deletions(-) (limited to 'cgit.c') diff --git a/cgit.c b/cgit.c index 7264b8e..90ae124 100644 --- a/cgit.c +++ b/cgit.c @@ -42,9 +42,55 @@ struct cgit_filter *new_filter(const char *cmd, int extra_args) static void process_cached_repolist(const char *path); +void repo_config(struct cgit_repo *repo, const char *name, const char *value) +{ + if (!strcmp(name, "name")) + repo->name = xstrdup(value); + else if (!strcmp(name, "clone-url")) + repo->clone_url = xstrdup(value); + else if (!strcmp(name, "desc")) + repo->desc = xstrdup(value); + else if (!strcmp(name, "owner")) + repo->owner = xstrdup(value); + else if (!strcmp(name, "defbranch")) + repo->defbranch = xstrdup(value); + else if (!strcmp(name, "snapshots")) + repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); + else if (!strcmp(name, "enable-log-filecount")) + repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); + else if (!strcmp(name, "enable-log-linecount")) + repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); + else if (!strcmp(name, "max-stats")) + repo->max_stats = cgit_find_stats_period(value, NULL); + else if (!strcmp(name, "module-link")) + repo->module_link= xstrdup(value); + else if (!strcmp(name, "section")) + repo->section = xstrdup(value); + else if (!strcmp(name, "about-filter")) + repo->about_filter = new_filter(value, 0); + else if (!strcmp(name, "commit-filter")) + repo->commit_filter = new_filter(value, 0); + else if (!strcmp(name, "source-filter")) + repo->source_filter = new_filter(value, 1); + else if (!strcmp(name, "readme") && value != NULL) { + if (*value == '/') + ctx.repo->readme = xstrdup(value); + else + ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value)); + } +} + void config_cb(const char *name, const char *value) { - if (!strcmp(name, "root-title")) + if (!strcmp(name, "section") || !strcmp(name, "repo.group")) + ctx.cfg.section = xstrdup(value); + else if (!strcmp(name, "repo.url")) + ctx.repo = cgit_add_repo(value); + else if (ctx.repo && !strcmp(name, "repo.path")) + ctx.repo->path = trim_end(value, '/'); + else if (ctx.repo && !prefixcmp(name, "repo.")) + repo_config(ctx.repo, name + 5, value); + else if (!strcmp(name, "root-title")) ctx.cfg.root_title = xstrdup(value); else if (!strcmp(name, "root-desc")) ctx.cfg.root_desc = xstrdup(value); @@ -143,46 +189,7 @@ void config_cb(const char *name, const char *value) ctx.cfg.local_time = atoi(value); else if (!prefixcmp(name, "mimetype.")) add_mimetype(name + 9, value); - else if (!strcmp(name, "section") || !strcmp(name, "repo.group")) - ctx.cfg.section = xstrdup(value); - else if (!strcmp(name, "repo.url")) - ctx.repo = cgit_add_repo(value); - else if (!strcmp(name, "repo.name")) - ctx.repo->name = xstrdup(value); - else if (ctx.repo && !strcmp(name, "repo.path")) - ctx.repo->path = trim_end(value, '/'); - else if (ctx.repo && !strcmp(name, "repo.clone-url")) - ctx.repo->clone_url = xstrdup(value); - else if (ctx.repo && !strcmp(name, "repo.desc")) - ctx.repo->desc = xstrdup(value); - else if (ctx.repo && !strcmp(name, "repo.owner")) - ctx.repo->owner = xstrdup(value); - else if (ctx.repo && !strcmp(name, "repo.defbranch")) - ctx.repo->defbranch = xstrdup(value); - else if (ctx.repo && !strcmp(name, "repo.snapshots")) - ctx.repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */ - else if (ctx.repo && !strcmp(name, "repo.enable-log-filecount")) - ctx.repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); - else if (ctx.repo && !strcmp(name, "repo.enable-log-linecount")) - ctx.repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); - else if (ctx.repo && !strcmp(name, "repo.max-stats")) - ctx.repo->max_stats = cgit_find_stats_period(value, NULL); - else if (ctx.repo && !strcmp(name, "repo.module-link")) - ctx.repo->module_link= xstrdup(value); - else if (ctx.repo && !strcmp(name, "repo.section")) - ctx.repo->section = xstrdup(value); - else if (ctx.repo && !strcmp(name, "repo.about-filter")) - ctx.repo->about_filter = new_filter(value, 0); - else if (ctx.repo && !strcmp(name, "repo.commit-filter")) - ctx.repo->commit_filter = new_filter(value, 0); - else if (ctx.repo && !strcmp(name, "repo.source-filter")) - ctx.repo->source_filter = new_filter(value, 1); - else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) { - if (*value == '/') - ctx.repo->readme = xstrdup(value); - else - ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value)); - } else if (!strcmp(name, "include")) + else if (!strcmp(name, "include")) parse_configfile(value, config_cb); } -- cgit v1.2.3-70-g09d2 From 74061ed5f03e72796450aa3b8ca1cf6ced5d59e2 Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Mon, 24 Aug 2009 00:04:58 +0200 Subject: Add support for repo-local cgitrc file When recursively scanning a directory tree looking for git repositories, cgit will now parse cgitrc files found within such repositories. The repo-specific config files can include any repo-specific options except 'repo.url' and 'repo.path'. Also, in such config files the 'repo.' prefix can not be used, i.e. the valid options then becomes: * name * clone-url * desc * ower * defbranch * snapshots * enable-log-filecount * enable-log-linecount * max-stats * module-link * section * about-filter * commit-filter * source-filter * readme Signed-off-by: Lars Hjemli --- cgit.c | 8 ++++---- cgit.h | 3 +++ cgitrc.5.txt | 9 +++++++++ scan-tree.c | 30 ++++++++++++++++++++++-------- scan-tree.h | 2 +- 5 files changed, 39 insertions(+), 13 deletions(-) (limited to 'cgit.c') diff --git a/cgit.c b/cgit.c index 90ae124..e281aa9 100644 --- a/cgit.c +++ b/cgit.c @@ -168,7 +168,7 @@ void config_cb(const char *name, const char *value) if (!ctx.cfg.nocache && ctx.cfg.cache_size) process_cached_repolist(value); else - scan_tree(value); + scan_tree(value, repo_config); else if (!strcmp(name, "source-filter")) ctx.cfg.source_filter = new_filter(value, 1); else if (!strcmp(name, "summary-log")) @@ -476,7 +476,7 @@ static int generate_cached_repolist(const char *path, const char *cached_rc) return errno; } idx = cgit_repolist.count; - scan_tree(path); + scan_tree(path, repo_config); print_repolist(f, &cgit_repolist, idx); if (rename(locked_rc, cached_rc)) fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", @@ -500,7 +500,7 @@ static void process_cached_repolist(const char *path) * invoke scan_tree manually. */ if (generate_cached_repolist(path, cached_rc)) - scan_tree(path); + scan_tree(path, repo_config); return; } @@ -559,7 +559,7 @@ static void cgit_parse_args(int argc, const char **argv) if (!strncmp(argv[i], "--scan-tree=", 12) || !strncmp(argv[i], "--scan-path=", 12)) { scan++; - scan_tree(argv[i] + 12); + scan_tree(argv[i] + 12, repo_config); } } if (scan) { diff --git a/cgit.h b/cgit.h index fc7c7d5..3359be9 100644 --- a/cgit.h +++ b/cgit.h @@ -79,6 +79,9 @@ struct cgit_repo { struct cgit_filter *source_filter; }; +typedef void (*repo_config_fn)(struct cgit_repo *repo, const char *name, + const char *value); + struct cgit_repolist { int length; int count; diff --git a/cgitrc.5.txt b/cgitrc.5.txt index e99c9f7..df494aa 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt @@ -326,6 +326,15 @@ repo.url:: setting specified for each repo. Default value: none. +REPOSITORY-SPECIFIC CGITRC FILE +------------------------------- +When the option 'scan-path' is used to auto-discover git repositories, cgit +will try to parse the file 'cgitrc' within any found repository. Such a repo- +specific config file may contain any of the repo-specific options described +above, except 'repo.url' and 'repo.path'. Also, in a repo-specific config +file, the 'repo.' prefix is dropped from the config option names. + + EXAMPLE CGITRC FILE ------------------- diff --git a/scan-tree.c b/scan-tree.c index 67f4550..dbca797 100644 --- a/scan-tree.c +++ b/scan-tree.c @@ -1,4 +1,5 @@ #include "cgit.h" +#include "configfile.h" #include "html.h" #define MAX_PATH 4096 @@ -35,9 +36,16 @@ static int is_git_dir(const char *path) return 1; } -static void add_repo(const char *base, const char *path) +struct cgit_repo *repo; +repo_config_fn config_fn; + +static void repo_config(const char *name, const char *value) +{ + config_fn(repo, name, value); +} + +static void add_repo(const char *base, const char *path, repo_config_fn fn) { - struct cgit_repo *repo; struct stat st; struct passwd *pwd; char *p; @@ -76,9 +84,15 @@ static void add_repo(const char *base, const char *path) p = fmt("%s/README.html", path); if (!stat(p, &st)) repo->readme = "README.html"; + + p = fmt("%s/cgitrc", path); + if (!stat(p, &st)) { + config_fn = fn; + parse_configfile(xstrdup(p), &repo_config); + } } -static void scan_path(const char *base, const char *path) +static void scan_path(const char *base, const char *path, repo_config_fn fn) { DIR *dir; struct dirent *ent; @@ -86,11 +100,11 @@ static void scan_path(const char *base, const char *path) struct stat st; if (is_git_dir(path)) { - add_repo(base, path); + add_repo(base, path, fn); return; } if (is_git_dir(fmt("%s/.git", path))) { - add_repo(base, fmt("%s/.git", path)); + add_repo(base, fmt("%s/.git", path), fn); return; } dir = opendir(path); @@ -120,13 +134,13 @@ static void scan_path(const char *base, const char *path) continue; } if (S_ISDIR(st.st_mode)) - scan_path(base, buf); + scan_path(base, buf, fn); free(buf); } closedir(dir); } -void scan_tree(const char *path) +void scan_tree(const char *path, repo_config_fn fn) { - scan_path(path, path); + scan_path(path, path, fn); } 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 @@ -extern void scan_tree(const char *path); +extern void scan_tree(const char *path, repo_config_fn fn); -- cgit v1.2.3-70-g09d2 From e01229cf80bc618a132d2154c0ebd71792d31c64 Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Mon, 24 Aug 2009 07:42:03 +0200 Subject: ui-repolist: handle empty sections similar to NULL sections Signed-off-by: Lars Hjemli --- cgit.c | 1 + ui-repolist.c | 18 +++++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) (limited to 'cgit.c') diff --git a/cgit.c b/cgit.c index e281aa9..167b5dd 100644 --- a/cgit.c +++ b/cgit.c @@ -269,6 +269,7 @@ static void prepare_context(struct cgit_context *ctx) ctx->cfg.root_title = "Git repository browser"; ctx->cfg.root_desc = "a fast webinterface for the git dscm"; ctx->cfg.script_name = CGIT_SCRIPT_NAME; + ctx->cfg.section = ""; ctx->cfg.summary_branches = 10; ctx->cfg.summary_log = 10; ctx->cfg.summary_tags = 10; diff --git a/ui-repolist.c b/ui-repolist.c index d56654d..3ef2e99 100644 --- a/ui-repolist.c +++ b/ui-repolist.c @@ -217,6 +217,7 @@ void cgit_print_repolist() { int i, columns = 4, hits = 0, header = 0; char *last_section = NULL; + char *section; int sorted = 0; if (ctx.cfg.enable_index_links) @@ -247,19 +248,22 @@ void cgit_print_repolist() continue; if (!header++) print_header(columns); + section = ctx.repo->section; + if (section && !strcmp(section, "")) + section = NULL; if (!sorted && - ((last_section == NULL && ctx.repo->section != NULL) || - (last_section != NULL && ctx.repo->section == NULL) || - (last_section != NULL && ctx.repo->section != NULL && - strcmp(ctx.repo->section, last_section)))) { + ((last_section == NULL && section != NULL) || + (last_section != NULL && section == NULL) || + (last_section != NULL && section != NULL && + strcmp(section, last_section)))) { htmlf("", columns); - html_txt(ctx.repo->section); + html_txt(section); html(""); - last_section = ctx.repo->section; + last_section = section; } htmlf("", - !sorted && ctx.repo->section ? "sublevel-repo" : "toplevel-repo"); + !sorted && section ? "sublevel-repo" : "toplevel-repo"); cgit_summary_link(ctx.repo->name, ctx.repo->name, NULL, NULL); html(""); html_link_open(cgit_repourl(ctx.repo->url), NULL, NULL); -- cgit v1.2.3-70-g09d2 From 2273c2c821bfc77d492d7e97ae38f162d7fc91aa Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Mon, 24 Aug 2009 08:53:21 +0200 Subject: Add config option 'enable-filter-overrides' This option must be enabled if repo-specific cgitrc files should be allowed to override any of the 'filter' options. Signed-off-by: Lars Hjemli --- cgit.c | 15 +++++++++------ cgit.h | 1 + cgitrc.5.txt | 21 ++++++++++++++++----- 3 files changed, 26 insertions(+), 11 deletions(-) (limited to 'cgit.c') diff --git a/cgit.c b/cgit.c index 167b5dd..f1ea03c 100644 --- a/cgit.c +++ b/cgit.c @@ -66,17 +66,18 @@ void repo_config(struct cgit_repo *repo, const char *name, const char *value) repo->module_link= xstrdup(value); else if (!strcmp(name, "section")) repo->section = xstrdup(value); - else if (!strcmp(name, "about-filter")) - repo->about_filter = new_filter(value, 0); - else if (!strcmp(name, "commit-filter")) - repo->commit_filter = new_filter(value, 0); - else if (!strcmp(name, "source-filter")) - repo->source_filter = new_filter(value, 1); else if (!strcmp(name, "readme") && value != NULL) { if (*value == '/') ctx.repo->readme = xstrdup(value); else ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, value)); + } else if (ctx.cfg.enable_filter_overrides) { + if (!strcmp(name, "about-filter")) + repo->about_filter = new_filter(value, 0); + else if (!strcmp(name, "commit-filter")) + repo->commit_filter = new_filter(value, 0); + else if (!strcmp(name, "source-filter")) + repo->source_filter = new_filter(value, 1); } } @@ -128,6 +129,8 @@ void config_cb(const char *name, const char *value) ctx.cfg.noheader = atoi(value); else if (!strcmp(name, "snapshots")) ctx.cfg.snapshots = cgit_parse_snapshots_mask(value); + else if (!strcmp(name, "enable-filter-overrides")) + ctx.cfg.enable_filter_overrides = atoi(value); else if (!strcmp(name, "enable-index-links")) ctx.cfg.enable_index_links = atoi(value); else if (!strcmp(name, "enable-log-filecount")) diff --git a/cgit.h b/cgit.h index 3359be9..ef109aa 100644 --- a/cgit.h +++ b/cgit.h @@ -174,6 +174,7 @@ struct cgit_config { int cache_scanrc_ttl; int cache_static_ttl; int embedded; + int enable_filter_overrides; int enable_index_links; int enable_log_filecount; int enable_log_linecount; diff --git a/cgitrc.5.txt b/cgitrc.5.txt index 46df291..617b7c3 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt @@ -88,6 +88,10 @@ embedded:: suitable for embedding in other html pages. Default value: none. See also: "noheader". +enable-filter-overrides:: + Flag which, when set to "1", allows all filter settings to be + overridden in repository-specific cgitrc files. Default value: none. + enable-index-links:: Flag which, when set to "1", will make cgit generate extra links for each repo in the repository index (specifically, to the "summary", @@ -266,14 +270,16 @@ virtual-root:: REPOSITORY SETTINGS ------------------- repo.about-filter:: - Override the default about-filter. Default value: . + Override the default about-filter. Default value: none. See also: + "enable-filter-overrides". repo.clone-url:: A list of space-separated urls which can be used to clone this repo. Default value: none. repo.commit-filter:: - Override the default commit-filter. Default value: . + Override the default commit-filter. Default value: none. See also: + "enable-filter-overrides". repo.defbranch:: The name of the default branch for this repository. If no such branch @@ -320,7 +326,8 @@ repo.section:: none. repo.source-filter:: - Override the default source-filter. Default value: . + Override the default source-filter. Default value: none. See also: + "enable-filter-overrides". repo.url:: The relative url used to access the repository. This must be the first @@ -332,8 +339,12 @@ REPOSITORY-SPECIFIC CGITRC FILE When the option "scan-path" is used to auto-discover git repositories, cgit will try to parse the file "cgitrc" within any found repository. Such a repo-specific config file may contain any of the repo-specific options -described above, except "repo.url" and "repo.path". Also, in a repo-specific -config file, the "repo." prefix is dropped from the config option names. +described above, except "repo.url" and "repo.path". Additionally, the "filter" +options are only acknowledged in repo-specific config files when +"enable-filter-overrides" is set to "1". + +Note: the "repo." prefix is dropped from the option names in repo-specific +config files, e.g. "repo.desc" becomes "desc". EXAMPLE CGITRC FILE -- cgit v1.2.3-70-g09d2 From 3548320004512276ea0bbfe80b2ae9b5cc7e2c76 Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Mon, 24 Aug 2009 10:22:21 +0200 Subject: cgit.c: add missing options to print_repo() Note: print_repo() still ignores repo.max-stats and repo.snapshots, which both requires additional work since these settings are represented internally as an enum and a bitmap. Signed-off-by: Lars Hjemli --- cgit.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'cgit.c') diff --git a/cgit.c b/cgit.c index f1ea03c..8ab6889 100644 --- a/cgit.c +++ b/cgit.c @@ -448,6 +448,24 @@ void print_repo(FILE *f, struct cgit_repo *repo) fprintf(f, "repo.desc=%s\n", repo->desc); if (repo->readme) fprintf(f, "repo.readme=%s\n", repo->readme); + if (repo->defbranch) + fprintf(f, "repo.defbranch=%s\n", repo->defbranch); + if (repo->module_link) + fprintf(f, "repo.module-link=%s\n", repo->module_link); + if (repo->section) + fprintf(f, "repo.section=%s\n", repo->section); + if (repo->clone_url) + fprintf(f, "repo.clone-url=%s\n", repo->clone_url); + fprintf(f, "repo.enable-log-filecount=%d\n", + repo->enable_log_filecount); + fprintf(f, "repo.enable-log-linecount=%d\n", + repo->enable_log_linecount); + if (repo->about_filter && repo->about_filter != ctx.cfg.about_filter) + fprintf(f, "repo.about-filter=%s\n", repo->about_filter->cmd); + if (repo->commit_filter && repo->commit_filter != ctx.cfg.commit_filter) + fprintf(f, "repo.commit-filter=%s\n", repo->commit_filter->cmd); + if (repo->source_filter && repo->source_filter != ctx.cfg.source_filter) + fprintf(f, "repo.source-filter=%s\n", repo->source_filter->cmd); fprintf(f, "\n"); } -- cgit v1.2.3-70-g09d2 From 5ca8df0a3d75ba1ca5af28872977f7714b66ff37 Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Mon, 24 Aug 2009 10:55:01 +0200 Subject: cgit.c: generate repo.snapshots in print_repo() Signed-off-by: Lars Hjemli --- cgit.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'cgit.c') diff --git a/cgit.c b/cgit.c index 8ab6889..b0e202e 100644 --- a/cgit.c +++ b/cgit.c @@ -437,6 +437,26 @@ int cmp_repos(const void *a, const void *b) return strcmp(ra->url, rb->url); } +char *build_snapshot_setting(int bitmap) +{ + const struct cgit_snapshot_format *f; + char *result = xstrdup(""); + char *tmp; + int len; + + for (f = cgit_snapshot_formats; f->suffix; f++) { + if (f->bit & bitmap) { + tmp = result; + result = xstrdup(fmt("%s%s ", tmp, f->suffix)); + free(tmp); + } + } + len = strlen(result); + if (len) + result[len - 1] = '\0'; + return result; +} + void print_repo(FILE *f, struct cgit_repo *repo) { fprintf(f, "repo.url=%s\n", repo->url); @@ -466,6 +486,11 @@ void print_repo(FILE *f, struct cgit_repo *repo) fprintf(f, "repo.commit-filter=%s\n", repo->commit_filter->cmd); if (repo->source_filter && repo->source_filter != ctx.cfg.source_filter) fprintf(f, "repo.source-filter=%s\n", repo->source_filter->cmd); + if (repo->snapshots != ctx.cfg.snapshots) { + char *tmp = build_snapshot_setting(repo->snapshots); + fprintf(f, "repo.snapshots=%s\n", tmp); + free(tmp); + } fprintf(f, "\n"); } -- cgit v1.2.3-70-g09d2 From b47b7bd1d0fb872763214e674b53a562c7513fc0 Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Mon, 24 Aug 2009 11:02:48 +0200 Subject: Add and use cgit_find_stats_periodname() in print_repo() Signed-off-by: Lars Hjemli --- cgit.c | 3 +++ ui-stats.c | 8 ++++++++ ui-stats.h | 1 + 3 files changed, 12 insertions(+) (limited to 'cgit.c') diff --git a/cgit.c b/cgit.c index b0e202e..93a7a69 100644 --- a/cgit.c +++ b/cgit.c @@ -491,6 +491,9 @@ void print_repo(FILE *f, struct cgit_repo *repo) fprintf(f, "repo.snapshots=%s\n", tmp); free(tmp); } + if (repo->max_stats != ctx.cfg.max_stats) + fprintf(f, "repo.max-stats=%s\n", + cgit_find_stats_periodname(repo->max_stats)); fprintf(f, "\n"); } diff --git a/ui-stats.c b/ui-stats.c index 9fc06d3..bdaf9cc 100644 --- a/ui-stats.c +++ b/ui-stats.c @@ -154,6 +154,14 @@ int cgit_find_stats_period(const char *expr, struct cgit_period **period) return 0; } +const char *cgit_find_stats_periodname(int idx) +{ + if (idx > 0 && idx < 4) + return periods[idx - 1].name; + else + return ""; +} + static void add_commit(struct string_list *authors, struct commit *commit, struct cgit_period *period) { diff --git a/ui-stats.h b/ui-stats.h index 4f13dba..f0761ba 100644 --- a/ui-stats.h +++ b/ui-stats.h @@ -21,6 +21,7 @@ struct cgit_period { }; extern int cgit_find_stats_period(const char *expr, struct cgit_period **period); +extern const char *cgit_find_stats_periodname(int idx); extern void cgit_show_stats(struct cgit_context *ctx); -- cgit v1.2.3-70-g09d2 From 588fb8efc69778b85062e8fc2f482a8de43bad75 Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Mon, 24 Aug 2009 13:27:15 +0200 Subject: cgit.c: only print first line of repo.desc in print_repo() Since repo.desc might have been populated by reading the 'description' file in GIT_DIR, it may contain newlines. And by printing the literal value, we may then generate an invalid cgitrc include-file. Signed-off-by: Lars Hjemli --- cgit.c | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) (limited to 'cgit.c') diff --git a/cgit.c b/cgit.c index 93a7a69..8381630 100644 --- a/cgit.c +++ b/cgit.c @@ -457,6 +457,15 @@ char *build_snapshot_setting(int bitmap) return result; } +char *get_first_line(char *txt) +{ + char *t = xstrdup(txt); + char *p = strchr(t, '\n'); + if (p) + *p = '\0'; + return t; +} + void print_repo(FILE *f, struct cgit_repo *repo) { fprintf(f, "repo.url=%s\n", repo->url); @@ -464,8 +473,11 @@ void print_repo(FILE *f, struct cgit_repo *repo) fprintf(f, "repo.path=%s\n", repo->path); if (repo->owner) fprintf(f, "repo.owner=%s\n", repo->owner); - if (repo->desc) - fprintf(f, "repo.desc=%s\n", repo->desc); + if (repo->desc) { + char *tmp = get_first_line(repo->desc); + fprintf(f, "repo.desc=%s\n", tmp); + free(tmp); + } if (repo->readme) fprintf(f, "repo.readme=%s\n", repo->readme); if (repo->defbranch) -- cgit v1.2.3-70-g09d2 From ee554849ac7209fa8f7486327ec9f3b370e4c876 Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Mon, 24 Aug 2009 13:31:49 +0200 Subject: 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 --- cgit.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'cgit.c') diff --git a/cgit.c b/cgit.c index 8381630..3fcca2a 100644 --- a/cgit.c +++ b/cgit.c @@ -620,6 +620,16 @@ static void cgit_parse_args(int argc, const char **argv) } if (!strncmp(argv[i], "--scan-tree=", 12) || !strncmp(argv[i], "--scan-path=", 12)) { + /* HACK: the global snapshot bitmask defines the + * set of allowed snapshot formats, but the config + * file hasn't been parsed yet so the mask is + * currently 0. By setting all bits high before + * scanning we make sure that any in-repo cgitrc + * snapshot setting is respected by scan_tree(). + * BTW: we assume that there'll never be more than + * 255 different snapshot formats supported by cgit... + */ + ctx.cfg.snapshots = 0xFF; scan++; scan_tree(argv[i] + 12, repo_config); } -- cgit v1.2.3-70-g09d2