-rw-r--r-- | cgit.c | 23 | ||||
-rw-r--r-- | cgit.h | 16 | ||||
-rw-r--r-- | cgitrc.5.txt | 20 | ||||
-rw-r--r-- | shared.c | 37 | ||||
-rw-r--r-- | ui-commit.c | 8 | ||||
-rw-r--r-- | ui-snapshot.c | 35 | ||||
-rw-r--r-- | ui-tree.c | 18 |
7 files changed, 125 insertions, 32 deletions
@@ -27,2 +27,17 @@ void add_mimetype(const char *name, const char *value) +struct cgit_filter *new_filter(const char *cmd, int extra_args) +{ + struct cgit_filter *f; + + if (!cmd || !cmd[0]) + return NULL; + + f = xmalloc(sizeof(struct cgit_filter)); + f->cmd = xstrdup(cmd); + f->argv = xmalloc((2 + extra_args) * sizeof(char *)); + f->argv[0] = f->cmd; + f->argv[1] = NULL; + return f; +} + void config_cb(const char *name, const char *value) @@ -87,2 +102,4 @@ void config_cb(const char *name, const char *value) ctx.cfg.cache_dynamic_ttl = atoi(value); + else if (!strcmp(name, "commit-filter")) + ctx.cfg.commit_filter = new_filter(value, 0); else if (!strcmp(name, "embedded")) @@ -97,2 +114,4 @@ void config_cb(const char *name, const char *value) ctx.cfg.max_commit_count = atoi(value); + else if (!strcmp(name, "source-filter")) + ctx.cfg.source_filter = new_filter(value, 1); else if (!strcmp(name, "summary-log")) @@ -141,2 +160,6 @@ void config_cb(const char *name, const char *value) ctx.repo->module_link= xstrdup(value); + 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) { @@ -51,2 +51,11 @@ typedef void (*linediff_fn)(char *line, int len); +struct cgit_filter { + char *cmd; + char **argv; + int old_stdout; + int pipe_fh[2]; + int pid; + int exitstatus; +}; + struct cgit_repo { @@ -67,2 +76,4 @@ struct cgit_repo { time_t mtime; + struct cgit_filter *commit_filter; + struct cgit_filter *source_filter; }; @@ -179,2 +190,4 @@ struct cgit_config { struct string_list mimetypes; + struct cgit_filter *commit_filter; + struct cgit_filter *source_filter; }; @@ -253,2 +266,5 @@ extern int cgit_parse_snapshots_mask(const char *str); +extern int cgit_open_filter(struct cgit_filter *filter); +extern int cgit_close_filter(struct cgit_filter *filter); + 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:: +commit-filter:: + Specifies a command which will be invoked to format commit messages. + 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 + be used to implement bugtracker integration. Default value: none. + css:: @@ -208,2 +214,10 @@ snapshots:: +source-filter:: + Specifies a command which will be invoked to format plaintext blobs + in the tree view. The command will get the blob content on its STDIN + 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. + this can be used to implement e.g. syntax highlighting. Default value: + none. + summary-branches:: @@ -234,2 +248,5 @@ repo.clone-url:: +repo.commit-filter:: + Override the default commit-filter. Default value: <commit-filter>. + repo.defbranch:: @@ -274,2 +291,5 @@ repo.snapshots:: +repo.source-filter:: + Override the default source-filter. Default value: <source-filter>. + repo.url:: @@ -64,2 +64,4 @@ struct cgit_repo *cgit_add_repo(const char *url) ret->mtime = -1; + ret->commit_filter = ctx.cfg.commit_filter; + ret->source_filter = ctx.cfg.source_filter; return ret; @@ -357 +359,36 @@ int cgit_parse_snapshots_mask(const char *str) } + +int cgit_open_filter(struct cgit_filter *filter) +{ + + filter->old_stdout = chk_positive(dup(STDOUT_FILENO), + "Unable to duplicate STDOUT"); + chk_zero(pipe(filter->pipe_fh), "Unable to create pipe to subprocess"); + filter->pid = chk_non_negative(fork(), "Unable to create subprocess"); + if (filter->pid == 0) { + close(filter->pipe_fh[1]); + chk_non_negative(dup2(filter->pipe_fh[0], STDIN_FILENO), + "Unable to use pipe as STDIN"); + execvp(filter->cmd, filter->argv); + die("Unable to exec subprocess %s: %s (%d)", filter->cmd, + strerror(errno), errno); + } + close(filter->pipe_fh[0]); + chk_non_negative(dup2(filter->pipe_fh[1], STDOUT_FILENO), + "Unable to use pipe as STDOUT"); + close(filter->pipe_fh[1]); + return 0; +} + +int cgit_close_filter(struct cgit_filter *filter) +{ + chk_non_negative(dup2(filter->old_stdout, STDOUT_FILENO), + "Unable to restore STDOUT"); + close(filter->old_stdout); + if (filter->pid < 0) + return 0; + waitpid(filter->pid, &filter->exitstatus, 0); + if (WIFEXITED(filter->exitstatus) && !WEXITSTATUS(filter->exitstatus)) + return 0; + die("Subprocess %s exited abnormally", filter->cmd); +} 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) html("<div class='commit-subject'>"); + if (ctx.repo->commit_filter) + cgit_open_filter(ctx.repo->commit_filter); html_txt(info->subject); + if (ctx.repo->commit_filter) + cgit_close_filter(ctx.repo->commit_filter); show_commit_decorations(commit); @@ -99,3 +103,7 @@ void cgit_print_commit(char *hex) html("<div class='commit-msg'>"); + if (ctx.repo->commit_filter) + cgit_open_filter(ctx.repo->commit_filter); html_txt(info->msg); + if (ctx.repo->commit_filter) + cgit_close_filter(ctx.repo->commit_filter); 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 { - int rw[2]; - pid_t gzpid; - int stdout2; - int status; int rv; + struct cgit_filter f; - stdout2 = chk_non_negative(dup(STDIN_FILENO), "Preserving STDOUT before compressing"); - chk_zero(pipe(rw), "Opening pipe from compressor subprocess"); - gzpid = chk_non_negative(fork(), "Forking compressor subprocess"); - if(gzpid==0) { - /* child */ - chk_zero(close(rw[1]), "Closing write end of pipe in child"); - chk_zero(close(STDIN_FILENO), "Closing STDIN"); - chk_non_negative(dup2(rw[0],STDIN_FILENO), "Redirecting compressor input to stdin"); - execlp(filter,filter,NULL); - _exit(-1); - } - /* parent */ - chk_zero(close(rw[0]), "Closing read end of pipe"); - chk_non_negative(dup2(rw[1],STDOUT_FILENO), "Redirecting output to compressor"); - + f.cmd = xstrdup(filter); + f.argv = malloc(2 * sizeof(char *)); + f.argv[0] = f.cmd; + f.argv[1] = NULL; + cgit_open_filter(&f); rv = write_tar_archive(args); - - chk_zero(close(STDOUT_FILENO), "Closing STDOUT redirected to compressor"); - chk_non_negative(dup2(stdout2,STDOUT_FILENO), "Restoring uncompressed STDOUT"); - chk_zero(close(stdout2), "Closing uncompressed STDOUT"); - chk_zero(close(rw[1]), "Closing write end of pipe in parent"); - chk_positive(waitpid(gzpid,&status,0), "Waiting on compressor process"); - if(! ( WIFEXITED(status) && WEXITSTATUS(status)==0 ) ) - cgit_print_error("Failed to compress archive"); - + cgit_close_filter(&f); return rv; @@ -17,3 +17,3 @@ int header = 0; -static void print_text_buffer(char *buf, unsigned long size) +static void print_text_buffer(const char *name, char *buf, unsigned long size) { @@ -24,2 +24,12 @@ static void print_text_buffer(char *buf, unsigned long size) html("<table summary='blob content' class='blob'>\n"); + if (ctx.repo->source_filter) { + html("<tr><td class='lines'><pre><code>"); + ctx.repo->source_filter->argv[1] = xstrdup(name); + cgit_open_filter(ctx.repo->source_filter); + write(STDOUT_FILENO, buf, size); + cgit_close_filter(ctx.repo->source_filter); + html("</code></pre></td></tr></table>\n"); + return; + } + html("<tr><td class='linenumbers'><pre>"); @@ -67,3 +77,3 @@ static void print_binary_buffer(char *buf, unsigned long size) -static void print_object(const unsigned char *sha1, char *path) +static void print_object(const unsigned char *sha1, char *path, const char *basename) { @@ -95,3 +105,3 @@ static void print_object(const unsigned char *sha1, char *path) else - print_text_buffer(buf, size); + print_text_buffer(basename, buf, size); } @@ -221,3 +231,3 @@ static int walk_tree(const unsigned char *sha1, const char *base, int baselen, } else { - print_object(sha1, buffer); + print_object(sha1, buffer, pathname); return 0; |