From: Lars Hjemli Date: Sun, 19 Sep 2010 18:58:15 +0000 (+0200) Subject: Merge branch 'stable' X-Git-Url: https://gitweb.ps.run/ps-cgit/commitdiff_plain/9043b46f85eb43c918a172663af34c084587bd1a?hp=aaa3f7854232726d5530f66b9459e036bbba15cb Merge branch 'stable' --- diff --git a/Makefile b/Makefile index 5162020..6a47ed2 100644 --- a/Makefile +++ b/Makefile @@ -5,14 +5,22 @@ CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH) CGIT_CONFIG = /etc/cgitrc CACHE_ROOT = /var/cache/cgit SHA1_HEADER = -GIT_VER = 1.6.4.3 +GIT_VER = 1.7.3 GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2 INSTALL = install # Define NO_STRCASESTR if you don't have strcasestr. # +# Define NO_OPENSSL to disable linking with OpenSSL and use bundled SHA1 +# implementation (slower). +# # Define NEEDS_LIBICONV if linking with libc is not enough (eg. Darwin). # +# Define NO_C99_FORMAT if your formatted IO functions (printf/scanf et.al.) +# do not support the 'size specifiers' introduced by C99, namely ll, hh, +# j, z, t. (representing long long int, char, intmax_t, size_t, ptrdiff_t). +# some C compilers supported these specifiers prior to C99 as an extension. +# #-include config.mak @@ -68,7 +76,7 @@ endif $(QUIET_CC)$(CC) -o $*.o -c $(CFLAGS) $< -EXTLIBS = git/libgit.a git/xdiff/lib.a -lz -lcrypto +EXTLIBS = git/libgit.a git/xdiff/lib.a -lz -lpthread OBJECTS = OBJECTS += cache.o OBJECTS += cgit.o @@ -90,6 +98,7 @@ OBJECTS += ui-refs.o OBJECTS += ui-repolist.o OBJECTS += ui-shared.o OBJECTS += ui-snapshot.o +OBJECTS += ui-ssdiff.o OBJECTS += ui-stats.o OBJECTS += ui-summary.o OBJECTS += ui-tag.o @@ -123,17 +132,28 @@ endif ifdef NO_STRCASESTR CFLAGS += -DNO_STRCASESTR endif +ifdef NO_C99_FORMAT + CFLAGS += -DNO_C99_FORMAT +endif +ifdef NO_OPENSSL + CFLAGS += -DNO_OPENSSL + GIT_OPTIONS += NO_OPENSSL=1 +else + EXTLIBS += -lcrypto +endif cgit: $(OBJECTS) libgit $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o cgit $(OBJECTS) $(EXTLIBS) cgit.o: VERSION --include $(OBJECTS:.o=.d) +ifneq "$(MAKECMDGOALS)" "clean" + -include $(OBJECTS:.o=.d) +endif libgit: - $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) NO_CURL=1 libgit.a - $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) NO_CURL=1 xdiff/lib.a + $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) NO_CURL=1 $(GIT_OPTIONS) libgit.a + $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) NO_CURL=1 $(GIT_OPTIONS) xdiff/lib.a test: all $(QUIET_SUBDIR0)tests $(QUIET_SUBDIR1) all 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, extern int cache_ls(const char *path); /* Print a message to stdout */ +__attribute__((format (printf,1,2))) extern void cache_log(const char *format, ...); extern unsigned long hash_str(const char *str); diff --git a/cgit.c b/cgit.c index 6c7e811..96900bb 100644 --- a/cgit.c +++ b/cgit.c @@ -1,6 +1,7 @@ /* cgit.c: cgi for the git scm * * Copyright (C) 2006 Lars Hjemli + * Copyright (C) 2010 Jason A. Donenfeld * * Licensed under GNU General Public License v2 * (see COPYING for full license text) @@ -21,7 +22,7 @@ void add_mimetype(const char *name, const char *value) { struct string_list_item *item; - item = string_list_insert(xstrdup(name), &ctx.cfg.mimetypes); + item = string_list_insert(&ctx.cfg.mimetypes, xstrdup(name)); item->util = xstrdup(value); } @@ -60,6 +61,10 @@ void repo_config(struct cgit_repo *repo, const char *name, const char *value) repo->enable_log_filecount = ctx.cfg.enable_log_filecount * atoi(value); else if (!strcmp(name, "enable-log-linecount")) repo->enable_log_linecount = ctx.cfg.enable_log_linecount * atoi(value); + else if (!strcmp(name, "enable-remote-branches")) + repo->enable_remote_branches = atoi(value); + else if (!strcmp(name, "enable-subject-links")) + repo->enable_subject_links = atoi(value); else if (!strcmp(name, "max-stats")) repo->max_stats = cgit_find_stats_period(value, NULL); else if (!strcmp(name, "module-link")) @@ -67,10 +72,7 @@ void repo_config(struct cgit_repo *repo, const char *name, const char *value) else if (!strcmp(name, "section")) repo->section = xstrdup(value); else if (!strcmp(name, "readme") && value != NULL) { - if (*value == '/') - repo->readme = xstrdup(value); - else - repo->readme = xstrdup(fmt("%s/%s", repo->path, value)); + repo->readme = xstrdup(value); } else if (ctx.cfg.enable_filter_overrides) { if (!strcmp(name, "about-filter")) repo->about_filter = new_filter(value, 0); @@ -91,6 +93,8 @@ void config_cb(const char *name, const char *value) ctx.repo->path = trim_end(value, '/'); else if (ctx.repo && !prefixcmp(name, "repo.")) repo_config(ctx.repo, name + 5, value); + else if (!strcmp(name, "readme")) + ctx.cfg.readme = xstrdup(value); else if (!strcmp(name, "root-title")) ctx.cfg.root_title = xstrdup(value); else if (!strcmp(name, "root-desc")) @@ -131,12 +135,18 @@ void config_cb(const char *name, const char *value) ctx.cfg.snapshots = cgit_parse_snapshots_mask(value); else if (!strcmp(name, "enable-filter-overrides")) ctx.cfg.enable_filter_overrides = atoi(value); + else if (!strcmp(name, "enable-gitweb-owner")) + ctx.cfg.enable_gitweb_owner = atoi(value); else if (!strcmp(name, "enable-index-links")) ctx.cfg.enable_index_links = atoi(value); else if (!strcmp(name, "enable-log-filecount")) ctx.cfg.enable_log_filecount = atoi(value); else if (!strcmp(name, "enable-log-linecount")) ctx.cfg.enable_log_linecount = atoi(value); + else if (!strcmp(name, "enable-remote-branches")) + ctx.cfg.enable_remote_branches = atoi(value); + else if (!strcmp(name, "enable-subject-links")) + ctx.cfg.enable_subject_links = atoi(value); else if (!strcmp(name, "enable-tree-linenumbers")) ctx.cfg.enable_tree_linenumbers = atoi(value); else if (!strcmp(name, "max-stats")) @@ -144,7 +154,7 @@ void config_cb(const char *name, const char *value) else if (!strcmp(name, "cache-size")) ctx.cfg.cache_size = atoi(value); else if (!strcmp(name, "cache-root")) - ctx.cfg.cache_root = xstrdup(value); + ctx.cfg.cache_root = xstrdup(expand_macros(value)); else if (!strcmp(name, "cache-root-ttl")) ctx.cfg.cache_root_ttl = atoi(value); else if (!strcmp(name, "cache-repo-ttl")) @@ -161,19 +171,30 @@ void config_cb(const char *name, const char *value) ctx.cfg.commit_filter = new_filter(value, 0); else if (!strcmp(name, "embedded")) ctx.cfg.embedded = atoi(value); + else if (!strcmp(name, "max-atom-items")) + ctx.cfg.max_atom_items = atoi(value); else if (!strcmp(name, "max-message-length")) ctx.cfg.max_msg_len = atoi(value); else if (!strcmp(name, "max-repodesc-length")) ctx.cfg.max_repodesc_len = atoi(value); + else if (!strcmp(name, "max-blob-size")) + ctx.cfg.max_blob_size = atoi(value); else if (!strcmp(name, "max-repo-count")) ctx.cfg.max_repo_count = atoi(value); else if (!strcmp(name, "max-commit-count")) ctx.cfg.max_commit_count = atoi(value); + else if (!strcmp(name, "project-list")) + ctx.cfg.project_list = xstrdup(expand_macros(value)); else if (!strcmp(name, "scan-path")) if (!ctx.cfg.nocache && ctx.cfg.cache_size) - process_cached_repolist(value); + process_cached_repolist(expand_macros(value)); + else if (ctx.cfg.project_list) + scan_projects(expand_macros(value), + ctx.cfg.project_list, repo_config); else - scan_tree(value, repo_config); + scan_tree(expand_macros(value), repo_config); + else if (!strcmp(name, "section-from-path")) + ctx.cfg.section_from_path = atoi(value); else if (!strcmp(name, "source-filter")) ctx.cfg.source_filter = new_filter(value, 1); else if (!strcmp(name, "summary-log")) @@ -182,10 +203,14 @@ void config_cb(const char *name, const char *value) ctx.cfg.summary_branches = atoi(value); else if (!strcmp(name, "summary-tags")) ctx.cfg.summary_tags = atoi(value); + else if (!strcmp(name, "side-by-side-diffs")) + ctx.cfg.ssdiff = atoi(value); else if (!strcmp(name, "agefile")) ctx.cfg.agefile = xstrdup(value); else if (!strcmp(name, "renamelimit")) ctx.cfg.renamelimit = atoi(value); + else if (!strcmp(name, "remove-suffix")) + ctx.cfg.remove_suffix = atoi(value); else if (!strcmp(name, "robots")) ctx.cfg.robots = xstrdup(value); else if (!strcmp(name, "clone-prefix")) @@ -195,7 +220,7 @@ void config_cb(const char *name, const char *value) else if (!prefixcmp(name, "mimetype.")) add_mimetype(name + 9, value); else if (!strcmp(name, "include")) - parse_configfile(value, config_cb); + parse_configfile(expand_macros(value), config_cb); } static void querystring_cb(const char *name, const char *value) @@ -209,6 +234,8 @@ static void querystring_cb(const char *name, const char *value) } else if (!strcmp(name, "p")) { ctx.qry.page = xstrdup(value); } else if (!strcmp(name, "url")) { + if (*value == '/') + value++; ctx.qry.url = xstrdup(value); cgit_parse_url(value); } else if (!strcmp(name, "qt")) { @@ -238,6 +265,14 @@ static void querystring_cb(const char *name, const char *value) ctx.qry.showmsg = atoi(value); } else if (!strcmp(name, "period")) { ctx.qry.period = xstrdup(value); + } else if (!strcmp(name, "ss")) { + ctx.qry.ssdiff = atoi(value); + } else if (!strcmp(name, "all")) { + ctx.qry.show_all = atoi(value); + } else if (!strcmp(name, "context")) { + ctx.qry.context = atoi(value); + } else if (!strcmp(name, "ignorews")) { + ctx.qry.ignorews = atoi(value); } } @@ -262,15 +297,19 @@ static void prepare_context(struct cgit_context *ctx) ctx->cfg.css = "/cgit.css"; ctx->cfg.logo = "/cgit.png"; ctx->cfg.local_time = 0; + ctx->cfg.enable_gitweb_owner = 1; ctx->cfg.enable_tree_linenumbers = 1; ctx->cfg.max_repo_count = 50; ctx->cfg.max_commit_count = 50; ctx->cfg.max_lock_attempts = 5; ctx->cfg.max_msg_len = 80; ctx->cfg.max_repodesc_len = 80; + ctx->cfg.max_blob_size = 0; ctx->cfg.max_stats = 0; ctx->cfg.module_link = "./?repo=%s&page=commit&id=%s"; + ctx->cfg.project_list = NULL; ctx->cfg.renamelimit = -1; + ctx->cfg.remove_suffix = 0; ctx->cfg.robots = "index, nofollow"; ctx->cfg.root_title = "Git repository browser"; ctx->cfg.root_desc = "a fast webinterface for the git dscm"; @@ -279,6 +318,8 @@ static void prepare_context(struct cgit_context *ctx) ctx->cfg.summary_branches = 10; ctx->cfg.summary_log = 10; ctx->cfg.summary_tags = 10; + ctx->cfg.max_atom_items = 10; + ctx->cfg.ssdiff = 0; ctx->env.cgit_config = xstrdupn(getenv("CGIT_CONFIG")); ctx->env.http_host = xstrdupn(getenv("HTTP_HOST")); ctx->env.https = xstrdupn(getenv("HTTPS")); @@ -410,6 +451,12 @@ static void process_request(void *cbdata) return; } + /* If cmd->want_vpath is set, assume ctx->qry.path contains a "virtual" + * in-project path limit to be made available at ctx->qry.vpath. + * Otherwise, no path limit is in effect (ctx->qry.vpath = NULL). + */ + ctx->qry.vpath = cmd->want_vpath ? ctx->qry.path : NULL; + if (cmd->want_repo && !ctx->repo) { cgit_print_http_headers(ctx); cgit_print_docstart(ctx); @@ -541,7 +588,10 @@ static int generate_cached_repolist(const char *path, const char *cached_rc) return errno; } idx = cgit_repolist.count; - scan_tree(path, repo_config); + if (ctx.cfg.project_list) + scan_projects(path, ctx.cfg.project_list, repo_config); + else + scan_tree(path, repo_config); print_repolist(f, &cgit_repolist, idx); if (rename(locked_rc, cached_rc)) fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", @@ -555,17 +605,25 @@ static void process_cached_repolist(const char *path) struct stat st; char *cached_rc; time_t age; + unsigned long hash; - cached_rc = xstrdup(fmt("%s/rc-%8x", ctx.cfg.cache_root, - hash_str(path))); + hash = hash_str(path); + if (ctx.cfg.project_list) + hash += hash_str(ctx.cfg.project_list); + cached_rc = xstrdup(fmt("%s/rc-%8lx", ctx.cfg.cache_root, hash)); if (stat(cached_rc, &st)) { /* Nothing is cached, we need to scan without forking. And * if we fail to generate a cached repolist, we need to * invoke scan_tree manually. */ - if (generate_cached_repolist(path, cached_rc)) - scan_tree(path, repo_config); + if (generate_cached_repolist(path, cached_rc)) { + if (ctx.cfg.project_list) + scan_projects(path, ctx.cfg.project_list, + repo_config); + else + scan_tree(path, repo_config); + } return; } @@ -674,7 +732,7 @@ int main(int argc, const char **argv) cgit_repolist.repos = NULL; cgit_parse_args(argc, argv); - parse_configfile(ctx.env.cgit_config, config_cb); + parse_configfile(expand_macros(ctx.env.cgit_config), config_cb); ctx.repo = NULL; http_parse_querystring(ctx.qry.raw, querystring_cb); diff --git a/cgit.css b/cgit.css index c47ebc9..0c88b65 100644 --- a/cgit.css +++ b/cgit.css @@ -64,7 +64,7 @@ table#header td.sub { } table.tabs { - /* border-bottom: solid 2px #ccc; */ + border-bottom: solid 3px #ccc; border-collapse: collapse; margin-top: 2em; margin-bottom: 0px; @@ -102,10 +102,16 @@ table.tabs td.form select { font-size: 90%; } +div.path { + margin: 0px; + padding: 5px 2em 2px 2em; + color: #000; + background-color: #eee; +} + div.content { margin: 0px; padding: 2em; - border-top: solid 3px #ccc; border-bottom: solid 3px #ccc; } @@ -158,10 +164,26 @@ table.list td.logmsg { padding: 1em 0.5em 2em 0.5em; } +table.list td.lognotes-label { + text-align:right; + vertical-align:top; +} + +table.list td.lognotes { + font-family: monospace; + white-space: pre; + padding: 0em 0.5em 2em 0.5em; +} + table.list td a { color: black; } +table.list td a.ls-dir { + font-weight: bold; + color: #00f; +} + table.list td a:hover { color: #00f; } @@ -315,6 +337,24 @@ div.commit-msg { font-family: monospace; } +div.notes-header { + font-weight: bold; + padding-top: 1.5em; +} + +div.notes { + white-space: pre; + font-family: monospace; + border: solid 1px #ee9; + background-color: #ffd; + padding: 0.3em 2em 0.3em 1em; + float: left; +} + +div.notes-footer { + clear: left; +} + div.diffstat-header { font-weight: bold; padding-top: 1.5em; @@ -520,7 +560,10 @@ a.deco { border: solid 1px #770000; } -div.commit-subject a { +div.commit-subject a.branch-deco, +div.commit-subject a.tag-deco, +div.commit-subject a.remote-deco, +div.commit-subject a.deco { margin-left: 1em; font-size: 75%; } @@ -601,3 +644,102 @@ table.hgraph div.bar { background-color: #eee; height: 1em; } + +table.ssdiff { + width: 100%; +} + +table.ssdiff td { + font-size: 75%; + font-family: monospace; + white-space: pre; + padding: 1px 4px 1px 4px; + border-left: solid 1px #aaa; + border-right: solid 1px #aaa; +} + +table.ssdiff td.add { + color: black; + background: #cfc; + min-width: 50%; +} + +table.ssdiff td.add_dark { + color: black; + background: #aca; + min-width: 50%; +} + +table.ssdiff span.add { + background: #cfc; + font-weight: bold; +} + +table.ssdiff td.del { + color: black; + background: #fcc; + min-width: 50%; +} + +table.ssdiff td.del_dark { + color: black; + background: #caa; + min-width: 50%; +} + +table.ssdiff span.del { + background: #fcc; + font-weight: bold; +} + +table.ssdiff td.changed { + color: black; + background: #ffc; + min-width: 50%; +} + +table.ssdiff td.changed_dark { + color: black; + background: #cca; + min-width: 50%; +} + +table.ssdiff td.lineno { + color: black; + background: #eee; + text-align: right; + width: 3em; + min-width: 3em; +} + +table.ssdiff td.hunk { + color: #black; + background: #ccf; + border-top: solid 1px #aaa; + border-bottom: solid 1px #aaa; +} + +table.ssdiff td.head { + border-top: solid 1px #aaa; + border-bottom: solid 1px #aaa; +} + +table.ssdiff td.head div.head { + font-weight: bold; + color: black; +} + +table.ssdiff td.foot { + border-top: solid 1px #aaa; + border-left: none; + border-right: none; + border-bottom: none; +} + +table.ssdiff td.space { + border: none; +} + +table.ssdiff td.space div { + min-height: 3em; +} \ No newline at end of file diff --git a/cgit.h b/cgit.h index 6c6c460..8f5dd2a 100644 --- a/cgit.h +++ b/cgit.h @@ -19,6 +19,7 @@ #include #include #include +#include /* @@ -72,6 +73,8 @@ struct cgit_repo { int snapshots; int enable_log_filecount; int enable_log_linecount; + int enable_remote_branches; + int enable_subject_links; int max_stats; time_t mtime; struct cgit_filter *about_filter; @@ -143,6 +146,11 @@ struct cgit_query { int nohead; char *sort; int showmsg; + int ssdiff; + int show_all; + int context; + int ignorews; + char *vpath; }; struct cgit_config { @@ -159,6 +167,8 @@ struct cgit_config { char *logo; char *logo_link; char *module_link; + char *project_list; + char *readme; char *robots; char *root_title; char *root_desc; @@ -175,25 +185,33 @@ struct cgit_config { int cache_static_ttl; int embedded; int enable_filter_overrides; + int enable_gitweb_owner; int enable_index_links; int enable_log_filecount; int enable_log_linecount; + int enable_remote_branches; + int enable_subject_links; int enable_tree_linenumbers; int local_time; + int max_atom_items; int max_repo_count; int max_commit_count; int max_lock_attempts; int max_msg_len; int max_repodesc_len; + int max_blob_size; int max_stats; int nocache; int noplainemail; int noheader; int renamelimit; + int remove_suffix; + int section_from_path; int snapshots; int summary_branches; int summary_log; int summary_tags; + int ssdiff; struct string_list mimetypes; struct cgit_filter *about_filter; struct cgit_filter *commit_filter; @@ -268,14 +286,16 @@ extern void *cgit_free_commitinfo(struct commitinfo *info); extern int cgit_diff_files(const unsigned char *old_sha1, const unsigned char *new_sha1, unsigned long *old_size, unsigned long *new_size, - int *binary, linediff_fn fn); + int *binary, int context, int ignorews, + linediff_fn fn); extern void cgit_diff_tree(const unsigned char *old_sha1, const unsigned char *new_sha1, - filepair_fn fn, const char *prefix); + filepair_fn fn, const char *prefix, int ignorews); extern void cgit_diff_commit(struct commit *commit, filepair_fn fn); +__attribute__((format (printf,1,2))) extern char *fmt(const char *format,...); extern struct commitinfo *cgit_parse_commit(struct commit *commit); @@ -291,4 +311,6 @@ extern int cgit_close_filter(struct cgit_filter *filter); extern int readfile(const char *path, char **buf, size_t *size); +extern char *expand_macros(const char *txt); + #endif /* CGIT_H */ diff --git a/cgitrc.5.txt b/cgitrc.5.txt index 0c13485..ce78d41 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt @@ -95,6 +95,11 @@ enable-filter-overrides:: Flag which, when set to "1", allows all filter settings to be overridden in repository-specific cgitrc files. Default value: none. +enable-gitweb-owner:: + If set to "1" and scan-path is enabled, we first check each repository + for the git config value "gitweb.owner" to determine the owner. + Default value: "1". See also: scan-path. + enable-index-links:: Flag which, when set to "1", will make cgit generate extra links for each repo in the repository index (specifically, to the "summary", @@ -110,6 +115,17 @@ enable-log-linecount:: and removed lines for each commit on the repository log page. Default value: "0". +enable-remote-branches:: + Flag which, when set to "1", will make cgit display remote branches + in the summary and refs views. Default value: "0". See also: + "repo.enable-remote-branches". + +enable-subject-links:: + Flag which, when set to "1", will make cgit use the subject of the + parent commit as link text when generating links to parent commits + in commit view. Default value: "0". See also: + "repo.enable-subject-links". + enable-tree-linenumbers:: Flag which, when set to "1", will make cgit generate linenumber links for plaintext blobs printed in the tree view. Default value: "1". @@ -161,6 +177,10 @@ logo-link:: calculated url of the repository index page will be used. Default value: none. +max-atom-items:: + Specifies the number of items to display in atom feeds view. Default + value: "10". + max-commit-count:: Specifies the number of entries to list per page in "log" view. Default value: "50". @@ -177,6 +197,10 @@ max-repodesc-length:: Specifies the maximum number of repo description characters to display on the repository index page. Default value: "80". +max-blob-size:: + Specifies the maximum size of a blob to display HTML for in KBytes. + Default value: "0" (limit disabled). + max-stats:: Set the default maximum statistics period. Valid values are "week", "month", "quarter" and "year". If unspecified, statistics are @@ -205,6 +229,20 @@ noheader:: Flag which, when set to "1", will make cgit omit the standard header on all pages. Default value: none. See also: "embedded". +project-list:: + A list of subdirectories inside of scan-path, relative to it, that + should loaded as git repositories. This must be defined prior to + scan-path. Default value: none. See also: scan-path. + +readme:: + Text which will be used as default value for "repo.readme". Default + value: none. + +remove-suffix:: + If set to "1" and scan-path is enabled, if any repositories are found + with a suffix of ".git", this suffix will be removed for the url and + name. Default value: "0". See also: scan-path. + renamelimit:: Maximum number of files to consider when detecting renames. The value "-1" uses the compiletime value in git (for further info, look at @@ -234,13 +272,26 @@ root-title:: scan-path:: A path which will be scanned for repositories. If caching is enabled, the result will be cached as a cgitrc include-file in the cache - directory. Default value: none. See also: cache-scanrc-ttl. + directory. If project-list has been defined prior to scan-path, + scan-path loads only the directories listed in the file pointed to by + project-list. Default value: none. See also: cache-scanrc-ttl, + project-list. section:: The name of the current repository section - all repositories defined after this option will inherit the current section name. Default value: none. +section-from-path:: + A number which, if specified before scan-path, specifies how many + path elements from each repo path to use as a default section name. + If negative, cgit will discard the specified number of path elements + above the repo directory. Default value: 0. + +side-by-side-diffs:: + If set to "1" shows side-by-side diffs instead of unidiffs per + default. Default value: "0". + snapshots:: Text which specifies the default set of snapshot formats generated by cgit. The value is a space-separated list of zero or more of the @@ -304,6 +355,14 @@ repo.enable-log-linecount:: A flag which can be used to disable the global setting `enable-log-linecount'. Default value: none. +repo.enable-remote-branches:: + Flag which, when set to "1", will make cgit display remote branches + in the summary and refs views. Default value: . + +repo.enable-subject-links:: + A flag which can be used to override the global setting + `enable-subject-links'. Default value: none. + repo.max-stats:: Override the default maximum statistics period. Valid values are equal to the values specified for the global "max-stats" setting. Default @@ -322,7 +381,9 @@ repo.path:: repo.readme:: A path (relative to ) which specifies a file to include - verbatim as the "About" page for this repo. Default value: none. + verbatim as the "About" page for this repo. You may also specify a + git refspec by head or by hash by prepending the refspec followed by + a colon. For example, "master:docs/readme.mkd" Default value: . repo.snapshots:: A mask of allowed snapshot-formats for this repo, restricted by the @@ -413,7 +474,7 @@ snapshots=tar.gz tar.bz2 zip ## List of common mimetypes ## -mimetype.git=image/git +mimetype.gif=image/gif mimetype.html=text/html mimetype.jpg=image/jpeg mimetype.jpeg=image/jpeg @@ -499,3 +560,4 @@ will generate the following html element: AUTHOR ------ Lars Hjemli +Jason A. Donenfeld diff --git a/cmd.c b/cmd.c index 766f903..6dc9f5e 100644 --- a/cmd.c +++ b/cmd.c @@ -33,7 +33,7 @@ static void HEAD_fn(struct cgit_context *ctx) static void atom_fn(struct cgit_context *ctx) { - cgit_print_atom(ctx->qry.head, ctx->qry.path, 10); + cgit_print_atom(ctx->qry.head, ctx->qry.path, ctx->cfg.max_atom_items); } static void about_fn(struct cgit_context *ctx) @@ -51,7 +51,7 @@ static void blob_fn(struct cgit_context *ctx) static void commit_fn(struct cgit_context *ctx) { - cgit_print_commit(ctx->qry.sha1); + cgit_print_commit(ctx->qry.sha1, ctx->qry.path); } static void diff_fn(struct cgit_context *ctx) @@ -90,7 +90,7 @@ static void repolist_fn(struct cgit_context *ctx) static void patch_fn(struct cgit_context *ctx) { - cgit_print_patch(ctx->qry.sha1); + cgit_print_patch(ctx->qry.sha1, ctx->qry.path); } static void plain_fn(struct cgit_context *ctx) @@ -129,31 +129,31 @@ static void tree_fn(struct cgit_context *ctx) cgit_print_tree(ctx->qry.sha1, ctx->qry.path); } -#define def_cmd(name, want_repo, want_layout) \ - {#name, name##_fn, want_repo, want_layout} +#define def_cmd(name, want_repo, want_layout, want_vpath) \ + {#name, name##_fn, want_repo, want_layout, want_vpath} struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx) { static struct cgit_cmd cmds[] = { - def_cmd(HEAD, 1, 0), - def_cmd(atom, 1, 0), - def_cmd(about, 0, 1), - def_cmd(blob, 1, 0), - def_cmd(commit, 1, 1), - def_cmd(diff, 1, 1), - def_cmd(info, 1, 0), - def_cmd(log, 1, 1), - def_cmd(ls_cache, 0, 0), - def_cmd(objects, 1, 0), - def_cmd(patch, 1, 0), - def_cmd(plain, 1, 0), - def_cmd(refs, 1, 1), - def_cmd(repolist, 0, 0), - def_cmd(snapshot, 1, 0), - def_cmd(stats, 1, 1), - def_cmd(summary, 1, 1), - def_cmd(tag, 1, 1), - def_cmd(tree, 1, 1), + def_cmd(HEAD, 1, 0, 0), + def_cmd(atom, 1, 0, 0), + def_cmd(about, 0, 1, 0), + def_cmd(blob, 1, 0, 0), + def_cmd(commit, 1, 1, 1), + def_cmd(diff, 1, 1, 1), + def_cmd(info, 1, 0, 0), + def_cmd(log, 1, 1, 1), + def_cmd(ls_cache, 0, 0, 0), + def_cmd(objects, 1, 0, 0), + def_cmd(patch, 1, 0, 1), + def_cmd(plain, 1, 0, 0), + def_cmd(refs, 1, 1, 0), + def_cmd(repolist, 0, 0, 0), + def_cmd(snapshot, 1, 0, 0), + def_cmd(stats, 1, 1, 1), + def_cmd(summary, 1, 1, 0), + def_cmd(tag, 1, 1, 0), + def_cmd(tree, 1, 1, 1), }; int i; diff --git a/cmd.h b/cmd.h index ec9e691..8dc01bd 100644 --- a/cmd.h +++ b/cmd.h @@ -7,7 +7,8 @@ struct cgit_cmd { const char *name; cgit_cmd_fn fn; unsigned int want_repo:1, - want_layout:1; + want_layout:1, + want_vpath:1; }; extern struct cgit_cmd *cgit_get_cmd(struct cgit_context *ctx); diff --git a/filters/commit-links.sh b/filters/commit-links.sh index 165a533..110c609 100755 --- a/filters/commit-links.sh +++ b/filters/commit-links.sh @@ -1,12 +1,14 @@ #!/bin/sh -# This script can be used to generate links in commit messages - the first -# sed expression generates links to commits referenced by their SHA1, while -# the second expression generates links to a fictional bugtracker. +# This script can be used to generate links in commit messages. # # To use this script, refer to this file with either the commit-filter or the # repo.commit-filter options in cgitrc. -sed -re ' -s|\b([0-9a-fA-F]{8,40})\b|\1|g -s| #([0-9]+)\b|#\1|g -' +# This expression generates links to commits referenced by their SHA1. +regex=$regex' +s|\b([0-9a-fA-F]{8,40})\b|\1|g' +# This expression generates links to a fictional bugtracker. +regex=$regex' +s| #([0-9]+)\b|#\1|g' + +sed -re "$regex" diff --git a/filters/syntax-highlighting.sh b/filters/syntax-highlighting.sh index 999ad0c..6b1c576 100755 --- a/filters/syntax-highlighting.sh +++ b/filters/syntax-highlighting.sh @@ -3,6 +3,10 @@ # tree-view by refering to this file with the source-filter or repo.source- # filter options in cgitrc. # +# This script requires a shell supporting the ${var##pattern} syntax. +# It is supported by at least dash and bash, however busybox environments +# might have to use an external call to sed instead. +# # Note: the highlight command (http://www.andre-simon.de/) uses css for syntax # highlighting, so you'll probably want something like the following included # in your css file (generated by highlight 2.4.8 and adapted for cgit): @@ -20,20 +24,11 @@ # table.blob .kwc { color:#000000; font-weight:bold; } # table.blob .kwd { color:#010181; } -case "$1" in - *.c) - highlight -f -I -X -S c - ;; - *.h) - highlight -f -I -X -S c - ;; - *.sh) - highlight -f -I -X -S sh - ;; - *.css) - highlight -f -I -X -S css - ;; - *) - highlight -f -I -X -S txt - ;; -esac +# store filename and extension in local vars +BASENAME="$1" +EXTENSION="${BASENAME##*.}" + +# map Makefile and Makefile.* to .mk +[ "${BASENAME%%.*}" == "Makefile" ] && EXTENSION=mk + +exec highlight --force -f -I -X -S $EXTENSION 2>/dev/null diff --git a/git b/git index 7fb6bcf..87b5054 160000 --- a/git +++ b/git @@ -1 +1 @@ -Subproject commit 7fb6bcff2dece2ff9fbc5ebfe526d9b2a7e764c4 +Subproject commit 87b50542a08ac6caa083ddc376e674424e37940a diff --git a/html.c b/html.c index d86b2c1..1305910 100644 --- a/html.c +++ b/html.c @@ -13,6 +13,32 @@ #include #include +/* Percent-encoding of each character, except: a-zA-Z0-9!$()*,./:;@- */ +static const char* url_escape_table[256] = { + "%00", "%01", "%02", "%03", "%04", "%05", "%06", "%07", "%08", "%09", + "%0a", "%0b", "%0c", "%0d", "%0e", "%0f", "%10", "%11", "%12", "%13", + "%14", "%15", "%16", "%17", "%18", "%19", "%1a", "%1b", "%1c", "%1d", + "%1e", "%1f", "%20", 0, "%22", "%23", 0, "%25", "%26", "%27", 0, 0, 0, + "%2b", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "%3c", "%3d", + "%3e", "%3f", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, "%5c", 0, "%5e", 0, "%60", 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "%7b", + "%7c", "%7d", 0, "%7f", "%80", "%81", "%82", "%83", "%84", "%85", + "%86", "%87", "%88", "%89", "%8a", "%8b", "%8c", "%8d", "%8e", "%8f", + "%90", "%91", "%92", "%93", "%94", "%95", "%96", "%97", "%98", "%99", + "%9a", "%9b", "%9c", "%9d", "%9e", "%9f", "%a0", "%a1", "%a2", "%a3", + "%a4", "%a5", "%a6", "%a7", "%a8", "%a9", "%aa", "%ab", "%ac", "%ad", + "%ae", "%af", "%b0", "%b1", "%b2", "%b3", "%b4", "%b5", "%b6", "%b7", + "%b8", "%b9", "%ba", "%bb", "%bc", "%bd", "%be", "%bf", "%c0", "%c1", + "%c2", "%c3", "%c4", "%c5", "%c6", "%c7", "%c8", "%c9", "%ca", "%cb", + "%cc", "%cd", "%ce", "%cf", "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", + "%d6", "%d7", "%d8", "%d9", "%da", "%db", "%dc", "%dd", "%de", "%df", + "%e0", "%e1", "%e2", "%e3", "%e4", "%e5", "%e6", "%e7", "%e8", "%e9", + "%ea", "%eb", "%ec", "%ed", "%ee", "%ef", "%f0", "%f1", "%f2", "%f3", + "%f4", "%f5", "%f6", "%f7", "%f8", "%f9", "%fa", "%fb", "%fc", "%fd", + "%fe", "%ff" +}; + int htmlfd = STDOUT_FILENO; char *fmt(const char *format, ...) @@ -63,13 +89,13 @@ void html_status(int code, const char *msg, int more_headers) html("\n"); } -void html_txt(char *txt) +void html_txt(const char *txt) { - char *t = txt; + const char *t = txt; while(t && *t){ int c = *t; if (c=='<' || c=='>' || c=='&') { - write(htmlfd, txt, t - txt); + html_raw(txt, t - txt); if (c=='>') html(">"); else if (c=='<') @@ -84,13 +110,13 @@ void html_txt(char *txt) html(txt); } -void html_ntxt(int len, char *txt) +void html_ntxt(int len, const char *txt) { - char *t = txt; + const char *t = txt; while(t && *t && len--){ int c = *t; if (c=='<' || c=='>' || c=='&') { - write(htmlfd, txt, t - txt); + html_raw(txt, t - txt); if (c=='>') html(">"); else if (c=='<') @@ -102,18 +128,18 @@ void html_ntxt(int len, char *txt) t++; } if (t!=txt) - write(htmlfd, txt, t - txt); + html_raw(txt, t - txt); if (len<0) html("..."); } -void html_attr(char *txt) +void html_attr(const char *txt) { - char *t = txt; + const char *t = txt; while(t && *t){ int c = *t; if (c=='<' || c=='>' || c=='\'' || c=='\"') { - write(htmlfd, txt, t - txt); + html_raw(txt, t - txt); if (c=='>') html(">"); else if (c=='<') @@ -130,14 +156,15 @@ void html_attr(char *txt) html(txt); } -void html_url_path(char *txt) +void html_url_path(const char *txt) { - char *t = txt; + const char *t = txt; while(t && *t){ int c = *t; - if (c=='"' || c=='#' || c=='\'' || c=='?') { - write(htmlfd, txt, t - txt); - write(htmlfd, fmt("%%%2x", c), 3); + const char *e = url_escape_table[c]; + if (e && c!='+' && c!='&' && c!='+') { + html_raw(txt, t - txt); + html_raw(e, 3); txt = t+1; } t++; @@ -146,14 +173,15 @@ void html_url_path(char *txt) html(txt); } -void html_url_arg(char *txt) +void html_url_arg(const char *txt) { - char *t = txt; + const char *t = txt; while(t && *t){ int c = *t; - if (c=='"' || c=='#' || c=='%' || c=='&' || c=='\'' || c=='+' || c=='?') { - write(htmlfd, txt, t - txt); - write(htmlfd, fmt("%%%2x", c), 3); + const char *e = url_escape_table[c]; + if (e) { + html_raw(txt, t - txt); + html_raw(e, 3); txt = t+1; } t++; @@ -162,7 +190,7 @@ void html_url_arg(char *txt) html(txt); } -void html_hidden(char *name, char *value) +void html_hidden(const char *name, const char *value) { html(""); } -void html_option(char *value, char *text, char *selected_value) +void html_option(const char *value, const char *text, const char *selected_value) { html("