Merge branch 'fh/filter-api'
Conflicts: cgit.c
This commit is contained in:
commit
ab350a77b1
27
cgit.c
27
cgit.c
@ -26,14 +26,27 @@ void add_mimetype(const char *name, const char *value)
|
|||||||
item->util = xstrdup(value);
|
item->util = xstrdup(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cgit_filter *new_filter(const char *cmd, int extra_args)
|
struct cgit_filter *new_filter(const char *cmd, filter_type filtertype)
|
||||||
{
|
{
|
||||||
struct cgit_filter *f;
|
struct cgit_filter *f;
|
||||||
int args_size = 0;
|
int args_size = 0;
|
||||||
|
int extra_args;
|
||||||
|
|
||||||
if (!cmd || !cmd[0])
|
if (!cmd || !cmd[0])
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
switch (filtertype) {
|
||||||
|
case SOURCE:
|
||||||
|
extra_args = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ABOUT:
|
||||||
|
case COMMIT:
|
||||||
|
default:
|
||||||
|
extra_args = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
f = xmalloc(sizeof(struct cgit_filter));
|
f = xmalloc(sizeof(struct cgit_filter));
|
||||||
f->cmd = xstrdup(cmd);
|
f->cmd = xstrdup(cmd);
|
||||||
args_size = (2 + extra_args) * sizeof(char *);
|
args_size = (2 + extra_args) * sizeof(char *);
|
||||||
@ -83,11 +96,11 @@ void repo_config(struct cgit_repo *repo, const char *name, const char *value)
|
|||||||
repo->logo_link = xstrdup(value);
|
repo->logo_link = xstrdup(value);
|
||||||
else if (ctx.cfg.enable_filter_overrides) {
|
else if (ctx.cfg.enable_filter_overrides) {
|
||||||
if (!strcmp(name, "about-filter"))
|
if (!strcmp(name, "about-filter"))
|
||||||
repo->about_filter = new_filter(value, 0);
|
repo->about_filter = new_filter(value, ABOUT);
|
||||||
else if (!strcmp(name, "commit-filter"))
|
else if (!strcmp(name, "commit-filter"))
|
||||||
repo->commit_filter = new_filter(value, 0);
|
repo->commit_filter = new_filter(value, COMMIT);
|
||||||
else if (!strcmp(name, "source-filter"))
|
else if (!strcmp(name, "source-filter"))
|
||||||
repo->source_filter = new_filter(value, 1);
|
repo->source_filter = new_filter(value, SOURCE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -180,9 +193,9 @@ void config_cb(const char *name, const char *value)
|
|||||||
else if (!strcmp(name, "cache-dynamic-ttl"))
|
else if (!strcmp(name, "cache-dynamic-ttl"))
|
||||||
ctx.cfg.cache_dynamic_ttl = atoi(value);
|
ctx.cfg.cache_dynamic_ttl = atoi(value);
|
||||||
else if (!strcmp(name, "about-filter"))
|
else if (!strcmp(name, "about-filter"))
|
||||||
ctx.cfg.about_filter = new_filter(value, 0);
|
ctx.cfg.about_filter = new_filter(value, ABOUT);
|
||||||
else if (!strcmp(name, "commit-filter"))
|
else if (!strcmp(name, "commit-filter"))
|
||||||
ctx.cfg.commit_filter = new_filter(value, 0);
|
ctx.cfg.commit_filter = new_filter(value, COMMIT);
|
||||||
else if (!strcmp(name, "embedded"))
|
else if (!strcmp(name, "embedded"))
|
||||||
ctx.cfg.embedded = atoi(value);
|
ctx.cfg.embedded = atoi(value);
|
||||||
else if (!strcmp(name, "max-atom-items"))
|
else if (!strcmp(name, "max-atom-items"))
|
||||||
@ -212,7 +225,7 @@ void config_cb(const char *name, const char *value)
|
|||||||
else if (!strcmp(name, "section-from-path"))
|
else if (!strcmp(name, "section-from-path"))
|
||||||
ctx.cfg.section_from_path = atoi(value);
|
ctx.cfg.section_from_path = atoi(value);
|
||||||
else if (!strcmp(name, "source-filter"))
|
else if (!strcmp(name, "source-filter"))
|
||||||
ctx.cfg.source_filter = new_filter(value, 1);
|
ctx.cfg.source_filter = new_filter(value, SOURCE);
|
||||||
else if (!strcmp(name, "summary-log"))
|
else if (!strcmp(name, "summary-log"))
|
||||||
ctx.cfg.summary_log = atoi(value);
|
ctx.cfg.summary_log = atoi(value);
|
||||||
else if (!strcmp(name, "summary-branches"))
|
else if (!strcmp(name, "summary-branches"))
|
||||||
|
6
cgit.h
6
cgit.h
@ -51,6 +51,10 @@ typedef void (*configfn)(const char *name, const char *value);
|
|||||||
typedef void (*filepair_fn)(struct diff_filepair *pair);
|
typedef void (*filepair_fn)(struct diff_filepair *pair);
|
||||||
typedef void (*linediff_fn)(char *line, int len);
|
typedef void (*linediff_fn)(char *line, int len);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ABOUT, COMMIT, SOURCE
|
||||||
|
} filter_type;
|
||||||
|
|
||||||
struct cgit_filter {
|
struct cgit_filter {
|
||||||
char *cmd;
|
char *cmd;
|
||||||
char **argv;
|
char **argv;
|
||||||
@ -315,7 +319,7 @@ extern const char *cgit_repobasename(const char *reponame);
|
|||||||
|
|
||||||
extern int cgit_parse_snapshots_mask(const char *str);
|
extern int cgit_parse_snapshots_mask(const char *str);
|
||||||
|
|
||||||
extern int cgit_open_filter(struct cgit_filter *filter);
|
extern int cgit_open_filter(struct cgit_filter *filter, struct cgit_repo * repo);
|
||||||
extern int cgit_close_filter(struct cgit_filter *filter);
|
extern int cgit_close_filter(struct cgit_filter *filter);
|
||||||
|
|
||||||
extern int readfile(const char *path, char **buf, size_t *size);
|
extern int readfile(const char *path, char **buf, size_t *size);
|
||||||
|
47
cgitrc.5.txt
47
cgitrc.5.txt
@ -31,7 +31,7 @@ about-filter::
|
|||||||
about pages (both top-level and for each repository). The command will
|
about pages (both top-level and for each repository). The command will
|
||||||
get the content of the about-file on its STDIN, and the STDOUT from the
|
get the content of the about-file on its STDIN, and the STDOUT from the
|
||||||
command will be included verbatim on the about page. Default value:
|
command will be included verbatim on the about page. Default value:
|
||||||
none.
|
none. See also: "FILTER API".
|
||||||
|
|
||||||
agefile::
|
agefile::
|
||||||
Specifies a path, relative to each repository path, which can be used
|
Specifies a path, relative to each repository path, which can be used
|
||||||
@ -81,6 +81,7 @@ commit-filter::
|
|||||||
The command will get the message on its STDIN, and the STDOUT from the
|
The command will get the message on its STDIN, and the STDOUT from the
|
||||||
command will be included verbatim as the commit message, i.e. this can
|
command will be included verbatim as the commit message, i.e. this can
|
||||||
be used to implement bugtracker integration. Default value: none.
|
be used to implement bugtracker integration. Default value: none.
|
||||||
|
See also: "FILTER API".
|
||||||
|
|
||||||
css::
|
css::
|
||||||
Url which specifies the css document to include in all cgit pages.
|
Url which specifies the css document to include in all cgit pages.
|
||||||
@ -323,7 +324,7 @@ source-filter::
|
|||||||
and the name of the blob as its only command line argument. The STDOUT
|
and the name of the blob as its only command line argument. The STDOUT
|
||||||
from the command will be included verbatim as the blob contents, i.e.
|
from the command will be included verbatim as the blob contents, i.e.
|
||||||
this can be used to implement e.g. syntax highlighting. Default value:
|
this can be used to implement e.g. syntax highlighting. Default value:
|
||||||
none.
|
none. See also: "FILTER API".
|
||||||
|
|
||||||
summary-branches::
|
summary-branches::
|
||||||
Specifies the number of branches to display in the repository "summary"
|
Specifies the number of branches to display in the repository "summary"
|
||||||
@ -356,7 +357,7 @@ REPOSITORY SETTINGS
|
|||||||
-------------------
|
-------------------
|
||||||
repo.about-filter::
|
repo.about-filter::
|
||||||
Override the default about-filter. Default value: none. See also:
|
Override the default about-filter. Default value: none. See also:
|
||||||
"enable-filter-overrides".
|
"enable-filter-overrides". See also: "FILTER API".
|
||||||
|
|
||||||
repo.clone-url::
|
repo.clone-url::
|
||||||
A list of space-separated urls which can be used to clone this repo.
|
A list of space-separated urls which can be used to clone this repo.
|
||||||
@ -364,7 +365,7 @@ repo.clone-url::
|
|||||||
|
|
||||||
repo.commit-filter::
|
repo.commit-filter::
|
||||||
Override the default commit-filter. Default value: none. See also:
|
Override the default commit-filter. Default value: none. See also:
|
||||||
"enable-filter-overrides".
|
"enable-filter-overrides". See also: "FILTER API".
|
||||||
|
|
||||||
repo.defbranch::
|
repo.defbranch::
|
||||||
The name of the default branch for this repository. If no such branch
|
The name of the default branch for this repository. If no such branch
|
||||||
@ -435,7 +436,7 @@ repo.section::
|
|||||||
|
|
||||||
repo.source-filter::
|
repo.source-filter::
|
||||||
Override the default source-filter. Default value: none. See also:
|
Override the default source-filter. Default value: none. See also:
|
||||||
"enable-filter-overrides".
|
"enable-filter-overrides". See also: "FILTER API".
|
||||||
|
|
||||||
repo.url::
|
repo.url::
|
||||||
The relative url used to access the repository. This must be the first
|
The relative url used to access the repository. This must be the first
|
||||||
@ -455,6 +456,42 @@ Note: the "repo." prefix is dropped from the option names in repo-specific
|
|||||||
config files, e.g. "repo.desc" becomes "desc".
|
config files, e.g. "repo.desc" becomes "desc".
|
||||||
|
|
||||||
|
|
||||||
|
FILTER API
|
||||||
|
----------
|
||||||
|
- about filter::
|
||||||
|
This filter is given no arguments.
|
||||||
|
The about text that is to be filtered is available on standard input and the
|
||||||
|
filtered text is expected on standard output.
|
||||||
|
- commit filter::
|
||||||
|
This filter is given no arguments.
|
||||||
|
The commit message text that is to be filtered is available on standard input
|
||||||
|
and the filtered text is expected on standard output.
|
||||||
|
- source filter::
|
||||||
|
This filter is given a single parameter: the filename of the source file to
|
||||||
|
filter. The filter can use the filename to determine (for example) the syntax
|
||||||
|
highlighting mode.
|
||||||
|
The contents of the source file that is to be filtered is available on
|
||||||
|
standard input and the filtered contents is expected on standard output.
|
||||||
|
|
||||||
|
Also, all filters are handed the following environment variables:
|
||||||
|
- CGIT_REPO_URL ( = repo.url setting )
|
||||||
|
- CGIT_REPO_NAME ( = repo.name setting )
|
||||||
|
- CGIT_REPO_PATH ( = repo.path setting )
|
||||||
|
- CGIT_REPO_OWNER ( = repo.owner setting )
|
||||||
|
- CGIT_REPO_DEFBRANCH ( = repo.defbranch setting )
|
||||||
|
- CGIT_REPO_SECTION ( = section setting )
|
||||||
|
- CGIT_REPO_CLONE_URL ( = repo.clone-url setting )
|
||||||
|
|
||||||
|
If a setting is not defined for a repository and the corresponding global
|
||||||
|
setting is also not defined (if applicable), then the corresponding
|
||||||
|
environment variable will be an empty string.
|
||||||
|
|
||||||
|
Note that under normal circumstance all these environment variables are
|
||||||
|
defined. If however the total size of the defined settings exceed the
|
||||||
|
allocated buffer within cgit then only the environment variables that fit
|
||||||
|
in the allocated buffer are handed to the filter.
|
||||||
|
|
||||||
|
|
||||||
EXAMPLE CGITRC FILE
|
EXAMPLE CGITRC FILE
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
|
@ -3,6 +3,17 @@
|
|||||||
#
|
#
|
||||||
# To use this script, refer to this file with either the commit-filter or the
|
# To use this script, refer to this file with either the commit-filter or the
|
||||||
# repo.commit-filter options in cgitrc.
|
# repo.commit-filter options in cgitrc.
|
||||||
|
#
|
||||||
|
# The following environment variables can be used to retrieve the configuration
|
||||||
|
# of the repository for which this script is called:
|
||||||
|
# CGIT_REPO_URL ( = repo.url setting )
|
||||||
|
# CGIT_REPO_NAME ( = repo.name setting )
|
||||||
|
# CGIT_REPO_PATH ( = repo.path setting )
|
||||||
|
# CGIT_REPO_OWNER ( = repo.owner setting )
|
||||||
|
# CGIT_REPO_DEFBRANCH ( = repo.defbranch setting )
|
||||||
|
# CGIT_REPO_SECTION ( = section setting )
|
||||||
|
# CGIT_REPO_CLONE_URL ( = repo.clone-url setting )
|
||||||
|
#
|
||||||
|
|
||||||
# This expression generates links to commits referenced by their SHA1.
|
# This expression generates links to commits referenced by their SHA1.
|
||||||
regex=$regex'
|
regex=$regex'
|
||||||
|
@ -23,6 +23,17 @@
|
|||||||
# table.blob .kwb { color:#830000; }
|
# table.blob .kwb { color:#830000; }
|
||||||
# table.blob .kwc { color:#000000; font-weight:bold; }
|
# table.blob .kwc { color:#000000; font-weight:bold; }
|
||||||
# table.blob .kwd { color:#010181; }
|
# table.blob .kwd { color:#010181; }
|
||||||
|
#
|
||||||
|
# The following environment variables can be used to retrieve the configuration
|
||||||
|
# of the repository for which this script is called:
|
||||||
|
# CGIT_REPO_URL ( = repo.url setting )
|
||||||
|
# CGIT_REPO_NAME ( = repo.name setting )
|
||||||
|
# CGIT_REPO_PATH ( = repo.path setting )
|
||||||
|
# CGIT_REPO_OWNER ( = repo.owner setting )
|
||||||
|
# CGIT_REPO_DEFBRANCH ( = repo.defbranch setting )
|
||||||
|
# CGIT_REPO_SECTION ( = section setting )
|
||||||
|
# CGIT_REPO_CLONE_URL ( = repo.clone-url setting )
|
||||||
|
#
|
||||||
|
|
||||||
# store filename and extension in local vars
|
# store filename and extension in local vars
|
||||||
BASENAME="$1"
|
BASENAME="$1"
|
||||||
|
32
shared.c
32
shared.c
@ -7,6 +7,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cgit.h"
|
#include "cgit.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <linux/limits.h>
|
||||||
|
|
||||||
struct cgit_repolist cgit_repolist;
|
struct cgit_repolist cgit_repolist;
|
||||||
struct cgit_context ctx;
|
struct cgit_context ctx;
|
||||||
@ -367,7 +369,33 @@ int cgit_parse_snapshots_mask(const char *str)
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cgit_open_filter(struct cgit_filter *filter)
|
typedef struct {
|
||||||
|
char * name;
|
||||||
|
char * value;
|
||||||
|
} cgit_env_var;
|
||||||
|
|
||||||
|
static void prepare_env(struct cgit_repo * repo) {
|
||||||
|
cgit_env_var env_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 }
|
||||||
|
};
|
||||||
|
int env_var_count = ARRAY_SIZE(env_vars);
|
||||||
|
cgit_env_var *p, *q;
|
||||||
|
static char *warn = "cgit warning: failed to set env: %s=%s\n";
|
||||||
|
|
||||||
|
p = env_vars;
|
||||||
|
q = p + env_var_count;
|
||||||
|
for (; p < q; p++)
|
||||||
|
if (setenv(p->name, p->value, 1))
|
||||||
|
fprintf(stderr, warn, p->name, p->value);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cgit_open_filter(struct cgit_filter *filter, struct cgit_repo * repo)
|
||||||
{
|
{
|
||||||
|
|
||||||
filter->old_stdout = chk_positive(dup(STDOUT_FILENO),
|
filter->old_stdout = chk_positive(dup(STDOUT_FILENO),
|
||||||
@ -378,6 +406,8 @@ int cgit_open_filter(struct cgit_filter *filter)
|
|||||||
close(filter->pipe_fh[1]);
|
close(filter->pipe_fh[1]);
|
||||||
chk_non_negative(dup2(filter->pipe_fh[0], STDIN_FILENO),
|
chk_non_negative(dup2(filter->pipe_fh[0], STDIN_FILENO),
|
||||||
"Unable to use pipe as STDIN");
|
"Unable to use pipe as STDIN");
|
||||||
|
if (repo)
|
||||||
|
prepare_env(repo);
|
||||||
execvp(filter->cmd, filter->argv);
|
execvp(filter->cmd, filter->argv);
|
||||||
die("Unable to exec subprocess %s: %s (%d)", filter->cmd,
|
die("Unable to exec subprocess %s: %s (%d)", filter->cmd,
|
||||||
strerror(errno), errno);
|
strerror(errno), errno);
|
||||||
|
@ -110,7 +110,7 @@ void cgit_print_commit(char *hex, const char *prefix)
|
|||||||
html("</table>\n");
|
html("</table>\n");
|
||||||
html("<div class='commit-subject'>");
|
html("<div class='commit-subject'>");
|
||||||
if (ctx.repo->commit_filter)
|
if (ctx.repo->commit_filter)
|
||||||
cgit_open_filter(ctx.repo->commit_filter);
|
cgit_open_filter(ctx.repo->commit_filter, ctx.repo);
|
||||||
html_txt(info->subject);
|
html_txt(info->subject);
|
||||||
if (ctx.repo->commit_filter)
|
if (ctx.repo->commit_filter)
|
||||||
cgit_close_filter(ctx.repo->commit_filter);
|
cgit_close_filter(ctx.repo->commit_filter);
|
||||||
@ -118,7 +118,7 @@ void cgit_print_commit(char *hex, const char *prefix)
|
|||||||
html("</div>");
|
html("</div>");
|
||||||
html("<div class='commit-msg'>");
|
html("<div class='commit-msg'>");
|
||||||
if (ctx.repo->commit_filter)
|
if (ctx.repo->commit_filter)
|
||||||
cgit_open_filter(ctx.repo->commit_filter);
|
cgit_open_filter(ctx.repo->commit_filter, ctx.repo);
|
||||||
html_txt(info->msg);
|
html_txt(info->msg);
|
||||||
if (ctx.repo->commit_filter)
|
if (ctx.repo->commit_filter)
|
||||||
cgit_close_filter(ctx.repo->commit_filter);
|
cgit_close_filter(ctx.repo->commit_filter);
|
||||||
@ -127,7 +127,7 @@ void cgit_print_commit(char *hex, const char *prefix)
|
|||||||
html("<div class='notes-header'>Notes</div>");
|
html("<div class='notes-header'>Notes</div>");
|
||||||
html("<div class='notes'>");
|
html("<div class='notes'>");
|
||||||
if (ctx.repo->commit_filter)
|
if (ctx.repo->commit_filter)
|
||||||
cgit_open_filter(ctx.repo->commit_filter);
|
cgit_open_filter(ctx.repo->commit_filter, ctx.repo);
|
||||||
html_txt(notes.buf);
|
html_txt(notes.buf);
|
||||||
if (ctx.repo->commit_filter)
|
if (ctx.repo->commit_filter)
|
||||||
cgit_close_filter(ctx.repo->commit_filter);
|
cgit_close_filter(ctx.repo->commit_filter);
|
||||||
|
@ -291,7 +291,7 @@ void cgit_print_site_readme()
|
|||||||
if (!ctx.cfg.root_readme)
|
if (!ctx.cfg.root_readme)
|
||||||
return;
|
return;
|
||||||
if (ctx.cfg.about_filter)
|
if (ctx.cfg.about_filter)
|
||||||
cgit_open_filter(ctx.cfg.about_filter);
|
cgit_open_filter(ctx.cfg.about_filter, NULL);
|
||||||
html_include(ctx.cfg.root_readme);
|
html_include(ctx.cfg.root_readme);
|
||||||
if (ctx.cfg.about_filter)
|
if (ctx.cfg.about_filter)
|
||||||
cgit_close_filter(ctx.cfg.about_filter);
|
cgit_close_filter(ctx.cfg.about_filter);
|
||||||
|
@ -19,7 +19,7 @@ static int write_compressed_tar_archive(struct archiver_args *args,const char *f
|
|||||||
f.argv = malloc(2 * sizeof(char *));
|
f.argv = malloc(2 * sizeof(char *));
|
||||||
f.argv[0] = f.cmd;
|
f.argv[0] = f.cmd;
|
||||||
f.argv[1] = NULL;
|
f.argv[1] = NULL;
|
||||||
cgit_open_filter(&f);
|
cgit_open_filter(&f, NULL);
|
||||||
rv = write_tar_archive(args);
|
rv = write_tar_archive(args);
|
||||||
cgit_close_filter(&f);
|
cgit_close_filter(&f);
|
||||||
return rv;
|
return rv;
|
||||||
|
@ -113,7 +113,7 @@ void cgit_print_repo_readme(char *path)
|
|||||||
*/
|
*/
|
||||||
html("<div id='summary'>");
|
html("<div id='summary'>");
|
||||||
if (ctx.repo->about_filter)
|
if (ctx.repo->about_filter)
|
||||||
cgit_open_filter(ctx.repo->about_filter);
|
cgit_open_filter(ctx.repo->about_filter, ctx.repo);
|
||||||
if (ref)
|
if (ref)
|
||||||
cgit_print_file(tmp, ref);
|
cgit_print_file(tmp, ref);
|
||||||
else
|
else
|
||||||
|
@ -45,7 +45,7 @@ static void print_text_buffer(const char *name, char *buf, unsigned long size)
|
|||||||
if (ctx.repo->source_filter) {
|
if (ctx.repo->source_filter) {
|
||||||
html("<td class='lines'><pre><code>");
|
html("<td class='lines'><pre><code>");
|
||||||
ctx.repo->source_filter->argv[1] = xstrdup(name);
|
ctx.repo->source_filter->argv[1] = xstrdup(name);
|
||||||
cgit_open_filter(ctx.repo->source_filter);
|
cgit_open_filter(ctx.repo->source_filter, ctx.repo);
|
||||||
html_raw(buf, size);
|
html_raw(buf, size);
|
||||||
cgit_close_filter(ctx.repo->source_filter);
|
cgit_close_filter(ctx.repo->source_filter);
|
||||||
free(ctx.repo->source_filter->argv[1]);
|
free(ctx.repo->source_filter->argv[1]);
|
||||||
|
Loading…
Reference in New Issue
Block a user