Merge branch 'lh/plugins'
Conflicts: cgit.c cgit.h
This commit is contained in:
		
							
								
								
									
										23
									
								
								cgit.c
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								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); | ||||
|   | ||||
							
								
								
									
										16
									
								
								cgit.h
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								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 */ | ||||
|   | ||||
							
								
								
									
										20
									
								
								cgitrc.5.txt
									
									
									
									
									
								
							
							
						
						
									
										20
									
								
								cgitrc.5.txt
									
									
									
									
									
								
							| @@ -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. | ||||
|   | ||||
							
								
								
									
										37
									
								
								shared.c
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								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); | ||||
| } | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
| @@ -12,37 +12,16 @@ | ||||
|  | ||||
| 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; | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										18
									
								
								ui-tree.c
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								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; | ||||
| 		} | ||||
| 	} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Lars Hjemli
					Lars Hjemli