about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorLars Hjemli2011-05-23 23:28:38 +0200
committerLars Hjemli2011-05-23 23:28:38 +0200
commitab350a77b1d3b0e251cc28329f2e16f0566e521e (patch)
tree1af2b0760858fcd87ce1e628465f9b60af7815e3
parentMerge branch 'stable' (diff)
parentshared.c: use execvp() to execute filter commands (diff)
downloadcgit-ab350a77b1d3b0e251cc28329f2e16f0566e521e.tar.gz
cgit-ab350a77b1d3b0e251cc28329f2e16f0566e521e.zip
Merge branch 'fh/filter-api'
Conflicts:
	cgit.c
-rw-r--r--cgit.c27
-rw-r--r--cgit.h6
-rw-r--r--cgitrc.5.txt47
-rwxr-xr-xfilters/commit-links.sh11
-rwxr-xr-xfilters/syntax-highlighting.sh11
-rw-r--r--shared.c32
-rw-r--r--ui-commit.c6
-rw-r--r--ui-repolist.c2
-rw-r--r--ui-snapshot.c2
-rw-r--r--ui-summary.c2
-rw-r--r--ui-tree.c2
11 files changed, 127 insertions, 21 deletions
diff --git a/cgit.c b/cgit.c index eb964ac..6be3754 100644 --- a/cgit.c +++ b/cgit.c
@@ -26,14 +26,27 @@ void add_mimetype(const char *name, const char *value)
26 item->util = xstrdup(value); 26 item->util = xstrdup(value);
27} 27}
28 28
29struct cgit_filter *new_filter(const char *cmd, int extra_args) 29struct cgit_filter *new_filter(const char *cmd, filter_type filtertype)
30{ 30{
31 struct cgit_filter *f; 31 struct cgit_filter *f;
32 int args_size = 0; 32 int args_size = 0;
33 int extra_args;
33 34
34 if (!cmd || !cmd[0]) 35 if (!cmd || !cmd[0])
35 return NULL; 36 return NULL;
36 37
38 switch (filtertype) {
39 case SOURCE:
40 extra_args = 1;
41 break;
42
43 case ABOUT:
44 case COMMIT:
45 default:
46 extra_args = 0;
47 break;
48 }
49
37 f = xmalloc(sizeof(struct cgit_filter)); 50 f = xmalloc(sizeof(struct cgit_filter));
38 f->cmd = xstrdup(cmd); 51 f->cmd = xstrdup(cmd);
39 args_size = (2 + extra_args) * sizeof(char *); 52 args_size = (2 + extra_args) * sizeof(char *);
@@ -83,11 +96,11 @@ void repo_config(struct cgit_repo *repo, const char *name, const char *value)
83 repo->logo_link = xstrdup(value); 96 repo->logo_link = xstrdup(value);
84 else if (ctx.cfg.enable_filter_overrides) { 97 else if (ctx.cfg.enable_filter_overrides) {
85 if (!strcmp(name, "about-filter")) 98 if (!strcmp(name, "about-filter"))
86 repo->about_filter = new_filter(value, 0); 99 repo->about_filter = new_filter(value, ABOUT);
87 else if (!strcmp(name, "commit-filter")) 100 else if (!strcmp(name, "commit-filter"))
88 repo->commit_filter = new_filter(value, 0); 101 repo->commit_filter = new_filter(value, COMMIT);
89 else if (!strcmp(name, "source-filter")) 102 else if (!strcmp(name, "source-filter"))
90 repo->source_filter = new_filter(value, 1); 103 repo->source_filter = new_filter(value, SOURCE);
91 } 104 }
92} 105}
93 106
@@ -180,9 +193,9 @@ void config_cb(const char *name, const char *value)
180 else if (!strcmp(name, "cache-dynamic-ttl")) 193 else if (!strcmp(name, "cache-dynamic-ttl"))
181 ctx.cfg.cache_dynamic_ttl = atoi(value); 194 ctx.cfg.cache_dynamic_ttl = atoi(value);
182 else if (!strcmp(name, "about-filter")) 195 else if (!strcmp(name, "about-filter"))
183 ctx.cfg.about_filter = new_filter(value, 0); 196 ctx.cfg.about_filter = new_filter(value, ABOUT);
184 else if (!strcmp(name, "commit-filter")) 197 else if (!strcmp(name, "commit-filter"))
185 ctx.cfg.commit_filter = new_filter(value, 0); 198 ctx.cfg.commit_filter = new_filter(value, COMMIT);
186 else if (!strcmp(name, "embedded")) 199 else if (!strcmp(name, "embedded"))
187 ctx.cfg.embedded = atoi(value); 200 ctx.cfg.embedded = atoi(value);
188 else if (!strcmp(name, "max-atom-items")) 201 else if (!strcmp(name, "max-atom-items"))
@@ -212,7 +225,7 @@ void config_cb(const char *name, const char *value)
212 else if (!strcmp(name, "section-from-path")) 225 else if (!strcmp(name, "section-from-path"))
213 ctx.cfg.section_from_path = atoi(value); 226 ctx.cfg.section_from_path = atoi(value);
214 else if (!strcmp(name, "source-filter")) 227 else if (!strcmp(name, "source-filter"))
215 ctx.cfg.source_filter = new_filter(value, 1); 228 ctx.cfg.source_filter = new_filter(value, SOURCE);
216 else if (!strcmp(name, "summary-log")) 229 else if (!strcmp(name, "summary-log"))
217 ctx.cfg.summary_log = atoi(value); 230 ctx.cfg.summary_log = atoi(value);
218 else if (!strcmp(name, "summary-branches")) 231 else if (!strcmp(name, "summary-branches"))
diff --git a/cgit.h b/cgit.h index ecae453..caa9d8e 100644 --- a/cgit.h +++ b/cgit.h
@@ -51,6 +51,10 @@ typedef void (*configfn)(const char *name, const char *value);
51typedef void (*filepair_fn)(struct diff_filepair *pair); 51typedef void (*filepair_fn)(struct diff_filepair *pair);
52typedef void (*linediff_fn)(char *line, int len); 52typedef void (*linediff_fn)(char *line, int len);
53 53
54typedef enum {
55 ABOUT, COMMIT, SOURCE
56} filter_type;
57
54struct cgit_filter { 58struct cgit_filter {
55 char *cmd; 59 char *cmd;
56 char **argv; 60 char **argv;
@@ -315,7 +319,7 @@ extern const char *cgit_repobasename(const char *reponame);
315 319
316extern int cgit_parse_snapshots_mask(const char *str); 320extern int cgit_parse_snapshots_mask(const char *str);
317 321
318extern int cgit_open_filter(struct cgit_filter *filter); 322extern int cgit_open_filter(struct cgit_filter *filter, struct cgit_repo * repo);
319extern int cgit_close_filter(struct cgit_filter *filter); 323extern int cgit_close_filter(struct cgit_filter *filter);
320 324
321extern int readfile(const char *path, char **buf, size_t *size); 325extern int readfile(const char *path, char **buf, size_t *size);
diff --git a/cgitrc.5.txt b/cgitrc.5.txt index 875d51f..5903a93 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt
@@ -31,7 +31,7 @@ about-filter::
31 about pages (both top-level and for each repository). The command will 31 about pages (both top-level and for each repository). The command will
32 get the content of the about-file on its STDIN, and the STDOUT from the 32 get the content of the about-file on its STDIN, and the STDOUT from the
33 command will be included verbatim on the about page. Default value: 33 command will be included verbatim on the about page. Default value:
34 none. 34 none. See also: "FILTER API".
35 35
36agefile:: 36agefile::
37 Specifies a path, relative to each repository path, which can be used 37 Specifies a path, relative to each repository path, which can be used
@@ -81,6 +81,7 @@ commit-filter::
81 The command will get the message on its STDIN, and the STDOUT from the 81 The command will get the message on its STDIN, and the STDOUT from the
82 command will be included verbatim as the commit message, i.e. this can 82 command will be included verbatim as the commit message, i.e. this can
83 be used to implement bugtracker integration. Default value: none. 83 be used to implement bugtracker integration. Default value: none.
84 See also: "FILTER API".
84 85
85css:: 86css::
86 Url which specifies the css document to include in all cgit pages. 87 Url which specifies the css document to include in all cgit pages.
@@ -323,7 +324,7 @@ source-filter::
323 and the name of the blob as its only command line argument. The STDOUT 324 and the name of the blob as its only command line argument. The STDOUT
324 from the command will be included verbatim as the blob contents, i.e. 325 from the command will be included verbatim as the blob contents, i.e.
325 this can be used to implement e.g. syntax highlighting. Default value: 326 this can be used to implement e.g. syntax highlighting. Default value:
326 none. 327 none. See also: "FILTER API".
327 328
328summary-branches:: 329summary-branches::
329 Specifies the number of branches to display in the repository "summary" 330 Specifies the number of branches to display in the repository "summary"
@@ -356,7 +357,7 @@ REPOSITORY SETTINGS
356------------------- 357-------------------
357repo.about-filter:: 358repo.about-filter::
358 Override the default about-filter. Default value: none. See also: 359 Override the default about-filter. Default value: none. See also:
359 "enable-filter-overrides". 360 "enable-filter-overrides". See also: "FILTER API".
360 361
361repo.clone-url:: 362repo.clone-url::
362 A list of space-separated urls which can be used to clone this repo. 363 A list of space-separated urls which can be used to clone this repo.
@@ -364,7 +365,7 @@ repo.clone-url::
364 365
365repo.commit-filter:: 366repo.commit-filter::
366 Override the default commit-filter. Default value: none. See also: 367 Override the default commit-filter. Default value: none. See also:
367 "enable-filter-overrides". 368 "enable-filter-overrides". See also: "FILTER API".
368 369
369repo.defbranch:: 370repo.defbranch::
370 The name of the default branch for this repository. If no such branch 371 The name of the default branch for this repository. If no such branch
@@ -435,7 +436,7 @@ repo.section::
435 436
436repo.source-filter:: 437repo.source-filter::
437 Override the default source-filter. Default value: none. See also: 438 Override the default source-filter. Default value: none. See also:
438 "enable-filter-overrides". 439 "enable-filter-overrides". See also: "FILTER API".
439 440
440repo.url:: 441repo.url::
441 The relative url used to access the repository. This must be the first 442 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
455config files, e.g. "repo.desc" becomes "desc". 456config files, e.g. "repo.desc" becomes "desc".
456 457
457 458
459FILTER API
460----------
461- about filter::
462 This filter is given no arguments.
463 The about text that is to be filtered is available on standard input and the
464 filtered text is expected on standard output.
465- commit filter::
466 This filter is given no arguments.
467 The commit message text that is to be filtered is available on standard input
468 and the filtered text is expected on standard output.
469- source filter::
470 This filter is given a single parameter: the filename of the source file to
471 filter. The filter can use the filename to determine (for example) the syntax
472 highlighting mode.
473 The contents of the source file that is to be filtered is available on
474 standard input and the filtered contents is expected on standard output.
475
476Also, all filters are handed the following environment variables:
477- CGIT_REPO_URL ( = repo.url setting )
478- CGIT_REPO_NAME ( = repo.name setting )
479- CGIT_REPO_PATH ( = repo.path setting )
480- CGIT_REPO_OWNER ( = repo.owner setting )
481- CGIT_REPO_DEFBRANCH ( = repo.defbranch setting )
482- CGIT_REPO_SECTION ( = section setting )
483- CGIT_REPO_CLONE_URL ( = repo.clone-url setting )
484
485If a setting is not defined for a repository and the corresponding global
486setting is also not defined (if applicable), then the corresponding
487environment variable will be an empty string.
488
489Note that under normal circumstance all these environment variables are
490defined. If however the total size of the defined settings exceed the
491allocated buffer within cgit then only the environment variables that fit
492in the allocated buffer are handed to the filter.
493
494
458EXAMPLE CGITRC FILE 495EXAMPLE CGITRC FILE
459------------------- 496-------------------
460 497
diff --git a/filters/commit-links.sh b/filters/commit-links.sh index 110c609..d2cd2b3 100755 --- a/filters/commit-links.sh +++ b/filters/commit-links.sh
@@ -3,6 +3,17 @@
3# 3#
4# To use this script, refer to this file with either the commit-filter or the 4# To use this script, refer to this file with either the commit-filter or the
5# repo.commit-filter options in cgitrc. 5# repo.commit-filter options in cgitrc.
6#
7# The following environment variables can be used to retrieve the configuration
8# of the repository for which this script is called:
9# CGIT_REPO_URL ( = repo.url setting )
10# CGIT_REPO_NAME ( = repo.name setting )
11# CGIT_REPO_PATH ( = repo.path setting )
12# CGIT_REPO_OWNER ( = repo.owner setting )
13# CGIT_REPO_DEFBRANCH ( = repo.defbranch setting )
14# CGIT_REPO_SECTION ( = section setting )
15# CGIT_REPO_CLONE_URL ( = repo.clone-url setting )
16#
6 17
7# This expression generates links to commits referenced by their SHA1. 18# This expression generates links to commits referenced by their SHA1.
8regex=$regex' 19regex=$regex'
diff --git a/filters/syntax-highlighting.sh b/filters/syntax-highlighting.sh index 6b1c576..6283ce9 100755 --- a/filters/syntax-highlighting.sh +++ b/filters/syntax-highlighting.sh
@@ -23,6 +23,17 @@
23# table.blob .kwb { color:#830000; } 23# table.blob .kwb { color:#830000; }
24# table.blob .kwc { color:#000000; font-weight:bold; } 24# table.blob .kwc { color:#000000; font-weight:bold; }
25# table.blob .kwd { color:#010181; } 25# table.blob .kwd { color:#010181; }
26#
27# The following environment variables can be used to retrieve the configuration
28# of the repository for which this script is called:
29# CGIT_REPO_URL ( = repo.url setting )
30# CGIT_REPO_NAME ( = repo.name setting )
31# CGIT_REPO_PATH ( = repo.path setting )
32# CGIT_REPO_OWNER ( = repo.owner setting )
33# CGIT_REPO_DEFBRANCH ( = repo.defbranch setting )
34# CGIT_REPO_SECTION ( = section setting )
35# CGIT_REPO_CLONE_URL ( = repo.clone-url setting )
36#
26 37
27# store filename and extension in local vars 38# store filename and extension in local vars
28BASENAME="$1" 39BASENAME="$1"
diff --git a/shared.c b/shared.c index 3778a5b..be2ae59 100644 --- a/shared.c +++ b/shared.c
@@ -7,6 +7,8 @@
7 */ 7 */
8 8
9#include "cgit.h" 9#include "cgit.h"
10#include <stdio.h>
11#include <linux/limits.h>
10 12
11struct cgit_repolist cgit_repolist; 13struct cgit_repolist cgit_repolist;
12struct cgit_context ctx; 14struct cgit_context ctx;
@@ -367,7 +369,33 @@ int cgit_parse_snapshots_mask(const char *str)
367 return rv; 369 return rv;
368} 370}
369 371
370int cgit_open_filter(struct cgit_filter *filter) 372typedef struct {
373 char * name;
374 char * value;
375} cgit_env_var;
376
377static void prepare_env(struct cgit_repo * repo) {
378 cgit_env_var env_vars[] = {
379 { .name = "CGIT_REPO_URL", .value = repo->url },
380 { .name = "CGIT_REPO_NAME", .value = repo->name },
381 { .name = "CGIT_REPO_PATH", .value = repo->path },
382 { .name = "CGIT_REPO_OWNER", .value = repo->owner },
383 { .name = "CGIT_REPO_DEFBRANCH", .value = repo->defbranch },
384 { .name = "CGIT_REPO_SECTION", .value = repo->section },
385 { .name = "CGIT_REPO_CLONE_URL", .value = repo->clone_url }
386 };
387 int env_var_count = ARRAY_SIZE(env_vars);
388 cgit_env_var *p, *q;
389 static char *warn = "cgit warning: failed to set env: %s=%s\n";
390
391 p = env_vars;
392 q = p + env_var_count;
393 for (; p < q; p++)
394 if (setenv(p->name, p->value, 1))
395 fprintf(stderr, warn, p->name, p->value);
396}
397
398int cgit_open_filter(struct cgit_filter *filter, struct cgit_repo * repo)
371{ 399{
372 400
373 filter->old_stdout = chk_positive(dup(STDOUT_FILENO), 401 filter->old_stdout = chk_positive(dup(STDOUT_FILENO),
@@ -378,6 +406,8 @@ int cgit_open_filter(struct cgit_filter *filter)
378 close(filter->pipe_fh[1]); 406 close(filter->pipe_fh[1]);
379 chk_non_negative(dup2(filter->pipe_fh[0], STDIN_FILENO), 407 chk_non_negative(dup2(filter->pipe_fh[0], STDIN_FILENO),
380 "Unable to use pipe as STDIN"); 408 "Unable to use pipe as STDIN");
409 if (repo)
410 prepare_env(repo);
381 execvp(filter->cmd, filter->argv); 411 execvp(filter->cmd, filter->argv);
382 die("Unable to exec subprocess %s: %s (%d)", filter->cmd, 412 die("Unable to exec subprocess %s: %s (%d)", filter->cmd,
383 strerror(errno), errno); 413 strerror(errno), errno);
diff --git a/ui-commit.c b/ui-commit.c index 2b4f677..2da9fcf 100644 --- a/ui-commit.c +++ b/ui-commit.c
@@ -110,7 +110,7 @@ void cgit_print_commit(char *hex, const char *prefix)
110 html("</table>\n"); 110 html("</table>\n");
111 html("<div class='commit-subject'>"); 111 html("<div class='commit-subject'>");
112 if (ctx.repo->commit_filter) 112 if (ctx.repo->commit_filter)
113 cgit_open_filter(ctx.repo->commit_filter); 113 cgit_open_filter(ctx.repo->commit_filter, ctx.repo);
114 html_txt(info->subject); 114 html_txt(info->subject);
115 if (ctx.repo->commit_filter) 115 if (ctx.repo->commit_filter)
116 cgit_close_filter(ctx.repo->commit_filter); 116 cgit_close_filter(ctx.repo->commit_filter);
@@ -118,7 +118,7 @@ void cgit_print_commit(char *hex, const char *prefix)
118 html("</div>"); 118 html("</div>");
119 html("<div class='commit-msg'>"); 119 html("<div class='commit-msg'>");
120 if (ctx.repo->commit_filter) 120 if (ctx.repo->commit_filter)
121 cgit_open_filter(ctx.repo->commit_filter); 121 cgit_open_filter(ctx.repo->commit_filter, ctx.repo);
122 html_txt(info->msg); 122 html_txt(info->msg);
123 if (ctx.repo->commit_filter) 123 if (ctx.repo->commit_filter)
124 cgit_close_filter(ctx.repo->commit_filter); 124 cgit_close_filter(ctx.repo->commit_filter);
@@ -127,7 +127,7 @@ void cgit_print_commit(char *hex, const char *prefix)
127 html("<div class='notes-header'>Notes</div>"); 127 html("<div class='notes-header'>Notes</div>");
128 html("<div class='notes'>"); 128 html("<div class='notes'>");
129 if (ctx.repo->commit_filter) 129 if (ctx.repo->commit_filter)
130 cgit_open_filter(ctx.repo->commit_filter); 130 cgit_open_filter(ctx.repo->commit_filter, ctx.repo);
131 html_txt(notes.buf); 131 html_txt(notes.buf);
132 if (ctx.repo->commit_filter) 132 if (ctx.repo->commit_filter)
133 cgit_close_filter(ctx.repo->commit_filter); 133 cgit_close_filter(ctx.repo->commit_filter);
diff --git a/ui-repolist.c b/ui-repolist.c index e138f59..6f304bb 100644 --- a/ui-repolist.c +++ b/ui-repolist.c
@@ -291,7 +291,7 @@ void cgit_print_site_readme()
291 if (!ctx.cfg.root_readme) 291 if (!ctx.cfg.root_readme)
292 return; 292 return;
293 if (ctx.cfg.about_filter) 293 if (ctx.cfg.about_filter)
294 cgit_open_filter(ctx.cfg.about_filter); 294 cgit_open_filter(ctx.cfg.about_filter, NULL);
295 html_include(ctx.cfg.root_readme); 295 html_include(ctx.cfg.root_readme);
296 if (ctx.cfg.about_filter) 296 if (ctx.cfg.about_filter)
297 cgit_close_filter(ctx.cfg.about_filter); 297 cgit_close_filter(ctx.cfg.about_filter);
diff --git a/ui-snapshot.c b/ui-snapshot.c index 6e3412c..067082c 100644 --- a/ui-snapshot.c +++ b/ui-snapshot.c
@@ -19,7 +19,7 @@ static int write_compressed_tar_archive(struct archiver_args *args,const char *f
19 f.argv = malloc(2 * sizeof(char *)); 19 f.argv = malloc(2 * sizeof(char *));
20 f.argv[0] = f.cmd; 20 f.argv[0] = f.cmd;
21 f.argv[1] = NULL; 21 f.argv[1] = NULL;
22 cgit_open_filter(&f); 22 cgit_open_filter(&f, NULL);
23 rv = write_tar_archive(args); 23 rv = write_tar_archive(args);
24 cgit_close_filter(&f); 24 cgit_close_filter(&f);
25 return rv; 25 return rv;
diff --git a/ui-summary.c b/ui-summary.c index 5be2545..1e9a1b6 100644 --- a/ui-summary.c +++ b/ui-summary.c
@@ -113,7 +113,7 @@ void cgit_print_repo_readme(char *path)
113 */ 113 */
114 html("<div id='summary'>"); 114 html("<div id='summary'>");
115 if (ctx.repo->about_filter) 115 if (ctx.repo->about_filter)
116 cgit_open_filter(ctx.repo->about_filter); 116 cgit_open_filter(ctx.repo->about_filter, ctx.repo);
117 if (ref) 117 if (ref)
118 cgit_print_file(tmp, ref); 118 cgit_print_file(tmp, ref);
119 else 119 else
diff --git a/ui-tree.c b/ui-tree.c index 442b6be..2d8d2f3 100644 --- a/ui-tree.c +++ b/ui-tree.c
@@ -45,7 +45,7 @@ static void print_text_buffer(const char *name, char *buf, unsigned long size)
45 if (ctx.repo->source_filter) { 45 if (ctx.repo->source_filter) {
46 html("<td class='lines'><pre><code>"); 46 html("<td class='lines'><pre><code>");
47 ctx.repo->source_filter->argv[1] = xstrdup(name); 47 ctx.repo->source_filter->argv[1] = xstrdup(name);
48 cgit_open_filter(ctx.repo->source_filter); 48 cgit_open_filter(ctx.repo->source_filter, ctx.repo);
49 html_raw(buf, size); 49 html_raw(buf, size);
50 cgit_close_filter(ctx.repo->source_filter); 50 cgit_close_filter(ctx.repo->source_filter);
51 free(ctx.repo->source_filter->argv[1]); 51 free(ctx.repo->source_filter->argv[1]);