aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile99
-rw-r--r--README2
-rw-r--r--cache.h1
-rw-r--r--cgit.c105
-rw-r--r--cgit.css184
-rw-r--r--cgit.h36
-rw-r--r--cgit.pngbin1840 -> 1488 bytes
-rw-r--r--cgitrc.5.txt117
-rw-r--r--cmd.c51
-rw-r--r--cmd.h3
-rwxr-xr-xfilters/commit-links.sh16
-rwxr-xr-xfilters/syntax-highlighting.sh29
m---------git0
-rw-r--r--html.c84
-rw-r--r--html.h21
-rw-r--r--scan-tree.c147
-rw-r--r--scan-tree.h3
-rw-r--r--shared.c93
-rw-r--r--ui-atom.c14
-rw-r--r--ui-blob.c37
-rw-r--r--ui-blob.h1
-rw-r--r--ui-commit.c46
-rw-r--r--ui-commit.h2
-rw-r--r--ui-diff.c106
-rw-r--r--ui-diff.h6
-rw-r--r--ui-log.c292
-rw-r--r--ui-log.h3
-rw-r--r--ui-patch.c8
-rw-r--r--ui-patch.h2
-rw-r--r--ui-plain.c68
-rw-r--r--ui-refs.c4
-rw-r--r--ui-repolist.c6
-rw-r--r--ui-shared.c288
-rw-r--r--ui-shared.h71
-rw-r--r--ui-snapshot.c14
-rw-r--r--ui-ssdiff.c383
-rw-r--r--ui-ssdiff.h13
-rw-r--r--ui-stats.c20
-rw-r--r--ui-summary.c44
-rw-r--r--ui-tag.c24
-rw-r--r--ui-tree.c27
-rw-r--r--vector.c38
-rw-r--r--vector.h17
43 files changed, 2117 insertions, 408 deletions
diff --git a/Makefile b/Makefile
index 304521e..14b4df4 100644
--- a/Makefile
+++ b/Makefile
@@ -4,15 +4,35 @@ CGIT_SCRIPT_PATH = /var/www/htdocs/cgit
4CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH) 4CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH)
5CGIT_CONFIG = /etc/cgitrc 5CGIT_CONFIG = /etc/cgitrc
6CACHE_ROOT = /var/cache/cgit 6CACHE_ROOT = /var/cache/cgit
7prefix = /usr
8libdir = $(prefix)/lib
9filterdir = $(libdir)/cgit/filters
10docdir = $(prefix)/share/doc/cgit
11htmldir = $(docdir)
12pdfdir = $(docdir)
13mandir = $(prefix)/share/man
7SHA1_HEADER = <openssl/sha.h> 14SHA1_HEADER = <openssl/sha.h>
8GIT_VER = 1.7.3 15GIT_VER = 1.7.4
9GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2 16GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2
10INSTALL = install 17INSTALL = install
18MAN5_TXT = $(wildcard *.5.txt)
19MAN_TXT = $(MAN5_TXT)
20DOC_MAN5 = $(patsubst %.txt,%,$(MAN5_TXT))
21DOC_HTML = $(patsubst %.txt,%.html,$(MAN_TXT))
22DOC_PDF = $(patsubst %.txt,%.pdf,$(MAN_TXT))
11 23
12# Define NO_STRCASESTR if you don't have strcasestr. 24# Define NO_STRCASESTR if you don't have strcasestr.
13# 25#
26# Define NO_OPENSSL to disable linking with OpenSSL and use bundled SHA1
27# implementation (slower).
28#
14# Define NEEDS_LIBICONV if linking with libc is not enough (eg. Darwin). 29# Define NEEDS_LIBICONV if linking with libc is not enough (eg. Darwin).
15# 30#
31# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.)
32# do not support the 'size specifiers' introduced by C99, namely ll, hh,
33# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t).
34# some C compilers supported these specifiers prior to C99 as an extension.
35#
16 36
17#-include config.mak 37#-include config.mak
18 38
@@ -59,7 +79,7 @@ endif
59# Define a pattern rule for automatic dependency building 79# Define a pattern rule for automatic dependency building
60# 80#
61%.d: %.c 81%.d: %.c
62 $(QUIET_MM)$(CC) $(CFLAGS) -MM $< | sed -e 's/\($*\)\.o:/\1.o $@:/g' >$@ 82 $(QUIET_MM)$(CC) $(CFLAGS) -MM -MP $< | sed -e 's/\($*\)\.o:/\1.o $@:/g' >$@
63 83
64# 84#
65# Define a pattern rule for silent object building 85# Define a pattern rule for silent object building
@@ -68,7 +88,7 @@ endif
68 $(QUIET_CC)$(CC) -o $*.o -c $(CFLAGS) $< 88 $(QUIET_CC)$(CC) -o $*.o -c $(CFLAGS) $<
69 89
70 90
71EXTLIBS = git/libgit.a git/xdiff/lib.a -lz -lcrypto -lpthread 91EXTLIBS = git/libgit.a git/xdiff/lib.a -lz -lpthread
72OBJECTS = 92OBJECTS =
73OBJECTS += cache.o 93OBJECTS += cache.o
74OBJECTS += cgit.o 94OBJECTS += cgit.o
@@ -90,10 +110,12 @@ OBJECTS += ui-refs.o
90OBJECTS += ui-repolist.o 110OBJECTS += ui-repolist.o
91OBJECTS += ui-shared.o 111OBJECTS += ui-shared.o
92OBJECTS += ui-snapshot.o 112OBJECTS += ui-snapshot.o
113OBJECTS += ui-ssdiff.o
93OBJECTS += ui-stats.o 114OBJECTS += ui-stats.o
94OBJECTS += ui-summary.o 115OBJECTS += ui-summary.o
95OBJECTS += ui-tag.o 116OBJECTS += ui-tag.o
96OBJECTS += ui-tree.o 117OBJECTS += ui-tree.o
118OBJECTS += vector.o
97 119
98ifdef NEEDS_LIBICONV 120ifdef NEEDS_LIBICONV
99 EXTLIBS += -liconv 121 EXTLIBS += -liconv
@@ -101,7 +123,8 @@ endif
101 123
102 124
103.PHONY: all libgit test install uninstall clean force-version get-git \ 125.PHONY: all libgit test install uninstall clean force-version get-git \
104 doc man-doc html-doc clean-doc 126 doc clean-doc install-doc install-man install-html install-pdf \
127 uninstall-doc uninstall-man uninstall-html uninstall-pdf
105 128
106all: cgit 129all: cgit
107 130
@@ -117,23 +140,36 @@ CFLAGS += -DCGIT_CONFIG='"$(CGIT_CONFIG)"'
117CFLAGS += -DCGIT_SCRIPT_NAME='"$(CGIT_SCRIPT_NAME)"' 140CFLAGS += -DCGIT_SCRIPT_NAME='"$(CGIT_SCRIPT_NAME)"'
118CFLAGS += -DCGIT_CACHE_ROOT='"$(CACHE_ROOT)"' 141CFLAGS += -DCGIT_CACHE_ROOT='"$(CACHE_ROOT)"'
119 142
143GIT_OPTIONS = prefix=/usr
144
120ifdef NO_ICONV 145ifdef NO_ICONV
121 CFLAGS += -DNO_ICONV 146 CFLAGS += -DNO_ICONV
122endif 147endif
123ifdef NO_STRCASESTR 148ifdef NO_STRCASESTR
124 CFLAGS += -DNO_STRCASESTR 149 CFLAGS += -DNO_STRCASESTR
125endif 150endif
151ifdef NO_C99_FORMAT
152 CFLAGS += -DNO_C99_FORMAT
153endif
154ifdef NO_OPENSSL
155 CFLAGS += -DNO_OPENSSL
156 GIT_OPTIONS += NO_OPENSSL=1
157else
158 EXTLIBS += -lcrypto
159endif
126 160
127cgit: $(OBJECTS) libgit 161cgit: $(OBJECTS) libgit
128 $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o cgit $(OBJECTS) $(EXTLIBS) 162 $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o cgit $(OBJECTS) $(EXTLIBS)
129 163
130cgit.o: VERSION 164cgit.o: VERSION
131 165
132-include $(OBJECTS:.o=.d) 166ifneq "$(MAKECMDGOALS)" "clean"
167 -include $(OBJECTS:.o=.d)
168endif
133 169
134libgit: 170libgit:
135 $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) NO_CURL=1 libgit.a 171 $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) NO_CURL=1 $(GIT_OPTIONS) libgit.a
136 $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) NO_CURL=1 xdiff/lib.a 172 $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) NO_CURL=1 $(GIT_OPTIONS) xdiff/lib.a
137 173
138test: all 174test: all
139 $(QUIET_SUBDIR0)tests $(QUIET_SUBDIR1) all 175 $(QUIET_SUBDIR0)tests $(QUIET_SUBDIR1) all
@@ -144,21 +180,58 @@ install: all
144 $(INSTALL) -m 0755 -d $(DESTDIR)$(CGIT_DATA_PATH) 180 $(INSTALL) -m 0755 -d $(DESTDIR)$(CGIT_DATA_PATH)
145 $(INSTALL) -m 0644 cgit.css $(DESTDIR)$(CGIT_DATA_PATH)/cgit.css 181 $(INSTALL) -m 0644 cgit.css $(DESTDIR)$(CGIT_DATA_PATH)/cgit.css
146 $(INSTALL) -m 0644 cgit.png $(DESTDIR)$(CGIT_DATA_PATH)/cgit.png 182 $(INSTALL) -m 0644 cgit.png $(DESTDIR)$(CGIT_DATA_PATH)/cgit.png
183 $(INSTALL) -m 0755 -d $(DESTDIR)$(filterdir)
184 $(INSTALL) -m 0755 filters/* $(DESTDIR)$(filterdir)
185
186install-doc: install-man install-html install-pdf
187
188install-man: doc-man
189 $(INSTALL) -m 0755 -d $(DESTDIR)$(mandir)/man5
190 $(INSTALL) -m 0644 $(DOC_MAN5) $(DESTDIR)$(mandir)/man5
191
192install-html: doc-html
193 $(INSTALL) -m 0755 -d $(DESTDIR)$(htmldir)
194 $(INSTALL) -m 0644 $(DOC_HTML) $(DESTDIR)$(htmldir)
195
196install-pdf: doc-pdf
197 $(INSTALL) -m 0755 -d $(DESTDIR)$(pdfdir)
198 $(INSTALL) -m 0644 $(DOC_PDF) $(DESTDIR)$(pdfdir)
147 199
148uninstall: 200uninstall:
149 rm -f $(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME) 201 rm -f $(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME)
150 rm -f $(CGIT_DATA_PATH)/cgit.css 202 rm -f $(CGIT_DATA_PATH)/cgit.css
151 rm -f $(CGIT_DATA_PATH)/cgit.png 203 rm -f $(CGIT_DATA_PATH)/cgit.png
152 204
153doc: man-doc html-doc pdf-doc 205uninstall-doc: uninstall-man uninstall-html uninstall-pdf
206
207uninstall-man:
208 @for i in $(DOC_MAN5); do \
209 rm -fv $(DESTDIR)$(mandir)/man5/$$i; \
210 done
211
212uninstall-html:
213 @for i in $(DOC_HTML); do \
214 rm -fv $(DESTDIR)$(htmldir)/$$i; \
215 done
216
217uninstall-pdf:
218 @for i in $(DOC_PDF); do \
219 rm -fv $(DESTDIR)$(pdfdir)/$$i; \
220 done
221
222doc: doc-man doc-html doc-pdf
223doc-man: doc-man5
224doc-man5: $(DOC_MAN5)
225doc-html: $(DOC_HTML)
226doc-pdf: $(DOC_PDF)
154 227
155man-doc: cgitrc.5.txt 228%.5 : %.5.txt
156 a2x -f manpage cgitrc.5.txt 229 a2x -f manpage $<
157 230
158html-doc: cgitrc.5.txt 231$(DOC_HTML): %.html : %.txt
159 a2x -f xhtml --stylesheet=cgit-doc.css cgitrc.5.txt 232 a2x -f xhtml --stylesheet=cgit-doc.css $<
160 233
161pdf-doc: cgitrc.5.txt 234$(DOC_PDF): %.pdf : %.txt
162 a2x -f pdf cgitrc.5.txt 235 a2x -f pdf cgitrc.5.txt
163 236
164clean: clean-doc 237clean: clean-doc
diff --git a/README b/README
index 73ec332..050e21e 100644
--- a/README
+++ b/README
@@ -49,7 +49,7 @@ like this:
49 49
50 <Directory "/var/www/htdocs/cgit/"> 50 <Directory "/var/www/htdocs/cgit/">
51 AllowOverride None 51 AllowOverride None
52 Options ExecCGI 52 Options +ExecCGI
53 Order allow,deny 53 Order allow,deny
54 Allow from all 54 Allow from all
55 </Directory> 55 </Directory>
diff --git a/cache.h b/cache.h
index ac9276b..5cfdb4f 100644
--- a/cache.h
+++ b/cache.h
@@ -30,6 +30,7 @@ extern int cache_process(int size, const char *path, const char *key, int ttl,
30extern int cache_ls(const char *path); 30extern int cache_ls(const char *path);
31 31
32/* Print a message to stdout */ 32/* Print a message to stdout */
33__attribute__((format (printf,1,2)))
33extern void cache_log(const char *format, ...); 34extern void cache_log(const char *format, ...);
34 35
35extern unsigned long hash_str(const char *str); 36extern unsigned long hash_str(const char *str);
diff --git a/cgit.c b/cgit.c
index af9832f..f4dd6ef 100644
--- a/cgit.c
+++ b/cgit.c
@@ -1,6 +1,7 @@
1/* cgit.c: cgi for the git scm 1/* cgit.c: cgi for the git scm
2 * 2 *
3 * Copyright (C) 2006 Lars Hjemli 3 * Copyright (C) 2006 Lars Hjemli
4 * Copyright (C) 2010 Jason A. Donenfeld <Jason@zx2c4.com>
4 * 5 *
5 * Licensed under GNU General Public License v2 6 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text) 7 * (see COPYING for full license text)
@@ -56,22 +57,29 @@ void repo_config(struct cgit_repo *repo, const char *name, const char *value)
56 repo->defbranch = xstrdup(value); 57 repo->defbranch = xstrdup(value);
57 else if (!strcmp(name, "snapshots")) 58 else if (!strcmp(name, "snapshots"))
58 repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value); 59 repo->snapshots = ctx.cfg.snapshots & cgit_parse_snapshots_mask(value);
60 else if (!strcmp(name, "enable-commit-graph"))
61 repo->enable_commit_graph = ctx.cfg.enable_commit_graph * atoi(value);
59 else if (!strcmp(name, "enable-log-filecount")) 62 else if (!strcmp(name, "enable-log-filecount"))
60 repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); 63 repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value);
61 else if (!strcmp(name, "enable-log-linecount")) 64 else if (!strcmp(name, "enable-log-linecount"))
62 repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); 65 repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value);
66 else if (!strcmp(name, "enable-remote-branches"))
67 repo->enable_remote_branches = atoi(value);
68 else if (!strcmp(name, "enable-subject-links"))
69 repo->enable_subject_links = atoi(value);
63 else if (!strcmp(name, "max-stats")) 70 else if (!strcmp(name, "max-stats"))
64 repo->max_stats = cgit_find_stats_period(value, NULL); 71 repo->max_stats = cgit_find_stats_period(value, NULL);
65 else if (!strcmp(name, "module-link")) 72 else if (!strcmp(name, "module-link"))
66 repo->module_link= xstrdup(value); 73 repo->module_link= xstrdup(value);
67 else if (!strcmp(name, "section")) 74 else if (!strcmp(name, "section"))
68 repo->section = xstrdup(value); 75 repo->section = xstrdup(value);
69 else if (!strcmp(name, "readme") && value != NULL) { 76 else if (!strcmp(name, "readme") && value != NULL)
70 if (*value == '/') 77 repo->readme = xstrdup(value);
71 repo->readme = xstrdup(value); 78 else if (!strcmp(name, "logo") && value != NULL)
72 else 79 repo->logo = xstrdup(value);
73 repo->readme = xstrdup(fmt("%s/%s", repo->path, value)); 80 else if (!strcmp(name, "logo-link") && value != NULL)
74 } else if (ctx.cfg.enable_filter_overrides) { 81 repo->logo_link = xstrdup(value);
82 else if (ctx.cfg.enable_filter_overrides) {
75 if (!strcmp(name, "about-filter")) 83 if (!strcmp(name, "about-filter"))
76 repo->about_filter = new_filter(value, 0); 84 repo->about_filter = new_filter(value, 0);
77 else if (!strcmp(name, "commit-filter")) 85 else if (!strcmp(name, "commit-filter"))
@@ -91,6 +99,8 @@ void config_cb(const char *name, const char *value)
91 ctx.repo->path = trim_end(value, '/'); 99 ctx.repo->path = trim_end(value, '/');
92 else if (ctx.repo && !prefixcmp(name, "repo.")) 100 else if (ctx.repo && !prefixcmp(name, "repo."))
93 repo_config(ctx.repo, name + 5, value); 101 repo_config(ctx.repo, name + 5, value);
102 else if (!strcmp(name, "readme"))
103 ctx.cfg.readme = xstrdup(value);
94 else if (!strcmp(name, "root-title")) 104 else if (!strcmp(name, "root-title"))
95 ctx.cfg.root_title = xstrdup(value); 105 ctx.cfg.root_title = xstrdup(value);
96 else if (!strcmp(name, "root-desc")) 106 else if (!strcmp(name, "root-desc"))
@@ -117,6 +127,8 @@ void config_cb(const char *name, const char *value)
117 ctx.cfg.logo_link = xstrdup(value); 127 ctx.cfg.logo_link = xstrdup(value);
118 else if (!strcmp(name, "module-link")) 128 else if (!strcmp(name, "module-link"))
119 ctx.cfg.module_link = xstrdup(value); 129 ctx.cfg.module_link = xstrdup(value);
130 else if (!strcmp(name, "strict-export"))
131 ctx.cfg.strict_export = xstrdup(value);
120 else if (!strcmp(name, "virtual-root")) { 132 else if (!strcmp(name, "virtual-root")) {
121 ctx.cfg.virtual_root = trim_end(value, '/'); 133 ctx.cfg.virtual_root = trim_end(value, '/');
122 if (!ctx.cfg.virtual_root && (!strcmp(value, "/"))) 134 if (!ctx.cfg.virtual_root && (!strcmp(value, "/")))
@@ -131,12 +143,20 @@ void config_cb(const char *name, const char *value)
131 ctx.cfg.snapshots = cgit_parse_snapshots_mask(value); 143 ctx.cfg.snapshots = cgit_parse_snapshots_mask(value);
132 else if (!strcmp(name, "enable-filter-overrides")) 144 else if (!strcmp(name, "enable-filter-overrides"))
133 ctx.cfg.enable_filter_overrides = atoi(value); 145 ctx.cfg.enable_filter_overrides = atoi(value);
146 else if (!strcmp(name, "enable-gitweb-owner"))
147 ctx.cfg.enable_gitweb_owner = atoi(value);
134 else if (!strcmp(name, "enable-index-links")) 148 else if (!strcmp(name, "enable-index-links"))
135 ctx.cfg.enable_index_links = atoi(value); 149 ctx.cfg.enable_index_links = atoi(value);
150 else if (!strcmp(name, "enable-commit-graph"))
151 ctx.cfg.enable_commit_graph = atoi(value);
136 else if (!strcmp(name, "enable-log-filecount")) 152 else if (!strcmp(name, "enable-log-filecount"))
137 ctx.cfg.enable_log_filecount = atoi(value); 153 ctx.cfg.enable_log_filecount = atoi(value);
138 else if (!strcmp(name, "enable-log-linecount")) 154 else if (!strcmp(name, "enable-log-linecount"))
139 ctx.cfg.enable_log_linecount = atoi(value); 155 ctx.cfg.enable_log_linecount = atoi(value);
156 else if (!strcmp(name, "enable-remote-branches"))
157 ctx.cfg.enable_remote_branches = atoi(value);
158 else if (!strcmp(name, "enable-subject-links"))
159 ctx.cfg.enable_subject_links = atoi(value);
140 else if (!strcmp(name, "enable-tree-linenumbers")) 160 else if (!strcmp(name, "enable-tree-linenumbers"))
141 ctx.cfg.enable_tree_linenumbers = atoi(value); 161 ctx.cfg.enable_tree_linenumbers = atoi(value);
142 else if (!strcmp(name, "max-stats")) 162 else if (!strcmp(name, "max-stats"))
@@ -144,7 +164,7 @@ void config_cb(const char *name, const char *value)
144 else if (!strcmp(name, "cache-size")) 164 else if (!strcmp(name, "cache-size"))
145 ctx.cfg.cache_size = atoi(value); 165 ctx.cfg.cache_size = atoi(value);
146 else if (!strcmp(name, "cache-root")) 166 else if (!strcmp(name, "cache-root"))
147 ctx.cfg.cache_root = xstrdup(value); 167 ctx.cfg.cache_root = xstrdup(expand_macros(value));
148 else if (!strcmp(name, "cache-root-ttl")) 168 else if (!strcmp(name, "cache-root-ttl"))
149 ctx.cfg.cache_root_ttl = atoi(value); 169 ctx.cfg.cache_root_ttl = atoi(value);
150 else if (!strcmp(name, "cache-repo-ttl")) 170 else if (!strcmp(name, "cache-repo-ttl"))
@@ -161,19 +181,32 @@ void config_cb(const char *name, const char *value)
161 ctx.cfg.commit_filter = new_filter(value, 0); 181 ctx.cfg.commit_filter = new_filter(value, 0);
162 else if (!strcmp(name, "embedded")) 182 else if (!strcmp(name, "embedded"))
163 ctx.cfg.embedded = atoi(value); 183 ctx.cfg.embedded = atoi(value);
184 else if (!strcmp(name, "max-atom-items"))
185 ctx.cfg.max_atom_items = atoi(value);
164 else if (!strcmp(name, "max-message-length")) 186 else if (!strcmp(name, "max-message-length"))
165 ctx.cfg.max_msg_len = atoi(value); 187 ctx.cfg.max_msg_len = atoi(value);
166 else if (!strcmp(name, "max-repodesc-length")) 188 else if (!strcmp(name, "max-repodesc-length"))
167 ctx.cfg.max_repodesc_len = atoi(value); 189 ctx.cfg.max_repodesc_len = atoi(value);
190 else if (!strcmp(name, "max-blob-size"))
191 ctx.cfg.max_blob_size = atoi(value);
168 else if (!strcmp(name, "max-repo-count")) 192 else if (!strcmp(name, "max-repo-count"))
169 ctx.cfg.max_repo_count = atoi(value); 193 ctx.cfg.max_repo_count = atoi(value);
170 else if (!strcmp(name, "max-commit-count")) 194 else if (!strcmp(name, "max-commit-count"))
171 ctx.cfg.max_commit_count = atoi(value); 195 ctx.cfg.max_commit_count = atoi(value);
196 else if (!strcmp(name, "project-list"))
197 ctx.cfg.project_list = xstrdup(expand_macros(value));
172 else if (!strcmp(name, "scan-path")) 198 else if (!strcmp(name, "scan-path"))
173 if (!ctx.cfg.nocache && ctx.cfg.cache_size) 199 if (!ctx.cfg.nocache && ctx.cfg.cache_size)
174 process_cached_repolist(value); 200 process_cached_repolist(expand_macros(value));
201 else if (ctx.cfg.project_list)
202 scan_projects(expand_macros(value),
203 ctx.cfg.project_list, repo_config);
175 else 204 else
176 scan_tree(value, repo_config); 205 scan_tree(expand_macros(value), repo_config);
206 else if (!strcmp(name, "scan-hidden-path"))
207 ctx.cfg.scan_hidden_path = atoi(value);
208 else if (!strcmp(name, "section-from-path"))
209 ctx.cfg.section_from_path = atoi(value);
177 else if (!strcmp(name, "source-filter")) 210 else if (!strcmp(name, "source-filter"))
178 ctx.cfg.source_filter = new_filter(value, 1); 211 ctx.cfg.source_filter = new_filter(value, 1);
179 else if (!strcmp(name, "summary-log")) 212 else if (!strcmp(name, "summary-log"))
@@ -182,10 +215,14 @@ void config_cb(const char *name, const char *value)
182 ctx.cfg.summary_branches = atoi(value); 215 ctx.cfg.summary_branches = atoi(value);
183 else if (!strcmp(name, "summary-tags")) 216 else if (!strcmp(name, "summary-tags"))
184 ctx.cfg.summary_tags = atoi(value); 217 ctx.cfg.summary_tags = atoi(value);
218 else if (!strcmp(name, "side-by-side-diffs"))
219 ctx.cfg.ssdiff = atoi(value);
185 else if (!strcmp(name, "agefile")) 220 else if (!strcmp(name, "agefile"))
186 ctx.cfg.agefile = xstrdup(value); 221 ctx.cfg.agefile = xstrdup(value);
187 else if (!strcmp(name, "renamelimit")) 222 else if (!strcmp(name, "renamelimit"))
188 ctx.cfg.renamelimit = atoi(value); 223 ctx.cfg.renamelimit = atoi(value);
224 else if (!strcmp(name, "remove-suffix"))
225 ctx.cfg.remove_suffix = atoi(value);
189 else if (!strcmp(name, "robots")) 226 else if (!strcmp(name, "robots"))
190 ctx.cfg.robots = xstrdup(value); 227 ctx.cfg.robots = xstrdup(value);
191 else if (!strcmp(name, "clone-prefix")) 228 else if (!strcmp(name, "clone-prefix"))
@@ -195,7 +232,7 @@ void config_cb(const char *name, const char *value)
195 else if (!prefixcmp(name, "mimetype.")) 232 else if (!prefixcmp(name, "mimetype."))
196 add_mimetype(name + 9, value); 233 add_mimetype(name + 9, value);
197 else if (!strcmp(name, "include")) 234 else if (!strcmp(name, "include"))
198 parse_configfile(value, config_cb); 235 parse_configfile(expand_macros(value), config_cb);
199} 236}
200 237
201static void querystring_cb(const char *name, const char *value) 238static void querystring_cb(const char *name, const char *value)
@@ -209,6 +246,8 @@ static void querystring_cb(const char *name, const char *value)
209 } else if (!strcmp(name, "p")) { 246 } else if (!strcmp(name, "p")) {
210 ctx.qry.page = xstrdup(value); 247 ctx.qry.page = xstrdup(value);
211 } else if (!strcmp(name, "url")) { 248 } else if (!strcmp(name, "url")) {
249 if (*value == '/')
250 value++;
212 ctx.qry.url = xstrdup(value); 251 ctx.qry.url = xstrdup(value);
213 cgit_parse_url(value); 252 cgit_parse_url(value);
214 } else if (!strcmp(name, "qt")) { 253 } else if (!strcmp(name, "qt")) {
@@ -238,6 +277,14 @@ static void querystring_cb(const char *name, const char *value)
238 ctx.qry.showmsg = atoi(value); 277 ctx.qry.showmsg = atoi(value);
239 } else if (!strcmp(name, "period")) { 278 } else if (!strcmp(name, "period")) {
240 ctx.qry.period = xstrdup(value); 279 ctx.qry.period = xstrdup(value);
280 } else if (!strcmp(name, "ss")) {
281 ctx.qry.ssdiff = atoi(value);
282 } else if (!strcmp(name, "all")) {
283 ctx.qry.show_all = atoi(value);
284 } else if (!strcmp(name, "context")) {
285 ctx.qry.context = atoi(value);
286 } else if (!strcmp(name, "ignorews")) {
287 ctx.qry.ignorews = atoi(value);
241 } 288 }
242} 289}
243 290
@@ -262,23 +309,30 @@ static void prepare_context(struct cgit_context *ctx)
262 ctx->cfg.css = "/cgit.css"; 309 ctx->cfg.css = "/cgit.css";
263 ctx->cfg.logo = "/cgit.png"; 310 ctx->cfg.logo = "/cgit.png";
264 ctx->cfg.local_time = 0; 311 ctx->cfg.local_time = 0;
312 ctx->cfg.enable_gitweb_owner = 1;
265 ctx->cfg.enable_tree_linenumbers = 1; 313 ctx->cfg.enable_tree_linenumbers = 1;
266 ctx->cfg.max_repo_count = 50; 314 ctx->cfg.max_repo_count = 50;
267 ctx->cfg.max_commit_count = 50; 315 ctx->cfg.max_commit_count = 50;
268 ctx->cfg.max_lock_attempts = 5; 316 ctx->cfg.max_lock_attempts = 5;
269 ctx->cfg.max_msg_len = 80; 317 ctx->cfg.max_msg_len = 80;
270 ctx->cfg.max_repodesc_len = 80; 318 ctx->cfg.max_repodesc_len = 80;
319 ctx->cfg.max_blob_size = 0;
271 ctx->cfg.max_stats = 0; 320 ctx->cfg.max_stats = 0;
272 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; 321 ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s";
322 ctx->cfg.project_list = NULL;
273 ctx->cfg.renamelimit = -1; 323 ctx->cfg.renamelimit = -1;
324 ctx->cfg.remove_suffix = 0;
274 ctx->cfg.robots = "index, nofollow"; 325 ctx->cfg.robots = "index, nofollow";
275 ctx->cfg.root_title = "Git repository browser"; 326 ctx->cfg.root_title = "Git repository browser";
276 ctx->cfg.root_desc = "a fast webinterface for the git dscm"; 327 ctx->cfg.root_desc = "a fast webinterface for the git dscm";
328 ctx->cfg.scan_hidden_path = 0;
277 ctx->cfg.script_name = CGIT_SCRIPT_NAME; 329 ctx->cfg.script_name = CGIT_SCRIPT_NAME;
278 ctx->cfg.section = ""; 330 ctx->cfg.section = "";
279 ctx->cfg.summary_branches = 10; 331 ctx->cfg.summary_branches = 10;
280 ctx->cfg.summary_log = 10; 332 ctx->cfg.summary_log = 10;
281 ctx->cfg.summary_tags = 10; 333 ctx->cfg.summary_tags = 10;
334 ctx->cfg.max_atom_items = 10;
335 ctx->cfg.ssdiff = 0;
282 ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG")); 336 ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG"));
283 ctx->env.http_host = xstrdupn(getenv("HTTP_HOST")); 337 ctx->env.http_host = xstrdupn(getenv("HTTP_HOST"));
284 ctx->env.https = xstrdupn(getenv("HTTPS")); 338 ctx->env.https = xstrdupn(getenv("HTTPS"));
@@ -410,6 +464,12 @@ static void process_request(void *cbdata)
410 return; 464 return;
411 } 465 }
412 466
467 /* If cmd->want_vpath is set, assume ctx->qry.path contains a "virtual"
468 * in-project path limit to be made available at ctx->qry.vpath.
469 * Otherwise, no path limit is in effect (ctx->qry.vpath = NULL).
470 */
471 ctx->qry.vpath = cmd->want_vpath ? ctx->qry.path : NULL;
472
413 if (cmd->want_repo && !ctx->repo) { 473 if (cmd->want_repo && !ctx->repo) {
414 cgit_print_http_headers(ctx); 474 cgit_print_http_headers(ctx);
415 cgit_print_docstart(ctx); 475 cgit_print_docstart(ctx);
@@ -491,6 +551,8 @@ void print_repo(FILE *f, struct cgit_repo *repo)
491 fprintf(f, "repo.section=%s\n", repo->section); 551 fprintf(f, "repo.section=%s\n", repo->section);
492 if (repo->clone_url) 552 if (repo->clone_url)
493 fprintf(f, "repo.clone-url=%s\n", repo->clone_url); 553 fprintf(f, "repo.clone-url=%s\n", repo->clone_url);
554 fprintf(f, "repo.enable-commit-graph=%d\n",
555 repo->enable_commit_graph);
494 fprintf(f, "repo.enable-log-filecount=%d\n", 556 fprintf(f, "repo.enable-log-filecount=%d\n",
495 repo->enable_log_filecount); 557 repo->enable_log_filecount);
496 fprintf(f, "repo.enable-log-linecount=%d\n", 558 fprintf(f, "repo.enable-log-linecount=%d\n",
@@ -541,7 +603,10 @@ static int generate_cached_repolist(const char *path, const char *cached_rc)
541 return errno; 603 return errno;
542 } 604 }
543 idx = cgit_repolist.count; 605 idx = cgit_repolist.count;
544 scan_tree(path, repo_config); 606 if (ctx.cfg.project_list)
607 scan_projects(path, ctx.cfg.project_list, repo_config);
608 else
609 scan_tree(path, repo_config);
545 print_repolist(f, &cgit_repolist, idx); 610 print_repolist(f, &cgit_repolist, idx);
546 if (rename(locked_rc, cached_rc)) 611 if (rename(locked_rc, cached_rc))
547 fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", 612 fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n",
@@ -555,17 +620,25 @@ static void process_cached_repolist(const char *path)
555 struct stat st; 620 struct stat st;
556 char *cached_rc; 621 char *cached_rc;
557 time_t age; 622 time_t age;
623 unsigned long hash;
558 624
559 cached_rc = xstrdup(fmt("%s/rc-%8x", ctx.cfg.cache_root, 625 hash = hash_str(path);
560 hash_str(path))); 626 if (ctx.cfg.project_list)
627 hash += hash_str(ctx.cfg.project_list);
628 cached_rc = xstrdup(fmt("%s/rc-%8lx", ctx.cfg.cache_root, hash));
561 629
562 if (stat(cached_rc, &st)) { 630 if (stat(cached_rc, &st)) {
563 /* Nothing is cached, we need to scan without forking. And 631 /* Nothing is cached, we need to scan without forking. And
564 * if we fail to generate a cached repolist, we need to 632 * if we fail to generate a cached repolist, we need to
565 * invoke scan_tree manually. 633 * invoke scan_tree manually.
566 */ 634 */
567 if (generate_cached_repolist(path, cached_rc)) 635 if (generate_cached_repolist(path, cached_rc)) {
568 scan_tree(path, repo_config); 636 if (ctx.cfg.project_list)
637 scan_projects(path, ctx.cfg.project_list,
638 repo_config);
639 else
640 scan_tree(path, repo_config);
641 }
569 return; 642 return;
570 } 643 }
571 644
@@ -674,7 +747,7 @@ int main(int argc, const char **argv)
674 cgit_repolist.repos = NULL; 747 cgit_repolist.repos = NULL;
675 748
676 cgit_parse_args(argc, argv); 749 cgit_parse_args(argc, argv);
677 parse_configfile(ctx.env.cgit_config, config_cb); 750 parse_configfile(expand_macros(ctx.env.cgit_config), config_cb);
678 ctx.repo = NULL; 751 ctx.repo = NULL;
679 http_parse_querystring(ctx.qry.raw, querystring_cb); 752 http_parse_querystring(ctx.qry.raw, querystring_cb);
680 753
diff --git a/cgit.css b/cgit.css
index c47ebc9..1d90057 100644
--- a/cgit.css
+++ b/cgit.css
@@ -64,7 +64,7 @@ table#header td.sub {
64} 64}
65 65
66table.tabs { 66table.tabs {
67 /* border-bottom: solid 2px #ccc; */ 67 border-bottom: solid 3px #ccc;
68 border-collapse: collapse; 68 border-collapse: collapse;
69 margin-top: 2em; 69 margin-top: 2em;
70 margin-bottom: 0px; 70 margin-bottom: 0px;
@@ -102,10 +102,16 @@ table.tabs td.form select {
102 font-size: 90%; 102 font-size: 90%;
103} 103}
104 104
105div.path {
106 margin: 0px;
107 padding: 5px 2em 2px 2em;
108 color: #000;
109 background-color: #eee;
110}
111
105div.content { 112div.content {
106 margin: 0px; 113 margin: 0px;
107 padding: 2em; 114 padding: 2em;
108 border-top: solid 3px #ccc;
109 border-bottom: solid 3px #ccc; 115 border-bottom: solid 3px #ccc;
110} 116}
111 117
@@ -147,6 +153,35 @@ table.list td {
147 padding: 0.1em 0.5em 0.1em 0.5em; 153 padding: 0.1em 0.5em 0.1em 0.5em;
148} 154}
149 155
156table.list td.commitgraph {
157 font-family: monospace;
158 white-space: pre;
159}
160
161table.list td.commitgraph .column1 {
162 color: #a00;
163}
164
165table.list td.commitgraph .column2 {
166 color: #0a0;
167}
168
169table.list td.commitgraph .column3 {
170 color: #aa0;
171}
172
173table.list td.commitgraph .column4 {
174 color: #00a;
175}
176
177table.list td.commitgraph .column5 {
178 color: #a0a;
179}
180
181table.list td.commitgraph .column6 {
182 color: #0aa;
183}
184
150table.list td.logsubject { 185table.list td.logsubject {
151 font-family: monospace; 186 font-family: monospace;
152 font-weight: bold; 187 font-weight: bold;
@@ -155,13 +190,18 @@ table.list td.logsubject {
155table.list td.logmsg { 190table.list td.logmsg {
156 font-family: monospace; 191 font-family: monospace;
157 white-space: pre; 192 white-space: pre;
158 padding: 1em 0.5em 2em 0.5em; 193 padding: 0 0.5em;
159} 194}
160 195
161table.list td a { 196table.list td a {
162 color: black; 197 color: black;
163} 198}
164 199
200table.list td a.ls-dir {
201 font-weight: bold;
202 color: #00f;
203}
204
165table.list td a:hover { 205table.list td a:hover {
166 color: #00f; 206 color: #00f;
167} 207}
@@ -253,7 +293,7 @@ table.blob pre {
253 padding: 0; margin: 0; 293 padding: 0; margin: 0;
254} 294}
255 295
256table.blob a.no { 296table.blob a.no, table.ssdiff a.no {
257 color: gray; 297 color: gray;
258 text-align: right; 298 text-align: right;
259 text-decoration: none; 299 text-decoration: none;
@@ -315,6 +355,24 @@ div.commit-msg {
315 font-family: monospace; 355 font-family: monospace;
316} 356}
317 357
358div.notes-header {
359 font-weight: bold;
360 padding-top: 1.5em;
361}
362
363div.notes {
364 white-space: pre;
365 font-family: monospace;
366 border: solid 1px #ee9;
367 background-color: #ffd;
368 padding: 0.3em 2em 0.3em 1em;
369 float: left;
370}
371
372div.notes-footer {
373 clear: left;
374}
375
318div.diffstat-header { 376div.diffstat-header {
319 font-weight: bold; 377 font-weight: bold;
320 padding-top: 1.5em; 378 padding-top: 1.5em;
@@ -520,7 +578,10 @@ a.deco {
520 border: solid 1px #770000; 578 border: solid 1px #770000;
521} 579}
522 580
523div.commit-subject a { 581div.commit-subject a.branch-deco,
582div.commit-subject a.tag-deco,
583div.commit-subject a.remote-deco,
584div.commit-subject a.deco {
524 margin-left: 1em; 585 margin-left: 1em;
525 font-size: 75%; 586 font-size: 75%;
526} 587}
@@ -601,3 +662,116 @@ table.hgraph div.bar {
601 background-color: #eee; 662 background-color: #eee;
602 height: 1em; 663 height: 1em;
603} 664}
665
666table.ssdiff {
667 width: 100%;
668}
669
670table.ssdiff td {
671 font-size: 75%;
672 font-family: monospace;
673 white-space: pre;
674 padding: 1px 4px 1px 4px;
675 border-left: solid 1px #aaa;
676 border-right: solid 1px #aaa;
677}
678
679table.ssdiff td.add {
680 color: black;
681 background: #cfc;
682 min-width: 50%;
683}
684
685table.ssdiff td.add_dark {
686 color: black;
687 background: #aca;
688 min-width: 50%;
689}
690
691table.ssdiff span.add {
692 background: #cfc;
693 font-weight: bold;
694}
695
696table.ssdiff td.del {
697 color: black;
698 background: #fcc;
699 min-width: 50%;
700}
701
702table.ssdiff td.del_dark {
703 color: black;
704 background: #caa;
705 min-width: 50%;
706}
707
708table.ssdiff span.del {
709 background: #fcc;
710 font-weight: bold;
711}
712
713table.ssdiff td.changed {
714 color: black;
715 background: #ffc;
716 min-width: 50%;
717}
718
719table.ssdiff td.changed_dark {
720 color: black;
721 background: #cca;
722 min-width: 50%;
723}
724
725table.ssdiff td.lineno {
726 color: black;
727 background: #eee;
728 text-align: right;
729 width: 3em;
730 min-width: 3em;
731}
732
733table.ssdiff td.hunk {
734 color: #black;
735 background: #ccf;
736 border-top: solid 1px #aaa;
737 border-bottom: solid 1px #aaa;
738}
739
740table.ssdiff td.head {
741 border-top: solid 1px #aaa;
742 border-bottom: solid 1px #aaa;
743}
744
745table.ssdiff td.head div.head {
746 font-weight: bold;
747 color: black;
748}
749
750table.ssdiff td.foot {
751 border-top: solid 1px #aaa;
752 border-left: none;
753 border-right: none;
754 border-bottom: none;
755}
756
757table.ssdiff td.space {
758 border: none;
759}
760
761table.ssdiff td.space div {
762 min-height: 3em;
763}
764
765/* Syntax highlighting */
766table.blob .num { color:#2928ff; }
767table.blob .esc { color:#ff00ff; }
768table.blob .str { color:#ff0000; }
769table.blob .dstr { color:#818100; }
770table.blob .slc { color:#838183; font-style:italic; }
771table.blob .com { color:#838183; font-style:italic; }
772table.blob .dir { color:#008200; }
773table.blob .sym { color:#000000; }
774table.blob .kwa { color:#000000; font-weight:bold; }
775table.blob .kwb { color:#830000; }
776table.blob .kwc { color:#000000; font-weight:bold; }
777table.blob .kwd { color:#010181; }
diff --git a/cgit.h b/cgit.h
index 6c6c460..b5f00fc 100644
--- a/cgit.h
+++ b/cgit.h
@@ -19,6 +19,8 @@
19#include <xdiff-interface.h> 19#include <xdiff-interface.h>
20#include <xdiff/xdiff.h> 20#include <xdiff/xdiff.h>
21#include <utf8.h> 21#include <utf8.h>
22#include <notes.h>
23#include <graph.h>
22 24
23 25
24/* 26/*
@@ -69,9 +71,14 @@ struct cgit_repo {
69 char *readme; 71 char *readme;
70 char *section; 72 char *section;
71 char *clone_url; 73 char *clone_url;
74 char *logo;
75 char *logo_link;
72 int snapshots; 76 int snapshots;
77 int enable_commit_graph;
73 int enable_log_filecount; 78 int enable_log_filecount;
74 int enable_log_linecount; 79 int enable_log_linecount;
80 int enable_remote_branches;
81 int enable_subject_links;
75 int max_stats; 82 int max_stats;
76 time_t mtime; 83 time_t mtime;
77 struct cgit_filter *about_filter; 84 struct cgit_filter *about_filter;
@@ -143,6 +150,11 @@ struct cgit_query {
143 int nohead; 150 int nohead;
144 char *sort; 151 char *sort;
145 int showmsg; 152 int showmsg;
153 int ssdiff;
154 int show_all;
155 int context;
156 int ignorews;
157 char *vpath;
146}; 158};
147 159
148struct cgit_config { 160struct cgit_config {
@@ -159,6 +171,8 @@ struct cgit_config {
159 char *logo; 171 char *logo;
160 char *logo_link; 172 char *logo_link;
161 char *module_link; 173 char *module_link;
174 char *project_list;
175 char *readme;
162 char *robots; 176 char *robots;
163 char *root_title; 177 char *root_title;
164 char *root_desc; 178 char *root_desc;
@@ -166,6 +180,7 @@ struct cgit_config {
166 char *script_name; 180 char *script_name;
167 char *section; 181 char *section;
168 char *virtual_root; 182 char *virtual_root;
183 char *strict_export;
169 int cache_size; 184 int cache_size;
170 int cache_dynamic_ttl; 185 int cache_dynamic_ttl;
171 int cache_max_create_time; 186 int cache_max_create_time;
@@ -175,25 +190,35 @@ struct cgit_config {
175 int cache_static_ttl; 190 int cache_static_ttl;
176 int embedded; 191 int embedded;
177 int enable_filter_overrides; 192 int enable_filter_overrides;
193 int enable_gitweb_owner;
178 int enable_index_links; 194 int enable_index_links;
195 int enable_commit_graph;
179 int enable_log_filecount; 196 int enable_log_filecount;
180 int enable_log_linecount; 197 int enable_log_linecount;
198 int enable_remote_branches;
199 int enable_subject_links;
181 int enable_tree_linenumbers; 200 int enable_tree_linenumbers;
182 int local_time; 201 int local_time;
202 int max_atom_items;
183 int max_repo_count; 203 int max_repo_count;
184 int max_commit_count; 204 int max_commit_count;
185 int max_lock_attempts; 205 int max_lock_attempts;
186 int max_msg_len; 206 int max_msg_len;
187 int max_repodesc_len; 207 int max_repodesc_len;
208 int max_blob_size;
188 int max_stats; 209 int max_stats;
189 int nocache; 210 int nocache;
190 int noplainemail; 211 int noplainemail;
191 int noheader; 212 int noheader;
192 int renamelimit; 213 int renamelimit;
214 int remove_suffix;
215 int scan_hidden_path;
216 int section_from_path;
193 int snapshots; 217 int snapshots;
194 int summary_branches; 218 int summary_branches;
195 int summary_log; 219 int summary_log;
196 int summary_tags; 220 int summary_tags;
221 int ssdiff;
197 struct string_list mimetypes; 222 struct string_list mimetypes;
198 struct cgit_filter *about_filter; 223 struct cgit_filter *about_filter;
199 struct cgit_filter *commit_filter; 224 struct cgit_filter *commit_filter;
@@ -268,14 +293,17 @@ extern void *cgit_free_commitinfo(struct commitinfo *info);
268extern int cgit_diff_files(const unsigned char *old_sha1, 293extern int cgit_diff_files(const unsigned char *old_sha1,
269 const unsigned char *new_sha1, 294 const unsigned char *new_sha1,
270 unsigned long *old_size, unsigned long *new_size, 295 unsigned long *old_size, unsigned long *new_size,
271 int *binary, linediff_fn fn); 296 int *binary, int context, int ignorews,
297 linediff_fn fn);
272 298
273extern void cgit_diff_tree(const unsigned char *old_sha1, 299extern void cgit_diff_tree(const unsigned char *old_sha1,
274 const unsigned char *new_sha1, 300 const unsigned char *new_sha1,
275 filepair_fn fn, const char *prefix); 301 filepair_fn fn, const char *prefix, int ignorews);
276 302
277extern void cgit_diff_commit(struct commit *commit, filepair_fn fn); 303extern void cgit_diff_commit(struct commit *commit, filepair_fn fn,
304 const char *prefix);
278 305
306__attribute__((format (printf,1,2)))
279extern char *fmt(const char *format,...); 307extern char *fmt(const char *format,...);
280 308
281extern struct commitinfo *cgit_parse_commit(struct commit *commit); 309extern struct commitinfo *cgit_parse_commit(struct commit *commit);
@@ -291,4 +319,6 @@ extern int cgit_close_filter(struct cgit_filter *filter);
291 319
292extern int readfile(const char *path, char **buf, size_t *size); 320extern int readfile(const char *path, char **buf, size_t *size);
293 321
322extern char *expand_macros(const char *txt);
323
294#endif /* CGIT_H */ 324#endif /* CGIT_H */
diff --git a/cgit.png b/cgit.png
index d7f70bc..0bdf5a7 100644
--- a/cgit.png
+++ b/cgit.png
Binary files differ
diff --git a/cgitrc.5.txt b/cgitrc.5.txt
index 0c13485..c3698a6 100644
--- a/cgitrc.5.txt
+++ b/cgitrc.5.txt
@@ -90,11 +90,21 @@ embedded::
90 Flag which, when set to "1", will make cgit generate a html fragment 90 Flag which, when set to "1", will make cgit generate a html fragment
91 suitable for embedding in other html pages. Default value: none. See 91 suitable for embedding in other html pages. Default value: none. See
92 also: "noheader". 92 also: "noheader".
93 93
94enable-commit-graph::
95 Flag which, when set to "1", will make cgit print an ASCII-art commit
96 history graph to the left of the commit messages in the repository
97 log page. Default value: "0".
98
94enable-filter-overrides:: 99enable-filter-overrides::
95 Flag which, when set to "1", allows all filter settings to be 100 Flag which, when set to "1", allows all filter settings to be
96 overridden in repository-specific cgitrc files. Default value: none. 101 overridden in repository-specific cgitrc files. Default value: none.
97 102
103enable-gitweb-owner::
104 If set to "1" and scan-path is enabled, we first check each repository
105 for the git config value "gitweb.owner" to determine the owner.
106 Default value: "1". See also: scan-path.
107
98enable-index-links:: 108enable-index-links::
99 Flag which, when set to "1", will make cgit generate extra links for 109 Flag which, when set to "1", will make cgit generate extra links for
100 each repo in the repository index (specifically, to the "summary", 110 each repo in the repository index (specifically, to the "summary",
@@ -110,6 +120,17 @@ enable-log-linecount::
110 and removed lines for each commit on the repository log page. Default 120 and removed lines for each commit on the repository log page. Default
111 value: "0". 121 value: "0".
112 122
123enable-remote-branches::
124 Flag which, when set to "1", will make cgit display remote branches
125 in the summary and refs views. Default value: "0". See also:
126 "repo.enable-remote-branches".
127
128enable-subject-links::
129 Flag which, when set to "1", will make cgit use the subject of the
130 parent commit as link text when generating links to parent commits
131 in commit view. Default value: "0". See also:
132 "repo.enable-subject-links".
133
113enable-tree-linenumbers:: 134enable-tree-linenumbers::
114 Flag which, when set to "1", will make cgit generate linenumber links 135 Flag which, when set to "1", will make cgit generate linenumber links
115 for plaintext blobs printed in the tree view. Default value: "1". 136 for plaintext blobs printed in the tree view. Default value: "1".
@@ -161,6 +182,10 @@ logo-link::
161 calculated url of the repository index page will be used. Default 182 calculated url of the repository index page will be used. Default
162 value: none. 183 value: none.
163 184
185max-atom-items::
186 Specifies the number of items to display in atom feeds view. Default
187 value: "10".
188
164max-commit-count:: 189max-commit-count::
165 Specifies the number of entries to list per page in "log" view. Default 190 Specifies the number of entries to list per page in "log" view. Default
166 value: "50". 191 value: "50".
@@ -177,6 +202,10 @@ max-repodesc-length::
177 Specifies the maximum number of repo description characters to display 202 Specifies the maximum number of repo description characters to display
178 on the repository index page. Default value: "80". 203 on the repository index page. Default value: "80".
179 204
205max-blob-size::
206 Specifies the maximum size of a blob to display HTML for in KBytes.
207 Default value: "0" (limit disabled).
208
180max-stats:: 209max-stats::
181 Set the default maximum statistics period. Valid values are "week", 210 Set the default maximum statistics period. Valid values are "week",
182 "month", "quarter" and "year". If unspecified, statistics are 211 "month", "quarter" and "year". If unspecified, statistics are
@@ -205,6 +234,20 @@ noheader::
205 Flag which, when set to "1", will make cgit omit the standard header 234 Flag which, when set to "1", will make cgit omit the standard header
206 on all pages. Default value: none. See also: "embedded". 235 on all pages. Default value: none. See also: "embedded".
207 236
237project-list::
238 A list of subdirectories inside of scan-path, relative to it, that
239 should loaded as git repositories. This must be defined prior to
240 scan-path. Default value: none. See also: scan-path.
241
242readme::
243 Text which will be used as default value for "repo.readme". Default
244 value: none.
245
246remove-suffix::
247 If set to "1" and scan-path is enabled, if any repositories are found
248 with a suffix of ".git", this suffix will be removed for the url and
249 name. Default value: "0". See also: scan-path.
250
208renamelimit:: 251renamelimit::
209 Maximum number of files to consider when detecting renames. The value 252 Maximum number of files to consider when detecting renames. The value
210 "-1" uses the compiletime value in git (for further info, look at 253 "-1" uses the compiletime value in git (for further info, look at
@@ -231,16 +274,37 @@ root-title::
231 Text printed as heading on the repository index page. Default value: 274 Text printed as heading on the repository index page. Default value:
232 "Git Repository Browser". 275 "Git Repository Browser".
233 276
277scan-hidden-path::
278 If set to "1" and scan-path is enabled, scan-path will recurse into
279 directories whose name starts with a period ('.'). Otherwise,
280 scan-path will stay away from such directories (considered as
281 "hidden"). Note that this does not apply to the ".git" directory in
282 non-bare repos. This must be defined prior to scan-path.
283 Default value: 0. See also: scan-path.
284
234scan-path:: 285scan-path::
235 A path which will be scanned for repositories. If caching is enabled, 286 A path which will be scanned for repositories. If caching is enabled,
236 the result will be cached as a cgitrc include-file in the cache 287 the result will be cached as a cgitrc include-file in the cache
237 directory. Default value: none. See also: cache-scanrc-ttl. 288 directory. If project-list has been defined prior to scan-path,
289 scan-path loads only the directories listed in the file pointed to by
290 project-list. Default value: none. See also: cache-scanrc-ttl,
291 project-list.
238 292
239section:: 293section::
240 The name of the current repository section - all repositories defined 294 The name of the current repository section - all repositories defined
241 after this option will inherit the current section name. Default value: 295 after this option will inherit the current section name. Default value:
242 none. 296 none.
243 297
298section-from-path::
299 A number which, if specified before scan-path, specifies how many
300 path elements from each repo path to use as a default section name.
301 If negative, cgit will discard the specified number of path elements
302 above the repo directory. Default value: 0.
303
304side-by-side-diffs::
305 If set to "1" shows side-by-side diffs instead of unidiffs per
306 default. Default value: "0".
307
244snapshots:: 308snapshots::
245 Text which specifies the default set of snapshot formats generated by 309 Text which specifies the default set of snapshot formats generated by
246 cgit. The value is a space-separated list of zero or more of the 310 cgit. The value is a space-separated list of zero or more of the
@@ -266,6 +330,13 @@ summary-tags::
266 Specifies the number of tags to display in the repository "summary" 330 Specifies the number of tags to display in the repository "summary"
267 view. Default value: "10". 331 view. Default value: "10".
268 332
333strict-export::
334 Filename which, if specified, needs to be present within the repository
335 for cgit to allow access to that repository. This can be used to emulate
336 gitweb's EXPORT_OK and STRICT_EXPORT functionality and limit cgit's
337 repositories to match those exported by git-daemon. This option MUST come
338 before 'scan-path'.
339
269virtual-root:: 340virtual-root::
270 Url which, if specified, will be used as root for all cgit links. It 341 Url which, if specified, will be used as root for all cgit links. It
271 will also cause cgit to generate 'virtual urls', i.e. urls like 342 will also cause cgit to generate 'virtual urls', i.e. urls like
@@ -296,6 +367,10 @@ repo.defbranch::
296repo.desc:: 367repo.desc::
297 The value to show as repository description. Default value: none. 368 The value to show as repository description. Default value: none.
298 369
370repo.enable-commit-graph::
371 A flag which can be used to disable the global setting
372 `enable-commit-graph'. Default value: none.
373
299repo.enable-log-filecount:: 374repo.enable-log-filecount::
300 A flag which can be used to disable the global setting 375 A flag which can be used to disable the global setting
301 `enable-log-filecount'. Default value: none. 376 `enable-log-filecount'. Default value: none.
@@ -304,6 +379,23 @@ repo.enable-log-linecount::
304 A flag which can be used to disable the global setting 379 A flag which can be used to disable the global setting
305 `enable-log-linecount'. Default value: none. 380 `enable-log-linecount'. Default value: none.
306 381
382repo.enable-remote-branches::
383 Flag which, when set to "1", will make cgit display remote branches
384 in the summary and refs views. Default value: <enable-remote-branches>.
385
386repo.enable-subject-links::
387 A flag which can be used to override the global setting
388 `enable-subject-links'. Default value: none.
389
390repo.logo::
391 Url which specifies the source of an image which will be used as a logo
392 on this repo's pages. Default value: global logo.
393
394repo.logo-link::
395 Url loaded when clicking on the cgit logo image. If unspecified the
396 calculated url of the repository index page will be used. Default
397 value: global logo-link.
398
307repo.max-stats:: 399repo.max-stats::
308 Override the default maximum statistics period. Valid values are equal 400 Override the default maximum statistics period. Valid values are equal
309 to the values specified for the global "max-stats" setting. Default 401 to the values specified for the global "max-stats" setting. Default
@@ -322,7 +414,9 @@ repo.path::
322 414
323repo.readme:: 415repo.readme::
324 A path (relative to <repo.path>) which specifies a file to include 416 A path (relative to <repo.path>) which specifies a file to include
325 verbatim as the "About" page for this repo. Default value: none. 417 verbatim as the "About" page for this repo. You may also specify a
418 git refspec by head or by hash by prepending the refspec followed by
419 a colon. For example, "master:docs/readme.mkd" Default value: <readme>.
326 420
327repo.snapshots:: 421repo.snapshots::
328 A mask of allowed snapshot-formats for this repo, restricted by the 422 A mask of allowed snapshot-formats for this repo, restricted by the
@@ -363,7 +457,7 @@ cache-size=1000
363 457
364 458
365# Specify some default clone prefixes 459# Specify some default clone prefixes
366clone-prefix=git://foobar.com ssh://foobar.com/pub/git http://foobar.com/git 460clone-prefix=git://example.com ssh://example.com/pub/git http://example.com/git
367 461
368# Specify the css url 462# Specify the css url
369css=/css/cgit.css 463css=/css/cgit.css
@@ -373,6 +467,10 @@ css=/css/cgit.css
373enable-index-links=1 467enable-index-links=1
374 468
375 469
470# Enable ASCII art commit history graph on the log pages
471enable-commit-graph=1
472
473
376# Show number of affected files per commit on the log pages 474# Show number of affected files per commit on the log pages
377enable-log-filecount=1 475enable-log-filecount=1
378 476
@@ -394,14 +492,14 @@ max-stats=quarter
394 492
395 493
396# Set the title and heading of the repository index page 494# Set the title and heading of the repository index page
397root-title=foobar.com git repositories 495root-title=example.com git repositories
398 496
399 497
400# Set a subheading for the repository index page 498# Set a subheading for the repository index page
401root-desc=tracking the foobar development 499root-desc=tracking the foobar development
402 500
403 501
404# Include some more info about foobar.com on the index page 502# Include some more info about example.com on the index page
405root-readme=/var/www/htdocs/about.html 503root-readme=/var/www/htdocs/about.html
406 504
407 505
@@ -413,7 +511,7 @@ snapshots=tar.gz tar.bz2 zip
413## List of common mimetypes 511## List of common mimetypes
414## 512##
415 513
416mimetype.git=image/git 514mimetype.gif=image/gif
417mimetype.html=text/html 515mimetype.html=text/html
418mimetype.jpg=image/jpeg 516mimetype.jpg=image/jpeg
419mimetype.jpeg=image/jpeg 517mimetype.jpeg=image/jpeg
@@ -435,14 +533,14 @@ mimetype.svg=image/svg+xml
435repo.url=foo 533repo.url=foo
436repo.path=/pub/git/foo.git 534repo.path=/pub/git/foo.git
437repo.desc=the master foo repository 535repo.desc=the master foo repository
438repo.owner=fooman@foobar.com 536repo.owner=fooman@example.com
439repo.readme=info/web/about.html 537repo.readme=info/web/about.html
440 538
441 539
442repo.url=bar 540repo.url=bar
443repo.path=/pub/git/bar.git 541repo.path=/pub/git/bar.git
444repo.desc=the bars for your foo 542repo.desc=the bars for your foo
445repo.owner=barman@foobar.com 543repo.owner=barman@example.com
446repo.readme=info/web/about.html 544repo.readme=info/web/about.html
447 545
448 546
@@ -499,3 +597,4 @@ will generate the following html element:
499AUTHOR 597AUTHOR
500------ 598------
501Lars Hjemli <hjemli@gmail.com> 599Lars Hjemli <hjemli@gmail.com>
600Jason A. Donenfeld <Jason@zx2c4.com>
diff --git a/cmd.c b/cmd.c
index 766f903..536515b 100644
--- a/cmd.c
+++ b/cmd.c
@@ -33,7 +33,7 @@ static void HEAD_fn(struct cgit_context *ctx)
33 33
34static void atom_fn(struct cgit_context *ctx) 34static void atom_fn(struct cgit_context *ctx)
35{ 35{
36 cgit_print_atom(ctx->qry.head, ctx->qry.path, 10); 36 cgit_print_atom(ctx->qry.head, ctx->qry.path, ctx->cfg.max_atom_items);
37} 37}
38 38
39static void about_fn(struct cgit_context *ctx) 39static void about_fn(struct cgit_context *ctx)
@@ -51,7 +51,7 @@ static void blob_fn(struct cgit_context *ctx)
51 51
52static void commit_fn(struct cgit_context *ctx) 52static void commit_fn(struct cgit_context *ctx)
53{ 53{
54 cgit_print_commit(ctx->qry.sha1); 54 cgit_print_commit(ctx->qry.sha1, ctx->qry.path);
55} 55}
56 56
57static void diff_fn(struct cgit_context *ctx) 57static void diff_fn(struct cgit_context *ctx)
@@ -67,7 +67,8 @@ static void info_fn(struct cgit_context *ctx)
67static void log_fn(struct cgit_context *ctx) 67static void log_fn(struct cgit_context *ctx)
68{ 68{
69 cgit_print_log(ctx->qry.sha1, ctx->qry.ofs, ctx->cfg.max_commit_count, 69 cgit_print_log(ctx->qry.sha1, ctx->qry.ofs, ctx->cfg.max_commit_count,
70 ctx->qry.grep, ctx->qry.search, ctx->qry.path, 1); 70 ctx->qry.grep, ctx->qry.search, ctx->qry.path, 1,
71 ctx->repo->enable_commit_graph);
71} 72}
72 73
73static void ls_cache_fn(struct cgit_context *ctx) 74static void ls_cache_fn(struct cgit_context *ctx)
@@ -90,7 +91,7 @@ static void repolist_fn(struct cgit_context *ctx)
90 91
91static void patch_fn(struct cgit_context *ctx) 92static void patch_fn(struct cgit_context *ctx)
92{ 93{
93 cgit_print_patch(ctx->qry.sha1); 94 cgit_print_patch(ctx->qry.sha1, ctx->qry.path);
94} 95}
95 96
96static void plain_fn(struct cgit_context *ctx) 97static void plain_fn(struct cgit_context *ctx)
@@ -129,31 +130,31 @@ static void tree_fn(struct cgit_context *ctx)
129 cgit_print_tree(ctx->qry.sha1, ctx->qry.path); 130 cgit_print_tree(ctx->qry.sha1, ctx->qry.path);
130} 131}
131 132
132#define def_cmd(name, want_repo, want_layout) \ 133#define def_cmd(name, want_repo, want_layout, want_vpath) \
133 {#name, name##_fn, want_repo, want_layout} 134 {#name, name##_fn, want_repo, want_layout, want_vpath}
134 135
135struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx) 136struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx)
136{ 137{
137 static struct cgit_cmd cmds[] = { 138 static struct cgit_cmd cmds[] = {
138 def_cmd(HEAD, 1, 0), 139 def_cmd(HEAD, 1, 0, 0),
139 def_cmd(atom, 1, 0), 140 def_cmd(atom, 1, 0, 0),
140 def_cmd(about, 0, 1), 141 def_cmd(about, 0, 1, 0),
141 def_cmd(blob, 1, 0), 142 def_cmd(blob, 1, 0, 0),
142 def_cmd(commit, 1, 1),