]> gitweb.ps.run Git - ps-cgit/commitdiff
Merge branch 'lh/plugins'
authorLars Hjemli <hjemli@gmail.com>
Sun, 9 Aug 2009 11:46:01 +0000 (13:46 +0200)
committerLars Hjemli <hjemli@gmail.com>
Sun, 9 Aug 2009 11:46:01 +0000 (13:46 +0200)
Conflicts:
cgit.c
cgit.h

cgit.c
cgit.h
cgitrc.5.txt
shared.c
ui-commit.c
ui-snapshot.c
ui-tree.c

diff --git a/cgit.c b/cgit.c
index aa1107ae2100f0c13b47f18085f38542bfb3c570..dbec1962763145d3c88f89b3ba947dd9ca11bbd5 100644 (file)
--- a/cgit.c
+++ b/cgit.c
@@ -25,6 +25,21 @@ void add_mimetype(const char *name, const char *value)
        item->util = xstrdup(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)
 {
        if (!strcmp(name, "root-title"))
@@ -85,6 +100,8 @@ void config_cb(const char *name, const char *value)
                ctx.cfg.cache_static_ttl = atoi(value);
        else if (!strcmp(name, "cache-dynamic-ttl"))
                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"))
                ctx.cfg.embedded = atoi(value);
        else if (!strcmp(name, "max-message-length"))
@@ -95,6 +112,8 @@ void config_cb(const char *name, const char *value)
                ctx.cfg.max_repo_count = atoi(value);
        else if (!strcmp(name, "max-commit-count"))
                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"))
                ctx.cfg.summary_log = atoi(value);
        else if (!strcmp(name, "summary-branches"))
@@ -139,6 +158,10 @@ void config_cb(const char *name, const char *value)
                ctx.repo->max_stats = cgit_find_stats_period(value, NULL);
        else if (ctx.repo && !strcmp(name, "repo.module-link"))
                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) {
                if (*value == '/')
                        ctx.repo->readme = xstrdup(value);
diff --git a/cgit.h b/cgit.h
index 1194eb0209880289729ac3a196d6037ea7427561..b8557ace3912b4b62c59eb709fc37dea2f1f506c 100644 (file)
--- a/cgit.h
+++ b/cgit.h
@@ -49,6 +49,15 @@ typedef void (*configfn)(const char *name, const char *value);
 typedef void (*filepair_fn)(struct diff_filepair *pair);
 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 {
        char *url;
        char *name;
@@ -65,6 +74,8 @@ struct cgit_repo {
        int enable_log_linecount;
        int max_stats;
        time_t mtime;
+       struct cgit_filter *commit_filter;
+       struct cgit_filter *source_filter;
 };
 
 struct cgit_repolist {
@@ -177,6 +188,8 @@ struct cgit_config {
        int summary_log;
        int summary_tags;
        struct string_list mimetypes;
+       struct cgit_filter *commit_filter;
+       struct cgit_filter *source_filter;
 };
 
 struct cgit_page {
@@ -251,5 +264,8 @@ extern const char *cgit_repobasename(const char *reponame);
 
 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);
+
 
 #endif /* CGIT_H */
index 0412f64acb507b3a2fa652108890e367017c0732..dc63637b4bb7b17f9a5aeb7088e94db343189d72 100644 (file)
@@ -55,6 +55,12 @@ clone-prefix::
        setting is only used if `repo.clone-url` is unspecified. Default value:
        none.
 
+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::
        Url which specifies the css document to include in all cgit pages.
        Default value: "/cgit.css".
@@ -206,6 +212,14 @@ snapshots::
                "zip"           zip-file
        Default value: none.
 
+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::
        Specifies the number of branches to display in the repository "summary"
        view. Default value: "10".
@@ -232,6 +246,9 @@ repo.clone-url::
        A list of space-separated urls which can be used to clone this repo.
        Default value: none.
 
+repo.commit-filter::
+       Override the default commit-filter. Default value: <commit-filter>.
+
 repo.defbranch::
        The name of the default branch for this repository. If no such branch
        exists in the repository, the first branch name (when sorted) is used
@@ -272,6 +289,9 @@ repo.snapshots::
        A mask of allowed snapshot-formats for this repo, restricted by the
        "snapshots" global setting. Default value: <snapshots>.
 
+repo.source-filter::
+       Override the default source-filter. Default value: <source-filter>.
+
 repo.url::
        The relative url used to access the repository. This must be the first
        setting specified for each repo. Default value: none.
index cce0af40db29b77527fe1f6a7a897b4076c9621b..783604beba81510f4e155c6de8edced39c8ac3df 100644 (file)
--- a/shared.c
+++ b/shared.c
@@ -62,6 +62,8 @@ struct cgit_repo *cgit_add_repo(const char *url)
        ret->module_link = ctx.cfg.module_link;
        ret->readme = NULL;
        ret->mtime = -1;
+       ret->commit_filter = ctx.cfg.commit_filter;
+       ret->source_filter = ctx.cfg.source_filter;
        return ret;
 }
 
@@ -355,3 +357,38 @@ int cgit_parse_snapshots_mask(const char *str)
        }
        return rv;
 }
+
+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);
+}
index 9fdb8eed4d2118c968571db50839bac55f0f7c3f..d6b73eed90aaf5ee232e89f5a1655c94db392577 100644 (file)
@@ -93,11 +93,19 @@ void cgit_print_commit(char *hex)
        }
        html("</table>\n");
        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);
        html("</div>");
        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>");
        if (parents < 3) {
                if (parents)
index 5372f5d3d8b42a474713fe0867f4b50d96f5acf1..4136b3eb8d05001b614b4f3ce3423dd897d4db0e 100644 (file)
 
 static int write_compressed_tar_archive(struct archiver_args *args,const char *filter)
 {
-       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;
 }
 
index 61fcf5a0776433a3a129a8fa805f7ab2ce11ff6f..c608754f3e8e930169fda2ad08b7aba00a07cdb1 100644 (file)
--- a/ui-tree.c
+++ b/ui-tree.c
@@ -15,13 +15,23 @@ char *curr_rev;
 char *match_path;
 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)
 {
        unsigned long lineno, idx;
        const char *numberfmt =
                "<a class='no' id='n%1$d' name='n%1$d' href='#n%1$d'>%1$d</a>\n";
 
        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>");
        idx = 0;
        lineno = 0;
@@ -65,7 +75,7 @@ static void print_binary_buffer(char *buf, unsigned long size)
        html("</table>\n");
 }
 
-static void print_object(const unsigned char *sha1, char *path)
+static void print_object(const unsigned char *sha1, char *path, const char *basename)
 {
        enum object_type type;
        char *buf;
@@ -93,7 +103,7 @@ static void print_object(const unsigned char *sha1, char *path)
        if (buffer_is_binary(buf, size))
                print_binary_buffer(buf, size);
        else
-               print_text_buffer(buf, size);
+               print_text_buffer(basename, buf, size);
 }
 
 
@@ -219,7 +229,7 @@ static int walk_tree(const unsigned char *sha1, const char *base, int baselen,
                        ls_head();
                        return READ_TREE_RECURSIVE;
                } else {
-                       print_object(sha1, buffer);
+                       print_object(sha1, buffer, pathname);
                        return 0;
                }
        }