From ab2ab95f09994560f62fd631f07d3b6e3577aa6e Mon Sep 17 00:00:00 2001 From: Lars Hjemli Date: Thu, 8 Feb 2007 13:53:13 +0100 Subject: 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 --- Makefile | 3 ++- cgit.c | 39 ++++++++++++++++++++++++++++++++------- cgit.h | 10 ++++++++++ git.h | 27 +++++++++++++++++++++++++++ shared.c | 17 +++++++++++++++++ ui-commit.c | 7 +++++++ ui-shared.c | 11 +++++++++++ ui-snapshot.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 153 insertions(+), 8 deletions(-) create mode 100644 ui-snapshot.c diff --git a/Makefile b/Makefile index d826f97..b1c3a4e 100644 --- a/Makefile +++ b/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 diff --git a/cgit.c b/cgit.c index 0fa203c..2795ecc 100644 --- a/cgit.c +++ b/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); diff --git a/cgit.h b/cgit.h index 2a3cd5a..03c2fdb 100644 --- a/cgit.h +++ b/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 */ diff --git a/git.h b/git.h index eca48d5..a1d1c4b 100644 --- a/git.h +++ b/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 */ diff --git a/shared.c b/shared.c index 6fd70a8..5757d0c 100644 --- a/shared.c +++ b/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); } } diff --git a/ui-commit.c b/ui-commit.c index 73fa104..de3f2cf 100644 --- a/ui-commit.c +++ b/ui-commit.c @@ -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\n", sha1_to_hex(p->item->object.sha1)); } + htmlf("download%s", filename); + html("\n"); html("
"); html_txt(info->subject); diff --git a/ui-shared.c b/ui-shared.c index 3322561..172499c 100644 --- a/ui-shared.c +++ b/ui-shared.c @@ -144,3 +144,14 @@ void cgit_print_pageheader(char *title, int show_search) html(""); html(""); } + +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"); +} diff --git a/ui-snapshot.c b/ui-snapshot.c new file mode 100644 index 0000000..2257d6b --- /dev/null +++ b/ui-snapshot.c @@ -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)); +} -- cgit v1.2.3-59-g8ed1b