Diff options
authorBryce Kwon <bryce@brycekwon.com>
committerBryce Kwon <bryce@brycekwon.com>
commit
parent
tree
download
Move cgit.c's own helpers out of shared.c
Diffstat (limited to '')
-rw-r--r--source/cgit.c84
1 file changed, 78 insertions, 6 deletions
diff --git a/source/cgit.c b/source/cgit.c
index dd90fed..3ae895d 100644
--- a/source/cgit.c
+++ b/source/cgit.c
@@ -86,6 +86,13 @@ static NORETURN void die_routine(const char *msg, va_list params)
exit(0);
}
+static char *ensure_end(const char *str, char c)
+{
+ size_t len = strlen(str);
+
+ return len && str[len - 1] == c ? xstrdup(str) : xstrfmt("%s%c", str, c);
+}
+
static void prepare_context(void)
{
const char *script_name = getenv("SCRIPT_NAME");
@@ -154,7 +161,7 @@ static void prepare_context(void)
string_list_init_dup(&ctx.cfg.mimetypes);
if (script_name)
ctx.cfg.script_name = xstrdup(script_name);
- ctx.cfg.virtual_root = cgit_ensure_end(ctx.cfg.script_name, '/');
+ ctx.cfg.virtual_root = ensure_end(ctx.cfg.script_name, '/');
if (ctx.env.query_string)
ctx.qry.raw = xstrdup(ctx.env.query_string);
if (!ctx.env.cgit_config)
@@ -463,6 +470,46 @@ static void add_mimetype(const char *name, const char *value)
item->util = xstrdup(value);
}
+/*
+ * Accept only the date formats cgit documents, leaving mode unchanged for
+ * anything else. Git's parse_date_format dies on anything unknown, which would
+ * turn a cgitrc typo into a failed request.
+ */
+static void parse_date_setting(const char *format, struct date_mode *mode)
+{
+ static const char * const names[] = {
+ "default", "human", "iso", "iso-strict", "iso8601",
+ "iso8601-strict", "raw", "relative", "rfc",
+ "rfc2822", "short", "unix",
+ };
+ const char *rest;
+ size_t i;
+
+ if (skip_prefix(format, "format:", &rest)) {
+ // An empty strftime format would render every date blank.
+ if (*rest)
+ parse_date_format(format, mode);
+ return;
+ }
+
+ // git reads local only as a whole alias of default-local, and dies on
+ // it with a suffix of its own.
+ if (!strcmp(format, "local")) {
+ parse_date_format(format, mode);
+ return;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(names); i++) {
+ if (!skip_prefix(format, names[i], &rest))
+ continue;
+ // "iso" also prefixes "iso8601", so a partial hit is skipped.
+ if (*rest && strcmp(rest, "-local"))
+ continue;
+ parse_date_format(format, mode);
+ return;
+ }
+}
+
static void apply_config(const char *name, const char *value)
{
const char *arg;
@@ -504,7 +551,7 @@ static void apply_config(const char *name, const char *value)
else if (!strcmp(name, "strict-export"))
ctx.cfg.strict_export = cgit_strdup_first_line(value);
else if (!strcmp(name, "virtual-root"))
- ctx.cfg.virtual_root = cgit_ensure_end(value, '/');
+ ctx.cfg.virtual_root = ensure_end(value, '/');
else if (!strcmp(name, "enable-plain-email"))
ctx.cfg.enable_plain_email = atoi(value);
else if (!strcmp(name, "enable-header"))
@@ -656,7 +703,7 @@ static void apply_config(const char *name, const char *value)
else if (!strcmp(name, "local-time"))
ctx.cfg.local_time = atoi(value);
else if (!strcmp(name, "date-format"))
- cgit_parse_date_format(value, &ctx.cfg.date_mode);
+ parse_date_setting(value, &ctx.cfg.date_mode);
else if (!strcmp(name, "commit-sort")) {
if (!strcmp(value, "date"))
ctx.cfg.commit_sort = 1;
@@ -1024,6 +1071,31 @@ static void choose_readme(struct cgit_repo *repo)
string_list_append(&repo->readme, filename)->util = ref;
}
+/*
+ * Export the CGIT_REPO_* variables that filters and hooks read.
+ */
+static void prepare_repo_env(struct cgit_repo *repo)
+{
+ const struct {
+ const char *name;
+ const char *value;
+ } vars[] = {
+ { .name = "CGIT_REPO_URL", .value = repo->url },
+ { .name = "CGIT_REPO_NAME", .value = repo->name },
+ { .name = "CGIT_REPO_PATH", .value = repo->path },
+ { .name = "CGIT_REPO_OWNER", .value = repo->owner },
+ { .name = "CGIT_REPO_DEFBRANCH", .value = repo->defbranch },
+ { .name = "CGIT_REPO_SECTION", .value = repo->section },
+ { .name = "CGIT_REPO_CLONE_URL", .value = repo->clone_url }
+ };
+ size_t i;
+
+ for (i = 0; i < ARRAY_SIZE(vars); i++)
+ if (vars[i].value && setenv(vars[i].name, vars[i].value, 1))
+ fprintf(stderr, "[cgit] Unable to set %s=%s: %s (%d)\n",
+ vars[i].name, vars[i].value, strerror(errno), errno);
+}
+
static void open_repo(int *nongit, int *err)
{
// A repository configured without a path has nothing to open.
@@ -1085,14 +1157,14 @@ static int prepare_repo_cmd(int nongit, int err, int clone)
// The dumb transport serves refs and objects off the disk and
// asks nothing of the head, and an empty repository clones.
if (clone) {
- cgit_prepare_repo_env(ctx.repo);
+ prepare_repo_env(ctx.repo);
return 0;
}
ctx.empty_repo = 1;
// Before the document starts, since the <head> carries
// <link rel='vcs-git'> and those clone urls expand macros such
// as $CGIT_REPO_URL out of this environment.
- cgit_prepare_repo_env(ctx.repo);
+ prepare_repo_env(ctx.repo);
cgit_print_layout_start();
cgit_print_empty_repo();
cgit_print_layout_end();
@@ -1116,7 +1188,7 @@ static int prepare_repo_cmd(int nongit, int err, int clone)
return 1;
}
string_list_sort(&ctx.repo->submodules);
- cgit_prepare_repo_env(ctx.repo);
+ prepare_repo_env(ctx.repo);
choose_readme(ctx.repo);
return 0;
}