diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | cgit.c | 25 | ||||
-rw-r--r-- | cgit.css | 347 | ||||
-rw-r--r-- | cgit.h | 2 | ||||
-rw-r--r-- | cgitrc.5.txt | 13 | ||||
-rwxr-xr-x | filters/syntax-highlighting.sh | 28 | ||||
-rw-r--r-- | html.c | 4 | ||||
-rw-r--r-- | parsing.c | 2 | ||||
-rw-r--r-- | shared.c | 5 | ||||
-rwxr-xr-x | tests/setup.sh | 5 | ||||
-rwxr-xr-x | tests/t0108-patch.sh | 2 | ||||
-rw-r--r-- | ui-diff.c | 17 | ||||
-rw-r--r-- | ui-log.c | 3 | ||||
-rw-r--r-- | ui-plain.c | 9 | ||||
-rw-r--r-- | ui-repolist.c | 9 | ||||
-rw-r--r-- | ui-shared.c | 86 | ||||
-rw-r--r-- | ui-shared.h | 5 | ||||
-rw-r--r-- | ui-ssdiff.c | 29 | ||||
-rw-r--r-- | ui-ssdiff.h | 12 | ||||
-rw-r--r-- | ui-tree.c | 13 |
20 files changed, 393 insertions, 227 deletions
@@ -1,4 +1,4 @@ -CGIT_VERSION = v0.9.0.1 +CGIT_VERSION = v0.9.0.3 CGIT_SCRIPT_NAME = cgit.cgi CGIT_SCRIPT_PATH = /var/www/htdocs/cgit CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH) @@ -13,7 +13,7 @@ pdfdir = $(docdir) mandir = $(prefix)/share/man SHA1_HEADER = <openssl/sha.h> GIT_VER = 1.7.4 -GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2 +GIT_URL = http://hjemli.net/git/git/snapshot/git-$(GIT_VER).tar.bz2 INSTALL = install MAN5_TXT = $(wildcard *.5.txt) MAN_TXT = $(MAN5_TXT) @@ -60,6 +60,8 @@ static void process_cached_repolist(const char *path); void repo_config(struct cgit_repo *repo, const char *name, const char *value) { + struct string_list_item *item; + if (!strcmp(name, "name")) repo->name = xstrdup(value); else if (!strcmp(name, "clone-url")) @@ -86,7 +88,10 @@ void repo_config(struct cgit_repo *repo, const char *name, const char *value) repo->max_stats = cgit_find_stats_period(value, NULL); else if (!strcmp(name, "module-link")) repo->module_link= xstrdup(value); - else if (!strcmp(name, "section")) + else if (!prefixcmp(name, "module-link.")) { + item = string_list_append(&repo->submodules, name + 12); + item->util = xstrdup(value); + } else if (!strcmp(name, "section")) repo->section = xstrdup(value); else if (!strcmp(name, "readme") && value != NULL) repo->readme = xstrdup(value); @@ -300,6 +305,7 @@ static void querystring_cb(const char *name, const char *value) ctx.qry.period = xstrdup(value); } else if (!strcmp(name, "ss")) { ctx.qry.ssdiff = atoi(value); + ctx.qry.has_ssdiff = 1; } else if (!strcmp(name, "all")) { ctx.qry.show_all = atoi(value); } else if (!strcmp(name, "context")) { @@ -340,7 +346,6 @@ static void prepare_context(struct cgit_context *ctx) 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; @@ -418,6 +423,17 @@ char *find_default_branch(struct cgit_repo *repo) return ref; } +static char *guess_defbranch(const char *repo_path) +{ + const char *ref; + unsigned char sha1[20]; + + ref = resolve_ref("HEAD", sha1, 0, NULL); + if (!ref || prefixcmp(ref, "refs/heads/")) + return "master"; + return xstrdup(ref + 11); +} + static int prepare_repo_cmd(struct cgit_context *ctx) { char *tmp; @@ -444,10 +460,12 @@ static int prepare_repo_cmd(struct cgit_context *ctx) } ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc); + if (!ctx->repo->defbranch) + ctx->repo->defbranch = guess_defbranch(ctx->repo->path); + if (!ctx->qry.head) { ctx->qry.nohead = 1; ctx->qry.head = find_default_branch(ctx->repo); - ctx->repo->defbranch = ctx->qry.head; } if (!ctx->qry.head) { @@ -471,6 +489,7 @@ static int prepare_repo_cmd(struct cgit_context *ctx) cgit_print_docend(); return 1; } + sort_string_list(&ctx->repo->submodules); cgit_prepare_repo_env(ctx->repo); return 0; } @@ -1,4 +1,4 @@ -body, table, form { +body, div#cgit table, div#cgit form { padding: 0em; margin: 0em; } @@ -11,39 +11,40 @@ body { padding: 4px; } -a { +div#cgit a { color: blue; text-decoration: none; } -a:hover { +div#cgit a:hover { text-decoration: underline; } -table { +div#cgit table { border-collapse: collapse; } -table#header { +div#cgit table#header { width: 100%; margin-bottom: 1em; } -table#header td.logo { +div#cgit table#header td.logo { width: 96px; + vertical-align: top; } -table#header td.main { +div#cgit table#header td.main { font-size: 250%; padding-left: 10px; white-space: nowrap; } -table#header td.main a { +div#cgit table#header td.main a { color: #000; } -table#header td.form { +div#cgit table#header td.form { text-align: right; vertical-align: bottom; padding-right: 1em; @@ -51,19 +52,19 @@ table#header td.form { white-space: nowrap; } -table#header td.form form, -table#header td.form input, -table#header td.form select { +div#cgit table#header td.form form, +div#cgit table#header td.form input, +div#cgit table#header td.form select { font-size: 90%; } -table#header td.sub { +div#cgit table#header td.sub { color: #777; border-top: solid 1px #ccc; padding-left: 10px; } -table.tabs { +div#cgit table.tabs { border-bottom: solid 3px #ccc; border-collapse: collapse; margin-top: 2em; @@ -71,74 +72,74 @@ table.tabs { width: 100%; } -table.tabs td { +div#cgit table.tabs td { padding: 0px 1em; vertical-align: bottom; } -table.tabs td a { +div#cgit table.tabs td a { padding: 2px 0.75em; color: #777; font-size: 110%; } -table.tabs td a.active { +div#cgit table.tabs td a.active { color: #000; background-color: #ccc; } -table.tabs td.form { +div#cgit table.tabs td.form { text-align: right; } -table.tabs td.form form { +div#cgit table.tabs td.form form { padding-bottom: 2px; font-size: 90%; white-space: nowrap; } -table.tabs td.form input, -table.tabs td.form select { +div#cgit table.tabs td.form input, +div#cgit table.tabs td.form select { font-size: 90%; } -div.path { +div#cgit div.path { margin: 0px; padding: 5px 2em 2px 2em; color: #000; background-color: #eee; } -div.content { +div#cgit div.content { margin: 0px; padding: 2em; border-bottom: solid 3px #ccc; } -table.list { +div#cgit table.list { width: 100%; border: none; border-collapse: collapse; } -table.list tr { +div#cgit table.list tr { background: white; } -table.list tr.logheader { +div#cgit table.list tr.logheader { background: #eee; } -table.list tr:hover { +div#cgit table.list tr:hover { background: #eee; } -table.list tr.nohover:hover { +div#cgit table.list tr.nohover:hover { background: white; } -table.list th { +div#cgit table.list th { font-weight: bold; /* color: #888; border-top: dashed 1px #888; @@ -148,93 +149,93 @@ table.list th { vertical-align: baseline; } -table.list td { +div#cgit table.list td { border: none; padding: 0.1em 0.5em 0.1em 0.5em; } -table.list td.commitgraph { +div#cgit table.list td.commitgraph { font-family: monospace; white-space: pre; } -table.list td.commitgraph .column1 { +div#cgit table.list td.commitgraph .column1 { color: #a00; } -table.list td.commitgraph .column2 { +div#cgit table.list td.commitgraph .column2 { color: #0a0; } -table.list td.commitgraph .column3 { +div#cgit table.list td.commitgraph .column3 { color: #aa0; } -table.list td.commitgraph .column4 { +div#cgit table.list td.commitgraph .column4 { color: #00a; } -table.list td.commitgraph .column5 { +div#cgit table.list td.commitgraph .column5 { color: #a0a; } -table.list td.commitgraph .column6 { +div#cgit table.list td.commitgraph .column6 { color: #0aa; } -table.list td.logsubject { +div#cgit table.list td.logsubject { font-family: monospace; font-weight: bold; } -table.list td.logmsg { +div#cgit table.list td.logmsg { font-family: monospace; white-space: pre; padding: 0 0.5em; } -table.list td a { +div#cgit table.list td a { color: black; } -table.list td a.ls-dir { +div#cgit table.list td a.ls-dir { font-weight: bold; color: #00f; } -table.list td a:hover { +div#cgit table.list td a:hover { color: #00f; } -img { +div#cgit img { border: none; } -input#switch-btn { +div#cgit input#switch-btn { margin: 2px 0px 0px 0px; } -td#sidebar input.txt { +div#cgit td#sidebar input.txt { width: 100%; margin: 2px 0px 0px 0px; } -table#grid { +div#cgit table#grid { margin: 0px; } -td#content { +div#cgit td#content { vertical-align: top; padding: 1em 2em 1em 1em; border: none; } -div#summary { +div#cgit div#summary { vertical-align: top; margin-bottom: 1em; } -table#downloads { +div#cgit table#downloads { float: right; border-collapse: collapse; border: solid 1px #777; @@ -242,152 +243,152 @@ table#downloads { margin-bottom: 0.5em; } -table#downloads th { +div#cgit table#downloads th { background-color: #ccc; } -div#blob { +div#cgit div#blob { border: solid 1px black; } -div.error { +div#cgit div.error { color: red; font-weight: bold; margin: 1em 2em; } -a.ls-blob, a.ls-dir, a.ls-mod { +div#cgit a.ls-blob, div#cgit a.ls-dir, div#cgit a.ls-mod { font-family: monospace; } -td.ls-size { +div#cgit td.ls-size { text-align: right; font-family: monospace; width: 10em; } -td.ls-mode { +div#cgit td.ls-mode { font-family: monospace; width: 10em; } -table.blob { +div#cgit table.blob { margin-top: 0.5em; border-top: solid 1px black; } -table.blob td.lines { +div#cgit table.blob td.lines { margin: 0; padding: 0 0 0 0.5em; vertical-align: top; color: black; } -table.blob td.linenumbers { +div#cgit table.blob td.linenumbers { margin: 0; padding: 0 0.5em 0 0.5em; vertical-align: top; text-align: right; border-right: 1px solid gray; } -table.blob pre { +div#cgit table.blob pre { padding: 0; margin: 0; } -table.blob a.no, table.ssdiff a.no { +div#cgit table.blob a.no, div#cgit table.ssdiff a.no { color: gray; text-align: right; text-decoration: none; } -table.blob a.no a:hover { +div#cgit table.blob a.no a:hover { color: black; } -table.bin-blob { +div#cgit table.bin-blob { margin-top: 0.5em; border: solid 1px black; } -table.bin-blob th { +div#cgit table.bin-blob th { font-family: monospace; white-space: pre; border: solid 1px #777; padding: 0.5em 1em; } -table.bin-blob td { +div#cgit table.bin-blob td { font-family: monospace; white-space: pre; border-left: solid 1px #777; padding: 0em 1em; } -table.nowrap td { +div#cgit table.nowrap td { white-space: nowrap; } -table.commit-info { +div#cgit table.commit-info { border-collapse: collapse; margin-top: 1.5em; } -div.cgit-panel { +div#cgit div.cgit-panel { float: right; margin-top: 1.5em; } -div.cgit-panel table { +div#cgit div.cgit-panel table { border-collapse: collapse; border: solid 1px #aaa; background-color: #eee; } -div.cgit-panel th { +div#cgit div.cgit-panel th { text-align: center; } -div.cgit-panel td { +div#cgit div.cgit-panel td { padding: 0.25em 0.5em; } -div.cgit-panel td.label { +div#cgit div.cgit-panel td.label { padding-right: 0.5em; } -div.cgit-panel td.ctrl { +div#cgit div.cgit-panel td.ctrl { padding-left: 0.5em; } -table.commit-info th { +div#cgit 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 { +div#cgit table.commit-info td { font-weight: normal; padding: 0.1em 1em 0.1em 0.1em; } -div.commit-subject { +div#cgit div.commit-subject { font-weight: bold; font-size: 125%; margin: 1.5em 0em 0.5em 0em; padding: 0em; } -div.commit-msg { +div#cgit div.commit-msg { white-space: pre; font-family: monospace; } -div.notes-header { +div#cgit div.notes-header { font-weight: bold; padding-top: 1.5em; } -div.notes { +div#cgit div.notes { white-space: pre; font-family: monospace; border: solid 1px #ee9; @@ -396,22 +397,22 @@ div.notes { float: left; } -div.notes-footer { +div#cgit div.notes-footer { clear: left; } -div.diffstat-header { +div#cgit div.diffstat-header { font-weight: bold; padding-top: 1.5em; } -table.diffstat { +div#cgit table.diffstat { border-collapse: collapse; border: solid 1px #aaa; background-color: #eee; } -table.diffstat th { +div#cgit table.diffstat th { font-weight: normal; text-align: left; text-decoration: underline; @@ -419,282 +420,286 @@ table.diffstat th { font-size: 100%; } -table.diffstat td { +div#cgit table.diffstat td { padding: 0.2em 0.2em 0.1em 0.1em; font-size: 100%; border: none; } -table.diffstat td.mode { +div#cgit table.diffstat td.mode { white-space: nowrap; } -table.diffstat td span.modechange { +div#cgit table.diffstat td span.modechange { padding-left: 1em; color: red; } -table.diffstat td.add a { +div#cgit table.diffstat td.add a { color: green; } -table.diffstat td.del a { +div#cgit table.diffstat td.del a { color: red; } -table.diffstat td.upd a { +div#cgit table.diffstat td.upd a { color: blue; } -table.diffstat td.graph { +div#cgit table.diffstat td.graph { width: 500px; vertical-align: middle; } -table.diffstat td.graph table { +div#cgit table.diffstat td.graph table { border: none; } -table.diffstat td.graph td { +div#cgit table.diffstat td.graph td { padding: 0px; border: 0px; height: 7pt; } -table.diffstat td.graph td.add { +div#cgit table.diffstat td.graph td.add { background-color: #5c5; } -table.diffstat td.graph td.rem { +div#cgit table.diffstat td.graph td.rem { background-color: #c55; } -div.diffstat-summary { +div#cgit div.diffstat-summary { color: #888; padding-top: 0.5em; } -table.diff { +div#cgit table.diff { width: 100%; } -table.diff td { +div#cgit table.diff td { font-family: monospace; white-space: pre; } -table.diff td div.head { +div#cgit table.diff td div.head { font-weight: bold; margin-top: 1em; color: black; } -table.diff td div.hunk { +div#cgit table.diff td div.hunk { color: #009; } -table.diff td div.add { +div#cgit table.diff td div.add { color: green; } -table.diff td div.del { +div#cgit table.diff td div.del { color: red; } -.sha1 { +div#cgit .sha1 { font-family: monospace; font-size: 90%; } -.left { +div#cgit .left { text-align: left; } -.right { +div#cgit .right { text-align: right; } -table.list td.reposection { +div#cgit table.list td.reposection { font-style: italic; color: #888; } -a.button { +div#cgit a.button { font-size: 80%; padding: 0em 0.5em; } -a.primary { +div#cgit a.primary { font-size: 100%; } -a.secondary { +div#cgit a.secondary { font-size: 90%; } -td.toplevel-repo { +div#cgit td.toplevel-repo { } -table.list td.sublevel-repo { +div#cgit table.list td.sublevel-repo { padding-left: 1.5em; } -div.pager { +div#cgit div.pager { text-align: center; margin: 1em 0em 0em 0em; } -div.pager a { +div#cgit div.pager a { color: #777; margin: 0em 0.5em; } -span.age-mins { +div#cgit span.age-mins { font-weight: bold; color: #080; } -span.age-hours { +div#cgit span.age-hours { color: #080; } -span.age-days { +div#cgit span.age-days { color: #040; } -span.age-weeks { +div#cgit span.age-weeks { color: #444; } -span.age-months { +div#cgit span.age-months { color: #888; } -span.age-years { +div#cgit span.age-years { color: #bbb; } -div.footer { +div#cgit div.footer { margin-top: 0.5em; text-align: center; font-size: 80%; color: #ccc; } -a.branch-deco { +div#cgit a.branch-deco { + color: #000; margin: 0px 0.5em; padding: 0px 0.25em; background-color: #88ff88; border: solid 1px #007700; } -a.tag-deco { +div#cgit a.tag-deco { + color: #000; margin: 0px 0.5em; padding: 0px 0.25em; background-color: #ffff88; border: solid 1px #777700; } -a.remote-deco { +div#cgit a.remote-deco { + color: #000; margin: 0px 0.5em; padding: 0px 0.25em; background-color: #ccccff; border: solid 1px #000077; } -a.deco { +div#cgit a.deco { + color: #000; margin: 0px 0.5em; padding: 0px 0.25em; background-color: #ff8888; border: solid 1px #770000; } -div.commit-subject a.branch-deco, -div.commit-subject a.tag-deco, -div.commit-subject a.remote-deco, -div.commit-subject a.deco { +div#cgit div.commit-subject a.branch-deco, +div#cgit div.commit-subject a.tag-deco, +div#cgit div.commit-subject a.remote-deco, +div#cgit div.commit-subject a.deco { margin-left: 1em; font-size: 75%; } -table.stats { +div#cgit table.stats { border: solid 1px black; border-collapse: collapse; } -table.stats th { +div#cgit table.stats th { text-align: left; padding: 1px 0.5em; background-color: #eee; border: solid 1px black; } -table.stats td { +div#cgit table.stats td { text-align: right; padding: 1px 0.5em; border: solid 1px black; } -table.stats td.total { +div#cgit table.stats td.total { font-weight: bold; text-align: left; } -table.stats td.sum { +div#cgit table.stats td.sum { color: #c00; font-weight: bold; /* background-color: #eee; */ } -table.stats td.left { +div#cgit table.stats td.left { text-align: left; } -table.vgraph { +div#cgit table.vgraph { border-collapse: separate; border: solid 1px black; height: 200px; } -table.vgraph th { +div#cgit table.vgraph th { background-color: #eee; font-weight: bold; border: solid 1px white; padding: 1px 0.5em; } -table.vgraph td { +div#cgit table.vgraph td { vertical-align: bottom; padding: 0px 10px; } -table.vgraph div.bar { +div#cgit table.vgraph div.bar { background-color: #eee; } -table.hgraph { +div#cgit table.hgraph { border: solid 1px black; width: 800px; } -table.hgraph th { +div#cgit table.hgraph th { background-color: #eee; font-weight: bold; border: solid 1px black; padding: 1px 0.5em; } -table.hgraph td { - vertical-align: center; +div#cgit table.hgraph td { + vertical-align: middle; padding: 2px 2px; } -table.hgraph div.bar { +div#cgit table.hgraph div.bar { background-color: #eee; height: 1em; } -table.ssdiff { +div#cgit table.ssdiff { width: 100%; } -table.ssdiff td { +div#cgit table.ssdiff td { font-size: 75%; font-family: monospace; white-space: pre; @@ -703,53 +708,53 @@ table.ssdiff td { border-right: solid 1px #aaa; } -table.ssdiff td.add { +div#cgit table.ssdiff td.add { color: black; background: #cfc; min-width: 50%; } -table.ssdiff td.add_dark { +div#cgit table.ssdiff td.add_dark { color: black; background: #aca; min-width: 50%; } -table.ssdiff span.add { +div#cgit table.ssdiff span.add { background: #cfc; font-weight: bold; } -table.ssdiff td.del { +div#cgit table.ssdiff td.del { color: black; background: #fcc; min-width: 50%; } -table.ssdiff td.del_dark { +div#cgit table.ssdiff td.del_dark { color: black; background: #caa; min-width: 50%; } -table.ssdiff span.del { +div#cgit table.ssdiff span.del { background: #fcc; font-weight: bold; } -table.ssdiff td.changed { +div#cgit table.ssdiff td.changed { color: black; background: #ffc; min-width: 50%; } -table.ssdiff td.changed_dark { +div#cgit table.ssdiff td.changed_dark { color: black; background: #cca; min-width: 50%; } -table.ssdiff td.lineno { +div#cgit table.ssdiff td.lineno { color: black; background: #eee; text-align: right; @@ -757,48 +762,48 @@ table.ssdiff td.lineno { min-width: 3em; } -table.ssdiff td.hunk { - color: #black; +div#cgit table.ssdiff td.hunk { + color: black; background: #ccf; border-top: solid 1px #aaa; border-bottom: solid 1px #aaa; } -table.ssdiff td.head { +div#cgit table.ssdiff td.head { border-top: solid 1px #aaa; border-bottom: solid 1px #aaa; } -table.ssdiff td.head div.head { +div#cgit table.ssdiff td.head div.head { font-weight: bold; color: black; } -table.ssdiff td.foot { +div#cgit table.ssdiff td.foot { border-top: solid 1px #aaa; border-left: none; border-right: none; border-bottom: none; } -table.ssdiff td.space { +div#cgit table.ssdiff td.space { border: none; } -table.ssdiff td.space div { +div#cgit table.ssdiff td.space div { min-height: 3em; } /* Syntax highlighting */ -table.blob .num { color:#2928ff; } -table.blob .esc { color:#ff00ff; } -table.blob .str { color:#ff0000; } -table.blob .dstr { color:#818100; } -table.blob .slc { color:#838183; font-style:italic; } -table.blob .com { color:#838183; font-style:italic; } -table.blob .dir { color:#008200; } -table.blob .sym { color:#000000; } -table.blob .kwa { color:#000000; font-weight:bold; } -table.blob .kwb { color:#830000; } -table.blob .kwc { color:#000000; font-weight:bold; } -table.blob .kwd { color:#010181; } +div#cgit table.blob .num { color:#2928ff; } +div#cgit table.blob .esc { color:#ff00ff; } +div#cgit table.blob .str { color:#ff0000; } +div#cgit table.blob .dstr { color:#818100; } +div#cgit table.blob .slc { color:#838183; font-style:italic; } +div#cgit table.blob .com { color:#838183; font-style:italic; } +div#cgit table.blob .dir { color:#008200; } +div#cgit table.blob .sym { color:#000000; } +div#cgit table.blob .kwa { color:#000000; font-weight:bold; } +div#cgit table.blob .kwb { color:#830000; } +div#cgit table.blob .kwc { color:#000000; font-weight:bold; } +div#cgit table.blob .kwd { color:#010181; } @@ -88,6 +88,7 @@ struct cgit_repo { struct cgit_filter *about_filter; struct cgit_filter *commit_filter; struct cgit_filter *source_filter; + struct string_list submodules; }; typedef void (*repo_config_fn)(struct cgit_repo *repo, const char *name, @@ -137,6 +138,7 @@ struct reflist { struct cgit_query { int has_symref; int has_sha1; + int has_ssdiff; char *raw; char *repo; char *page; diff --git a/cgitrc.5.txt b/cgitrc.5.txt index 22a0dc3..a72241f 100644 --- a/cgitrc.5.txt +++ b/cgitrc.5.txt @@ -241,7 +241,7 @@ module-link:: Text which will be used as the formatstring for a hyperlink when a submodule is printed in a directory listing. The arguments for the formatstring are the path and SHA1 of the submodule commit. Default - value: "./?repo=%s&page=commit&id=%s" + value: none. nocache:: If set to the value "1" caching will be disabled. This settings is @@ -388,7 +388,8 @@ repo.commit-filter:: repo.defbranch:: The name of the default branch for this repository. If no such branch exists in the repository, the first branch name (when sorted) is used - as default instead. Default value: "master". + as default instead. Default value: branch pointed to by HEAD, or + "master" if there is no suitable HEAD. repo.desc:: The value to show as repository description. Default value: none. @@ -428,6 +429,12 @@ repo.module-link:: formatstring are the path and SHA1 of the submodule commit. Default value: <module-link> +repo.module-link.<path>:: + Text which will be used as the formatstring for a hyperlink when a + submodule with the specified subdirectory path is printed in a + directory listing. The only argument for the formatstring is the SHA1 + of the submodule commit. 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 @@ -511,7 +518,7 @@ Also, all filters are handed the following environment variables: If a setting is not defined for a repository and the corresponding global setting is also not defined (if applicable), then the corresponding -environment variable will be an empty string. +environment variable will be unset. MACRO EXPANSION diff --git a/filters/syntax-highlighting.sh b/filters/syntax-highlighting.sh index 6283ce9..5fcc9c9 100755 --- a/filters/syntax-highlighting.sh +++ b/filters/syntax-highlighting.sh @@ -42,4 +42,32 @@ EXTENSION="${BASENAME##*.}" # map Makefile and Makefile.* to .mk [ "${BASENAME%%.*}" == "Makefile" ] && EXTENSION=mk +# highlight versions 2 and 3 have different commandline options. Specifically, +# the -X option that is used for version 2 is replaced by the -O xhtml option +# for version 3. +# +# Version 2 can be found (for example) on EPEL 5, while version 3 can be +# found (for example) on EPEL 6. +# +# This is for version 2 exec highlight --force -f -I -X -S $EXTENSION 2>/dev/null + +# This is for version 3 +# +# On CentOS 6.2 (using highlight from EPEL), when highlight doesn't know about +# an EXTENSION, it outputs a lua error and _no_ text, even when the --force +# option is used. +# +# Also see the bug reports at: +# http://sourceforge.net/tracker/?func=detail&aid=3490017&group_id=215618&atid=1034391 +# https://bugzilla.redhat.com/show_bug.cgi?id=795567 +# +# This workaround can be removed when the bug is fixed upstream and the new +# version is packaged in most distributions. +# +# The workaround is to set the extension to 'txt' (plain text) when highlight +# exits with an error (doesn't know the format). +# +#echo "test" | highlight -f -I -O xhtml -S $EXTENSION &>/dev/null +#[ ${?} -ne 0 ] && EXTENSION="txt" +#exec highlight --force -f -I -O xhtml -S $EXTENSION 2>/dev/null @@ -162,7 +162,7 @@ void html_url_path(const char *txt) { const char *t = txt; while(t && *t){ - int c = *t; + unsigned char c = *t; const char *e = url_escape_table[c]; if (e && c!='+' && c!='&') { html_raw(txt, t - txt); @@ -179,7 +179,7 @@ void html_url_arg(const char *txt) { const char *t = txt; while(t && *t){ - int c = *t; + unsigned char c = *t; const char *e = url_escape_table[c]; if (c == ' ') e = "+"; @@ -125,7 +125,7 @@ const char *reencode(char **txt, const char *src_enc, const char *dst_enc) struct commitinfo *cgit_parse_commit(struct commit *commit) { struct commitinfo *ret; - char *p = commit->buffer, *t = commit->buffer; + char *p = commit->buffer, *t; ret = xmalloc(sizeof(*ret)); ret->commit = commit; @@ -8,7 +8,6 @@ #include "cgit.h" #include <stdio.h> -#include <linux/limits.h> struct cgit_repolist cgit_repolist; struct cgit_context ctx; @@ -56,7 +55,6 @@ struct cgit_repo *cgit_add_repo(const char *url) ret->desc = "[no description]"; ret->owner = NULL; ret->section = ctx.cfg.section; - ret->defbranch = "master"; ret->snapshots = ctx.cfg.snapshots; ret->enable_commit_graph = ctx.cfg.enable_commit_graph; ret->enable_log_filecount = ctx.cfg.enable_log_filecount; @@ -71,6 +69,7 @@ struct cgit_repo *cgit_add_repo(const char *url) ret->commit_filter = ctx.cfg.commit_filter; ret->source_filter = ctx.cfg.source_filter; ret->clone_url = ctx.cfg.clone_url; + ret->submodules.strdup_strings = 1; return ret; } @@ -393,7 +392,7 @@ void cgit_prepare_repo_env(struct cgit_repo * repo) p = env_vars; q = p + env_var_count; for (; p < q; p++) - if (setenv(p->name, p->value, 1)) + if (p->value && setenv(p->name, p->value, 1)) fprintf(stderr, warn, p->name, p->value); } diff --git a/tests/setup.sh b/tests/setup.sh index 1e06107..e3c6c17 100755 --- a/tests/setup.sh +++ b/tests/setup.sh @@ -15,13 +15,14 @@ # run_test 'repo index' 'cgit_url "/" | tidy -e' # run_test 'repo summary' 'cgit_url "/foo" | tidy -e' +unset CDPATH mkrepo() { name=$1 count=$2 dir=$PWD test -d "$name" && return - printf "Creating testrepo %s\n" $name + printf "Creating testrepo %s\n" "$name" mkdir -p "$name" cd "$name" git init @@ -40,7 +41,7 @@ mkrepo() { git commit -m "add a+b" git branch "1+2" fi - cd $dir + cd "$dir" } setup_repos() diff --git a/tests/t0108-patch.sh b/tests/t0108-patch.sh index e608104..6ee70b3 100755 --- a/tests/t0108-patch.sh +++ b/tests/t0108-patch.sh @@ -25,7 +25,7 @@ run_test 'find `cgit` signature' ' ' run_test 'find initial commit' ' - root=$(git --git-dir=$PWD/trash/repos/foo/.git rev-list HEAD | tail -1) + root=$(git --git-dir="$PWD/trash/repos/foo/.git" rev-list HEAD | tail -1) ' run_test 'generate patch for initial commit' ' @@ -97,10 +97,12 @@ static void print_fileinfo(struct fileinfo *info) htmlf("</td><td class='%s'>", class); cgit_diff_link(info->new_path, NULL, NULL, ctx.qry.head, ctx.qry.sha1, ctx.qry.sha2, info->new_path, 0); - 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); + if (info->status == DIFF_STATUS_COPIED || info->status == DIFF_STATUS_RENAMED) { + htmlf(" (%s from ", + info->status == DIFF_STATUS_COPIED ? "copied" : "renamed"); + html_txt(info->old_path); + html(")"); + } html("</td><td class='right'>"); if (info->binary) { htmlf("bin</td><td class='graph'>%ld -> %ld bytes", @@ -339,9 +341,7 @@ void cgit_print_diff_ctrls() html("<td class='label'>mode:</td>"); html("<td class='ctrl'>"); html("<select name='ss' onchange='this.form.submit();'>"); - curr = ctx.qry.ssdiff; - if (!curr && ctx.cfg.ssdiff) - curr = 1; + curr = ctx.qry.has_ssdiff ? ctx.qry.ssdiff : ctx.cfg.ssdiff; html_intoption(0, "unified", curr); html_intoption(1, "ssdiff", curr); html("</select></td></tr>"); @@ -393,8 +393,7 @@ void cgit_print_diff(const char *new_rev, const char *old_rev, } } - if ((ctx.qry.ssdiff && !ctx.cfg.ssdiff) || (!ctx.qry.ssdiff && ctx.cfg.ssdiff)) - use_ssdiff = 1; + use_ssdiff = ctx.qry.has_ssdiff ? ctx.qry.ssdiff : ctx.cfg.ssdiff; if (show_ctrls) cgit_print_diff_ctrls(); @@ -76,6 +76,8 @@ void show_commit_decorations(struct commit *commit) cgit_tag_link(buf, NULL, "tag-deco", ctx.qry.head, buf); } else if (!prefixcmp(deco->name, "refs/remotes/")) { + if (!ctx.repo->enable_remote_branches) + goto next; strncpy(buf, deco->name + 13, sizeof(buf) - 1); cgit_log_link(buf, NULL, "remote-deco", NULL, sha1_to_hex(commit->object.sha1), @@ -88,6 +90,7 @@ void show_commit_decorations(struct commit *commit) sha1_to_hex(commit->object.sha1), ctx.qry.vpath, 0); } +next: deco = deco->next; } } @@ -147,11 +147,14 @@ static void print_dir_entry(const unsigned char *sha1, const char *base, char *fullpath; fullpath = buildpath(base, baselen, path); - if (!S_ISDIR(mode)) + if (!S_ISDIR(mode) && !S_ISGITLINK(mode)) fullpath[strlen(fullpath) - 1] = 0; html(" <li>"); - cgit_plain_link(path, NULL, NULL, ctx.qry.head, ctx.qry.sha1, - fullpath); + if (S_ISGITLINK(mode)) { + cgit_submodule_link(NULL, fullpath, sha1_to_hex(sha1)); + } else + cgit_plain_link(path, NULL, NULL, ctx.qry.head, ctx.qry.sha1, + fullpath); html("</li>\n"); match = 2; } diff --git a/ui-repolist.c b/ui-repolist.c index 25c36ce..d946f32 100644 --- a/ui-repolist.c +++ b/ui-repolist.c @@ -45,7 +45,8 @@ static int get_repo_modtime(const struct cgit_repo *repo, time_t *mtime) return 1; } - path = fmt("%s/refs/heads/%s", repo->path, repo->defbranch); + path = fmt("%s/refs/heads/%s", repo->path, repo->defbranch ? + repo->defbranch : "master"); if (stat(path, &s) == 0) { *mtime = s.st_mtime; r->mtime = *mtime; @@ -118,13 +119,13 @@ void print_header(int columns) } -void print_pager(int items, int pagelen, char *search) +void print_pager(int items, int pagelen, char *search, char *sort) { int i; html("<div class='pager'>"); for(i = 0; i * pagelen < items; i++) cgit_index_link(fmt("[%d]", i+1), fmt("Page %d", i+1), NULL, - search, i * pagelen); + search, sort, i * pagelen); html("</div>"); } @@ -291,7 +292,7 @@ void cgit_print_repolist() if (!hits) cgit_print_error("No repositories found"); else if (hits > ctx.cfg.max_repo_count) - print_pager(hits, ctx.cfg.max_repo_count, ctx.qry.search); + print_pager(hits, ctx.cfg.max_repo_count, ctx.qry.search, ctx.qry.sort); cgit_print_docend(); } diff --git a/ui-shared.c b/ui-shared.c index 5aa9119..43166af 100644 --- a/ui-shared.c +++ b/ui-shared.c @@ -133,7 +133,7 @@ char *cgit_currurl() return fmt("%s/", ctx.cfg.virtual_root); } -static void site_url(const char *page, const char *search, int ofs) +static void site_url(const char *page, const char *search, const char *sort, int ofs) { char *delim = "?"; @@ -154,6 +154,12 @@ static void site_url(const char *page, const char *search, int ofs) html_attr(search); delim = "&"; } + if (sort) { + html(delim); + html("s="); + html_attr(sort); + delim = "&"; + } if (ofs) { html(delim); htmlf("ofs=%d", ofs); @@ -161,7 +167,7 @@ static void site_url(const char *page, const char *search, int ofs) } static void site_link(const char *page, const char *name, const char *title, - const char *class, const char *search, int ofs) + const char *class, const char *search, const char *sort, int ofs) { html("<a"); if (title) { @@ -175,16 +181,16 @@ static void site_link(const char *page, const char *name, const char *title, html("'"); } html(" href='"); - site_url(page, search, ofs); + site_url(page, search, sort, ofs); html("'>"); html_txt(name); html("</a>"); } void cgit_index_link(const char *name, const char *title, const char *class, - const char *pattern, int ofs) + const char *pattern, const char *sort, int ofs) { - site_link(NULL, name, title, class, pattern, ofs); + site_link(NULL, name, title, class, pattern, sort, ofs); } static char *repolink(const char *title, const char *class, const char *page, @@ -288,7 +294,7 @@ void cgit_log_link(const char *name, const char *title, const char *class, char *delim; delim = repolink(title, class, "log", head, path); - if (rev && strcmp(rev, ctx.qry.head)) { + if (rev && ctx.qry.head && strcmp(rev, ctx.qry.head)) { html(delim); html("id="); html_url_arg(rev); @@ -332,7 +338,7 @@ void cgit_commit_link(char *name, const char *title, const char *class, char *delim; delim = repolink(title, class, "commit", head, path); - if (rev && strcmp(rev, ctx.qry.head)) { + if (rev && ctx.qry.head && strcmp(rev, ctx.qry.head)) { html(delim); html("id="); html_url_arg(rev); @@ -428,7 +434,7 @@ void cgit_self_link(char *name, const char *title, const char *class, struct cgit_context *ctx) { if (!strcmp(ctx->qry.page, "repolist")) - return cgit_index_link(name, title, class, ctx->qry.search, + return cgit_index_link(name, title, class, ctx->qry.search, ctx->qry.sort, ctx->qry.ofs); else if (!strcmp(ctx->qry.page, "summary")) return cgit_summary_link(name, title, class, ctx->qry.head); @@ -503,6 +509,62 @@ void cgit_object_link(struct object *obj) reporevlink(page, name, NULL, NULL, ctx.qry.head, fullrev, NULL); } +struct string_list_item *lookup_path(struct string_list *list, + const char *path) +{ + struct string_list_item *item; + + while (path && path[0]) { + if ((item = string_list_lookup(list, path))) + return item; + if (!(path = strchr(path, '/'))) + break; + path++; + } + return NULL; +} + +void cgit_submodule_link(const char *class, char *path, const char *rev) +{ + struct string_list *list; + struct string_list_item *item; + char tail, *dir; + size_t len; + + tail = 0; + list = &ctx.repo->submodules; + item = lookup_path(list, path); + if (!item) { + len = strlen(path); + tail = path[len - 1]; + if (tail == '/') { + path[len - 1] = 0; + item = lookup_path(list, path); + } + } + html("<a "); + if (class) + htmlf("class='%s' ", class); + html("href='"); + if (item) { + html_attr(fmt(item->util, rev)); + } else if (ctx.repo->module_link) { + dir = strrchr(path, '/'); + if (dir) + dir++; + else + dir = path; + html_attr(fmt(ctx.repo->module_link, dir, rev)); + } else { + html("#"); + } + html("'>"); + html_txt(path); + html("</a>"); + if (item && tail) + path[len - 1] = tail; +} + void cgit_print_date(time_t secs, const char *format, int local_time) { char buf[64]; @@ -613,7 +675,7 @@ void cgit_print_docstart(struct cgit_context *ctx) html_attr(ctx->cfg.favicon); html("'/>\n"); } - if (host && ctx->repo) { + if (host && ctx->repo && ctx->qry.head) { html("<link rel='alternate' title='Atom feed' href='"); html(cgit_httpscheme()); html_attr(cgit_hosturl()); @@ -782,7 +844,7 @@ static void print_header(struct cgit_context *ctx) html("<td class='main'>"); if (ctx->repo) { - cgit_index_link("index", NULL, NULL, NULL, 0); + cgit_index_link("index", NULL, NULL, NULL, NULL, 0); html(" : "); cgit_summary_link(ctx->repo->name, ctx->repo->name, NULL, NULL); html("</td><td class='form'>"); @@ -858,10 +920,10 @@ void cgit_print_pageheader(struct cgit_context *ctx) html("<input type='submit' value='search'/>\n"); html("</form>\n"); } else { - site_link(NULL, "index", NULL, hc(ctx, "repolist"), NULL, 0); + site_link(NULL, "index", NULL, hc(ctx, "repolist"), NULL, NULL, 0); if (ctx->cfg.root_readme) site_link("about", "about", NULL, hc(ctx, "about"), - NULL, 0); + NULL, NULL, 0); html("</td><td class='form'>"); html("<form method='get' action='"); html_attr(cgit_rooturl()); diff --git a/ui-shared.h b/ui-shared.h index 3cc1258..87a7dac 100644 --- a/ui-shared.h +++ b/ui-shared.h @@ -11,7 +11,7 @@ extern char *cgit_pageurl(const char *reponame, const char *pagename, const char *query); extern void cgit_index_link(const char *name, const char *title, - const char *class, const char *pattern, int ofs); + const char *class, const char *pattern, const char *sort, int ofs); extern void cgit_summary_link(const char *name, const char *title, const char *class, const char *head); extern void cgit_tag_link(const char *name, const char *title, @@ -51,6 +51,9 @@ extern void cgit_self_link(char *name, const char *title, const char *class, struct cgit_context *ctx); extern void cgit_object_link(struct object *obj); +extern void cgit_submodule_link(const char *class, char *path, + const char *rev); + extern void cgit_print_error(const char *msg); extern void cgit_print_date(time_t secs, const char *format, int local_time); extern void cgit_print_age(time_t t, time_t max_relative, const char *format); diff --git a/ui-ssdiff.c b/ui-ssdiff.c index 2481585..0cff4b8 100644 --- a/ui-ssdiff.c +++ b/ui-ssdiff.c @@ -2,10 +2,12 @@ #include "html.h" #include "ui-shared.h" #include "ui-diff.h" +#include "ui-ssdiff.h" extern int use_ssdiff; static int current_old_line, current_new_line; +static int **L = NULL; struct deferred_lines { int line_no; @@ -16,16 +18,40 @@ struct deferred_lines { static struct deferred_lines *deferred_old, *deferred_old_last; static struct deferred_lines *deferred_new, *deferred_new_last; +static void create_or_reset_lcs_table() +{ + int i; + + if (L != NULL) { + memset(*L, 0, sizeof(int) * MAX_SSDIFF_SIZE); + return; + } + + // xcalloc will die if we ran out of memory; + // not very helpful for debugging + L = (int**)xcalloc(MAX_SSDIFF_M, sizeof(int *)); + *L = (int*)xcalloc(MAX_SSDIFF_SIZE, sizeof(int)); + + for (i = 1; i < MAX_SSDIFF_M; i++) { + L[i] = *L + i * MAX_SSDIFF_N; + } +} + static char *longest_common_subsequence(char *A, char *B) { int i, j, ri; int m = strlen(A); int n = strlen(B); - int L[m + 1][n + 1]; int tmp1, tmp2; int lcs_length; char *result; + // We bail if the lines are too long + if (m >= MAX_SSDIFF_M || n >= MAX_SSDIFF_N) + return NULL; + + create_or_reset_lcs_table(); + for (i = m; i >= 0; i--) { for (j = n; j >= 0; j--) { if (A[i] == '\0' || B[j] == '\0') { @@ -59,6 +85,7 @@ static char *longest_common_subsequence(char *A, char *B) j += 1; } } + return result; } diff --git a/ui-ssdiff.h b/ui-ssdiff.h index 64b4b12..88627e2 100644 --- a/ui-ssdiff.h +++ b/ui-ssdiff.h @@ -1,6 +1,18 @@ #ifndef UI_SSDIFF_H #define UI_SSDIFF_H +/* + * ssdiff line limits + */ +#ifndef MAX_SSDIFF_M +#define MAX_SSDIFF_M 128 +#endif + +#ifndef MAX_SSDIFF_N +#define MAX_SSDIFF_N 128 +#endif +#define MAX_SSDIFF_SIZE ((MAX_SSDIFF_M) * (MAX_SSDIFF_N)) + extern void cgit_ssdiff_print_deferred_lines(); extern void cgit_ssdiff_line_cb(char *line, int len); @@ -150,13 +150,7 @@ static int ls_item(const unsigned char *sha1, const char *base, int baselen, cgit_print_filemode(mode); html("</td><td>"); if (S_ISGITLINK(mode)) { - htmlf("<a class='ls-mod' href='"); - html_attr(fmt(ctx.repo->module_link, - name, - sha1_to_hex(sha1))); - html("'>"); - html_txt(name); - html("</a>"); + cgit_submodule_link("ls-mod", fullpath, sha1_to_hex(sha1)); } else if (S_ISDIR(mode)) { cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head, curr_rev, fullpath); @@ -177,8 +171,9 @@ static int ls_item(const unsigned char *sha1, const char *base, int baselen, if (ctx.repo->max_stats) cgit_stats_link("stats", NULL, "button", ctx.qry.head, fullpath); - cgit_plain_link("plain", NULL, "button", ctx.qry.head, curr_rev, - fullpath); + if (!S_ISGITLINK(mode)) + cgit_plain_link("plain", NULL, "button", ctx.qry.head, curr_rev, + fullpath); html("</td></tr>\n"); free(name); return 0; |