| -rw-r--r-- | .gitignore | 1 | ||||
| -rw-r--r-- | .gitmodules | 8 | ||||
| -rw-r--r-- | Makefile | 102 | ||||
| -rw-r--r-- | cgit.c | 36 | ||||
| -rw-r--r-- | cgit.css | 75 | ||||
| -rw-r--r-- | cgit.h | 47 | ||||
| -rw-r--r-- | cgitrc | 9 | ||||
| -rwxr-xr-x | gen-version.sh | 20 | ||||
| m--------- | git | 0 | ||||
| -rw-r--r-- | parsing.c | 2 | ||||
| -rw-r--r-- | shared.c | 45 | ||||
| -rwxr-xr-x | submodules.sh | 181 | ||||
| -rw-r--r-- | ui-commit.c | 78 | ||||
| -rw-r--r-- | ui-diff.c | 64 | ||||
| -rw-r--r-- | ui-log.c | 26 | ||||
| -rw-r--r-- | ui-repolist.c | 66 | ||||
| -rw-r--r-- | ui-shared.c | 234 | ||||
| -rw-r--r-- | ui-snapshot.c | 156 | ||||
| -rw-r--r-- | ui-summary.c | 49 | ||||
| -rw-r--r-- | ui-tag.c | 74 | ||||
| -rw-r--r-- | ui-tree.c | 211 | ||||
| -rw-r--r-- | ui-view.c | 55 |
22 files changed, 612 insertions, 927 deletions
@@ -1,5 +1,4 @@ # Files I don't care to see in git-status/commit cgit -VERSION *.o *~ diff --git a/.gitmodules b/.gitmodules index 1daea94..51dd1ef 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,5 @@ -[submodule "git"] - url = git://git.kernel.org/pub/scm/git/git.git - path = git +# This file maps a submodule path to an url from where the submodule +# can be obtained. The script "submodules.sh" finds the url in this file +# when invoked with -i to clone the submodules. + +git git://git.kernel.org/pub/scm/git/git.git @@ -1,71 +1,87 @@ -CGIT_VERSION = v0.5 -CGIT_SCRIPT_NAME = cgit.cgi -CGIT_SCRIPT_PATH = /var/www/htdocs/cgit -CGIT_CONFIG = /etc/cgitrc -CACHE_ROOT = /var/cache/cgit +CGIT_VERSION = 0.5 + +prefix = /var/www/htdocs/cgit + SHA1_HEADER = <openssl/sha.h> -GIT_VER = 1.5.2 -GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2 +CACHE_ROOT = /var/cache/cgit +CGIT_CONFIG = /etc/cgitrc +CGIT_SCRIPT_NAME = cgit.cgi # # Let the user override the above settings. # -include cgit.conf - EXTLIBS = git/libgit.a git/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-tree.o ui-commit.o ui-diff.o \ - ui-snapshot.o ui-blob.o ui-tag.o - - -.PHONY: all git install clean distclean force-version get-git + ui-summary.o ui-log.o ui-view.o ui-tree.o ui-commit.o ui-diff.o \ + ui-snapshot.o ui-blob.o -all: cgit git +CFLAGS += -Wall -VERSION: force-version - @./gen-version.sh "$(CGIT_VERSION)" --include VERSION +ifdef DEBUG + CFLAGS += -g +endif - -CFLAGS += -g -Wall -Igit +CFLAGS += -Igit CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER)' CFLAGS += -DCGIT_VERSION='"$(CGIT_VERSION)"' CFLAGS += -DCGIT_CONFIG='"$(CGIT_CONFIG)"' CFLAGS += -DCGIT_SCRIPT_NAME='"$(CGIT_SCRIPT_NAME)"' -cgit: cgit.c $(OBJECTS) - $(CC) $(CFLAGS) cgit.c -o cgit $(OBJECTS) $(EXTLIBS) +# +# If make is run on a nongit platform, get the git sources as a tarball. +# +GITVER = $(shell git version 2>/dev/null || echo nogit) +ifeq ($(GITVER),nogit) +GITURL = http://www.kernel.org/pub/software/scm/git/git-1.5.2.tar.bz2 +INITGIT = test -e git/git.c || ((curl "$(GITURL)" | tar -xj) && mv git-1.5.2 git) +else +INITGIT = ./submodules.sh -i +endif -$(OBJECTS): cgit.h git/xdiff/lib.a git/libgit.a VERSION -git/xdiff/lib.a: | git +# +# basic build rules +# +all: cgit -git/libgit.a: | git +cgit: cgit.c cgit.h $(OBJECTS) + $(CC) $(CFLAGS) cgit.c -o cgit $(OBJECTS) $(EXTLIBS) -git: - cd git && $(MAKE) xdiff/lib.a - cd git && $(MAKE) libgit.a +$(OBJECTS): cgit.h git/libgit.a -install: all - mkdir -p $(CGIT_SCRIPT_PATH) - install cgit $(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME) - install cgit.css $(CGIT_SCRIPT_PATH)/cgit.css - rm -rf $(CACHE_ROOT)/* +git/libgit.a: + $(INITGIT) + $(MAKE) -C git -uninstall: - rm -f $(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME) - rm -f $(CGIT_SCRIPT_PATH)/cgit.css - rm -rf $(CACHE_ROOT) +# +# phony targets +# +install: all clean-cache + mkdir -p $(prefix) + install cgit $(prefix)/$(CGIT_SCRIPT_NAME) + install cgit.css $(prefix)/cgit.css -clean: - rm -f cgit VERSION *.o - cd git && $(MAKE) clean +clean-cgit: + rm -f cgit *.o -distclean: clean +distclean-cgit: clean-cgit git clean -d -x - cd git && git clean -d -x -get-git: - curl $(GIT_URL) | tar -xj && rm -rf git && mv git-$(GIT_VER) git +clean-sub: + $(MAKE) -C git clean + +distclean-sub: clean-sub + $(shell cd git && git clean -d -x) + +clean-cache: + rm -rf $(CACHE_ROOT)/* + +clean: clean-cgit clean-sub + +distclean: distclean-cgit distclean-sub + +.PHONY: all install clean clean-cgit clean-sub clean-cache \ + distclean distclean-cgit distclean-sub @@ -8,6 +8,9 @@ #include "cgit.h" +const char cgit_version[] = CGIT_VERSION; + + static int cgit_prepare_cache(struct cacheitem *item) { if (!cgit_repo && cgit_query_repo) { @@ -26,15 +29,13 @@ static int cgit_prepare_cache(struct cacheitem *item) } if (!cgit_cmd) { - item->name = xstrdup(fmt("%s/%s/index.%s.html", cgit_cache_root, - cache_safe_filename(cgit_repo->url), - cache_safe_filename(cgit_querystring))); + item->name = xstrdup(fmt("%s/%s/index.html", cgit_cache_root, + cache_safe_filename(cgit_repo->url))); item->ttl = cgit_cache_repo_ttl; } else { item->name = xstrdup(fmt("%s/%s/%s/%s.html", cgit_cache_root, - cache_safe_filename(cgit_repo->url), - cgit_query_page, - cache_safe_filename(cgit_querystring))); + cache_safe_filename(cgit_repo->url), cgit_query_page, + cache_safe_filename(cgit_querystring))); if (cgit_query_has_symref) item->ttl = cgit_cache_dynamic_ttl; else if (cgit_query_has_sha1) @@ -68,10 +69,8 @@ static void cgit_print_repo_page(struct cacheitem *item) setenv("GIT_DIR", cgit_repo->path, 1); if ((cgit_cmd == CMD_SNAPSHOT) && cgit_repo->snapshots) { - cgit_print_snapshot(item, cgit_query_head, cgit_query_sha1, - cgit_repobasename(cgit_repo->url), - cgit_query_path, - cgit_repo->snapshots ); + cgit_print_snapshot(item, cgit_query_sha1, "zip", + cgit_repo->url, cgit_query_name); return; } @@ -93,21 +92,22 @@ static void cgit_print_repo_page(struct cacheitem *item) switch(cgit_cmd) { case CMD_LOG: - cgit_print_log(cgit_query_sha1, cgit_query_ofs, + cgit_print_log(cgit_query_head, cgit_query_ofs, cgit_max_commit_count, cgit_query_search, cgit_query_path, 1); break; case CMD_TREE: - cgit_print_tree(cgit_query_sha1, cgit_query_path); + cgit_print_tree(cgit_query_head, cgit_query_sha1, cgit_query_path); break; case CMD_COMMIT: - cgit_print_commit(cgit_query_sha1); + cgit_print_commit(cgit_query_head); break; - case CMD_TAG: - cgit_print_tag(cgit_query_sha1); + case CMD_VIEW: + cgit_print_view(cgit_query_sha1, cgit_query_path); break; case CMD_DIFF: - cgit_print_diff(cgit_query_sha1, cgit_query_sha2); + cgit_print_diff(cgit_query_head, cgit_query_sha1, cgit_query_sha2, + cgit_query_path); break; default: cgit_print_error("Invalid request"); @@ -227,7 +227,6 @@ static void cgit_parse_args(int argc, const char **argv) int main(int argc, const char **argv) { struct cacheitem item; - const char *cgit_config_env = getenv("CGIT_CONFIG"); htmlfd = STDOUT_FILENO; item.st.st_mtime = time(NULL); @@ -235,8 +234,7 @@ int main(int argc, const char **argv) cgit_repolist.count = 0; cgit_repolist.repos = NULL; - cgit_read_config(cgit_config_env ? cgit_config_env : CGIT_CONFIG, - cgit_global_config_cb); + cgit_read_config(CGIT_CONFIG, cgit_global_config_cb); cgit_repo = NULL; if (getenv("SCRIPT_NAME")) cgit_script_name = xstrdup(getenv("SCRIPT_NAME")); @@ -1,7 +1,6 @@ body { - font-family: arial, sans-serif; + font-family: arial; font-size: 11pt; - color: black; background: white; } @@ -95,14 +94,6 @@ td#header { vertical-align: text-bottom; } -td#header a { - color: #666; -} - -td#header a:hoved { - text-decoration: underline; -} - td#logo { text-align: right; vertical-align: middle; @@ -123,19 +114,15 @@ td#crumb { td#crumb a { color: #ccc; - background-color: #666; - padding: 0em 0.5em 0em 0.5em; } td#crumb a:hover { - color: #666; - background-color: #ccc; - text-decoration: none; + color: #eee; } td#search { text-align: right; - vertical-align: middle; + vertical-align: center; padding-right: 0.5em; } @@ -184,47 +171,35 @@ div.error { margin: 1em 2em; } -a.ls-blob, a.ls-dir, a.ls-mod { +td.ls-blob, td.ls-dir, td.ls-mod { font-family: monospace; } -td.ls-size { - text-align: right; +div.ls-dir a { + font-weight: bold; } -td.ls-size { - font-family: monospace; +th.filesize, td.filesize { + text-align: right; } -td.ls-mode { +td.filesize { font-family: monospace; } -table.blob { - margin-top: 0.5em; - border-top: solid 1px black; -} - -table.blob td.no { - border-right: solid 1px black; - color: black; - background-color: #eee; - text-align: right; -} - -table.blob td.no a { - color: black; +td.links { + font-size: 80%; + padding-left: 2em; } -table.blob td.no a:hover { - color: black; - text-decoration: none; +td.filemode { + font-family: monospace; } -table.blob td.txt { +td.blob { white-space: pre; font-family: monospace; - padding-left: 0.5em; + background-color: white; } table.nowrap td { @@ -240,7 +215,6 @@ table.commit-info th { text-align: left; font-weight: normal; padding: 0.1em 1em 0.1em 0.1em; - vertical-align: top; } table.commit-info td { @@ -313,7 +287,7 @@ table.diffstat td.upd a { table.diffstat td.graph { width: 75%; - vertical-align: middle; + vertical-align: center; } table.diffstat td.graph table { @@ -334,6 +308,10 @@ table.diffstat td.graph td.rem { background-color: #c55; } +table.diffstat td.graph td.none { + background-color: none; +} + div.diffstat-summary { color: #888; padding-top: 0.5em; @@ -362,7 +340,7 @@ table.diff td div.del { } .sha1 { - font-family: monospace; + font-family: courier; font-size: 90%; } @@ -381,17 +359,16 @@ table.list td.repogroup { a.button { font-size: 80%; - color: #aaa; - background-color: #eee; - border: solid 1px #aaa; + color: #333; + background-color: #ccc; + border: solid 1px #999; padding: 0em 0.5em; margin: 0.1em 0.25em; } a.button:hover { text-decoration: none; - color: #333; - background-color: #ccc; + background-color: #eee; } a.primary { @@ -25,9 +25,10 @@ #define CMD_COMMIT 2 #define CMD_DIFF 3 #define CMD_TREE 4 -#define CMD_BLOB 5 -#define CMD_SNAPSHOT 6 -#define CMD_TAG 7 +#define CMD_VIEW 5 +#define CMD_BLOB 6 +#define CMD_SNAPSHOT 7 + /* * Dateformats used on misc. pages @@ -98,7 +99,7 @@ struct taginfo { char *msg; }; -extern const char *cgit_version; +extern const char cgit_version[]; extern struct repolist cgit_repolist; extern struct repoinfo *cgit_repo; @@ -118,7 +119,6 @@ extern char *cgit_repo_group; extern int cgit_nocache; extern int cgit_snapshots; -extern int cgit_enable_index_links; extern int cgit_enable_log_filecount; extern int cgit_enable_log_linecount; extern int cgit_max_lock_attempts; @@ -157,10 +157,8 @@ 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 chk_non_negative(int result, char *msg); extern int hextoint(char c); -extern char *trim_end(const char *str, char c); extern void *cgit_free_commitinfo(struct commitinfo *info); @@ -201,26 +199,9 @@ extern int cache_exist(struct cacheitem *item); extern int cache_expired(struct cacheitem *item); 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, const char *query); -extern const char *cgit_repobasename(const char *reponame); - -extern void cgit_tree_link(char *name, char *title, char *class, char *head, - char *rev, char *path); -extern void cgit_log_link(char *name, char *title, char *class, char *head, - char *rev, char *path, int ofs); -extern void cgit_commit_link(char *name, char *title, char *class, char *head, - char *rev); -extern void cgit_snapshot_link(char *name, char *title, char *class, - char *head, char *rev, char *archivename); -extern void cgit_diff_link(char *name, char *title, char *class, char *head, - char *new_rev, char *old_rev, char *path); - -extern void cgit_object_link(struct object *obj); - extern void cgit_print_error(char *msg); extern void cgit_print_date(time_t secs, char *format); extern void cgit_print_age(time_t t, time_t max_relative, char *format); @@ -234,16 +215,14 @@ extern void cgit_print_snapshot_start(const char *mimetype, extern void cgit_print_repolist(struct cacheitem *item); extern void cgit_print_summary(); extern void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *path, int pager); +extern void cgit_print_view(const char *hex, char *path); extern void cgit_print_blob(struct cacheitem *item, const char *hex, char *path); -extern void cgit_print_tree(const char *rev, char *path); -extern void cgit_print_commit(char *hex); -extern void cgit_print_tag(char *revname); -extern void cgit_print_diff(const char *new_hex, const char *old_hex); -extern void cgit_print_snapshot(struct cacheitem *item, const char *head, - const char *hex, const char *prefix, - const char *filename, int snapshot); -extern void cgit_print_snapshot_links(const char *repo, const char *head, - const char *hex, int snapshots); -extern int cgit_parse_snapshots_mask(const char *str); +extern void cgit_print_tree(const char *rev, const char *hex, char *path); +extern void cgit_print_commit(const char *hex); +extern void cgit_print_diff(const char *head, const char *old_hex, const char *new_hex, + char *path); +extern void cgit_print_snapshot(struct cacheitem *item, const char *hex, + const char *format, const char *prefix, + const char *filename); #endif /* CGIT_H */ @@ -8,15 +8,10 @@ #nocache=0 -## Set allowed snapshot types by default. Can be overridden per repo -# can be any combination of zip/tar.gz/tar.bz2/tar +## Enable/disable snapshots by default. This can be overridden per repo #snapshots=0 -## Enable/disable extra links to summary/log/tree per repo on index page -#enable-index-links=0 - - ## Enable/disable display of 'number of files changed' in log view #enable-log-filecount=0 @@ -114,7 +109,7 @@ #repo.desc=the caching cgi for git #repo.path=/pub/git/cgit #repo.owner=Lars Hjemli -#repo.snapshots=tar.bz2 # override a sitewide snapshot-setting +#repo.snapshots=1 # override a sitewide snapshot-setting #repo.enable-log-filecount=0 # override the default filecount setting #repo.enable-log-linecount=0 # override the default linecount setting #repo.module-link=/git/%s/commit/?id=%s # override the standard module-link diff --git a/gen-version.sh b/gen-version.sh deleted file mode 100755 index 739c83e..0000000 --- a/gen-version.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh - -# Get version-info specified in Makefile -V=$1 - -# Use `git describe` to get current version if we're inside a git repo -if test -d .git -then - V=$(git describe --abbrev=4 HEAD 2>/dev/null | sed -e 's/-/./g') -fi - -new="CGIT_VERSION = $V" -old=$(cat VERSION 2>/dev/null) - -# Exit if VERSION is uptodate -test "$old" = "$new" && exit 0 - -# Update VERSION with new version-info -echo "$new" > VERSION -cat VERSION diff --git a/git b/git -Subproject 86bab9615c3516d4ac7756ae3c1285d331b78f0 +Subproject aba170cdb4874b72dd619e6f7bbc13c33295f83 @@ -168,7 +168,7 @@ void cgit_parse_url(const char *url) if (p) { p[0] = '\0'; if (p[1]) - cgit_query_path = trim_end(p + 1, '/'); + cgit_query_path = xstrdup(p + 1); } cgit_cmd = cgit_get_cmd_index(cmd + 1); cgit_query_page = xstrdup(cmd + 1); @@ -12,8 +12,6 @@ struct repolist cgit_repolist; struct repoinfo *cgit_repo; int cgit_cmd; -const char *cgit_version = CGIT_VERSION; - char *cgit_root_title = "Git repository browser"; char *cgit_css = "/cgit.css"; char *cgit_logo = "/git-logo.png"; @@ -28,7 +26,6 @@ char *cgit_repo_group = NULL; int cgit_nocache = 0; int cgit_snapshots = 0; -int cgit_enable_index_links = 0; int cgit_enable_log_filecount = 0; int cgit_enable_log_linecount = 0; int cgit_max_lock_attempts = 5; @@ -62,8 +59,7 @@ int htmlfd = 0; int cgit_get_cmd_index(const char *cmd) { - static char *cmds[] = {"log", "commit", "diff", "tree", "blob", - "snapshot", "tag", NULL}; + static char *cmds[] = {"log", "commit", "diff", "tree", "view", "blob", "snapshot", NULL}; int i; for(i = 0; cmds[i]; i++) @@ -86,13 +82,6 @@ int chk_positive(int result, char *msg) 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 *ret; @@ -155,9 +144,7 @@ void cgit_global_config_cb(const char *name, const char *value) else if (!strcmp(name, "nocache")) cgit_nocache = atoi(value); else if (!strcmp(name, "snapshots")) - cgit_snapshots = cgit_parse_snapshots_mask(value); - else if (!strcmp(name, "enable-index-links")) - cgit_enable_index_links = atoi(value); + cgit_snapshots = atoi(value); else if (!strcmp(name, "enable-log-filecount")) cgit_enable_log_filecount = atoi(value); else if (!strcmp(name, "enable-log-linecount")) @@ -197,7 +184,7 @@ void cgit_global_config_cb(const char *name, const char *value) else if (cgit_repo && !strcmp(name, "repo.defbranch")) cgit_repo->defbranch = xstrdup(value); else if (cgit_repo && !strcmp(name, "repo.snapshots")) - cgit_repo->snapshots = cgit_snapshots & cgit_parse_snapshots_mask(value); /* XXX: &? */ + cgit_repo->snapshots = cgit_snapshots * atoi(value); else if (cgit_repo && !strcmp(name, "repo.enable-log-filecount")) cgit_repo->enable_log_filecount = cgit_enable_log_filecount * atoi(value); else if (cgit_repo && !strcmp(name, "repo.enable-log-linecount")) @@ -237,7 +224,7 @@ void cgit_querystring_cb(const char *name, const char *value) } else if (!strcmp(name, "ofs")) { cgit_query_ofs = atoi(value); } else if (!strcmp(name, "path")) { - cgit_query_path = trim_end(value, '/'); + cgit_query_path = xstrdup(value); } else if (!strcmp(name, "name")) { cgit_query_name = xstrdup(value); } @@ -266,28 +253,6 @@ int hextoint(char c) return -1; } -char *trim_end(const char *str, char c) -{ - int len; - char *s, *t; - - if (str == NULL) - return NULL; - t = (char *)str; - len = strlen(t); - while(len > 0 && t[len - 1] == c) - len--; - - if (len == 0) - return NULL; - - c = t[len]; - t[len] = '\0'; - s = xstrdup(t); - t[len] = c; - return s; -} - void cgit_diff_tree_cb(struct diff_queue_struct *q, struct diff_options *options, void *data) { @@ -394,7 +359,7 @@ void cgit_diff_tree(const unsigned char *old_sha1, opt.format_callback_data = fn; diff_setup_done(&opt); - if (old_sha1 && !is_null_sha1(old_sha1)) + if (old_sha1) ret = diff_tree_sha1(old_sha1, new_sha1, "", &opt); else ret = diff_root_tree_sha1(new_sha1, "", &opt); diff --git a/submodules.sh b/submodules.sh new file mode 100755 index 0000000..1d7b13f --- /dev/null +++ b/submodules.sh @@ -0,0 +1,181 @@ +#!/bin/sh +# +# submodules.sh: init, update or list git submodules +# +# Copyright (C) 2006 Lars Hjemli +# +# Licensed under GNU General Public License v2 +# (see COPYING for full license text) +# + + +usage="submodules.sh [-i | -u] [-q] [--cached] [path...]" +init= +update= +quiet= +cached= + + +say() +{ + if test -z "$quiet" + then + echo -e "$@" + fi +} + + +die() +{ + echo >&2 -e "$@" + exit 1 +} + + + +# +# Silently checkout specified submodule revision, return exit status of git-checkout +# +# $1 = local path +# $2 = requested sha1 +# +module_checkout() +{ + $(cd "$1" && git checkout "$2" 1>/dev/null 2>/dev/null) +} + + +# +# Find all (requested) submodules, run clone + checkout on missing paths +# +# $@ = requested paths (default to all) +# +modules_init() +{ + git ls-files --stage -- $@ | grep -e '^160000 ' | + while read mode sha1 stage path + do + test -d "$path/.git" && continue + + if test -d "$path" + then + rmdir "$path" 2>/dev/null || + die "Directory '$path' exist, but not as a submodule" + fi + + test -e "$path" && die "A file already exist at path '$path'" + + url=$(sed -nre "s/^$path[ \t]+//p" .gitmodules) + test -z "$url" && die "No url found for $path in .gitmodules" + + git clone "$url" "$path" || die "Clone of submodule '$path' failed" + module_checkout "$path" "$sha1" || die "Checkout of submodule '$path' failed" + say "Submodule '$path' initialized" + done +} + +# +# Checkout correct revision of each initialized submodule +# +# $@ = requested paths (default to all) +# +modules_update() +{ + git ls-files --stage -- $@ | grep -e '^160000 ' | + while read mode sha1 stage path + do + if ! test -d "$path/.git" + then + say "Submodule '$path' not initialized" + continue; + fi + subsha1=$(cd "$path" && git rev-parse --verify HEAD) || + die "Unable to find current revision of submodule '$path'" + if test "$subsha1" != "$sha1" + then + module_checkout "$path" "$sha1" || + die "Unable to checkout revision $sha1 of submodule '$path'" + say "Submodule '$path' reset to revision $sha1" + fi + done +} + +# +# List all registered submodules, prefixed with: +# - submodule not initialized +# + different version checked out +# +# If --cached was specified the revision in the index will be printed +# instead of the currently checked out revision. +# +# $@ = requested paths (default to all) +# +modules_list() +{ + git ls-files --stage -- $@ | grep -e '^160000 ' | + while read mode sha1 stage path + do + if ! test -d "$path/.git" + then + say "-$sha1 $path" + continue; + fi + revname=$(cd "$path" && git describe $sha1) + if git diff-files --quiet -- "$path" + then + say " $sha1 $path\t($revname)" + else + if test -z "$cached" + then + sha1=$(cd "$path" && git rev-parse HEAD) + revname=$(cd "$path" && git describe HEAD) + fi + say "+$sha1 $path\t($revname)" + fi + done +} + + +while case "$#" in 0) break ;; esac +do + case "$1" in + -i) + init=1 + ;; + -u) + update=1 + ;; + -q) + quiet=1 + ;; + --cached) + cached=1 + ;; + --) + break + ;; + -*) + echo "Usage: $usage" + exit 1 + ;; + --*) + echo "Usage: $usage" + exit 1 + ;; + *) + break + ;; + esac + shift +done + + +if test "$init" = "1" +then + modules_init $@ +elif test "$update" = "1" +then + modules_update $@ +else + modules_list $@ +fi diff --git a/ui-commit.c b/ui-commit.c index 90e09ed..1d12bbb 100644 --- a/ui-commit.c +++ b/ui-commit.c @@ -11,7 +11,6 @@ static int files, slots; static int total_adds, total_rems, max_changes; static int lines_added, lines_removed; -static char *curr_rev; static struct fileinfo { char status; @@ -28,6 +27,7 @@ static struct fileinfo { void print_fileinfo(struct fileinfo *info) { + char *query, *query2; char *class; switch (info->status) { @@ -75,12 +75,24 @@ void print_fileinfo(struct fileinfo *info) html("]</span>"); } htmlf("</td><td class='%s'>", class); - cgit_tree_link(info->new_path, NULL, NULL, cgit_query_head, curr_rev, - info->new_path); - if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED) - htmlf(" (%s from %s)", - info->status == DIFF_STATUS_COPIED ? "copied" : "renamed", - info->old_path); + query = fmt("id=%s&id2=%s&path=%s", sha1_to_hex(info->old_sha1), + sha1_to_hex(info->new_sha1), info->new_path); + html_link_open(cgit_pageurl(cgit_query_repo, "diff", query), + NULL, NULL); + if (info->status == DIFF_STATUS_COPIED || + info->status == DIFF_STATUS_RENAMED) { + html_txt(info->new_path); + htmlf("</a> (%s from ", info->status == DIFF_STATUS_COPIED ? + "copied" : "renamed"); + query2 = fmt("id=%s", sha1_to_hex(info->old_sha1)); + html_link_open(cgit_pageurl(cgit_query_repo, "view", query2), + NULL, NULL); + html_txt(info->old_path); + html("</a>)"); + } else { + html_txt(info->new_path); + html("</a>"); + } html("</td><td class='right'>"); htmlf("%d", info->added + info->removed); html("</td><td class='graph'>"); @@ -133,19 +145,16 @@ void inspect_filepair(struct diff_filepair *pair) } -void cgit_print_commit(char *hex) +void cgit_print_commit(const char *hex) { struct commit *commit, *parent; struct commitinfo *info; struct commit_list *p; unsigned char sha1[20]; - char *tmp; + char *query; + char *filename; int i; - if (!hex) - hex = cgit_query_head; - curr_rev = hex; - if (get_sha1(hex, sha1)) { cgit_print_error(fmt("Bad object id: %s", hex)); return; @@ -172,11 +181,11 @@ void cgit_print_commit(char *hex) html("</td><td class='right'>"); cgit_print_date(info->committer_date, FMT_LONGDATE); html("</td></tr>\n"); - html("<tr><th>tree</th><td colspan='2' class='sha1'>"); - tmp = xstrdup(hex); - cgit_tree_link(sha1_to_hex(commit->tree->object.sha1), NULL, NULL, - cgit_query_head, tmp, NULL); - html("</td></tr>\n"); + html("<tr><th>tree</th><td colspan='2' class='sha1'><a href='"); + query = fmt("h=%s&id=%s", sha1_to_hex(commit->object.sha1), + sha1_to_hex(commit->tree->object.sha1)); + html_attr(cgit_pageurl(cgit_query_repo, "tree", query)); + htmlf("'>%s</a></td></tr>\n", sha1_to_hex(commit->tree->object.sha1)); for (p = commit->parents; p ; p = p->next) { parent = lookup_commit_reference(p->item->object.sha1); if (!parent) { @@ -186,19 +195,23 @@ void cgit_print_commit(char *hex) continue; } html("<tr><th>parent</th>" - "<td colspan='2' class='sha1'>"); - cgit_commit_link(sha1_to_hex(p->item->object.sha1), NULL, NULL, - cgit_query_head, sha1_to_hex(p->item->object.sha1)); - html(" ("); - cgit_diff_link("diff", NULL, NULL, cgit_query_head, hex, - sha1_to_hex(p->item->object.sha1), NULL); - html(")</td></tr>"); + "<td colspan='2' class='sha1'>" + "<a href='"); + query = fmt("h=%s", sha1_to_hex(p->item->object.sha1)); + html_attr(cgit_pageurl(cgit_query_repo, "commit", query)); + htmlf("'>%s</a> (<a href='", + sha1_to_hex(p->item->object.sha1)); + query = fmt("id=%s&id2=%s", sha1_to_hex(parent->tree->object.sha1), + sha1_to_hex(commit->tree->object.sha1)); + html_attr(cgit_pageurl(cgit_query_repo, "diff", query)); + html("'>diff</a>)</td></tr>"); } if (cgit_repo->snapshots) { - html("<tr><th>download</th><td colspan='2' class='sha1'>"); - cgit_print_snapshot_links(cgit_query_repo, cgit_query_head, - hex, cgit_repo->snapshots); - html("</td></tr>"); + 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'>"); @@ -218,9 +231,10 @@ void cgit_print_commit(char *hex) html("<div class='diffstat-summary'>"); htmlf("%d files changed, %d insertions, %d deletions (", files, total_adds, total_rems); - cgit_diff_link("show diff", NULL, NULL, cgit_query_head, hex, - NULL, NULL); - html(")</div>"); + query = fmt("h=%s", hex); + html_link_open(cgit_pageurl(cgit_query_repo, "diff", query), NULL, NULL); + html("show diff</a>)"); + html("</div>"); } cgit_free_commitinfo(info); } @@ -89,52 +89,54 @@ static void filepair_cb(struct diff_filepair *pair) cgit_print_error("Error running diff"); } -void cgit_print_diff(const char *new_rev, const char *old_rev) +void cgit_print_diff(const char *head, const char *old_hex, const char *new_hex, char *path) { unsigned char sha1[20], sha2[20]; enum object_type type; unsigned long size; - struct commit *commit, *commit2; + struct commit *commit; - if (!new_rev) - new_rev = cgit_query_head; - get_sha1(new_rev, sha1); - type = sha1_object_info(sha1, &size); - if (type == OBJ_BAD) { - cgit_print_error(fmt("Bad object name: %s", new_rev)); - return; - } - if (type != OBJ_COMMIT) { - cgit_print_error(fmt("Unhandled object type: %s", - typename(type))); + if (head && !old_hex && !new_hex) { + get_sha1(head, sha1); + commit = lookup_commit_reference(sha1); + if (commit && !parse_commit(commit)) { + html("<table class='diff'>"); + html("<tr><td>"); + cgit_diff_commit(commit, filepair_cb); + html("</td></tr>"); + html("</table>"); + } return; } - commit = lookup_commit_reference(sha1); - if (!commit || parse_commit(commit)) - cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(sha1))); + get_sha1(old_hex, sha1); + get_sha1(new_hex, sha2); - if (old_rev) - get_sha1(old_rev, sha2); - else if (commit->parents && commit->parents->item) - hashcpy(sha2, commit->parents->item->object.sha1); - else - hashclr(sha2); - - if (!is_null_sha1(sha2)) { + type = sha1_object_info(sha1, &size); + if (type == OBJ_BAD) { type = sha1_object_info(sha2, &size); if (type == OBJ_BAD) { - cgit_print_error(fmt("Bad object name: %s", sha1_to_hex(sha2))); + cgit_print_error(fmt("Bad object names: %s, %s", old_hex, new_hex)); return; } - commit2 = lookup_commit_reference(sha2); - if (!commit2 || parse_commit(commit2)) - cgit_print_error(fmt("Bad commit: %s", sha1_to_hex(sha2))); } html("<table class='diff'>"); - html("<tr><td>"); - cgit_diff_tree(sha2, sha1, filepair_cb); - html("</td></tr>"); + switch(type) { + case OBJ_BLOB: + html("<tr><td>"); + header(sha1, path, 0644, sha2, path, 0644); + if (cgit_diff_files(sha1, sha2, print_line)) + cgit_print_error("Error running diff"); + html("</td></tr>"); + break; + case OBJ_TREE: + cgit_diff_tree(sha1, sha2, filepair_cb); + break; + default: + cgit_print_error(fmt("Unhandled object type: %s", + typename(type))); + break; + } html("</table>"); } @@ -31,8 +31,11 @@ void print_commit(struct commit *commit) html("<tr><td>"); cgit_print_age(commit->date, TM_WEEK * 2, FMT_SHORTDATE); html("</td><td>"); - cgit_commit_link(info->subject, NULL, NULL, cgit_query_head, - sha1_to_hex(commit->object.sha1)); + char *qry = fmt("h=%s", sha1_to_hex(commit->object.sha1)); + char *url = cgit_pageurl(cgit_query_repo, "commit", qry); + html_link_open(url, NULL, NULL); + html_ntxt(cgit_max_msg_len, info->subject); + html_link_close(); if (cgit_repo->enable_log_filecount) { files = 0; lines = 0; @@ -59,9 +62,6 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *path, i int argc = 2; int i; - if (!tip) - argv[1] = cgit_query_head; - if (grep) argv[argc++] = fmt("--grep=%s", grep); if (path) { @@ -113,15 +113,17 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *path, i if (pager) { html("<div class='pager'>"); if (ofs > 0) { - cgit_log_link("[prev]", NULL, NULL, cgit_query_head, - cgit_query_sha1, cgit_query_path, - ofs - cnt); - html(" "); + html(" <a href='"); + html(cgit_pageurl(cgit_query_repo, cgit_query_page, + fmt("h=%s&ofs=%d", tip, ofs-cnt))); + html("'>[prev]</a> "); } + if ((commit = get_revision(&rev)) != NULL) { - cgit_log_link("[next]", NULL, NULL, cgit_query_head, - cgit_query_sha1, cgit_query_path, - ofs + cnt); + html(" <a href='"); + html(cgit_pageurl(cgit_query_repo, "log", + fmt("h=%s&ofs=%d", tip, ofs+cnt))); + html("'>[next]</a> "); } html("</div>"); } diff --git a/ui-repolist.c b/ui-repolist.c index 4c86543..e5c6c20 100644 --- a/ui-repolist.c +++ b/ui-repolist.c @@ -44,19 +44,16 @@ static void print_modtime(struct repoinfo *repo) void cgit_print_repolist(struct cacheitem *item) { - int i, columns = 4; + struct repoinfo *repo; + int i; char *last_group = NULL; - if (cgit_enable_index_links) - columns++; - cgit_print_docstart(cgit_root_title, item); cgit_print_pageheader(cgit_root_title, 0); html("<table class='list nowrap'>"); if (cgit_index_header) { - htmlf("<tr class='nohover'><td colspan='%d' class='include-block'>", - columns); + html("<tr class='nohover'><td colspan='5' class='include-block'>"); html_include(cgit_index_header); html("</td></tr>"); } @@ -64,45 +61,42 @@ void cgit_print_repolist(struct cacheitem *item) "<th class='left'>Name</th>" "<th class='left'>Description</th>" "<th class='left'>Owner</th>" - "<th class='left'>Idle</th>"); - if (cgit_enable_index_links) - html("<th>Links</th>"); - html("</tr>\n"); + "<th class='left'>Idle</th>" + "<th>Links</th></tr>\n"); for (i=0; i<cgit_repolist.count; i++) { - cgit_repo = &cgit_repolist.repos[i]; - if ((last_group == NULL && cgit_repo->group != NULL) || - (last_group != NULL && cgit_repo->group == NULL) || - (last_group != NULL && cgit_repo->group != NULL && - strcmp(cgit_repo->group, last_group))) { - htmlf("<tr class='nohover'><td colspan='%d' class='repogroup'>", - columns); - html_txt(cgit_repo->group); + repo = &cgit_repolist.repos[i]; + if ((last_group == NULL && repo->group != NULL) || + (last_group != NULL && repo->group == NULL) || + (last_group != NULL && repo->group!= NULL && + strcmp(repo->group, last_group))) { + html("<tr class='nohover'><td colspan='4' class='repogroup'>"); + html_txt(repo->group); html("</td></tr>"); - last_group = cgit_repo->group; + last_group = repo->group; } htmlf("<tr><td class='%s'>", - cgit_repo->group ? "sublevel-repo" : "toplevel-repo"); - html_link_open(cgit_repourl(cgit_repo->url), NULL, NULL); - html_txt(cgit_repo->name); + repo->group ? "sublevel-repo" : "toplevel-repo"); + html_link_open(cgit_repourl(repo->url), repo->desc, NULL); + html_txt(repo->name); html_link_close(); html("</td><td>"); - html_ntxt(cgit_max_repodesc_len, cgit_repo->desc); + html_ntxt(cgit_max_repodesc_len, repo->desc); html("</td><td>"); - html_txt(cgit_repo->owner); + html_txt(repo->owner); html("</td><td>"); - print_modtime(cgit_repo); - html("</td>"); - if (cgit_enable_index_links) { - html("<td>"); - html_link_open(cgit_repourl(cgit_repo->url), - NULL, "button"); - html("summary</a>"); - cgit_log_link("log", NULL, "button", NULL, NULL, NULL, 0); - cgit_tree_link("tree", NULL, "button", NULL, NULL, NULL); - html("</td>"); - } - html("</tr>\n"); + print_modtime(repo); + html("</td><td>"); + html_link_open(cgit_repourl(repo->url), + "Summary", "button"); + html("S</a>"); + html_link_open(cgit_pageurl(repo->name, "log", NULL), + "Log", "button"); + html("L</a>"); + html_link_open(cgit_pageurl(repo->name, "tree", NULL), + "Files", "button"); + html("F</a>"); + html("</td></tr>\n"); } html("</table>"); cgit_print_docend(); diff --git a/ui-shared.c b/ui-shared.c index 5c5bcf3..aba93e8 100644 --- a/ui-shared.c +++ b/ui-shared.c @@ -57,13 +57,13 @@ char *cgit_repourl(const char *reponame) } } -char *cgit_fileurl(const char *reponame, const char *pagename, - const char *filename, const char *query) +char *cgit_pageurl(const char *reponame, const char *pagename, + const char *query) { if (cgit_virtual_root) { if (query) - return fmt("%s/%s/%s/%s?%s", cgit_virtual_root, reponame, - pagename, filename?filename:"", query); + return fmt("%s/%s/%s/?%s", cgit_virtual_root, reponame, + pagename, query); else return fmt("%s/%s/%s/", cgit_virtual_root, reponame, pagename); @@ -75,37 +75,6 @@ char *cgit_fileurl(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() { if (!cgit_virtual_root) @@ -118,166 +87,6 @@ char *cgit_currurl() return fmt("%s/", cgit_virtual_root); } -static char *repolink(char *title, char *class, char *page, char *head, - char *path) -{ - char *delim = "?"; - - html("<a"); - if (title) { - html(" title='"); - html_attr(title); - html("'"); - } - if (class) { - html(" class='"); - html_attr(class); - html("'"); - } - html(" href='"); - if (cgit_virtual_root) { - html_attr(cgit_virtual_root); - if (cgit_virtual_root[strlen(cgit_virtual_root) - 1] != '/') - html("/"); - html_attr(cgit_repo->url); - if (cgit_repo->url[strlen(cgit_repo->url) - 1] != '/') - html("/"); - if (page) { - html(page); - html("/"); - if (path) - html_attr(path); - } - } else { - html(cgit_script_name); - html("?url="); - html_attr(cgit_repo->url); - if (cgit_repo->url[strlen(cgit_repo->url) - 1] != '/') - html("/"); - if (page) { - html(page); - html("/"); - if (path) - html_attr(path); - } - delim = "&"; - } - if (head && strcmp(head, cgit_repo->defbranch)) { - html(delim); - html("h="); - html_attr(head); - delim = "&"; - } - return fmt("%s", delim); -} - -static void reporevlink(char *page, char *name, char *title, char *class, - char *head, char *rev, char *path) -{ - char *delim; - - delim = repolink(title, class, page, head, path); - if (rev && strcmp(rev, cgit_query_head)) { - html(delim); - html("id="); - html_attr(rev); - } - html("'>"); - html_txt(name); - html("</a>"); -} - -void cgit_tree_link(char *name, char *title, char *class, char *head, - char *rev, char *path) -{ - reporevlink("tree", name, title, class, head, rev, path); -} - -void cgit_log_link(char *name, char *title, char *class, char *head, - char *rev, char *path, int ofs) -{ - char *delim; - - delim = repolink(title, class, "log", head, path); - if (rev && strcmp(rev, cgit_query_head)) { - html(delim); - html("id="); - html_attr(rev); - delim = "&"; - } - if (ofs > 0) { - html(delim); - html("ofs="); - htmlf("%d", ofs); - } - html("'>"); - html_txt(name); - html("</a>"); -} - -void cgit_commit_link(char *name, char *title, char *class, char *head, - char *rev) -{ - if (strlen(name) > cgit_max_msg_len && cgit_max_msg_len >= 15) { - name[cgit_max_msg_len] = '\0'; - name[cgit_max_msg_len - 1] = '.'; - name[cgit_max_msg_len - 2] = '.'; - name[cgit_max_msg_len - 3] = '.'; - } - reporevlink("commit", name, title, class, head, rev, NULL); -} - -void cgit_snapshot_link(char *name, char *title, char *class, char *head, - char *rev, char *archivename) -{ - reporevlink("snapshot", name, title, class, head, rev, archivename); -} - -void cgit_diff_link(char *name, char *title, char *class, char *head, - char *new_rev, char *old_rev, char *path) -{ - char *delim; - - delim = repolink(title, class, "diff", head, path); - if (new_rev && strcmp(new_rev, cgit_query_head)) { - html(delim); - html("id="); - html_attr(new_rev); - delim = "&"; - } - if (old_rev) { - html(delim); - html("id2="); - html_attr(old_rev); - } - html("'>"); - html_txt(name); - html("</a>"); -} - -void cgit_object_link(struct object *obj) -{ - char *page, *arg, *url; - - if (obj->type == OBJ_COMMIT) { - cgit_commit_link(fmt("commit %s", sha1_to_hex(obj->sha1)), NULL, NULL, - cgit_query_head, sha1_to_hex(obj->sha1)); - return; - } else if (obj->type == OBJ_TREE) { - page = "tree"; - arg = "id"; - } else { - page = "blob"; - arg = "id"; - } - - url = cgit_pageurl(cgit_query_repo, page, - fmt("%s=%s", arg, sha1_to_hex(obj->sha1))); - html_link_open(url, NULL, NULL); - htmlf("%s %s", typename(obj->type), - sha1_to_hex(obj->sha1)); - html_link_close(); -} void cgit_print_date(time_t secs, char *format) { @@ -343,7 +152,7 @@ void cgit_print_docstart(char *title, struct cacheitem *item) html("<title>"); html_txt(title); html("</title>\n"); - htmlf("<meta name='generator' content='cgit %s'/>\n", cgit_version); + htmlf("<meta name='generator' content='cgit v%s'/>\n", cgit_version); html("<link rel='stylesheet' type='text/css' href='"); html_attr(cgit_css); html("'/>\n"); @@ -360,38 +169,19 @@ void cgit_print_docend() void cgit_print_pageheader(char *title, int show_search) { html("<table id='layout'>"); - html("<tr><td id='header'><a href='"); - html_attr(cgit_rooturl()); - html("'>"); - html_txt(cgit_root_title); - html("</a></td><td id='logo'>"); + html("<tr><td id='header'>"); + html(cgit_root_title); + html("</td><td id='logo'>"); html("<a href='"); html_attr(cgit_logo_link); htmlf("'><img src='%s' alt='logo'/></a>", cgit_logo); html("</td></tr>"); html("<tr><td id='crumb'>"); + htmlf("<a href='%s'>root</a>", cgit_rooturl()); if (cgit_query_repo) { + htmlf(" : <a href='%s'>", cgit_repourl(cgit_repo->url)); html_txt(cgit_repo->name); - html(" ("); - html_txt(cgit_query_head); - html(") : "); - reporevlink(NULL, "summary", NULL, NULL, cgit_query_head, - NULL, NULL); - html(" "); - cgit_log_link("log", NULL, NULL, cgit_query_head, - cgit_query_sha1, cgit_query_path, 0); - html(" "); - cgit_tree_link("tree", NULL, NULL, cgit_query_head, - cgit_query_sha1, NULL); - html(" "); - cgit_commit_link("commit", NULL, NULL, cgit_query_head, - cgit_query_sha1); - html(" "); - cgit_diff_link("diff", NULL, NULL, cgit_query_head, - cgit_query_sha1, cgit_query_sha2, - cgit_query_path); - } else { - html_txt("Index of repositories"); + htmlf("</a> : %s", title); } html("</td>"); html("<td id='search'>"); @@ -429,5 +219,3 @@ void cgit_print_snapshot_start(const char *mimetype, const char *filename, ttl_seconds(item->ttl))); html("\n"); } - -/* vim:set sw=8: */ diff --git a/ui-snapshot.c b/ui-snapshot.c index bd34a28..2257d6b 100644 --- a/ui-snapshot.c +++ b/ui-snapshot.c @@ -8,148 +8,40 @@ #include "cgit.h" -static int write_compressed_tar_archive(struct archiver_args *args,const char *filter) +static void cgit_print_zip(struct cacheitem *item, const char *hex, + const char *prefix, const char *filename) { - int rw[2]; - pid_t gzpid; - int stdout2; - int status; - int rv; - - 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"); - - 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"); - - return rv; -} - -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 } -}; - -#define snapshot_archives_len (sizeof(snapshot_archives) / sizeof(*snapshot_archives)) - -void cgit_print_snapshot(struct cacheitem *item, const char *head, - const char *hex, const char *prefix, - const char *filename, int snapshots) -{ - const struct snapshot_archive_t* sat; struct archiver_args args; struct commit *commit; unsigned char sha1[20]; - int f, sl, fnl = strlen(filename); - for(f=0; f<snapshot_archives_len; f++) { - sat = &snapshot_archives[f]; - if(!(snapshots & sat->bit)) - continue; - sl = strlen(sat->suffix); - if(fnl<sl || strcmp(&filename[fnl-sl],sat->suffix)) - continue; - if (!hex) - hex = head; - 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); + if (get_sha1(hex, sha1)) { + cgit_print_error(fmt("Bad object id: %s", hex)); return; } - cgit_print_error(fmt("Unsupported snapshot format: %s", filename)); -} - -void cgit_print_snapshot_links(const char *repo, const char *head, - const char *hex, int snapshots) -{ - const struct snapshot_archive_t* sat; - char *filename; - int f; + commit = lookup_commit_reference(sha1); - for(f=0; f<snapshot_archives_len; f++) { - sat = &snapshot_archives[f]; - if(!(snapshots & sat->bit)) - continue; - filename = fmt("%s-%s%s", cgit_repobasename(repo), hex, - sat->suffix); - cgit_snapshot_link(filename, NULL, NULL, (char *)head, - (char *)hex, filename); - html("<br/>"); + 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); } -int cgit_parse_snapshots_mask(const char *str) -{ - const struct snapshot_archive_t* sat; - 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<snapshot_archives_len; f++) { - 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; +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)); } - -/* vim:set sw=8: */ diff --git a/ui-summary.c b/ui-summary.c index de8a180..4bda4c2 100644 --- a/ui-summary.c +++ b/ui-summary.c @@ -15,10 +15,8 @@ static int cgit_print_branch_cb(const char *refname, const unsigned char *sha1, { struct commit *commit; struct commitinfo *info; - char buf[256]; - char *ref; + char buf[256], *url; - ref = xstrdup(refname); strncpy(buf, refname, sizeof(buf)); commit = lookup_commit(sha1); // object is not really parsed at this point, because of some fallout @@ -27,13 +25,21 @@ static int cgit_print_branch_cb(const char *refname, const unsigned char *sha1, if (commit && !parse_commit(commit)){ info = cgit_parse_commit(commit); html("<tr><td>"); - cgit_log_link(ref, NULL, NULL, ref, NULL, NULL, 0); + url = cgit_pageurl(cgit_query_repo, "log", + fmt("h=%s", refname)); + html_link_open(url, NULL, NULL); + html_txt(buf); + html_link_close(); html("</td><td>"); cgit_print_age(commit->date, -1, NULL); html("</td><td>"); html_txt(info->author); html("</td><td>"); - cgit_commit_link(info->subject, NULL, NULL, ref, NULL); + url = cgit_pageurl(cgit_query_repo, "commit", + fmt("h=%s", sha1_to_hex(sha1))); + html_link_open(url, NULL, NULL); + html_ntxt(cgit_max_msg_len, info->subject); + html_link_close(); html("</td></tr>\n"); cgit_free_commitinfo(info); } else { @@ -43,10 +49,33 @@ static int cgit_print_branch_cb(const char *refname, const unsigned char *sha1, htmlf("*** bad ref %s ***", sha1_to_hex(sha1)); html("</td></tr>\n"); } - free(ref); return 0; } + +static void cgit_print_object_ref(struct object *obj) +{ + char *page, *arg, *url; + + if (obj->type == OBJ_COMMIT) { + page = "commit"; + arg = "h"; + } else if (obj->type == OBJ_TREE) { + page = "tree"; + arg = "id"; + } else { + page = "view"; + arg = "id"; + } + + url = cgit_pageurl(cgit_query_repo, page, + fmt("%s=%s", arg, sha1_to_hex(obj->sha1))); + html_link_open(url, NULL, NULL); + htmlf("%s %s", typename(obj->type), + sha1_to_hex(obj->sha1)); + html_link_close(); +} + static void print_tag_header() { html("<tr class='nohover'><th class='left'>Tag</th>" @@ -75,8 +104,8 @@ static int cgit_print_tag_cb(const char *refname, const unsigned char *sha1, if (!header) print_tag_header(); html("<tr><td>"); - url = cgit_pageurl(cgit_query_repo, "tag", - fmt("id=%s", refname)); + url = cgit_pageurl(cgit_query_repo, "view", + fmt("id=%s", sha1_to_hex(sha1))); html_link_open(url, NULL, NULL); html_txt(buf); html_link_close(); @@ -87,7 +116,7 @@ static int cgit_print_tag_cb(const char *refname, const unsigned char *sha1, if (info->tagger) html(info->tagger); html("</td><td>"); - cgit_object_link(tag->tagged); + cgit_print_object_ref(tag->tagged); html("</td></tr>\n"); } else { if (!header) @@ -95,7 +124,7 @@ static int cgit_print_tag_cb(const char *refname, const unsigned char *sha1, html("<tr><td>"); html_txt(buf); html("</td><td colspan='2'/><td>"); - cgit_object_link(obj); + cgit_print_object_ref(obj); html("</td></tr>\n"); } return 0; diff --git a/ui-tag.c b/ui-tag.c deleted file mode 100644 index 6d761f3..0000000 --- a/ui-tag.c +++ /dev/null @@ -1,74 +0,0 @@ -/* ui-tag.c: display a tag - * - * Copyright (C) 2007 Lars Hjemli - * - * Licensed under GNU General Public License v2 - * (see COPYING for full license text) - */ - -#include "cgit.h" - - -static void print_tag_content(char *buf) -{ - char *p; - - if (!buf) - return; - - html("<div class='commit-subject'>"); - p = strchr(buf, '\n'); - if (p) - *p = '\0'; - html_txt(buf); - html("</div>"); - if (p) { - html("<div class='commit-msg'>"); - html_txt(++p); - html("</div>"); - } -} - -void cgit_print_tag(char *revname) -{ - unsigned char sha1[20]; - struct object *obj; - struct tag *tag; - struct taginfo *info; - - if (get_sha1(revname, sha1)) { - cgit_print_error(fmt("Bad tag reference: %s", revname)); - return; - } - obj = parse_object(sha1); - if (!obj) { - cgit_print_error(fmt("Bad object id: %s", sha1_to_hex(sha1))); - return; - } - if (obj->type == OBJ_TAG) { - tag = lookup_tag(sha1); - if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) { - cgit_print_error(fmt("Bad tag object: %s", revname)); - return; - } - html("<table class='commit-info'>\n"); - htmlf("<tr><td>Tag name</td><td>%s (%s)</td></tr>\n", - revname, sha1_to_hex(sha1)); - if (info->tagger_date > 0) { - html("<tr><td>Tag date</td><td>"); - cgit_print_date(info->tagger_date, FMT_LONGDATE); - html("</td></tr>\n"); - } - if (info->tagger) { - html("<tr><td>Tagged by</td><td>"); - html_txt(info->tagger); - html("</td></tr>\n"); - } - html("<tr><td>Tagged object</td><td>"); - cgit_object_link(tag->tagged); - html("</td></tr>\n"); - html("</table>\n"); - print_tag_content(info->msg); - } - return; -} @@ -9,64 +9,16 @@ #include "cgit.h" char *curr_rev; -char *match_path; -int header = 0; -static void print_object(const unsigned char *sha1, char *path) -{ - enum object_type type; - unsigned char *buf; - unsigned long size, lineno, start, idx; - - type = sha1_object_info(sha1, &size); - if (type == OBJ_BAD) { - cgit_print_error(fmt("Bad object name: %s", - sha1_to_hex(sha1))); - return; - } - - buf = read_sha1_file(sha1, &type, &size); - if (!buf) { - cgit_print_error(fmt("Error reading object %s", - sha1_to_hex(sha1))); - 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"); - idx = 0; - start = 0; - lineno = 0; - while(idx < size) { - if (buf[idx] == '\n') { - buf[idx] = '\0'; - htmlf("<tr><td class='no'><a name='%d'>%1$d</a></td><td class='txt'>", - ++lineno); - html_txt(buf + start); - html("</td></tr>\n"); - start = idx + 1; - } - idx++; - } - html("</table>\n"); -} - - -static int ls_item(const unsigned char *sha1, const char *base, int baselen, - const char *pathname, unsigned int mode, int stage) +static int print_entry(const unsigned char *sha1, const char *base, + int baselen, const char *pathname, unsigned int mode, + int stage) { char *name; - char *fullpath; enum object_type type; unsigned long size = 0; name = xstrdup(pathname); - fullpath = fmt("%s%s%s", cgit_query_path ? cgit_query_path : "", - cgit_query_path ? "/" : "", name); - type = sha1_object_info(sha1, &size); if (type == OBJ_BAD && !S_ISGITLINK(mode)) { htmlf("<tr><td colspan='3'>Bad object: %s %s</td></tr>", @@ -74,140 +26,79 @@ static int ls_item(const unsigned char *sha1, const char *base, int baselen, sha1_to_hex(sha1)); return 0; } - - html("<tr><td class='ls-mode'>"); + html("<tr><td class='filemode'>"); html_filemode(mode); - html("</td><td>"); + html("</td><td "); if (S_ISGITLINK(mode)) { - htmlf("<a class='ls-mod' href='"); + htmlf("class='ls-mod'><a href='"); html_attr(fmt(cgit_repo->module_link, name, sha1_to_hex(sha1))); - html("'>"); - html_txt(name); - html("</a>"); } else if (S_ISDIR(mode)) { - cgit_tree_link(name, NULL, "ls-dir", cgit_query_head, - curr_rev, fullpath); + html("class='ls-dir'><a href='"); + html_attr(cgit_pageurl(cgit_query_repo, "tree", + fmt("h=%s&id=%s&path=%s%s/", + curr_rev, + sha1_to_hex(sha1), + cgit_query_path ? cgit_query_path : "", + pathname))); } else { - cgit_tree_link(name, NULL, "ls-blob", cgit_query_head, - curr_rev, fullpath); + html("class='ls-blob'><a href='"); + html_attr(cgit_pageurl(cgit_query_repo, "view", + fmt("h=%s&id=%s&path=%s%s", curr_rev, + sha1_to_hex(sha1), + cgit_query_path ? cgit_query_path : "", + pathname))); } - htmlf("</td><td class='ls-size'>%li</td>", size); + htmlf("'>%s</a></td>", name); + htmlf("<td class='filesize'>%li</td>", size); - html("<td>"); - cgit_log_link("log", NULL, "button", cgit_query_head, curr_rev, - fullpath, 0); - html("</td></tr>\n"); + html("<td class='links'><a href='"); + html_attr(cgit_pageurl(cgit_query_repo, "log", + fmt("h=%s&path=%s%s", + curr_rev, + cgit_query_path ? cgit_query_path : "", + pathname))); + html("'>history</a></td>"); + html("</tr>\n"); free(name); return 0; } -static void ls_head() -{ - html("<table class='list'>\n"); - html("<tr class='nohover'>"); - html("<th class='left'>Mode</th>"); - html("<th class='left'>Name</th>"); - html("<th class='right'>Size</th>"); - html("<th/>"); - html("</tr>\n"); - header = 1; -} - -static void ls_tail() -{ - if (!header) - return; - html("</table>\n"); - header = 0; -} - -static void ls_tree(const unsigned char *sha1, char *path) +void cgit_print_tree(const char *rev, const char *hex, char *path) { struct tree *tree; - - tree = parse_tree_indirect(sha1); - if (!tree) { - cgit_print_error(fmt("Not a tree object: %s", - sha1_to_hex(sha1))); - return; - } - - ls_head(); - read_tree_recursive(tree, "", 0, 1, NULL, ls_item); - ls_tail(); -} - - -static int walk_tree(const unsigned char *sha1, const char *base, int baselen, - const char *pathname, unsigned mode, int stage) -{ - static int state; - static char buffer[PATH_MAX]; - char *url; - - if (state == 0) { - memcpy(buffer, base, baselen); - strcpy(buffer+baselen, pathname); - url = cgit_pageurl(cgit_query_repo, "tree", - fmt("h=%s&path=%s", curr_rev, buffer)); - html("/"); - cgit_tree_link(xstrdup(pathname), NULL, NULL, cgit_query_head, - curr_rev, buffer); - - if (strcmp(match_path, buffer)) - return READ_TREE_RECURSIVE; - - if (S_ISDIR(mode)) { - state = 1; - ls_head(); - return READ_TREE_RECURSIVE; - } else { - print_object(sha1, buffer); - return 0; - } - } - ls_item(sha1, base, baselen, pathname, mode, stage); - return 0; -} - - -/* - * Show a tree or a blob - * rev: the commit pointing at the root tree object - * path: path to tree or blob - */ -void cgit_print_tree(const char *rev, char *path) -{ unsigned char sha1[20]; struct commit *commit; - const char *paths[] = {path, NULL}; - - if (!rev) - rev = cgit_query_head; curr_rev = xstrdup(rev); - if (get_sha1(rev, sha1)) { - cgit_print_error(fmt("Invalid revision name: %s", rev)); - return; - } + get_sha1(rev, sha1); commit = lookup_commit_reference(sha1); if (!commit || parse_commit(commit)) { - cgit_print_error(fmt("Invalid commit reference: %s", rev)); + cgit_print_error(fmt("Invalid head: %s", rev)); return; } + if (!hex) + hex = sha1_to_hex(commit->tree->object.sha1); - html("path: <a href='"); - html_attr(cgit_pageurl(cgit_query_repo, "tree", fmt("h=%s", rev))); - html("'>root</a>"); - - if (path == NULL) { - ls_tree(commit->tree->object.sha1, NULL); + if (get_sha1_hex(hex, sha1)) { + cgit_print_error(fmt("Invalid object id: %s", hex)); + return; + } + tree = parse_tree_indirect(sha1); + if (!tree) { + cgit_print_error(fmt("Not a tree object: %s", hex)); return; } - match_path = path; - read_tree_recursive(commit->tree, NULL, 0, 0, paths, walk_tree); - ls_tail(); + html_txt(path); + html("<table class='list'>\n"); + html("<tr class='nohover'>"); + html("<th class='left'>Mode</th>"); + html("<th class='left'>Name</th>"); + html("<th class='right'>Size</th>"); + html("<th/>"); + html("</tr>\n"); + read_tree_recursive(tree, "", 0, 1, NULL, print_entry); + html("</table>\n"); } diff --git a/ui-view.c b/ui-view.c new file mode 100644 index 0000000..8873415 --- /dev/null +++ b/ui-view.c @@ -0,0 +1,55 @@ +/* ui-view.c: functions to output _any_ object, given it's sha1 + * + * Copyright (C) 2006 Lars Hjemli + * + * Licensed under GNU General Public License v2 + * (see COPYING for full license text) + */ + +#include "cgit.h" + +void cgit_print_view(const char *hex, char *path) +{ + unsigned char sha1[20]; + enum object_type type; + unsigned char *buf; + unsigned long size; + + if (get_sha1_hex(hex, sha1)){ + cgit_print_error(fmt("Bad hex value: %s", hex)); + return; + } + + type = sha1_object_info(sha1, &size); + if (type == OBJ_BAD) { + cgit_print_error(fmt("Bad object name: %s", hex)); + return; + } + + buf = read_sha1_file(sha1, &type, &size); + if (!buf) { + cgit_print_error(fmt("Error reading object %s", hex)); + return; + } + + buf[size] = '\0'; + html("<table class='list'>\n"); + html("<tr class='nohover'><th class='left'>"); + if (path) + htmlf("%s (", path); + htmlf("%s %s, %li bytes", typename(type), hex, size); + if (path) + html(")"); + + html(" <a href='"); + html_attr(cgit_pageurl(cgit_query_repo, "blob", + fmt("id=%s&path=%s", + hex, + path))); + html("'>download</a>"); + html("</th></tr>\n"); + html("<tr><td class='blob'>\n"); + html_txt(buf); + html("\n</td></tr>\n"); + html("</table>\n"); +} |