summaryrefslogtreecommitdiffabout
Unidiff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--cgit.c23
-rw-r--r--cgit.h16
-rw-r--r--cgitrc.5.txt20
-rw-r--r--shared.c37
-rw-r--r--ui-commit.c8
-rw-r--r--ui-snapshot.c35
-rw-r--r--ui-tree.c18
7 files changed, 125 insertions, 32 deletions
diff --git a/cgit.c b/cgit.c
index aa1107a..dbec196 100644
--- a/cgit.c
+++ b/cgit.c
@@ -27,2 +27,17 @@ void add_mimetype(const char *name, const char *value)
27 27
28struct cgit_filter *new_filter(const char *cmd, int extra_args)
29{
30 struct cgit_filter *f;
31
32 if (!cmd || !cmd[0])
33 return NULL;
34
35 f = xmalloc(sizeof(struct cgit_filter));
36 f->cmd = xstrdup(cmd);
37 f->argv = xmalloc((2 + extra_args) * sizeof(char *));
38 f->argv[0] = f->cmd;
39 f->argv[1] = NULL;
40 return f;
41}
42
28void config_cb(const char *name, const char *value) 43void config_cb(const char *name, const char *value)
@@ -87,2 +102,4 @@ void config_cb(const char *name, const char *value)
87 ctx.cfg.cache_dynamic_ttl = atoi(value); 102 ctx.cfg.cache_dynamic_ttl = atoi(value);
103 else if (!strcmp(name, "commit-filter"))
104 ctx.cfg.commit_filter = new_filter(value, 0);
88 else if (!strcmp(name, "embedded")) 105 else if (!strcmp(name, "embedded"))
@@ -97,2 +114,4 @@ void config_cb(const char *name, const char *value)
97 ctx.cfg.max_commit_count = atoi(value); 114 ctx.cfg.max_commit_count = atoi(value);
115 else if (!strcmp(name, "source-filter"))
116 ctx.cfg.source_filter = new_filter(value, 1);
98 else if (!strcmp(name, "summary-log")) 117 else if (!strcmp(name, "summary-log"))
@@ -141,2 +160,6 @@ void config_cb(const char *name, const char *value)
141 ctx.repo->module_link= xstrdup(value); 160 ctx.repo->module_link= xstrdup(value);
161 else if (ctx.repo && !strcmp(name, "repo.commit-filter"))
162 ctx.repo->commit_filter = new_filter(value, 0);
163 else if (ctx.repo && !strcmp(name, "repo.source-filter"))
164 ctx.repo->source_filter = new_filter(value, 1);
142 else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) { 165 else if (ctx.repo && !strcmp(name, "repo.readme") && value != NULL) {
diff --git a/cgit.h b/cgit.h
index 1194eb0..b8557ac 100644
--- a/cgit.h
+++ b/cgit.h
@@ -51,2 +51,11 @@ typedef void (*linediff_fn)(char *line, int len);
51 51
52struct cgit_filter {
53 char *cmd;
54 char **argv;
55 int old_stdout;
56 int pipe_fh[2];
57 int pid;
58 int exitstatus;
59};
60
52struct cgit_repo { 61struct cgit_repo {
@@ -67,2 +76,4 @@ struct cgit_repo {
67 time_t mtime; 76 time_t mtime;
77 struct cgit_filter *commit_filter;
78 struct cgit_filter *source_filter;
68}; 79};
@@ -179,2 +190,4 @@ struct cgit_config {
179 struct string_list mimetypes; 190 struct string_list mimetypes;
191 struct cgit_filter *commit_filter;
192 struct cgit_filter *source_filter;
180}; 193};
@@ -253,2 +266,5 @@ extern int cgit_parse_snapshots_mask(const char *str);
253 266
267extern int cgit_open_filter(struct cgit_filter *filter);
268extern int cgit_close_filter(struct cgit_filter *filter);
269
254 270
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index 0412f64..dc63637 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -57,2 +57,8 @@ clone-prefix::
57 57
58commit-filter::
59 Specifies a command which will be invoked to format commit messages.
60 The command will get the message on its STDIN, and the STDOUT from the
61 command will be included verbatim as the commit message, i.e. this can
62 be used to implement bugtracker integration. Default value: none.
63
58css:: 64css::
@@ -208,2 +214,10 @@ snapshots::
208 214
215source-filter::
216 Specifies a command which will be invoked to format plaintext blobs
217 in the tree view. The command will get the blob content on its STDIN
218 and the name of the blob as its only command line argument. The STDOUT
219 from the command will be included verbatim as the blob contents, i.e.
220 this can be used to implement e.g. syntax highlighting. Default value:
221 none.
222
209summary-branches:: 223summary-branches::
@@ -234,2 +248,5 @@ repo.clone-url::
234 248
249repo.commit-filter::
250 Override the default commit-filter. Default value: <commit-filter>.
251
235repo.defbranch:: 252repo.defbranch::
@@ -274,2 +291,5 @@ repo.snapshots::
274 291
292repo.source-filter::
293 Override the default source-filter. Default value: <source-filter>.
294
275repo.url:: 295repo.url::
diff --git a/shared.c b/shared.c
index cce0af4..783604b 100644
--- a/shared.c
+++ b/shared.c
@@ -64,2 +64,4 @@ struct cgit_repo *cgit_add_repo(const char *url)
64 ret->mtime = -1; 64 ret->mtime = -1;
65 ret->commit_filter = ctx.cfg.commit_filter;
66 ret->source_filter = ctx.cfg.source_filter;
65 return ret; 67 return ret;
@@ -357 +359,36 @@ int cgit_parse_snapshots_mask(const char *str)
357} 359}
360
361int cgit_open_filter(struct cgit_filter *filter)
362{
363
364 filter->old_stdout = chk_positive(dup(STDOUT_FILENO),
365 "Unable to duplicate STDOUT");
366 chk_zero(pipe(filter->pipe_fh), "Unable to create pipe to subprocess");
367 filter->pid = chk_non_negative(fork(), "Unable to create subprocess");
368 if (filter->pid == 0) {
369 close(filter->pipe_fh[1]);
370 chk_non_negative(dup2(filter->pipe_fh[0], STDIN_FILENO),
371 "Unable to use pipe as STDIN");
372 execvp(filter->cmd, filter->argv);
373 die("Unable to exec subprocess %s: %s (%d)", filter->cmd,
374 strerror(errno), errno);
375 }
376 close(filter->pipe_fh[0]);
377 chk_non_negative(dup2(filter->pipe_fh[1], STDOUT_FILENO),
378 "Unable to use pipe as STDOUT");
379 close(filter->pipe_fh[1]);
380 return 0;
381}
382
383int cgit_close_filter(struct cgit_filter *filter)
384{
385 chk_non_negative(dup2(filter->old_stdout, STDOUT_FILENO),
386 "Unable to restore STDOUT");
387 close(filter->old_stdout);
388 if (filter->pid < 0)
389 return 0;
390 waitpid(filter->pid, &filter->exitstatus, 0);
391 if (WIFEXITED(filter->exitstatus) && !WEXITSTATUS(filter->exitstatus))
392 return 0;
393 die("Subprocess %s exited abnormally", filter->cmd);
394}
diff --git a/ui-commit.c b/ui-commit.c
index 9fdb8ee..d6b73ee 100644
--- a/ui-commit.c
+++ b/ui-commit.c
@@ -95,3 +95,7 @@ void cgit_print_commit(char *hex)
95 html("<div class='commit-subject'>"); 95 html("<div class='commit-subject'>");
96 if (ctx.repo->commit_filter)
97 cgit_open_filter(ctx.repo->commit_filter);
96 html_txt(info->subject); 98 html_txt(info->subject);
99 if (ctx.repo->commit_filter)
100 cgit_close_filter(ctx.repo->commit_filter);
97 show_commit_decorations(commit); 101 show_commit_decorations(commit);
@@ -99,3 +103,7 @@ void cgit_print_commit(char *hex)
99 html("<div class='commit-msg'>"); 103 html("<div class='commit-msg'>");
104 if (ctx.repo->commit_filter)
105 cgit_open_filter(ctx.repo->commit_filter);
100 html_txt(info->msg); 106 html_txt(info->msg);
107 if (ctx.repo->commit_filter)
108 cgit_close_filter(ctx.repo->commit_filter);
101 html("</div>"); 109 html("</div>");
diff --git a/ui-snapshot.c b/ui-snapshot.c
index 5372f5d..4136b3e 100644
--- a/ui-snapshot.c
+++ b/ui-snapshot.c
@@ -14,33 +14,12 @@ static int write_compressed_tar_archive(struct archiver_args *args,const char *f
14{ 14{
15 int rw[2];
16 pid_t gzpid;
17 int stdout2;
18 int status;
19 int rv; 15 int rv;
16 struct cgit_filter f;
20 17
21 stdout2 = chk_non_negative(dup(STDIN_FILENO), "Preserving STDOUT before compressing"); 18 f.cmd = xstrdup(filter);
22 chk_zero(pipe(rw), "Opening pipe from compressor subprocess"); 19 f.argv = malloc(2 * sizeof(char *));
23 gzpid = chk_non_negative(fork(), "Forking compressor subprocess"); 20 f.argv[0] = f.cmd;
24 if(gzpid==0) { 21 f.argv[1] = NULL;
25 /* child */ 22 cgit_open_filter(&f);
26 chk_zero(close(rw[1]), "Closing write end of pipe in child");
27 chk_zero(close(STDIN_FILENO), "Closing STDIN");
28 chk_non_negative(dup2(rw[0],STDIN_FILENO), "Redirecting compressor input to stdin");
29 execlp(filter,filter,NULL);
30 _exit(-1);
31 }
32 /* parent */
33 chk_zero(close(rw[0]), "Closing read end of pipe");
34 chk_non_negative(dup2(rw[1],STDOUT_FILENO), "Redirecting output to compressor");
35
36 rv = write_tar_archive(args); 23 rv = write_tar_archive(args);
37 24 cgit_close_filter(&f);
38 chk_zero(close(STDOUT_FILENO), "Closing STDOUT redirected to compressor");
39 chk_non_negative(dup2(stdout2,STDOUT_FILENO), "Restoring uncompressed STDOUT");
40 chk_zero(close(stdout2), "Closing uncompressed STDOUT");
41 chk_zero(close(rw[1]), "Closing write end of pipe in parent");
42 chk_positive(waitpid(gzpid,&status,0), "Waiting on compressor process");
43 if(! ( WIFEXITED(status) && WEXITSTATUS(status)==0 ) )
44 cgit_print_error("Failed to compress archive");
45
46 return rv; 25 return rv;
diff --git a/ui-tree.c b/ui-tree.c
index 61fcf5a..c608754 100644
--- a/ui-tree.c
+++ b/ui-tree.c
@@ -17,3 +17,3 @@ int header = 0;
17 17
18static void print_text_buffer(char *buf, unsigned long size) 18static void print_text_buffer(const char *name, char *buf, unsigned long size)
19{ 19{
@@ -24,2 +24,12 @@ static void print_text_buffer(char *buf, unsigned long size)
24 html("<table summary='blob content' class='blob'>\n"); 24 html("<table summary='blob content' class='blob'>\n");
25 if (ctx.repo->source_filter) {
26 html("<tr><td class='lines'><pre><code>");
27 ctx.repo->source_filter->argv[1] = xstrdup(name);
28 cgit_open_filter(ctx.repo->source_filter);
29 write(STDOUT_FILENO, buf, size);
30 cgit_close_filter(ctx.repo->source_filter);
31 html("</code></pre></td></tr></table>\n");
32 return;
33 }
34
25 html("<tr><td class='linenumbers'><pre>"); 35 html("<tr><td class='linenumbers'><pre>");
@@ -67,3 +77,3 @@ static void print_binary_buffer(char *buf, unsigned long size)
67 77
68static void print_object(const unsigned char *sha1, char *path) 78static void print_object(const unsigned char *sha1, char *path, const char *basename)
69{ 79{
@@ -95,3 +105,3 @@ static void print_object(const unsigned char *sha1, char *path)
95 else 105 else
96 print_text_buffer(buf, size); 106 print_text_buffer(basename, buf, size);
97} 107}
@@ -221,3 +231,3 @@ static int walk_tree(const unsigned char *sha1, const char *base, int baselen,
221 } else { 231 } else {
222 print_object(sha1, buffer); 232 print_object(sha1, buffer, pathname);
223 return 0; 233 return 0;