Add support for snapshots
Make a link from the commit viewer to a snapshot of the corresponding tree. Currently only zip-format is supported. Signed-off-by: Lars Hjemli <hjemli@gmail.com>
This commit is contained in:
		
							parent
							
								
									14d360df60
								
							
						
					
					
						commit
						ab2ab95f09
					
				
							
								
								
									
										3
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										3
									
								
								Makefile
									
									
									
									
									
								
							| @ -6,7 +6,8 @@ gitsrc = ../git | ||||
| CACHE_ROOT = /var/cache/cgit | ||||
| EXTLIBS = $(gitsrc)/libgit.a $(gitsrc)/xdiff/lib.a -lz -lcrypto | ||||
| OBJECTS = shared.o cache.o parsing.o html.o ui-shared.o ui-repolist.o \
 | ||||
| 	ui-summary.o ui-log.o ui-view.c ui-tree.c ui-commit.c ui-diff.o | ||||
| 	ui-summary.o ui-log.o ui-view.c ui-tree.c ui-commit.c ui-diff.o \
 | ||||
| 	ui-snapshot.o | ||||
| 
 | ||||
| CFLAGS += -Wall | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										39
									
								
								cgit.c
									
									
									
									
									
								
							
							
						
						
									
										39
									
								
								cgit.c
									
									
									
									
									
								
							| @ -78,6 +78,13 @@ static void cgit_print_repo_page(struct cacheitem *item) | ||||
| 	title = fmt("%s - %s", cgit_repo->name, cgit_repo->desc); | ||||
| 	show_search = 0; | ||||
| 	setenv("GIT_DIR", cgit_repo->path, 1); | ||||
| 
 | ||||
| 	if (cgit_query_page && !strcmp(cgit_query_page, "snapshot")) { | ||||
| 		cgit_print_snapshot(item, cgit_query_sha1, "zip",  | ||||
| 				    cgit_repo->url, cgit_query_name); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (cgit_query_page && !strcmp(cgit_query_page, "log")) | ||||
| 		show_search = 1; | ||||
| 	cgit_print_docstart(title, item); | ||||
| @ -85,7 +92,8 @@ static void cgit_print_repo_page(struct cacheitem *item) | ||||
| 	if (!cgit_query_page) { | ||||
| 		cgit_print_summary(); | ||||
| 	} else if (!strcmp(cgit_query_page, "log")) { | ||||
| 		cgit_print_log(cgit_query_head, cgit_query_ofs, 100, cgit_query_search); | ||||
| 		cgit_print_log(cgit_query_head, cgit_query_ofs, 100,  | ||||
| 			       cgit_query_search); | ||||
| 	} else if (!strcmp(cgit_query_page, "tree")) { | ||||
| 		cgit_print_tree(cgit_query_sha1, cgit_query_path); | ||||
| 	} else if (!strcmp(cgit_query_page, "commit")) { | ||||
| @ -94,21 +102,39 @@ static void cgit_print_repo_page(struct cacheitem *item) | ||||
| 		cgit_print_view(cgit_query_sha1); | ||||
| 	} else if (!strcmp(cgit_query_page, "diff")) { | ||||
| 		cgit_print_diff(cgit_query_sha1, cgit_query_sha2); | ||||
| 	} else { | ||||
| 		cgit_print_error("Invalid request"); | ||||
| 	} | ||||
| 	cgit_print_docend(); | ||||
| } | ||||
| 
 | ||||
| static void cgit_fill_cache(struct cacheitem *item) | ||||
| static void cgit_fill_cache(struct cacheitem *item, int use_cache) | ||||
| { | ||||
| 	static char buf[PATH_MAX]; | ||||
| 	int stdout2; | ||||
| 
 | ||||
| 	getcwd(buf, sizeof(buf)); | ||||
| 	htmlfd = item->fd; | ||||
| 	item->st.st_mtime = time(NULL); | ||||
| 
 | ||||
| 	if (use_cache) { | ||||
| 		stdout2 = chk_positive(dup(STDOUT_FILENO),  | ||||
| 				       "Preserving STDOUT"); | ||||
| 		chk_zero(close(STDOUT_FILENO), "Closing STDOUT"); | ||||
| 		chk_positive(dup2(item->fd, STDOUT_FILENO), "Dup2(cachefile)"); | ||||
| 	} | ||||
| 
 | ||||
| 	if (cgit_query_repo) | ||||
| 		cgit_print_repo_page(item); | ||||
| 	else | ||||
| 		cgit_print_repolist(item); | ||||
| 
 | ||||
| 	if (use_cache) { | ||||
| 		chk_zero(close(STDOUT_FILENO), "Close redirected STDOUT"); | ||||
| 		chk_positive(dup2(stdout2, STDOUT_FILENO),  | ||||
| 			     "Restoring original STDOUT"); | ||||
| 		chk_zero(close(stdout2), "Closing temporary STDOUT"); | ||||
| 	} | ||||
| 
 | ||||
| 	chdir(buf); | ||||
| } | ||||
| 
 | ||||
| @ -127,14 +153,14 @@ static void cgit_check_cache(struct cacheitem *item) | ||||
| 			goto top; | ||||
| 		} | ||||
| 		if (!cache_exist(item)) { | ||||
| 			cgit_fill_cache(item); | ||||
| 			cgit_fill_cache(item, 1); | ||||
| 			cache_unlock(item); | ||||
| 		} else { | ||||
| 			cache_cancel_lock(item); | ||||
| 		} | ||||
| 	} else if (cache_expired(item) && cache_lock(item)) { | ||||
| 		if (cache_expired(item)) { | ||||
| 			cgit_fill_cache(item); | ||||
| 			cgit_fill_cache(item, 1); | ||||
| 			cache_unlock(item); | ||||
| 		} else { | ||||
| 			cache_cancel_lock(item); | ||||
| @ -209,8 +235,7 @@ int main(int argc, const char **argv) | ||||
| 	if (!cgit_prepare_cache(&item)) | ||||
| 		return 0; | ||||
| 	if (cgit_nocache) { | ||||
| 		item.fd = STDOUT_FILENO; | ||||
| 		cgit_fill_cache(&item); | ||||
| 		cgit_fill_cache(&item, 0); | ||||
| 	} else { | ||||
| 		cgit_check_cache(&item); | ||||
| 		cgit_print_cache(&item); | ||||
|  | ||||
							
								
								
									
										10
									
								
								cgit.h
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								cgit.h
									
									
									
									
									
								
							| @ -85,6 +85,7 @@ extern char *cgit_query_head; | ||||
| extern char *cgit_query_sha1; | ||||
| extern char *cgit_query_sha2; | ||||
| extern char *cgit_query_path; | ||||
| extern char *cgit_query_name; | ||||
| extern int   cgit_query_ofs; | ||||
| 
 | ||||
| extern int htmlfd; | ||||
| @ -93,6 +94,9 @@ extern void cgit_global_config_cb(const char *name, const char *value); | ||||
| extern void cgit_repo_config_cb(const char *name, const char *value); | ||||
| extern void cgit_querystring_cb(const char *name, const char *value); | ||||
| 
 | ||||
| extern int chk_zero(int result, char *msg); | ||||
| extern int chk_positive(int result, char *msg); | ||||
| 
 | ||||
| extern int hextoint(char c); | ||||
| 
 | ||||
| extern void *cgit_free_commitinfo(struct commitinfo *info); | ||||
| @ -130,6 +134,9 @@ extern void cgit_print_date(unsigned long secs); | ||||
| extern void cgit_print_docstart(char *title, struct cacheitem *item); | ||||
| extern void cgit_print_docend(); | ||||
| extern void cgit_print_pageheader(char *title, int show_search); | ||||
| extern void cgit_print_snapshot_start(const char *mimetype,  | ||||
| 				      const char *filename,  | ||||
| 				      struct cacheitem *item); | ||||
| 
 | ||||
| extern void cgit_print_repolist(struct cacheitem *item); | ||||
| extern void cgit_print_summary(); | ||||
| @ -138,5 +145,8 @@ extern void cgit_print_view(const char *hex); | ||||
| extern void cgit_print_tree(const char *hex, char *path); | ||||
| extern void cgit_print_commit(const char *hex); | ||||
| extern void cgit_print_diff(const char *old_hex, const char *new_hex); | ||||
| extern void cgit_print_snapshot(struct cacheitem *item, const char *hex,  | ||||
| 				const char *format, const char *prefix, | ||||
| 				const char *filename); | ||||
| 
 | ||||
| #endif /* CGIT_H */ | ||||
|  | ||||
							
								
								
									
										27
									
								
								git.h
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								git.h
									
									
									
									
									
								
							| @ -669,4 +669,31 @@ int log_tree_commit(struct rev_info *, struct commit *); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* from git:archive.h */ | ||||
| 
 | ||||
| struct archiver_args { | ||||
| 	const char *base; | ||||
| 	struct tree *tree; | ||||
| 	const unsigned char *commit_sha1; | ||||
| 	time_t time; | ||||
| 	const char **pathspec; | ||||
| 	unsigned int verbose : 1; | ||||
| 	void *extra; | ||||
| }; | ||||
| 
 | ||||
| typedef int (*write_archive_fn_t)(struct archiver_args *); | ||||
| 
 | ||||
| typedef void *(*parse_extra_args_fn_t)(int argc, const char **argv); | ||||
| 
 | ||||
| struct archiver { | ||||
| 	const char *name; | ||||
| 	struct archiver_args args; | ||||
| 	write_archive_fn_t write_archive; | ||||
| 	parse_extra_args_fn_t parse_extra; | ||||
| }; | ||||
| 
 | ||||
| extern int write_tar_archive(struct archiver_args *); | ||||
| extern int write_zip_archive(struct archiver_args *); | ||||
| extern void *parse_extra_zip_args(int argc, const char **argv); | ||||
| 
 | ||||
| #endif /* GIT_H */ | ||||
|  | ||||
							
								
								
									
										17
									
								
								shared.c
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								shared.c
									
									
									
									
									
								
							| @ -44,10 +44,25 @@ char *cgit_query_search = NULL; | ||||
| char *cgit_query_sha1   = NULL; | ||||
| char *cgit_query_sha2   = NULL; | ||||
| char *cgit_query_path   = NULL; | ||||
| char *cgit_query_name   = NULL; | ||||
| int   cgit_query_ofs    = 0; | ||||
| 
 | ||||
| int htmlfd = 0; | ||||
| 
 | ||||
| int chk_zero(int result, char *msg) | ||||
| { | ||||
| 	if (result != 0) | ||||
| 		die("%s: %s", msg, strerror(errno)); | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| int chk_positive(int result, char *msg) | ||||
| { | ||||
| 	if (result <= 0) | ||||
| 		die("%s: %s", msg, strerror(errno)); | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| struct repoinfo *add_repo(const char *url) | ||||
| { | ||||
| 	struct repoinfo *ret; | ||||
| @ -140,6 +155,8 @@ void cgit_querystring_cb(const char *name, const char *value) | ||||
| 		cgit_query_ofs = atoi(value); | ||||
| 	} else if (!strcmp(name, "path")) { | ||||
| 		cgit_query_path = xstrdup(value); | ||||
| 	} else if (!strcmp(name, "name")) { | ||||
| 		cgit_query_name = xstrdup(value); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -128,6 +128,7 @@ void cgit_print_commit(const char *hex) | ||||
| 	struct commit_list *p; | ||||
| 	unsigned char sha1[20]; | ||||
| 	char *query; | ||||
| 	char *filename; | ||||
| 
 | ||||
| 	if (get_sha1(hex, sha1)) { | ||||
| 		cgit_print_error(fmt("Bad object id: %s", hex)); | ||||
| @ -168,6 +169,12 @@ void cgit_print_commit(const char *hex) | ||||
| 		htmlf("'>%s</a></td></tr>\n",  | ||||
| 		      sha1_to_hex(p->item->object.sha1)); | ||||
| 	} | ||||
| 	htmlf("<tr><th>download</th><td colspan='2' class='sha1'><a href='"); | ||||
| 	filename = fmt("%s-%s.zip", cgit_query_repo, hex); | ||||
| 	html_attr(cgit_pageurl(cgit_query_repo, "snapshot",  | ||||
| 			       fmt("id=%s&name=%s", hex, filename))); | ||||
| 	htmlf("'>%s</a></td></tr>", filename); | ||||
| 	 | ||||
| 	html("</table>\n"); | ||||
| 	html("<div class='commit-subject'>"); | ||||
| 	html_txt(info->subject); | ||||
|  | ||||
							
								
								
									
										11
									
								
								ui-shared.c
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								ui-shared.c
									
									
									
									
									
								
							| @ -144,3 +144,14 @@ void cgit_print_pageheader(char *title, int show_search) | ||||
| 		html("</a>"); | ||||
| 	html("</td></tr><tr><td id='content'>"); | ||||
| } | ||||
| 
 | ||||
| void cgit_print_snapshot_start(const char *mimetype, const char *filename,  | ||||
| 			       struct cacheitem *item) | ||||
| { | ||||
| 	htmlf("Content-Type: %s\n", mimetype); | ||||
| 	htmlf("Content-Disposition: inline; filename=\"%s\"\n", filename); | ||||
| 	htmlf("Last-Modified: %s\n", http_date(item->st.st_mtime)); | ||||
| 	htmlf("Expires: %s\n", http_date(item->st.st_mtime + | ||||
| 					 ttl_seconds(item->ttl))); | ||||
| 	html("\n"); | ||||
| } | ||||
|  | ||||
							
								
								
									
										47
									
								
								ui-snapshot.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								ui-snapshot.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | ||||
| /* ui-snapshot.c: generate snapshot of a commit
 | ||||
|  * | ||||
|  * Copyright (C) 2006 Lars Hjemli | ||||
|  * | ||||
|  * Licensed under GNU General Public License v2 | ||||
|  *   (see COPYING for full license text) | ||||
|  */ | ||||
| 
 | ||||
| #include "cgit.h" | ||||
| 
 | ||||
| static void cgit_print_zip(struct cacheitem *item, const char *hex,  | ||||
| 			   const char *prefix, const char *filename) | ||||
| { | ||||
| 	struct archiver_args args; | ||||
| 	struct commit *commit; | ||||
| 	unsigned char sha1[20]; | ||||
| 
 | ||||
| 	if (get_sha1(hex, sha1)) { | ||||
| 		cgit_print_error(fmt("Bad object id: %s", hex)); | ||||
| 		return; | ||||
| 	} | ||||
| 	commit = lookup_commit_reference(sha1); | ||||
| 
 | ||||
| 	if (!commit) { | ||||
| 		cgit_print_error(fmt("Not a commit reference: %s", hex)); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	memset(&args, 0, sizeof(args)); | ||||
| 	args.base = fmt("%s/", prefix); | ||||
| 	args.tree = commit->tree; | ||||
| 	 | ||||
| 	cgit_print_snapshot_start("application/x-zip", filename, item); | ||||
| 	write_zip_archive(&args); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void cgit_print_snapshot(struct cacheitem *item, const char *hex,  | ||||
| 			 const char *format, const char *prefix, | ||||
| 			 const char *filename) | ||||
| { | ||||
| 	if (!strcmp(format, "zip")) | ||||
| 		cgit_print_zip(item, hex, prefix, filename); | ||||
| 	else | ||||
| 		cgit_print_error(fmt("Unsupported snapshot format: %s",  | ||||
| 				     format)); | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user