mirror of
https://git.zx2c4.com/cgit
synced 2024-11-13 20:18:42 +00:00
Merge branch 'master' of git://git.klever.net/patchwork/cgit
* 'master' of git://git.klever.net/patchwork/cgit: link raw blob from tree file view fix: changed view link to blob in summary. allow selective enabling of snapshots shorten snapshot names to repo basename introduce cgit_repobasename added snapshot filename to the link add plain uncompressed tar snapshort format introduced .tar.bz2 snapshots compress .tar.gz using gzip as a filter added a chk_non_negative check css: adjust vertical-align of commit info th cells add support for snapshot tarballs Conflicts: ui-summary.c Signed-off-by: Lars Hjemli <hjemli@gmail.com>
This commit is contained in:
commit
1d4aaff696
6
cgit.c
6
cgit.c
@ -68,8 +68,10 @@ static void cgit_print_repo_page(struct cacheitem *item)
|
|||||||
setenv("GIT_DIR", cgit_repo->path, 1);
|
setenv("GIT_DIR", cgit_repo->path, 1);
|
||||||
|
|
||||||
if ((cgit_cmd == CMD_SNAPSHOT) && cgit_repo->snapshots) {
|
if ((cgit_cmd == CMD_SNAPSHOT) && cgit_repo->snapshots) {
|
||||||
cgit_print_snapshot(item, cgit_query_sha1, "zip",
|
cgit_print_snapshot(item, cgit_query_sha1,
|
||||||
cgit_repo->url, cgit_query_name);
|
cgit_repobasename(cgit_repo->url),
|
||||||
|
cgit_query_name,
|
||||||
|
cgit_repo->snapshots );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
cgit.css
1
cgit.css
@ -231,6 +231,7 @@ table.commit-info th {
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
padding: 0.1em 1em 0.1em 0.1em;
|
padding: 0.1em 1em 0.1em 0.1em;
|
||||||
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
|
||||||
table.commit-info td {
|
table.commit-info td {
|
||||||
|
11
cgit.h
11
cgit.h
@ -157,6 +157,7 @@ extern void cgit_querystring_cb(const char *name, const char *value);
|
|||||||
|
|
||||||
extern int chk_zero(int result, char *msg);
|
extern int chk_zero(int result, char *msg);
|
||||||
extern int chk_positive(int result, char *msg);
|
extern int chk_positive(int result, char *msg);
|
||||||
|
extern int chk_non_negative(int result, char *msg);
|
||||||
|
|
||||||
extern int hextoint(char c);
|
extern int hextoint(char c);
|
||||||
extern char *trim_end(const char *str, char c);
|
extern char *trim_end(const char *str, char c);
|
||||||
@ -200,9 +201,13 @@ extern int cache_exist(struct cacheitem *item);
|
|||||||
extern int cache_expired(struct cacheitem *item);
|
extern int cache_expired(struct cacheitem *item);
|
||||||
|
|
||||||
extern char *cgit_repourl(const char *reponame);
|
extern char *cgit_repourl(const char *reponame);
|
||||||
|
extern char *cgit_fileurl(const char *reponame, const char *pagename,
|
||||||
|
const char *filename, const char *query);
|
||||||
extern char *cgit_pageurl(const char *reponame, const char *pagename,
|
extern char *cgit_pageurl(const char *reponame, const char *pagename,
|
||||||
const char *query);
|
const char *query);
|
||||||
|
|
||||||
|
extern const char *cgit_repobasename(const char *reponame);
|
||||||
|
|
||||||
extern void cgit_tree_link(char *name, char *title, char *class, char *head,
|
extern void cgit_tree_link(char *name, char *title, char *class, char *head,
|
||||||
char *rev, char *path);
|
char *rev, char *path);
|
||||||
extern void cgit_log_link(char *name, char *title, char *class, char *head,
|
extern void cgit_log_link(char *name, char *title, char *class, char *head,
|
||||||
@ -233,7 +238,9 @@ extern void cgit_print_commit(char *hex);
|
|||||||
extern void cgit_print_tag(char *revname);
|
extern void cgit_print_tag(char *revname);
|
||||||
extern void cgit_print_diff(const char *new_hex, const char *old_hex);
|
extern void cgit_print_diff(const char *new_hex, const char *old_hex);
|
||||||
extern void cgit_print_snapshot(struct cacheitem *item, const char *hex,
|
extern void cgit_print_snapshot(struct cacheitem *item, const char *hex,
|
||||||
const char *format, const char *prefix,
|
const char *prefix, const char *filename,
|
||||||
const char *filename);
|
int snapshot);
|
||||||
|
extern void cgit_print_snapshot_links(const char *repo, const char *hex,int snapshots);
|
||||||
|
extern int cgit_parse_snapshots_mask(const char *str);
|
||||||
|
|
||||||
#endif /* CGIT_H */
|
#endif /* CGIT_H */
|
||||||
|
5
cgitrc
5
cgitrc
@ -8,7 +8,8 @@
|
|||||||
#nocache=0
|
#nocache=0
|
||||||
|
|
||||||
|
|
||||||
## Enable/disable snapshots by default. This can be overridden per repo
|
## Set allowed snapshot types by default. Can be overridden per repo
|
||||||
|
# can be any combination of zip/tar.gz/tar.bz2/tar
|
||||||
#snapshots=0
|
#snapshots=0
|
||||||
|
|
||||||
|
|
||||||
@ -113,7 +114,7 @@
|
|||||||
#repo.desc=the caching cgi for git
|
#repo.desc=the caching cgi for git
|
||||||
#repo.path=/pub/git/cgit
|
#repo.path=/pub/git/cgit
|
||||||
#repo.owner=Lars Hjemli
|
#repo.owner=Lars Hjemli
|
||||||
#repo.snapshots=1 # override a sitewide snapshot-setting
|
#repo.snapshots=tar.bz2 # override a sitewide snapshot-setting
|
||||||
#repo.enable-log-filecount=0 # override the default filecount setting
|
#repo.enable-log-filecount=0 # override the default filecount setting
|
||||||
#repo.enable-log-linecount=0 # override the default linecount setting
|
#repo.enable-log-linecount=0 # override the default linecount setting
|
||||||
#repo.module-link=/git/%s/commit/?id=%s # override the standard module-link
|
#repo.module-link=/git/%s/commit/?id=%s # override the standard module-link
|
||||||
|
11
shared.c
11
shared.c
@ -86,6 +86,13 @@ int chk_positive(int result, char *msg)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int chk_non_negative(int result, char *msg)
|
||||||
|
{
|
||||||
|
if (result < 0)
|
||||||
|
die("%s: %s",msg, strerror(errno));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
struct repoinfo *add_repo(const char *url)
|
struct repoinfo *add_repo(const char *url)
|
||||||
{
|
{
|
||||||
struct repoinfo *ret;
|
struct repoinfo *ret;
|
||||||
@ -148,7 +155,7 @@ void cgit_global_config_cb(const char *name, const char *value)
|
|||||||
else if (!strcmp(name, "nocache"))
|
else if (!strcmp(name, "nocache"))
|
||||||
cgit_nocache = atoi(value);
|
cgit_nocache = atoi(value);
|
||||||
else if (!strcmp(name, "snapshots"))
|
else if (!strcmp(name, "snapshots"))
|
||||||
cgit_snapshots = atoi(value);
|
cgit_snapshots = cgit_parse_snapshots_mask(value);
|
||||||
else if (!strcmp(name, "enable-index-links"))
|
else if (!strcmp(name, "enable-index-links"))
|
||||||
cgit_enable_index_links = atoi(value);
|
cgit_enable_index_links = atoi(value);
|
||||||
else if (!strcmp(name, "enable-log-filecount"))
|
else if (!strcmp(name, "enable-log-filecount"))
|
||||||
@ -190,7 +197,7 @@ void cgit_global_config_cb(const char *name, const char *value)
|
|||||||
else if (cgit_repo && !strcmp(name, "repo.defbranch"))
|
else if (cgit_repo && !strcmp(name, "repo.defbranch"))
|
||||||
cgit_repo->defbranch = xstrdup(value);
|
cgit_repo->defbranch = xstrdup(value);
|
||||||
else if (cgit_repo && !strcmp(name, "repo.snapshots"))
|
else if (cgit_repo && !strcmp(name, "repo.snapshots"))
|
||||||
cgit_repo->snapshots = cgit_snapshots * atoi(value);
|
cgit_repo->snapshots = cgit_snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */
|
||||||
else if (cgit_repo && !strcmp(name, "repo.enable-log-filecount"))
|
else if (cgit_repo && !strcmp(name, "repo.enable-log-filecount"))
|
||||||
cgit_repo->enable_log_filecount = cgit_enable_log_filecount * atoi(value);
|
cgit_repo->enable_log_filecount = cgit_enable_log_filecount * atoi(value);
|
||||||
else if (cgit_repo && !strcmp(name, "repo.enable-log-linecount"))
|
else if (cgit_repo && !strcmp(name, "repo.enable-log-linecount"))
|
||||||
|
@ -139,7 +139,6 @@ void cgit_print_commit(char *hex)
|
|||||||
struct commitinfo *info;
|
struct commitinfo *info;
|
||||||
struct commit_list *p;
|
struct commit_list *p;
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
char *filename;
|
|
||||||
char *tmp;
|
char *tmp;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@ -196,11 +195,9 @@ void cgit_print_commit(char *hex)
|
|||||||
html(")</td></tr>");
|
html(")</td></tr>");
|
||||||
}
|
}
|
||||||
if (cgit_repo->snapshots) {
|
if (cgit_repo->snapshots) {
|
||||||
htmlf("<tr><th>download</th><td colspan='2' class='sha1'><a href='");
|
html("<tr><th>download</th><td colspan='2' class='sha1'>");
|
||||||
filename = fmt("%s-%s.zip", cgit_query_repo, hex);
|
cgit_print_snapshot_links(cgit_query_repo,hex,cgit_repo->snapshots);
|
||||||
html_attr(cgit_pageurl(cgit_query_repo, "snapshot",
|
html("</td></tr>");
|
||||||
fmt("id=%s&name=%s", hex, filename)));
|
|
||||||
htmlf("'>%s</a></td></tr>", filename);
|
|
||||||
}
|
}
|
||||||
html("</table>\n");
|
html("</table>\n");
|
||||||
html("<div class='commit-subject'>");
|
html("<div class='commit-subject'>");
|
||||||
|
41
ui-shared.c
41
ui-shared.c
@ -57,13 +57,13 @@ char *cgit_repourl(const char *reponame)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char *cgit_pageurl(const char *reponame, const char *pagename,
|
char *cgit_fileurl(const char *reponame, const char *pagename,
|
||||||
const char *query)
|
const char *filename, const char *query)
|
||||||
{
|
{
|
||||||
if (cgit_virtual_root) {
|
if (cgit_virtual_root) {
|
||||||
if (query)
|
if (query)
|
||||||
return fmt("%s/%s/%s/?%s", cgit_virtual_root, reponame,
|
return fmt("%s/%s/%s/%s?%s", cgit_virtual_root, reponame,
|
||||||
pagename, query);
|
pagename, filename?filename:"", query);
|
||||||
else
|
else
|
||||||
return fmt("%s/%s/%s/", cgit_virtual_root, reponame,
|
return fmt("%s/%s/%s/", cgit_virtual_root, reponame,
|
||||||
pagename);
|
pagename);
|
||||||
@ -75,6 +75,37 @@ char *cgit_pageurl(const char *reponame, const char *pagename,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *cgit_pageurl(const char *reponame, const char *pagename,
|
||||||
|
const char *query)
|
||||||
|
{
|
||||||
|
return cgit_fileurl(reponame,pagename,0,query);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *cgit_repobasename(const char *reponame)
|
||||||
|
{
|
||||||
|
/* I assume we don't need to store more than one repo basename */
|
||||||
|
static char rvbuf[1024];
|
||||||
|
int p;
|
||||||
|
const char *rv;
|
||||||
|
strncpy(rvbuf,reponame,sizeof(rvbuf));
|
||||||
|
if(rvbuf[sizeof(rvbuf)-1])
|
||||||
|
die("cgit_repobasename: truncated repository name '%s'", reponame);
|
||||||
|
p = strlen(rvbuf)-1;
|
||||||
|
/* strip trailing slashes */
|
||||||
|
while(p && rvbuf[p]=='/') rvbuf[p--]=0;
|
||||||
|
/* strip trailing .git */
|
||||||
|
if(p>=3 && !strncmp(&rvbuf[p-3],".git",4)) {
|
||||||
|
p -= 3; rvbuf[p--] = 0;
|
||||||
|
}
|
||||||
|
/* strip more trailing slashes if any */
|
||||||
|
while( p && rvbuf[p]=='/') rvbuf[p--]=0;
|
||||||
|
/* find last slash in the remaining string */
|
||||||
|
rv = strrchr(rvbuf,'/');
|
||||||
|
if(rv)
|
||||||
|
return ++rv;
|
||||||
|
return rvbuf;
|
||||||
|
}
|
||||||
|
|
||||||
char *cgit_currurl()
|
char *cgit_currurl()
|
||||||
{
|
{
|
||||||
if (!cgit_virtual_root)
|
if (!cgit_virtual_root)
|
||||||
@ -392,3 +423,5 @@ void cgit_print_snapshot_start(const char *mimetype, const char *filename,
|
|||||||
ttl_seconds(item->ttl)));
|
ttl_seconds(item->ttl)));
|
||||||
html("\n");
|
html("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* vim:set sw=8: */
|
||||||
|
148
ui-snapshot.c
148
ui-snapshot.c
@ -8,40 +8,138 @@
|
|||||||
|
|
||||||
#include "cgit.h"
|
#include "cgit.h"
|
||||||
|
|
||||||
static void cgit_print_zip(struct cacheitem *item, const char *hex,
|
static int write_compressed_tar_archive(struct archiver_args *args,const char *filter)
|
||||||
const char *prefix, const char *filename)
|
|
||||||
{
|
{
|
||||||
struct archiver_args args;
|
int rw[2];
|
||||||
struct commit *commit;
|
pid_t gzpid;
|
||||||
unsigned char sha1[20];
|
int stdout2;
|
||||||
|
int status;
|
||||||
|
int rv;
|
||||||
|
|
||||||
if (get_sha1(hex, sha1)) {
|
stdout2 = chk_non_negative(dup(STDIN_FILENO), "Preserving STDOUT before compressing");
|
||||||
cgit_print_error(fmt("Bad object id: %s", hex));
|
chk_zero(pipe(rw), "Opening pipe from compressor subprocess");
|
||||||
return;
|
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);
|
||||||
}
|
}
|
||||||
commit = lookup_commit_reference(sha1);
|
/* parent */
|
||||||
|
chk_zero(close(rw[0]), "Closing read end of pipe");
|
||||||
|
chk_non_negative(dup2(rw[1],STDOUT_FILENO), "Redirecting output to compressor");
|
||||||
|
|
||||||
if (!commit) {
|
rv = write_tar_archive(args);
|
||||||
cgit_print_error(fmt("Not a commit reference: %s", hex));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&args, 0, sizeof(args));
|
chk_zero(close(STDOUT_FILENO), "Closing STDOUT redirected to compressor");
|
||||||
args.base = fmt("%s/", prefix);
|
chk_non_negative(dup2(stdout2,STDOUT_FILENO), "Restoring uncompressed STDOUT");
|
||||||
args.tree = commit->tree;
|
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_print_snapshot_start("application/x-zip", filename, item);
|
return rv;
|
||||||
write_zip_archive(&args);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int write_tar_gzip_archive(struct archiver_args *args)
|
||||||
|
{
|
||||||
|
return write_compressed_tar_archive(args,"gzip");
|
||||||
|
}
|
||||||
|
static int write_tar_bzip2_archive(struct archiver_args *args)
|
||||||
|
{
|
||||||
|
return write_compressed_tar_archive(args,"bzip2");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct snapshot_archive_t {
|
||||||
|
const char *suffix;
|
||||||
|
const char *mimetype;
|
||||||
|
write_archive_fn_t write_func;
|
||||||
|
int bit;
|
||||||
|
} snapshot_archives[] = {
|
||||||
|
{ ".zip", "application/x-zip", write_zip_archive, 0x1 },
|
||||||
|
{ ".tar.gz", "application/x-tar", write_tar_gzip_archive, 0x2 },
|
||||||
|
{ ".tar.bz2", "application/x-tar", write_tar_bzip2_archive, 0x4 },
|
||||||
|
{ ".tar", "application/x-tar", write_tar_archive, 0x8 }
|
||||||
|
};
|
||||||
|
|
||||||
void cgit_print_snapshot(struct cacheitem *item, const char *hex,
|
void cgit_print_snapshot(struct cacheitem *item, const char *hex,
|
||||||
const char *format, const char *prefix,
|
const char *prefix, const char *filename,
|
||||||
const char *filename)
|
int snapshots)
|
||||||
{
|
{
|
||||||
if (!strcmp(format, "zip"))
|
int fnl = strlen(filename);
|
||||||
cgit_print_zip(item, hex, prefix, filename);
|
int f;
|
||||||
else
|
for(f=0;f<(sizeof(snapshot_archives)/sizeof(*snapshot_archives));++f) {
|
||||||
cgit_print_error(fmt("Unsupported snapshot format: %s",
|
const struct snapshot_archive_t* sat = &snapshot_archives[f];
|
||||||
format));
|
int sl;
|
||||||
|
if(!(snapshots&sat->bit)) continue;
|
||||||
|
sl = strlen(sat->suffix);
|
||||||
|
if(fnl<sl || strcmp(&filename[fnl-sl],sat->suffix))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
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(sat->mimetype, filename, item);
|
||||||
|
(*sat->write_func)(&args);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
cgit_print_error(fmt("Unsupported snapshot format: %s", filename));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cgit_print_snapshot_links(const char *repo,const char *hex,int snapshots)
|
||||||
|
{
|
||||||
|
char *filename;
|
||||||
|
int f;
|
||||||
|
for(f=0;f<(sizeof(snapshot_archives)/sizeof(*snapshot_archives));++f) {
|
||||||
|
const struct snapshot_archive_t* sat = &snapshot_archives[f];
|
||||||
|
if(!(snapshots&sat->bit)) continue;
|
||||||
|
filename = fmt("%s-%s%s",cgit_repobasename(repo),hex,sat->suffix);
|
||||||
|
htmlf("<a href='%s'>%s</a><br/>",
|
||||||
|
cgit_fileurl(repo,"snapshot",filename,
|
||||||
|
fmt("id=%s&name=%s",hex,filename)), filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int cgit_parse_snapshots_mask(const char *str)
|
||||||
|
{
|
||||||
|
static const char *delim = " \t,:/|;";
|
||||||
|
int f, tl, rv = 0;
|
||||||
|
/* favor legacy setting */
|
||||||
|
if(atoi(str)) return 1;
|
||||||
|
for(;;) {
|
||||||
|
str += strspn(str,delim);
|
||||||
|
tl = strcspn(str,delim);
|
||||||
|
if(!tl)
|
||||||
|
break;
|
||||||
|
for(f=0;f<(sizeof(snapshot_archives)/sizeof(*snapshot_archives));++f) {
|
||||||
|
const struct snapshot_archive_t* sat = &snapshot_archives[f];
|
||||||
|
if(! ( strncmp(sat->suffix,str,tl) && strncmp(sat->suffix+1,str,tl-1) ) ) {
|
||||||
|
rv |= sat->bit;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
str += tl;
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* vim:set sw=8: */
|
||||||
|
@ -32,6 +32,10 @@ static void print_object(const unsigned char *sha1, char *path)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html(" blob: <a href='");
|
||||||
|
html_attr(cgit_pageurl(cgit_query_repo, "blob", fmt("id=%s", sha1_to_hex(sha1))));
|
||||||
|
htmlf("'>%s</a>",sha1_to_hex(sha1));
|
||||||
|
|
||||||
html("<table class='blob'>\n");
|
html("<table class='blob'>\n");
|
||||||
idx = 0;
|
idx = 0;
|
||||||
start = 0;
|
start = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user