diff options
context:
space:
mode:
authorBryce Kwon <bryce@brycekwon.com>
committerBryce Kwon <bryce@brycekwon.com>
commit
parent
tree
download
Trim the comments and dead code across the tree
Diffstat (limited to '')
-rw-r--r--MANUAL.txt4
-rw-r--r--Makefile21
-rw-r--r--assets/cgit.css127
-rw-r--r--assets/cgit.js51
-rw-r--r--custom/cgitrc102
-rw-r--r--custom/extensions/about-render.lua91
-rw-r--r--custom/extensions/auth-file.lua73
-rw-r--r--custom/extensions/auth-inline.lua66
-rw-r--r--custom/extensions/email-gravatar.lua22
-rw-r--r--custom/extensions/email-libravatar.lua19
-rw-r--r--custom/extensions/link-commits.lua53
-rw-r--r--custom/extensions/syntax-highlight.lua67
-rwxr-xr-xcustom/hooks/post-receive.cgit-cache7
-rw-r--r--source/cache.c38
-rw-r--r--source/cgit.c91
-rw-r--r--source/cgit.h3
-rw-r--r--source/cgit.mk28
-rw-r--r--source/config.c18
-rw-r--r--source/filter.c53
-rw-r--r--source/html.c22
-rw-r--r--source/html.h4
-rw-r--r--source/parsing.c11
-rw-r--r--source/parsing.h4
-rw-r--r--source/scan-tree.c11
-rw-r--r--source/shared.c24
-rw-r--r--source/ui-atom.c21
-rw-r--r--source/ui-blame.c11
-rw-r--r--source/ui-blob.c5
-rw-r--r--source/ui-clone.c1
-rw-r--r--source/ui-diff.c33
-rw-r--r--source/ui-log.c18
-rw-r--r--source/ui-patch.c8
-rw-r--r--source/ui-plain.c36
-rw-r--r--source/ui-repolist.c5
-rw-r--r--source/ui-shared.c36
-rw-r--r--source/ui-snapshot.c2
-rw-r--r--source/ui-snapshot.h5
-rw-r--r--source/ui-ssdiff.c19
-rw-r--r--source/ui-stats.c8
-rw-r--r--source/ui-stats.h1
-rw-r--r--source/ui-summary.c13
-rw-r--r--source/ui-tree.c15
-rw-r--r--tests/extensions/harness.lua8
-rw-r--r--tests/extensions/lib.sh5
-rw-r--r--tests/filters/dump.lua5
-rwxr-xr-xtests/setup.sh29
-rwxr-xr-xtests/t0001-git-version.sh8
-rwxr-xr-xtests/t0002-html-validity.sh10
-rwxr-xr-xtests/t0003-cache.sh10
-rwxr-xr-xtests/t0004-docs.sh4
-rwxr-xr-xtests/t0101-index.sh10
-rwxr-xr-xtests/t0102-summary.sh10
-rwxr-xr-xtests/t0103-log.sh8
-rwxr-xr-xtests/t0104-tree.sh10
-rwxr-xr-xtests/t0105-plain.sh10
-rwxr-xr-xtests/t0106-commit.sh8
-rwxr-xr-xtests/t0107-diff.sh11
-rwxr-xr-xtests/t0108-rawdiff.sh8
-rwxr-xr-xtests/t0109-patch.sh49
-rwxr-xr-xtests/t0110-snapshot.sh13
-rwxr-xr-xtests/t0111-atom.sh9
-rwxr-xr-xtests/t0201-filters.sh11
-rwxr-xr-xtests/t0202-submodule-links.sh10
-rwxr-xr-xtests/t0204-limits.sh14
-rwxr-xr-xtests/t0301-security.sh6
-rwxr-xr-xtests/t0502-syntax-highlight.sh16
-rwxr-xr-xtests/t0505-auth.sh15
-rwxr-xr-xtools/release-build.sh27
-rwxr-xr-xtools/serve.py23
69 files changed, 652 insertions, 942 deletions
diff --git a/MANUAL.txt b/MANUAL.txt
index 4c924cf..f59a64c 100644
--- a/MANUAL.txt
+++ b/MANUAL.txt
@@ -883,8 +883,8 @@ use of git notes. For example, the following command may be used to add a
signature to a .tar.xz archive:
git notes --ref=refs/notes/signatures/tar.xz add -C "$(
- gpg --output - --armor --detach-sign cgit-1.1.tar.xz |
- git hash-object -w --stdin
+ gpg --output - --armor --detach-sign cgit-1.1.tar.xz |
+ git hash-object -w --stdin
)" v1.1
If it is instead desirable to attach a signature of the underlying .tar, this
diff --git a/Makefile b/Makefile
index c0d6f7d..b22beb9 100644
--- a/Makefile
+++ b/Makefile
@@ -20,7 +20,7 @@ BUILDDIR = build
CGIT_ROOT = ../..
# The Git release that get-git fetches when the submodule is not checked out.
-# Keep it in step with the submodule pin in .gitmodules.
+# Keep it in step with the commit the submodule is pinned to.
GIT_VERSION = 2.55.0
GIT_URL = https://www.kernel.org/pub/software/scm/git/git-$(GIT_VERSION).tar.xz
@@ -42,7 +42,11 @@ filterdir = $(libdir)/cgit/filters
# The files that go into the data path and the filter directory. One list each
# drives both install and uninstall, so the two can never drift apart.
-ASSETS = cgit.css cgit.js cgit.png favicon.ico robots.txt
+ASSETS = cgit.css
+ASSETS += cgit.js
+ASSETS += cgit.png
+ASSETS += favicon.ico
+ASSETS += robots.txt
FILTER_FILES = $(notdir $(wildcard $(EXTDIR)/*.lua))
INSTALL = install
@@ -52,7 +56,8 @@ INSTALL = install
-include $(GITDIR)/config.mak.uname
-include cgit.conf
-export CGIT_VERSION CGIT_SCRIPT_NAME CGIT_SCRIPT_PATH CGIT_DATA_PATH CGIT_CONFIG CACHE_ROOT
+export CGIT_VERSION CGIT_SCRIPT_NAME CGIT_SCRIPT_PATH
+export CGIT_DATA_PATH CGIT_CONFIG CACHE_ROOT
all: cgit
@@ -81,11 +86,14 @@ cgit-with-git:
install: all
$(INSTALL) -m 0755 -d $(DESTDIR)$(CGIT_SCRIPT_PATH)
- $(INSTALL) -m 0755 $(BUILDDIR)/cgit $(DESTDIR)$(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME)
+ $(INSTALL) -m 0755 $(BUILDDIR)/cgit \
+ $(DESTDIR)$(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME)
$(INSTALL) -m 0755 -d $(DESTDIR)$(CGIT_DATA_PATH)
- $(INSTALL) -m 0644 $(addprefix $(ASSETDIR)/,$(ASSETS)) $(DESTDIR)$(CGIT_DATA_PATH)
+ $(INSTALL) -m 0644 $(addprefix $(ASSETDIR)/,$(ASSETS)) \
+ $(DESTDIR)$(CGIT_DATA_PATH)
$(INSTALL) -m 0755 -d $(DESTDIR)$(filterdir)
- $(INSTALL) -m 0644 $(EXTDIR)/*.lua $(DESTDIR)$(filterdir)
+ $(INSTALL) -m 0644 $(addprefix $(EXTDIR)/,$(FILTER_FILES)) \
+ $(DESTDIR)$(filterdir)
uninstall:
$(RM) $(DESTDIR)$(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME)
@@ -111,7 +119,6 @@ tags:
@mkdir -p $(BUILDDIR)
find $(SRCDIR) -name '*.[ch]' | xargs ctags -f $(BUILDDIR)/tags
-# Grouped to mirror the order of the targets above.
.PHONY: all cgit cgit-with-git sparse test
.PHONY: install uninstall
.PHONY: clean cleanall get-git tags
diff --git a/assets/cgit.css b/assets/cgit.css
index 66d9bb8..3d754a5 100644
--- a/assets/cgit.css
+++ b/assets/cgit.css
@@ -1,9 +1,8 @@
/*
- * cgit.css: styling for the cgit web interface
- *
* Colours are driven by CSS custom properties via light-dark(), so the
- * whole theme follows the reader's system preference. All rules stay
- * scoped under div#cgit so cgit can be embedded in another page.
+ * whole theme follows the reader's system preference. Rules stay scoped
+ * under div#cgit, or behind the cgit-standalone class cgit sets on its own
+ * pages, so cgit can be embedded in another page.
*/
div#cgit {
@@ -31,7 +30,7 @@ div#cgit {
--upd: light-dark(#0000cc, #6ea8fe);
--hunk: light-dark(#000099, #7aa2f7);
--accent: light-dark(#cc0000, #ff6b6b);
- /* Faded wash over the fragment targeted source line. */
+ /* Faded wash over the fragment-targeted source line. */
--line-hl: light-dark(rgba(212, 167, 44, 0.18), rgba(224, 192, 80, 0.14));
--notes-bg: light-dark(#ffffdd, #33331a);
@@ -89,7 +88,7 @@ div#cgit {
--radius-xs: 2px;
padding: 0;
- margin: 0em;
+ margin: 0;
font-family: var(--font-sans);
font-size: 13px;
line-height: 1.4;
@@ -124,7 +123,8 @@ div#cgit a:hover {
text-decoration: underline;
}
-div#cgit img {
+div#cgit img,
+div#cgit video {
border: none;
max-width: 100%;
}
@@ -133,11 +133,8 @@ div#cgit table {
border-collapse: collapse;
}
-/* Form controls */
-
div#cgit select,
-div#cgit input,
-div#cgit button {
+div#cgit input {
font-family: inherit;
font-size: inherit;
height: var(--control-h);
@@ -165,27 +162,21 @@ div#cgit select {
cursor: pointer;
}
-div#cgit button,
div#cgit input[type="submit"] {
cursor: pointer;
}
div#cgit select:hover,
-div#cgit button:hover,
div#cgit input[type="submit"]:hover {
border-color: var(--border-mid);
- color: var(--fg);
}
div#cgit select:focus-visible,
-div#cgit input:focus-visible,
-div#cgit button:focus-visible {
+div#cgit input:focus-visible {
outline: 2px solid var(--link);
outline-offset: 1px;
}
-/* Masthead */
-
div#cgit #header {
display: grid;
grid-template-columns: auto 1fr auto;
@@ -260,8 +251,6 @@ div#cgit #header .owner {
text-align: right;
}
-/* Tab bar */
-
div#cgit .tabs {
display: flex;
flex-wrap: wrap;
@@ -314,12 +303,10 @@ div#cgit input.txt {
max-width: 12em;
}
-/* Page frame */
-
div#cgit .path {
display: flex;
flex-wrap: wrap;
- margin: 0px;
+ margin: 0;
padding: 0.45rem var(--gutter);
color: var(--fg);
background-color: var(--surface);
@@ -331,18 +318,15 @@ div#cgit .path .rev {
}
div#cgit .content {
- margin: 0px;
+ margin: 0;
padding: 1.25rem var(--gutter);
border-bottom: solid 2px var(--border);
overflow-x: auto;
}
-/* Listing tables */
-
div#cgit table.list {
width: 100%;
border: none;
- border-collapse: collapse;
}
div#cgit table.list tr {
@@ -373,8 +357,6 @@ div#cgit table.list tr.nohover:hover {
background: var(--bg);
}
-/* Spacer rows between sections hold one empty cell. Cell height counts the
- border box, so the vertical padding is added back on top of the line. */
div#cgit table.list tr.nohover td:empty {
height: calc(1lh + 0.6em);
}
@@ -461,18 +443,11 @@ div#cgit table.list td a:hover {
color: var(--link);
}
-/* Repository index */
-
div#cgit div#summary {
vertical-align: top;
margin-bottom: 1em;
}
-div#cgit div#summary img,
-div#cgit div#summary video {
- max-width: 100%;
-}
-
div#cgit div#summary pre {
overflow-x: auto;
}
@@ -588,7 +563,6 @@ div#cgit .markdown pre code {
}
div#cgit .markdown table {
- border-collapse: collapse;
margin: 0.7em 0;
}
@@ -602,10 +576,6 @@ div#cgit .markdown th {
background: var(--surface-2);
}
-div#cgit div#blob {
- border: solid 1px var(--border-strong);
-}
-
div#cgit div.error {
color: var(--accent);
font-weight: bold;
@@ -621,8 +591,6 @@ div#cgit table.list td.sublevel-repo {
padding-left: 1.5em;
}
-/* Directory / blob listings */
-
div#cgit a.ls-blob,
div#cgit a.ls-dir,
div#cgit .ls-mod {
@@ -657,8 +625,6 @@ div#cgit td.ls-links {
white-space: nowrap;
}
-/* Source blob */
-
div#cgit table.blob {
margin-top: 0.5em;
border-top: solid 1px var(--border-strong);
@@ -669,14 +635,12 @@ div#cgit table.blob {
}
div#cgit table.blob td.lines {
- margin: 0;
padding: 0 0 0 0.5em;
vertical-align: top;
color: var(--fg);
}
div#cgit table.blob td.linenumbers {
- margin: 0;
padding: 0 0.5em 0 0.5em;
vertical-align: top;
text-align: right;
@@ -754,8 +718,6 @@ div#cgit .hl-func {
color: light-dark(#6639ba, #d2a8ff);
}
-/* Blame */
-
div#cgit table.blame {
display: block;
width: max-content;
@@ -801,8 +763,6 @@ div#cgit table.blame .oid {
font-size: 100%;
}
-/* Binary blob */
-
div#cgit table.bin-blob {
margin-top: 0.5em;
border: solid 1px var(--border-strong);
@@ -823,13 +783,10 @@ div#cgit table.bin-blob td {
font-family: var(--font-mono);
white-space: pre;
border-left: solid 1px var(--border-mid);
- padding: 0em 1em;
+ padding: 0 1em;
}
-/* Commit / tag */
-
div#cgit table.commit-info {
- border-collapse: collapse;
margin-top: 1.5em;
}
@@ -839,7 +796,6 @@ div#cgit div.cgit-panel {
}
div#cgit div.cgit-panel table {
- border-collapse: collapse;
border: solid 1px var(--border-mid);
background-color: var(--surface);
}
@@ -852,14 +808,6 @@ div#cgit div.cgit-panel td {
padding: 0.25em 0.5em;
}
-div#cgit div.cgit-panel td.label {
- padding-right: 0.5em;
-}
-
-div#cgit div.cgit-panel td.ctrl {
- padding-left: 0.5em;
-}
-
div#cgit table.commit-info th {
text-align: left;
font-weight: normal;
@@ -875,8 +823,8 @@ div#cgit table.commit-info td {
div#cgit div.commit-subject {
font-weight: bold;
font-size: 125%;
- margin: 1.5em 0em 0.5em 0em;
- padding: 0em;
+ margin: 1.5em 0 0.5em 0;
+ padding: 0;
overflow-wrap: anywhere;
}
@@ -905,15 +853,12 @@ div#cgit div.notes-footer {
clear: left;
}
-/* Diffstat */
-
div#cgit div.diffstat-header {
font-weight: bold;
padding-top: 1.5em;
}
div#cgit table.diffstat {
- border-collapse: collapse;
border: solid 1px var(--border-mid);
background-color: var(--surface);
max-width: 100%;
@@ -960,14 +905,13 @@ div#cgit table.diffstat td.graph {
div#cgit table.diffstat td.graph table {
border: none;
- border-spacing: 0;
table-layout: fixed;
width: 100%;
}
div#cgit table.diffstat td.graph td {
- padding: 0px;
- border: 0px;
+ padding: 0;
+ border: 0;
height: 7pt;
}
@@ -984,8 +928,6 @@ div#cgit div.diffstat-summary {
padding-top: 0.5em;
}
-/* Unified diff */
-
/* A scroll box beside the options float would shrink to fit the gap. */
div#cgit div.diff-scroll {
clear: right;
@@ -1044,17 +986,15 @@ div#cgit .right {
text-align: right;
}
-/* Buttons / pager */
-
div#cgit a.button {
font-size: 90%;
- padding: 0em 0.5em;
+ padding: 0 0.5em;
}
div#cgit ul.pager {
list-style-type: none;
text-align: center;
- margin: 1em 0em 0em 0em;
+ margin: 1em 0 0 0;
padding: 0;
}
@@ -1071,8 +1011,6 @@ div#cgit ul.pager .current {
font-weight: bold;
}
-/* Ages / line counts */
-
div#cgit time.age-mins,
div#cgit time.age-hours,
div#cgit time.age-days,
@@ -1115,8 +1053,6 @@ div#cgit span.deletions {
color: var(--del);
}
-/* Footer */
-
div#cgit .footer {
padding: 0.85rem var(--gutter);
text-align: center;
@@ -1133,8 +1069,6 @@ div#cgit .footer a:hover {
text-decoration: underline;
}
-/* Ref decorations */
-
div#cgit a.branch-deco,
div#cgit a.tag-deco,
div#cgit a.tag-annotated-deco,
@@ -1145,8 +1079,8 @@ div#cgit a.deco {
div#cgit a.branch-deco {
color: var(--deco-fg);
- margin: 0px 0.5em;
- padding: 0px 0.25em;
+ margin: 0 0.5em;
+ padding: 0 0.25em;
background-color: var(--branch-bg);
border: solid 1px var(--branch-bd);
border-radius: var(--radius-xs);
@@ -1154,8 +1088,8 @@ div#cgit a.branch-deco {
div#cgit a.tag-deco {
color: var(--deco-fg);
- margin: 0px 0.5em;
- padding: 0px 0.25em;
+ margin: 0 0.5em;
+ padding: 0 0.25em;
background-color: var(--tag-bg);
border: solid 1px var(--tag-bd);
border-radius: var(--radius-xs);
@@ -1163,8 +1097,8 @@ div#cgit a.tag-deco {
div#cgit a.tag-annotated-deco {
color: var(--deco-fg);
- margin: 0px 0.5em;
- padding: 0px 0.25em;
+ margin: 0 0.5em;
+ padding: 0 0.25em;
background-color: var(--tag-ann-bg);
border: solid 1px var(--tag-ann-bd);
border-radius: var(--radius-xs);
@@ -1172,8 +1106,8 @@ div#cgit a.tag-annotated-deco {
div#cgit a.remote-deco {
color: var(--deco-fg);
- margin: 0px 0.5em;
- padding: 0px 0.25em;
+ margin: 0 0.5em;
+ padding: 0 0.25em;
background-color: var(--remote-bg);
border: solid 1px var(--remote-bd);
border-radius: var(--radius-xs);
@@ -1181,8 +1115,8 @@ div#cgit a.remote-deco {
div#cgit a.deco {
color: var(--deco-fg);
- margin: 0px 0.5em;
- padding: 0px 0.25em;
+ margin: 0 0.5em;
+ padding: 0 0.25em;
background-color: var(--head-bg);
border: solid 1px var(--head-bd);
border-radius: var(--radius-xs);
@@ -1197,11 +1131,8 @@ div#cgit div.commit-subject a.deco {
font-size: 80%;
}
-/* Statistics */
-
div#cgit table.stats {
border: solid 1px var(--border-strong);
- border-collapse: collapse;
display: block;
width: max-content;
max-width: 100%;
@@ -1235,8 +1166,6 @@ div#cgit table.stats td.left {
text-align: left;
}
-/* Side-by-side diff */
-
div#cgit table.ssdiff {
width: 100%;
}
diff --git a/assets/cgit.js b/assets/cgit.js
index c5bdf33..29b9745 100644
--- a/assets/cgit.js
+++ b/assets/cgit.js
@@ -12,8 +12,7 @@
// Written the way SECONDS_PER_* are derived in source/cgit.h, so that the
// bucket a browser picks is the bucket cgit_print_age already picked on the
-// server. A month is a twelfth of a year rather than thirty days, which is
-// the definition the server uses.
+// server. A month is a twelfth of a year rather than thirty days.
var MINUTE = 60;
var HOUR = 60 * MINUTE;
var DAY = 24 * HOUR;
@@ -21,15 +20,18 @@ var WEEK = 7 * DAY;
var YEAR = 365 * DAY;
var MONTH = YEAR / 12;
-// The five arrays are indexed together by the bucket an age falls into. The
-// search in render_age can stop one place past the last class, so the arrays
-// it reads there repeat their final entry. Each limit is twice the next unit
-// up, matching the thresholds cgit_print_age compares against.
-var age_classes = [ "age-mins", "age-hours", "age-days", "age-weeks", "age-months", "age-years" ];
-var age_suffix = [ "min.", "hours", "days", "weeks", "months", "years", "years" ];
-var age_unit = [ MINUTE, HOUR, DAY, WEEK, MONTH, YEAR, YEAR ];
-var age_limit = [ 2 * HOUR, 2 * DAY, 2 * WEEK, 2 * MONTH, 2 * YEAR, 2 * YEAR ];
-var update_delay = [ 10, 5 * MINUTE, 30 * MINUTE, DAY, DAY, DAY, DAY ];
+// The five arrays are indexed together by the bucket an age falls into.
+// The search in render_age can stop one place past the last class, so
+// age_suffix and age_unit repeat their final entry. Each limit is twice the
+// next unit up, matching the thresholds cgit_print_age compares against.
+var age_classes = [ "age-mins", "age-hours", "age-days", "age-weeks",
+ "age-months", "age-years" ];
+var age_suffix = [ "min.", "hours", "days", "weeks", "months", "years",
+ "years" ];
+var age_unit = [ MINUTE, HOUR, DAY, WEEK, MONTH, YEAR, YEAR ];
+var age_limit = [ 2 * HOUR, 2 * DAY, 2 * WEEK, 2 * MONTH, 2 * YEAR,
+ 2 * YEAR ];
+var update_delay = [ 10, 5 * MINUTE, 30 * MINUTE, DAY, DAY, DAY ];
function render_age(element, age) {
var text, bucket;
@@ -40,13 +42,13 @@ function render_age(element, age) {
text = Math.round(age / age_unit[bucket]) + " " + age_suffix[bucket];
- // Every age on the page is measured again on each pass, so most of
- // them are already reading correctly and writing to them would cost a
- // repaint for nothing.
+ // Every age on the page is measured again on each pass, so most of them
+ // are already reading correctly and writing to them would cost a repaint
+ // for nothing.
if (element.textContent != text) {
element.textContent = text;
- // An age past the last limit is still counted in years, but
- // there is no class beyond age-years to put on it.
+ // An age past the last limit is still counted in years, but there
+ // is no class beyond age-years to put on it.
if (bucket == age_classes.length)
bucket--;
if (element.className != age_classes[bucket])
@@ -56,7 +58,7 @@ function render_age(element, age) {
/*
* Measures every age on the page against the clock and books the next pass.
- * There is no point coming back before the coarsest unit on the page could
+ * There is no point coming back before the finest unit on the page could
* change, so a page already counted in hours is left alone for minutes and
* one counted in years for a day.
*/
@@ -74,9 +76,8 @@ function refresh_ages() {
for (i = 0; i < elements.length; i++) {
age = now - elements[i].getAttribute("data-ut");
- // A commit dated ahead of the viewer's clock would
- // otherwise show a negative age, and ui-shared.c
- // clamps it the same way.
+ // A commit dated ahead of the viewer's clock would otherwise show
+ // a negative age, and ui-shared.c clamps it the same way.
if (age < 0)
age = 0;
@@ -87,11 +88,7 @@ function refresh_ages() {
window.setTimeout(refresh_ages, delay * 1000);
}
-document.addEventListener("DOMContentLoaded", function () {
- // Nothing here depends on layout, so the first pass can run as soon
- // as the document is parsed.
- refresh_ages();
-}, false);
+document.addEventListener("DOMContentLoaded", refresh_ages, false);
})();
@@ -136,8 +133,8 @@ function place_bar() {
bar.style.height = (bottom - top) + "px";
table.appendChild(bar);
- // A browser only scrolls to a fragment that names a real id, which a
- // range never does, so bring the start of one into view here.
+ // A browser only scrolls to a fragment that names a real id, which a range
+ // never does, so bring the start of one into view here.
if (match[2])
first.scrollIntoView({ block: "center" });
}
diff --git a/custom/cgitrc b/custom/cgitrc
index c522b90..8cb1831 100644
--- a/custom/cgitrc
+++ b/custom/cgitrc
@@ -10,17 +10,13 @@
# list repositories by hand in the per-repository section at the end of this
# file.
#
-# About pages (markdown, man and plain-text readmes) render through the bundled
-# about-render.lua about-filter, see the filter section below. Source syntax
+# About pages (markdown, man and plain-text readmes) can render through the
+# bundled about-render.lua about-filter in the filter section below. Source
+# syntax
# highlighting is optional and ships as a source-filter there too.
#
# One key=value pair per line. Lines starting with # are comments.
-
-##
-## Cache
-##
-
# Maximum number of entries in the cgit output cache. A value of 0 disables
# caching. Value is an integer. Default is 0.
cache-size=0
@@ -44,7 +40,7 @@ cache-summary-ttl=5
cache-scan-ttl=15
# Minutes to cache repo pages requested with a fixed SHA1. A negative value
-# never expires. Value is an integer number of minutes. Default is -1.
+# keeps the page forever. Value is an integer number of minutes. Default is -1.
cache-static-ttl=-1
# Minutes to cache repo pages requested without a fixed SHA1. Value is an
@@ -63,11 +59,6 @@ cache-snapshot-ttl=5
# requested. Values are 0 or 1. Default is 0.
enable-cache-list=0
-
-##
-## Site appearance
-##
-
# Heading text on the repository index page. Value is any text. Default is Git
# repository browser.
#root-title=Git repository browser
@@ -84,8 +75,8 @@ enable-cache-list=0
# is one or more [ref]path entries. Default is none.
#readme=:README.md
-# CSS document urls added to the head of every page. Value is one or more urls.
-# Default is /cgit.css.
+# CSS document urls added to the head of every page. An empty value disables
+# it. Value is one or more urls. Default is /cgit.css.
#css=/cgit.css
# JavaScript document urls included on every page. An empty value disables it.
@@ -133,11 +124,6 @@ embedded=0
# format string taking path and sha1. Default is none.
#module-link=/%s/commit/?id=%s
-
-##
-## Repository discovery
-##
-
# Directory scanned for git repositories at parse time. Value is a filesystem
# path that may use macros. Default is none.
#scan-path=/var/lib/git
@@ -184,11 +170,6 @@ enable-git-config=0
# filesystem path that may use macros. Default is none.
#include=/etc/cgitrc.d/extra
-
-##
-## Features
-##
-
# Provide a blame page for files and links to it. Values are 0 or 1. Default is
# 0.
enable-blame=0
@@ -251,13 +232,9 @@ enable-tree-group-dirs=0
# year. Default is unset.
#max-stats=year
-
-##
-## Snapshots and cloning
-##
-
-# Default set of snapshot archive formats to offer. Value is a space list of tar
-# tar.gz tar.bz2 tar.lz tar.xz tar.zst zip, or the word all. Default is none.
+# Default set of snapshot archive formats to offer. Value is a space-separated
+# list of tar tar.gz tar.bz2 tar.lz tar.xz tar.zst zip, or the word all. Default
+# is none.
#snapshots=tar.gz tar.xz zip
# Act as a dumb HTTP endpoint for git clones. Values are 0 or 1. Default is 1.
@@ -272,15 +249,10 @@ enable-http-clone=1
# space-separated url templates that may use macros. Default is none.
#clone-url=https://example.com/$CGIT_REPO_URL git://example.com/$CGIT_REPO_URL
-
-##
-## Filters
-##
-#
# A filter is an external command cgit runs to transform a piece of content.
# Prefix the command with lua: to run it through the built-in Lua interpreter,
# which avoids a fork per call, or with exec: to run a normal program. The
-# commands below that point at /usr/share/cgit/extensions/ use scripts this
+# commands below that point at /usr/local/lib/cgit/filters/ use scripts this
# repository ships under custom/extensions/. The ones written as
# /path/to/your-command mark where your own command goes.
@@ -291,36 +263,29 @@ enable-filter-overrides=0
# Filter command used to format about-page content. The bundled about-render.lua
# renders markdown, man pages and plain text. Value is a command optionally
# prefixed with exec or lua. Default is none.
-#about-filter=lua:/usr/share/cgit/extensions/about-render.lua
+#about-filter=lua:/usr/local/lib/cgit/filters/about-render.lua
# Filter command used to format commit messages, for example to turn object
# names and issue numbers into links. Value is a command optionally prefixed
# with exec or lua. Default is none.
-#commit-filter=lua:/usr/share/cgit/extensions/link-commits.lua
+#commit-filter=lua:/usr/local/lib/cgit/filters/link-commits.lua
# Filter command used to format author and committer emails, for example to add
# avatar images. Value is a command optionally prefixed with exec or lua.
# Default is none.
-#email-filter=lua:/usr/share/cgit/extensions/email-gravatar.lua
+#email-filter=lua:/usr/local/lib/cgit/filters/email-gravatar.lua
-# Filter command used to format plaintext blobs in the tree view. Without it
-# cgit serves the text plain. For syntax highlighting, the shipped filter below
-# uses the Scintillua lexers and needs the lpeg module installed too, on Debian
-# that is "apt install lua-lpeg". Missing either dependency means plain
-# uncolored text, not an error. See the comments in that file. Value is a
-# command optionally prefixed with exec or lua. Default is none.
-#source-filter=lua:/usr/share/cgit/extensions/syntax-highlight.lua
+# Filter command used to format plaintext blobs in the tree view. The shipped
+# filter uses the Scintillua lexers and needs lpeg, and missing either means
+# plain uncolored text, not an error.
+# Value is a command optionally prefixed with exec or lua. Default is none.
+#source-filter=lua:/usr/local/lib/cgit/filters/syntax-highlight.lua
# Filter command invoked to authenticate access, gating repositories behind a
# login. See custom/extensions/auth-inline.lua and
# custom/extensions/auth-file.lua. Value is a command optionally prefixed with
# exec or lua. Default is none.
-#auth-filter=lua:/usr/share/cgit/extensions/auth-inline.lua
-
-
-##
-## Limits and safety
-##
+#auth-filter=lua:/usr/local/lib/cgit/filters/auth-inline.lua
# Number of items to display in atom feeds. Value is an integer. Default is 10.
max-atom-items=10
@@ -337,7 +302,7 @@ max-repodesc-length=80
# value of 0 disables the limit. Value is an integer. Default is 10240.
max-blob-size=10240
-# Number of repos listed per page on the index. A value of 0 or negative shows
+# Number of repos listed per page on the index. Zero or a negative value shows
# all repos. Value is an integer. Default is 50.
max-repo-count=50
@@ -369,11 +334,6 @@ max-ref-count=200
# compile-time value. Value is an integer. Default is -1.
rename-limit=-1
-
-##
-## Presentation
-##
-
# Number of log entries shown in the summary view. Value is an integer. Default
# is 10.
summary-log=10
@@ -408,8 +368,8 @@ branch-sort=name
# Sort items in the repo list case-sensitively. Values are 0 or 1. Default is 1.
case-sensitive-sort=1
-# Show full author email addresses beside names. Set to 0 to hide them. Values
-# are 0 or 1. Default is 1.
+# Show full author email addresses beside names. Values are 0 or 1. Default is
+# 1.
enable-plain-email=1
# File giving the timestamp of the youngest commit. Value is a path relative to
@@ -429,16 +389,10 @@ enable-plain-email=1
#mimetype.png=image/png
#mimetype.svg=image/svg+xml
-
-##
-## Per-repository overrides
-##
-#
-# Each repository is introduced by a repo.url line, which must be the first
-# setting of the block. All following repo.* settings apply to that repo until
-# the next repo.url line. When repos are discovered via scan-path the repo.
-# prefix is dropped inside each repo cgitrc and repo.url and repo.path are not
-# allowed there.
+# Each repository is introduced by a repo.url line. All following repo.*
+# settings apply to that repo until the next repo.url line. When repos are
+# discovered via scan-path the repo. prefix is dropped inside each repo cgitrc
+# and repo.url and repo.path are not allowed there.
# Relative url for a repo. Must be the first setting of each repo block. Value
# is a relative url path. Default is none.
@@ -566,7 +520,7 @@ enable-plain-email=1
# Per-repo override of the commit-filter. Only honoured when
# enable-filter-overrides is 1. Value is a command. Default is the global
# commit-filter value.
-#repo.commit-filter=lua:/usr/share/cgit/extensions/link-commits.lua
+#repo.commit-filter=lua:/usr/local/lib/cgit/filters/link-commits.lua
# Per-repo override of the source-filter. Only honoured when
# enable-filter-overrides is 1. Value is a command. Default is the global
@@ -576,4 +530,4 @@ enable-plain-email=1
# Per-repo override of the email-filter. Only honoured when
# enable-filter-overrides is 1. Value is a command. Default is the global
# email-filter value.
-#repo.email-filter=lua:/usr/share/cgit/extensions/email-gravatar.lua
+#repo.email-filter=lua:/usr/local/lib/cgit/filters/email-gravatar.lua
diff --git a/custom/extensions/about-render.lua b/custom/extensions/about-render.lua
index ea13746..f4e7685 100644
--- a/custom/extensions/about-render.lua
+++ b/custom/extensions/about-render.lua
@@ -1,20 +1,15 @@
-- Server-side rendering of a repository's about page, named by the
-- about-filter setting in cgitrc and run inside cgit's embedded Lua
--- interpreter so a readme costs no extra process per request.
--- Markdown, man pages and plain text are the three formats, chosen from the
--- readme's file extension, and anything that fails to parse falls back to
--- escaped plain text. Adding a format takes a render function and a row in
--- the handler table at the foot of this file, and nothing else. The wrappers
--- it emits carry the classes that assets/cgit.css styles. It runs on Lua 5.1
--- through 5.4 and LuaJIT.
+-- interpreter so a readme costs no extra process per request. Markdown, man
+-- pages and plain text are the three formats, chosen from the readme's file
+-- extension, and anything that fails to parse falls back to escaped plain
+-- text. The wrappers it emits carry the classes that assets/cgit.css styles.
+-- It runs on Lua 5.1 through 5.4 and LuaJIT.
--
--- about-filter=lua:/usr/lib/cgit/filters/about-render.lua
+-- about-filter=lua:/usr/local/lib/cgit/filters/about-render.lua
--- Markdown and man pages are parsed with lpeg grammars, so where the parsing
--- module is missing both fall back to escaped plain text and only plain text
--- still renders. It has to be built for the Lua cgit is linked against.
--- cgit's syntax highlighter needs it too, so a cgit that colours source
--- already has it.
+-- Markdown and man pages need lpeg, built for the Lua cgit is linked
+-- against. Without it both fall back to escaped plain text.
--
-- # Debian and Ubuntu
-- sudo apt install lua-lpeg
@@ -42,9 +37,8 @@ local function trim(text)
return (text:gsub("^%s+", ""):gsub("%s+$", ""))
end
--- Split on newlines after normalising CRLF and CR, returning the lines
--- without their terminators. A trailing newline yields a final empty line,
--- which every caller treats as blank.
+-- Normalise CRLF and CR to newlines, then split. A trailing newline yields
+-- a final empty line, which every caller treats as blank.
local function split_lines(text)
text = text:gsub("\r\n?", "\n")
local lines, start = {}, 1
@@ -59,8 +53,6 @@ local function split_lines(text)
end
end
--- Split a table row into trimmed cells, dropping one optional leading and one
--- optional trailing pipe.
local function split_cells(row)
row = trim(row):gsub("^|", ""):gsub("|$", "")
local cells = {}
@@ -70,11 +62,10 @@ local function split_cells(row)
return cells
end
--- Return the URL if its scheme is safe, else nil. Control and whitespace
--- bytes are stripped anywhere first because a browser ignores them when
--- resolving the scheme, so "java\nscript:" must still be caught as
--- javascript. The class is %c%s rather than a literal 0x00 range so it is
--- safe on Lua 5.1, where an embedded zero byte ends a pattern.
+-- Control and whitespace bytes are stripped before the scheme check because
+-- a browser ignores them when resolving it, so "java\nscript:" must still be
+-- caught as javascript. The class is %c%s rather than a literal 0x00 range
+-- so it is safe on Lua 5.1, where an embedded zero byte ends a pattern.
local function safe_url(url)
url = url:gsub("[%c%s]", "")
-- A leading "//" or "/\" is scheme-relative, which a browser
@@ -94,14 +85,10 @@ local function safe_url(url)
end
--- The about page renders untrusted repository content, so the rule the two
--- functions below keep is that every run of text reaches the page through
--- cgit's own html_txt, every attribute value through html_attr, and every
--- link or image target through safe_url before html_attr. Those three come
--- from cgit's Lua filter host rather than from here, and the only thing
--- passed to html is literal tag scaffolding. Because all output is routed
--- through those sinks by construction, a bug in the parser can only
--- mis-render, never inject markup or a URL with a javascript scheme.
+-- The page renders untrusted repository content. Every run of text goes out
+-- through cgit's html_txt, every attribute value through html_attr, and
+-- every link or image target through safe_url before html_attr. html() only
+-- ever gets literal tag scaffolding.
local emit_inline
@@ -198,16 +185,12 @@ local function render_plaintext(text)
end
--- Markdown here is a deliberate subset rather than CommonMark, covering
--- headings, thematic breaks, fenced and inline code, blockquotes, pipe
--- tables, single-level lists, links, images and emphasis, and leaving out
--- reference links, raw HTML passthrough, nested lists and setext headings.
--- Emphasis does not span a hard line break inside a paragraph. Man rendering
--- covers the common macros, that is section headings, filled and no-fill
--- paragraphs, bold and italic and the font escapes, and drops the rest. Both
--- are parsed with lpeg into the node trees emit_blocks and emit_inline above
--- consume, and parsing only builds a tree, so a parse that fails falls back
--- to plain text without leaving half a page behind.
+-- Markdown is a deliberate subset rather than CommonMark, leaving out
+-- reference links, raw HTML passthrough, nested lists and setext headings,
+-- and emphasis does not span a hard line break. Man rendering covers the
+-- common macros and drops the rest. Both parse into a node tree before
+-- anything is emitted, so a failed parse falls back to plain text without
+-- leaving half a page behind.
local render_markdown, render_man
@@ -223,8 +206,6 @@ if has_lpeg then
-- Bound the link and image inner scans. Without a cap a readme of
-- unclosed brackets ("[[[[...") makes every position scan to the
-- end of the line for a "]" that never comes, which is quadratic.
- -- Real link text and urls sit far under this, and anything longer
- -- simply renders as plain text.
local max_scan = 512
local parse_inline
@@ -275,8 +256,6 @@ if has_lpeg then
return nodes
end
- -- Line matchers. Each is anchored at the start of a single line and
- -- returns its captures, or nil when the line is not of that kind.
local lang_char = R("az", "AZ", "09") + S("_.+#-")
local heading_line = C(P("#") * P("#") ^ -5) * space ^ 1 * C(P(1) ^ 0)
local function thematic(mark)
@@ -434,20 +413,24 @@ if has_lpeg then
html("</div>")
end
- -- Macro lines are matched with lpeg, and the roff inline font and
- -- character escapes are a grammar producing a flat token list that
- -- a fold turns into the same inline nodes markdown emits. Bold and
- -- italic are the current font, which carries across a run rather
- -- than being opened and closed, so the inline pass tokenises and
- -- folds instead of nesting the way markdown does.
+ -- Roff fonts are a current state carried across a run rather than
+ -- opened and closed, so the inline pass tokenises to a flat list
+ -- and folds it into the nodes markdown emits, instead of nesting.
local macro_line = S(".'") * space ^ 0 * C((1 - space) ^ 1)
* space ^ 0 * C(P(1) ^ 0)
local one_font = { B = "B", I = "I" }
local two_font = { CB = "B", BI = "B", CI = "I" }
local man_chars = {
- aq = "'", cq = "'", oq = "'", dq = '"', lq = '"', rq = '"',
- hy = "-", en = "-", em = "-",
+ aq = "'",
+ cq = "'",
+ oq = "'",
+ dq = '"',
+ lq = '"',
+ rq = '"',
+ hy = "-",
+ en = "-",
+ em = "-",
}
local backslash = P("\\")
local function font_token(name) return { kind = "font", font = name } end
@@ -610,7 +593,7 @@ function filter_write(str)
end
-- cgit takes filter output through a C string sink that stops at the first
--- NUL byte, so a readme holding one is truncated there.
+-- NUL byte, so a write holding one loses everything from the NUL on.
function filter_close()
local text = table.concat(chunks)
chunks = {}
diff --git a/custom/extensions/auth-file.lua b/custom/extensions/auth-file.lua
index 74a04b6..957bd49 100644
--- a/custom/extensions/auth-file.lua
+++ b/custom/extensions/auth-file.lua
@@ -11,11 +11,9 @@
-- be the same Lua that cgit was built against. Lua 5.5 will not do, because
-- luaossl has no 5.5 build.
--
--- Serve cgit over HTTPS and terminate TLS in the web server in front of it.
--- The session cookie is marked Secure by default, so a browser only sends it
--- back over HTTPS, and on an instance served over plain HTTP with no TLS
--- anywhere the cookie never comes back and login appears to loop until
--- cookie_insecure below is set.
+-- The session cookie is marked Secure by default, so a browser only sends
+-- it back over HTTPS. On an instance served over plain HTTP login loops
+-- until cookie_insecure below is set.
--
-- Two libraries are needed. luaossl provides openssl.rand and openssl.hmac and
-- lives at <https://github.com/wahern/luaossl>, and luaposix provides
@@ -42,16 +40,10 @@
-- luarocks install luaossl OPENSSL_DIR="$(brew --prefix openssl)"
-- luarocks install luaposix
--
--- Some distributions package both as well, for example lua-luaossl and
--- lua-posix on Debian, and such a package has to be built for the same Lua
--- version as cgit.
---
--- The cookie carries only a user name and there is no server-side session
--- store, so deleting an account does not revoke a cookie already issued until
--- it expires, and instances that share a secret file accept each other's
--- cookies. The login form carries no CSRF token. Both are acceptable for
--- gating read access to a git browser, so weigh them before guarding anything
--- more sensitive.
+-- There is no server-side session store and no CSRF token, so a deleted
+-- account's cookie stays valid until it expires and instances sharing a
+-- secret file accept each other's cookies. That is acceptable for gating
+-- read access to a git browser, so weigh it before guarding anything more.
local sysstat = require("posix.sys.stat")
local unistd = require("posix.unistd")
@@ -59,7 +51,6 @@ local rand = require("openssl.rand")
local hmac = require("openssl.hmac")
-- The values that follow are the configuration and are meant to be edited.
--- Nothing below them needs changing for ordinary use.
-- Accounts live one per line as username:hash. Generate a hash with
-- mkpasswd -m sha-512 -R 300000
@@ -73,7 +64,7 @@ local groups_filename = "/etc/cgit-auth/groups"
-- Per-repository access lives one per line as reponame:group1,group2 and so
-- on. A repository named here is protected and one that is not named is
-- public. The repository name has to match exactly, while group and user names
--- match whatever their case.
+-- match regardless of case.
local repos_filename = "/etc/cgit-auth/repos"
-- Where the cookie-signing secret is stored, created on first use. It must be
@@ -91,8 +82,7 @@ local cookie_name = "cgitauth"
-- more tightly.
local cookie_path = "/"
--- Leave this false so the cookie is marked Secure and only travels over HTTPS.
--- Set it true only if cgit is served over plain HTTP with no TLS anywhere.
+-- Set this true only if cgit is served over plain HTTP with no TLS anywhere.
local cookie_insecure = false
-- A throwaway hash of the documented shape, used only to spend the same work
@@ -104,9 +94,8 @@ local dummy_hash = "$6$rounds=300000$0000000000000000$"
-- open decodes is kept here for the calls that follow.
local action, http, cgit, post
--- The two lookups below, account_hash and repo_userset, are the only part of
--- this script that differs from auth-inline.lua. Replacing them is all it
--- takes to keep accounts somewhere else.
+-- The two lookups below, account_hash and repo_userset, are the only part
+-- of this script that differs from auth-inline.lua.
local function trim(s)
return (string.gsub(s, "^%s*(.-)%s*$", "%1"))
@@ -118,14 +107,12 @@ local function add_names(list, set)
end
end
--- A missing or unreadable users file is not fatal, and neither is a line that
--- does not parse, so a broken file turns every login down rather than failing
--- the request outright.
+-- A missing, unreadable or unparsable users file turns every login down
+-- rather than failing the request outright.
--
--- The hash is trimmed as well as the name because reading by line strips the
--- newline but not a carriage return, so a users file saved with CRLF endings
--- would otherwise hand crypt a hash with a trailing \r and fail every login
--- with nothing in the log to say why.
+-- The hash is trimmed as well as the name because reading by line strips
+-- the newline but not a carriage return, so a CRLF users file would hand
+-- crypt a hash with a trailing \r and fail every login.
function account_hash(user)
if user == nil then
return nil
@@ -224,14 +211,9 @@ local function pattern_escape(s)
return (string.gsub(s, "([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1"))
end
--- The stored token was already URL encoded by secure_value, so it comes back
--- verbatim and the write path in set_cookie stays symmetric with this read
--- path. Decoding it here would break the signature check for any value
--- carrying a percent escape.
---
--- The name is escaped because it lands in a pattern. A cookie_name holding a
--- magic character, say "cgit-auth", would otherwise read as a pattern and stop
--- matching its own cookie while matching names nobody configured.
+-- The token comes back still URL encoded by secure_value. Decoding it here
+-- would break the signature check for any value carrying a percent escape.
+-- The name is escaped because it lands in a Lua pattern.
function get_cookie(cookies, name)
cookies = string.gsub(";" .. (cookies or "") .. ";", "%s*;%s*", ";")
return string.match(cookies, ";" .. pattern_escape(name) .. "=(.-);")
@@ -516,18 +498,21 @@ function body()
html_attr(secure_value("redirect", target, 0))
html("'>")
html("<table>")
- html("<tr><td><label for='username'>Username:</label></td><td><input id='username' name='username' autocomplete='username' autofocus></td></tr>")
- html("<tr><td><label for='password'>Password:</label></td><td><input id='password' name='password' type='password' autocomplete='current-password'></td></tr>")
- html("<tr><td colspan='2'><input value='Login' type='submit'></td></tr>")
+ html("<tr><td><label for='username'>Username:</label></td><td>")
+ html("<input id='username' name='username'")
+ html(" autocomplete='username' autofocus></td></tr>")
+ html("<tr><td><label for='password'>Password:</label></td><td>")
+ html("<input id='password' name='password' type='password'")
+ html(" autocomplete='current-password'></td></tr>")
+ html("<tr><td colspan='2'>")
+ html("<input value='Login' type='submit'></td></tr>")
html("</table></form>")
return 0
end
--- cgit calls filter_open with the action name followed by the request fields
--- in a fixed order, so they are unpacked here into the tables the functions
--- above read. Only a post reaches filter_write, carrying the form body, and
--- filter_close is where the action finally runs and answers cgit.
+-- filter_open unpacks the action and request fields cgit passes in fixed
+-- order, filter_write collects a post body, and filter_close runs the action.
local actions = {}
actions["authenticate-post"] = authenticate_post
diff --git a/custom/extensions/auth-inline.lua b/custom/extensions/auth-inline.lua
index aa4b9f1..5489189 100644
--- a/custom/extensions/auth-inline.lua
+++ b/custom/extensions/auth-inline.lua
@@ -11,11 +11,9 @@
-- be the same Lua that cgit was built against. Lua 5.5 will not do, because
-- luaossl has no 5.5 build.
--
--- Serve cgit over HTTPS and terminate TLS in the web server in front of it.
--- The session cookie is marked Secure by default, so a browser only sends it
--- back over HTTPS, and on an instance served over plain HTTP with no TLS
--- anywhere the cookie never comes back and login appears to loop until
--- cookie_insecure below is set.
+-- The session cookie is marked Secure by default, so a browser only sends
+-- it back over HTTPS. On an instance served over plain HTTP login loops
+-- until cookie_insecure below is set.
--
-- Two libraries are needed. luaossl provides openssl.rand and openssl.hmac and
-- lives at <https://github.com/wahern/luaossl>, and luaposix provides
@@ -42,16 +40,10 @@
-- luarocks install luaossl OPENSSL_DIR="$(brew --prefix openssl)"
-- luarocks install luaposix
--
--- Some distributions package both as well, for example lua-luaossl and
--- lua-posix on Debian, and such a package has to be built for the same Lua
--- version as cgit.
---
--- The cookie carries only a user name and there is no server-side session
--- store, so deleting an account does not revoke a cookie already issued until
--- it expires, and instances that share a secret file accept each other's
--- cookies. The login form carries no CSRF token. Both are acceptable for
--- gating read access to a git browser, so weigh them before guarding anything
--- more sensitive.
+-- There is no server-side session store and no CSRF token, so a deleted
+-- account's cookie stays valid until it expires and instances sharing a
+-- secret file accept each other's cookies. That is acceptable for gating
+-- read access to a git browser, so weigh it before guarding anything more.
local sysstat = require("posix.sys.stat")
local unistd = require("posix.unistd")
@@ -59,13 +51,11 @@ local rand = require("openssl.rand")
local hmac = require("openssl.hmac")
-- The values that follow are the configuration and are meant to be edited.
--- Nothing below them needs changing for ordinary use.
-- Protected repositories and the users allowed into each. A repository named
-- here is protected and one that is not named is public. The repository key
--- has to match exactly, while user names match whatever their case. Replace
--- the examples below with your own. They are commented out, so an unedited
--- copy protects nothing and grants no accounts.
+-- has to match exactly, while user names match regardless of case. The
+-- examples are commented out, so an unedited copy protects nothing.
local protected_repos = {
-- ["secret-repo"] = { alice = true, bob = true },
-- ["another"] = { alice = true },
@@ -73,8 +63,6 @@ local protected_repos = {
-- Accounts as name and hash. Generate a hash with
-- mkpasswd -m sha-512 -R 300000
--- Replace the examples below. They are not real credentials and must not be
--- deployed as they stand.
local users = {
-- alice = "$6$rounds=300000$REPLACE_THIS_SALT$REPLACE_THIS_HASH",
-- bob = "$6$rounds=300000$REPLACE_THIS_SALT$REPLACE_THIS_HASH",
@@ -95,8 +83,7 @@ local cookie_name = "cgitauth"
-- more tightly.
local cookie_path = "/"
--- Leave this false so the cookie is marked Secure and only travels over HTTPS.
--- Set it true only if cgit is served over plain HTTP with no TLS anywhere.
+-- Set this true only if cgit is served over plain HTTP with no TLS anywhere.
local cookie_insecure = false
-- A throwaway hash of the documented shape, used only to spend the same work
@@ -108,9 +95,8 @@ local dummy_hash = "$6$rounds=300000$0000000000000000$"
-- open decodes is kept here for the calls that follow.
local action, http, cgit, post
--- The two lookups below, account_hash and repo_userset, are the only part of
--- this script that differs from auth-file.lua. Replacing them is all it takes
--- to keep accounts somewhere else.
+-- The two lookups below, account_hash and repo_userset, are the only part
+-- of this script that differs from auth-file.lua.
-- The configured tables are folded to lowercased user names once, so that a
-- lookup matches whatever case the login form was filled in with, the way
@@ -186,14 +172,9 @@ local function pattern_escape(s)
return (string.gsub(s, "([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1"))
end
--- The stored token was already URL encoded by secure_value, so it comes back
--- verbatim and the write path in set_cookie stays symmetric with this read
--- path. Decoding it here would break the signature check for any value
--- carrying a percent escape.
---
--- The name is escaped because it lands in a pattern. A cookie_name holding a
--- magic character, say "cgit-auth", would otherwise read as a pattern and stop
--- matching its own cookie while matching names nobody configured.
+-- The token comes back still URL encoded by secure_value. Decoding it here
+-- would break the signature check for any value carrying a percent escape.
+-- The name is escaped because it lands in a Lua pattern.
function get_cookie(cookies, name)
cookies = string.gsub(";" .. (cookies or "") .. ";", "%s*;%s*", ";")
return string.match(cookies, ";" .. pattern_escape(name) .. "=(.-);")
@@ -478,18 +459,21 @@ function body()
html_attr(secure_value("redirect", target, 0))
html("'>")
html("<table>")
- html("<tr><td><label for='username'>Username:</label></td><td><input id='username' name='username' autocomplete='username' autofocus></td></tr>")
- html("<tr><td><label for='password'>Password:</label></td><td><input id='password' name='password' type='password' autocomplete='current-password'></td></tr>")
- html("<tr><td colspan='2'><input value='Login' type='submit'></td></tr>")
+ html("<tr><td><label for='username'>Username:</label></td><td>")
+ html("<input id='username' name='username'")
+ html(" autocomplete='username' autofocus></td></tr>")
+ html("<tr><td><label for='password'>Password:</label></td><td>")
+ html("<input id='password' name='password' type='password'")
+ html(" autocomplete='current-password'></td></tr>")
+ html("<tr><td colspan='2'>")
+ html("<input value='Login' type='submit'></td></tr>")
html("</table></form>")
return 0
end
--- cgit calls filter_open with the action name followed by the request fields
--- in a fixed order, so they are unpacked here into the tables the functions
--- above read. Only a post reaches filter_write, carrying the form body, and
--- filter_close is where the action finally runs and answers cgit.
+-- filter_open unpacks the action and request fields cgit passes in fixed
+-- order, filter_write collects a post body, and filter_close runs the action.
local actions = {}
actions["authenticate-post"] = authenticate_post
diff --git a/custom/extensions/email-gravatar.lua b/custom/extensions/email-gravatar.lua
index 85947c4..6eb5376 100644
--- a/custom/extensions/email-gravatar.lua
+++ b/custom/extensions/email-gravatar.lua
@@ -27,29 +27,25 @@
-- luarocks install luaossl OPENSSL_DIR="$(brew --prefix openssl)"
--
-- Every page view sends the visitor's IP address and a hash of each
--- committer's email to a third-party service, so leave this filter off if that
--- is not acceptable for your instance. Addresses are hashed with MD5, which
--- Gravatar still accepts. Gravatar also supports SHA-256 now, so change the
--- digest in hash_hex if you prefer it.
+-- committer's email to a third-party service, so leave this filter off if
+-- that is not acceptable for your instance. Addresses are hashed with MD5,
+-- which Gravatar still accepts.
local digest = require("openssl.digest")
--- These are the values to change. The size is in pixels and serves both as the
--- image asked of the service and as the width and height attributes. The
--- default image is the style Gravatar draws for an address it has never seen,
--- and its documented choices include retro, identicon, monsterid and mp. The
--- endpoint is https so the icon is not blocked as mixed content on an https
--- page.
+-- The size is in pixels and serves both as the image asked of the service
+-- and as the width and height attributes. The default image is what
+-- Gravatar draws for an address it has never seen. The endpoint is https so
+-- the icon is not blocked as mixed content on an https page.
local avatar_size = 13
local default_image = "retro"
local base_url = "https://www.gravatar.com/avatar/"
local alt_text = "Gravatar"
--- cgit calls filter_open once, then filter_write for each piece of the name,
--- then filter_close, so what one call works out has to be left here for the
--- next one.
+-- One name reaches this filter as an open, writes and a close, so what the
+-- open works out is kept here for the close.
local buffer = ""
local avatar_hash = nil
diff --git a/custom/extensions/email-libravatar.lua b/custom/extensions/email-libravatar.lua
index e958346..9b3d595 100644
--- a/custom/extensions/email-libravatar.lua
+++ b/custom/extensions/email-libravatar.lua
@@ -26,27 +26,24 @@
-- luarocks install luaossl OPENSSL_DIR="$(brew --prefix openssl)"
--
-- Every page view sends the visitor's IP address and a hash of each
--- committer's email to a third-party service, so leave this filter off if that
--- is not acceptable for your instance. Addresses are hashed with MD5.
+-- committer's email to a third-party service, so leave this filter off if
+-- that is not acceptable for your instance. Addresses are hashed with MD5.
local digest = require("openssl.digest")
--- These are the values to change. The size is in pixels and serves both as the
--- image asked of the service and as the width and height attributes. The
--- default image is the style Libravatar draws for an address it has never
--- seen, and its documented choices include retro, identicon, monsterid and mm.
--- The endpoint is the secure CDN so the icon loads over https and is not
--- blocked as mixed content on an https page.
+-- The size is in pixels and serves both as the image asked of the service
+-- and as the width and height attributes. The default image is what
+-- Libravatar draws for an address it has never seen. The endpoint is the
+-- secure CDN so the icon is not blocked as mixed content on an https page.
local avatar_size = 13
local default_image = "retro"
local base_url = "https://seccdn.libravatar.org/avatar/"
local alt_text = "Libravatar"
--- cgit calls filter_open once, then filter_write for each piece of the name,
--- then filter_close, so what one call works out has to be left here for the
--- next one.
+-- One name reaches this filter as an open, writes and a close, so what the
+-- open works out is kept here for the close.
local buffer = ""
local avatar_hash = nil
diff --git a/custom/extensions/link-commits.lua b/custom/extensions/link-commits.lua
index 3f2429d..42252f3 100644
--- a/custom/extensions/link-commits.lua
+++ b/custom/extensions/link-commits.lua
@@ -10,12 +10,10 @@
-- Object names are handled apart from the rules below because the length
--- bound on them cannot be written as a plain Lua pattern. Recognition is by
--- shape, since a commit-filter cannot ask the repository whether a hash is
--- real, so any hex run within the bounds is linked whatever mix of digits and
--- letters it has and abbreviated and all-digit names are both caught. The
--- cost is that a long hex-looking number now and then links to an object that
--- does not exist, which cgit renders as a harmless "bad object name" page.
+-- bound on them cannot be written as a plain Lua pattern. A commit-filter
+-- cannot ask the repository whether a hash is real, so matching is by shape
+-- and a long hex number may link to an object that does not exist, which
+-- cgit renders as a harmless "Bad object id" page.
local objects = {
-- Set false to stop linking bare hashes.
enabled = true,
@@ -32,24 +30,23 @@ local objects = {
-- Text-reference rules, each one a Lua pattern with a single capture and a
-- URL where %s is replaced by that capture, percent-encoded. The whole match
-- is what gets shown and the capture is only what goes into the URL. Rules are
--- tried in order and the leftmost match on the line wins, so put the more
--- specific patterns first, and an empty list leaves only object names linked.
+-- tried in order and the leftmost match wins, so put the more specific
+-- patterns first, and an empty list leaves only object names linked.
--
--- Lua patterns are not regular expressions. There is no alternation and no
--- {n,m} repetition, %d is a digit, %a a letter, %w a letter or digit, %x a
--- hex digit, and a literal magic character is escaped with %, so a literal
--- dash is '%-'. The whole set is in the reference manual at
+-- Lua patterns are not regular expressions. The reference is
-- https://www.lua.org/manual/5.1/manual.html#5.4.1
--
--- Patterns run against the escaped message, so '&', '<' and '>' reach them as
--- '&amp;', '&lt;' and '&gt;'. Match those entity spellings rather than the
--- bare character, and keep a pattern from ending part way through one, since
--- the matched run is what gets wrapped in the anchor.
+-- Patterns run against the escaped message, so match the entity spellings
+-- '&amp;', '&lt;' and '&gt;' rather than the bare characters, and keep a
+-- pattern from ending part way through one.
local rules = {
{ pattern = "#(%d+)", url = "https://bugs.example.com/?bug=%s" },
- -- { pattern = "CVE%-(%d%d%d%d%-%d+)", url = "https://www.cve.org/CVERecord?id=CVE-%s" },
- -- { pattern = "!(%d+)", url = "https://gitlab.example.com/group/repo/-/merge_requests/%s" },
- -- { pattern = "RFC%s?(%d+)", url = "https://www.rfc-editor.org/rfc/rfc%s" },
+ -- { pattern = "CVE%-(%d%d%d%d%-%d+)",
+ -- url = "https://www.cve.org/CVERecord?id=CVE-%s" },
+ -- { pattern = "!(%d+)",
+ -- url = "https://gitlab.example.com/my/repo/-/merge_requests/%s" },
+ -- { pattern = "RFC%s?(%d+)",
+ -- url = "https://www.rfc-editor.org/rfc/rfc%s" },
}
@@ -68,7 +65,9 @@ end
-- for a gsub reference.
local function make_link(url_template, capture, display)
local encoded = url_encode(capture)
- local href = string.gsub(url_template, "%%s", function() return encoded end)
+ local href = string.gsub(url_template, "%%s", function()
+ return encoded
+ end)
return "<a href='" .. href .. "'>" .. display .. "</a>"
end
@@ -89,7 +88,9 @@ local function collect(text)
capture = string.sub(text, start, stop)
end
candidates[#candidates + 1] = {
- start = start, stop = stop, priority = priority,
+ start = start,
+ stop = stop,
+ priority = priority,
link = make_link(rule.url, capture,
string.sub(text, start, stop)),
}
@@ -106,9 +107,12 @@ local function collect(text)
local start, stop, run =
string.find(text, "%f[%w](%x+)%f[%W]", init)
if not start then break end
- if #run >= objects.min_length and #run <= objects.max_length then
+ if #run >= objects.min_length
+ and #run <= objects.max_length then
candidates[#candidates + 1] = {
- start = start, stop = stop, priority = priority,
+ start = start,
+ stop = stop,
+ priority = priority,
link = make_link(objects.url, run, run),
}
end
@@ -141,7 +145,8 @@ function filter_close()
-- A candidate reaching back into one already emitted is
-- dropped, so no run of text is ever wrapped twice.
if candidate.start >= pos then
- out[#out + 1] = string.sub(text, pos, candidate.start - 1)
+ out[#out + 1] =
+ string.sub(text, pos, candidate.start - 1)
out[#out + 1] = candidate.link
pos = candidate.stop + 1
end
diff --git a/custom/extensions/syntax-highlight.lua b/custom/extensions/syntax-highlight.lua
index 862965a..e2032aa 100644
--- a/custom/extensions/syntax-highlight.lua
+++ b/custom/extensions/syntax-highlight.lua
@@ -1,16 +1,13 @@
--- Server-side syntax highlighting for cgit's tree and blob views, run inside
--- cgit's embedded Lua interpreter so a coloured blob costs no extra process
--- per request. Colouring is deliberately left out of cgit itself, which
--- serves plain escaped text on its own, so this filter is named by the
--- source-filter setting and any other program could take its place. Tokens
--- come from the Scintillua lexers and reach the page wrapped in span elements
--- carrying the hl- classes that assets/cgit.css styles. Whenever a piece is
--- missing or will not load, from lpeg down to a single lexer, the file falls
--- back to plain escaped text instead of failing, so uncoloured code means a
--- missing dependency rather than an error. It runs on Lua 5.1 through 5.5 and
+-- Server-side syntax highlighting for cgit's tree and blob views, named by
+-- the source-filter setting and run inside cgit's embedded Lua interpreter
+-- so a coloured blob costs no extra process per request. Tokens come from the
+-- Scintillua lexers and reach the page wrapped in span elements carrying the
+-- hl- classes that assets/cgit.css styles. Whenever a piece is missing or
+-- will not load, from lpeg down to a single lexer, the filter falls back to
+-- plain escaped text instead of failing. It runs on Lua 5.1 through 5.5 and
-- LuaJIT.
--
--- source-filter=lua:/usr/lib/cgit/extensions/syntax-highlight.lua
+-- source-filter=lua:/usr/local/lib/cgit/filters/syntax-highlight.lua
-- Files larger than this many bytes are served escaped but unhighlighted, so
@@ -28,12 +25,10 @@ local scintillua_env = "CGIT_SCINTILLUA_PATH"
-- Directories probed for the lexers when that variable is not set, tried
-- after the directory of $CGIT_CONFIG, so placing or symlinking a scintillua
--- directory next to cgitrc is enough to be found. Scintillua is the lexer
--- collection from the Textadept editor, around 160 languages as plain .lua
--- files with nothing to compile, from
--- https://orbitalquark.github.io/scintillua/. It does not bundle lpeg, which
--- it needs and which has to be built for the Lua cgit is linked against, and
--- forgetting that is the usual reason nothing is coloured.
+-- directory next to cgitrc is enough for it to be found. The lexers come
+-- from https://orbitalquark.github.io/scintillua/ and need lpeg, built for
+-- the Lua cgit is linked against. Forgetting that is the usual reason
+-- nothing is coloured.
--
-- # Debian and Ubuntu
-- sudo apt install lua-lpeg
@@ -76,15 +71,23 @@ local css = {
["function"] = "hl-func",
}
--- Extension to lexer name fixes for the fallback path, reached only when this
--- Scintillua has no detect(). Most extensions already equal their lexer name
--- and these are the frequent exceptions. A wrong guess only falls back to
--- plain text, so a best-effort entry costs nothing.
+-- Extension to lexer name fixes for the fallback path, reached only when
+-- this Scintillua has no detect(). Most extensions already equal their lexer
+-- name and these are the frequent exceptions.
local ext_lexer = {
- py = "python", js = "javascript", ts = "typescript",
- rb = "ruby", pl = "perl", pm = "perl", sh = "bash",
- md = "markdown", htm = "html", yml = "yaml",
- rs = "rust", c = "ansi_c", h = "ansi_c",
+ py = "python",
+ js = "javascript",
+ ts = "typescript",
+ rb = "ruby",
+ pl = "perl",
+ pm = "perl",
+ sh = "bash",
+ md = "markdown",
+ htm = "html",
+ yml = "yaml",
+ rs = "rust",
+ c = "ansi_c",
+ h = "ansi_c",
}
@@ -108,7 +111,8 @@ local function scintillua_path()
if config then
local dir = string.match(config, "^(.*)/[^/]+$")
if dir then
- candidates[#candidates + 1] = dir .. "/scintillua/lexers"
+ candidates[#candidates + 1] =
+ dir .. "/scintillua/lexers"
end
end
for _, dir in ipairs(scintillua_dirs) do
@@ -159,9 +163,6 @@ local function load_lexer_name(name)
return nil
end
--- Resolve a lexer for the file, preferring Scintillua's own filename
--- detection where this version provides it, then the extension map above,
--- then the raw extension.
local function lexer_for(name)
if type(scintillua.detect) == "function" then
local ok, lang = pcall(scintillua.detect, name)
@@ -200,7 +201,8 @@ local function highlight(text)
local part = escape(string.sub(text, pos, stop - 1))
local class = css[string.match(tag, "^[%w_]+")]
if class and part ~= "" then
- part = "<span class='" .. class .. "'>" .. part .. "</span>"
+ part = "<span class='" .. class .. "'>"
+ .. part .. "</span>"
end
out[#out + 1] = part
pos = stop
@@ -223,8 +225,9 @@ function filter_write(str)
end
-- cgit takes filter output through a C string sink that stops at the first
--- NUL byte, so a blob holding one is truncated there. That reaches binary
--- files which slip past cgit's text detection, not ordinary source.
+-- NUL byte, so a write holding one loses everything from the NUL on. That
+-- reaches binary files which slip past cgit's text detection, not ordinary
+-- source.
function filter_close()
local text = table.concat(chunks)
chunks = {}
diff --git a/custom/hooks/post-receive.cgit-cache b/custom/hooks/post-receive.cgit-cache
index 235de27..4825a44 100755
--- a/custom/hooks/post-receive.cgit-cache
+++ b/custom/hooks/post-receive.cgit-cache
@@ -4,7 +4,7 @@
# show up right away instead of once the cache-*-ttl minutes have passed.
#
# This only matters when cache-size in your cgitrc is above 0, which turns
-# the cache on. With it off the hook does nothing and costs one stat call.
+# the cache on.
#
# cgit names each cache slot after a hash of the request url, so there is no
# way to expire one repository's pages on their own and this clears the lot.
@@ -16,9 +16,8 @@
# change the value in your cgitrc then you must also change it here.
#
# The web server owns the cache root, so the pushing user needs write access
-# to it. Making the directory group writable and putting both users in that
-# group is usually enough. Nothing here fails a push if that access is
-# missing, since a stale page is not worth rejecting a push over.
+# to it. Nothing here exits nonzero when that access is missing, so the
+# pusher is not shown an error over a stale page.
#
# To install the hook, copy (or link) it to the file "hooks/post-receive" in
# each of your repositories. Git runs one post-receive per repository, so
diff --git a/source/cache.c b/source/cache.c
index dd8ae7f..2d546bb 100644
--- a/source/cache.c
+++ b/source/cache.c
@@ -96,9 +96,8 @@ static int open_slot(struct cache_slot *slot)
}
/*
- * A key longer than the buffer above can never be read back by open_slot, so
- * a slot keyed on one would never match and every such request would
- * regenerate its page while still writing a slot nothing can use.
+ * A key longer than the buffer above can never be read back by open_slot,
+ * so a slot keyed on one would be written but never match.
*/
static int key_fits_slot(const char *key)
{
@@ -238,10 +237,8 @@ static int lock_slot(struct cache_slot *slot)
}
// The lock landed on whatever inode the path named at open. A holder
// finishing in between renames that inode into place as the live
- // slot, so truncating it on the strength of the stale descriptor
- // would tear down the page other requests are reading. Once the path
- // is confirmed to still name this file the rename can no longer
- // happen, because doing so takes the lock now held here.
+ // slot, and once the path is confirmed to still name this file that
+ // rename can no longer happen, because it takes the lock held here.
if (fstat(slot->lock_fd, &held) || stat(slot->lock_path, &named) ||
held.st_ino != named.st_ino || held.st_dev != named.st_dev) {
close(slot->lock_fd);
@@ -291,10 +288,9 @@ void cache_abandon_fill(void)
slot_being_filled = NULL;
slot->abandoned = 1;
- // The page is sitting in html.c's buffer and in stdio's, and both are
- // emptied while stdout still points at the lock file, so the half
- // rendered page goes into the file about to be removed rather than
- // reaching the client ahead of whatever is written next.
+ // The page is sitting in html.c's buffer and in stdio's. Empty both
+ // while stdout still points at the lock file so the half rendered
+ // page never reaches the client.
html_flush();
fflush(stdout);
@@ -323,10 +319,9 @@ static int fill_slot(struct cache_slot *slot)
slot->fn();
slot_being_filled = NULL;
- // The page is sitting in html.c's buffer and then in stdio's, and all
- // of it has to reach the lock file before that file is renamed into
- // place. After an abandoned fill stdout is the client again and this
- // same flush delivers the tail of the error page instead.
+ // All of the page has to reach the lock file before it is renamed
+ // into place. After an abandoned fill stdout is the client again and
+ // this same flush delivers the tail of the error page instead.
html_flush();
if (fflush(stdout))
return errno;
@@ -352,9 +347,7 @@ static void refresh_slot(struct cache_slot *slot)
return;
// If another process replaced the slot between open_slot and
- // lock_slot, the copy already open is served rather than the newer
- // one, which would mean opening that file and comparing the key in it,
- // not worth a second descriptor and read on every expiry.
+ // lock_slot, the copy already open is served rather than the newer.
if (is_modified(slot) || fill_slot(slot)) {
unlock_slot(slot, 0);
close_lock(slot);
@@ -391,8 +384,7 @@ static int process_slot(struct cache_slot *slot)
// A slot that opened cleanly but holds another key is a collision,
// and two popular pages sharing one slot evict each other on every
- // alternating visit. Nothing else makes that visible, because the
- // cache keeps working and only quietly stops helping.
+ // alternating visit.
if (!err)
log_error("[cgit] Cache slot %s holds a different key, "
"consider a larger cache-size\n", slot->path);
@@ -449,10 +441,8 @@ static char *format_time(const char *format, time_t when)
}
/*
- * The accumulator is an unsigned long rather than a fixed 32 bit type, so on a
- * 64 bit host this is not the published FNV-1 value. All that decides is which
- * slot a key lands in, and nothing outside a single build has to agree on the
- * answer.
+ * The accumulator is unsigned long, so on a 64 bit host this is not the
+ * published FNV-1 value. Only slot selection depends on it.
*/
unsigned long cache_hash_str(const char *str)
{
diff --git a/source/cgit.c b/source/cgit.c
index 730e2c6..dc56a0e 100644
--- a/source/cgit.c
+++ b/source/cgit.c
@@ -59,12 +59,10 @@ struct refmatch {
const char *cgit_version = CGIT_VERSION;
/*
- * Isolate git from the calling user's configuration, so a snapshot cannot be
- * broken by something like a core.excludesfile pointing at a "~" path that git
- * can no longer expand once HOME is unset below. Called from cmd_main rather
- * than from a constructor attribute, because git-compat-util.h defines
- * __attribute__ away on a compiler that does not support it, which would leave
- * this silently never running.
+ * Isolate git from the calling user's configuration, which could otherwise
+ * break once HOME is unset below. Called from cmd_main rather than from a
+ * constructor attribute, because git-compat-util.h defines __attribute__
+ * away on a compiler without it, which would leave this silently unrun.
*/
static void isolate_git_environment(void)
{
@@ -173,7 +171,8 @@ static void prepare_context(void)
static void print_version(void)
{
- printf("CGit %s | https://github.com/brycekwon/cgit\n\nCompiled in features:\n", CGIT_VERSION);
+ printf("CGit %s | https://github.com/brycekwon/cgit\n\n"
+ "Compiled in features:\n", CGIT_VERSION);
#ifdef NO_LUA
printf("[-] ");
#else
@@ -319,10 +318,9 @@ static void parse_args(int argc, const char **argv)
ctx.qry.ofs = atoi(arg);
} else if (skip_prefix(argv[i], "--scan-tree=", &arg) ||
skip_prefix(argv[i], "--scan-path=", &arg)) {
- // A repository's own snapshots setting is masked with
- // the global one, which normally comes from cgitrc.
- // That has not been read yet here, so an empty mask
- // would discard whatever the repository asked for.
+ // A repository's snapshots setting is masked with the
+ // global one, and cgitrc has not been read here, so an
+ // empty mask would discard what the repository set.
ctx.cfg.snapshots = ALL_SNAPSHOT_FORMATS;
scanned++;
scan_tree(arg);
@@ -338,9 +336,8 @@ static void parse_args(int argc, const char **argv)
/*
* The lock is a fcntl lock rather than the mere existence of the lock file,
- * because a lock the kernel drops with its process cannot outlive a scan that
- * was killed mid-run. A leftover lock file used to count as a scan in
- * progress, and one crash would silently freeze the repolist for good.
+ * because a lock the kernel drops with its process cannot outlive a scan
+ * killed mid-run. A leftover file would count as a scan forever in progress.
*/
static int generate_cached_repolist(const char *path, const char *cached_rc)
{
@@ -379,10 +376,8 @@ static int generate_cached_repolist(const char *path, const char *cached_rc)
}
// The lock landed on whatever inode the path named at open. A holder
// finishing in between renames that inode into place as the live
- // list, so truncating it on the strength of the stale descriptor
- // would tear down the list other requests are reading. Once the path
- // is confirmed to still name this file the rename can no longer
- // happen, because doing so takes the lock now held here.
+ // list, and once the path is confirmed to still name this file that
+ // rename can no longer happen, because it takes the lock held here.
if (fstat(fd, &held) || stat(locked_rc.buf, &named) ||
held.st_ino != named.st_ino || held.st_dev != named.st_dev) {
err = EAGAIN;
@@ -469,11 +464,10 @@ static void process_cached_repolist(const char *path)
if (fork())
goto out;
- // The child inherits the descriptors of the request, and the web server
- // reads stdout until every holder of it is gone, so leaving them in
- // place would keep the visitor waiting for the whole scan after their
- // page was written. Anything the scan prints would land on that
- // response as well.
+ // The child inherits the request's descriptors, and the web server
+ // reads stdout until every holder is gone, so left in place they
+ // would keep the visitor waiting on the scan and let its output
+ // land on the response.
devnull = open("/dev/null", O_RDWR);
if (devnull >= 0) {
dup2(devnull, STDIN_FILENO);
@@ -703,9 +697,8 @@ static void apply_config(const char *name, const char *value)
/*
* Read a whole number a request supplied, clamped into the range the caller
- * accepts. strtol rather than atoi, because atoi has no defined behaviour once
- * the digits overflow and every value here arrives straight from the query
- * string.
+ * accepts. strtol rather than atoi, because atoi is undefined on overflow
+ * and every value here arrives straight from the query string.
*/
static int query_int(const char *value, int min, int max)
{
@@ -729,10 +722,9 @@ static void apply_query_param(const char *name, const char *value)
} else if (!strcmp(name, "p")) {
ctx.qry.page = xstrdup(value);
} else if (!strcmp(name, "url")) {
- // Every leading slash goes, not just one. What is left is
- // joined onto the virtual root, so a value like //example.com
- // would otherwise survive as /example.com and make that join a
- // scheme-relative link to another host.
+ // Every leading slash goes, not just one, so a value like
+ // //example.com cannot survive as /example.com and make the
+ // virtual root join a scheme-relative link to another host.
while (*value == '/')
value++;
ctx.qry.url = xstrdup(value);
@@ -754,11 +746,9 @@ static void apply_query_param(const char *name, const char *value)
ctx.qry.oid2 = xstrdup(value);
ctx.qry.has_oid = 1;
} else if (!strcmp(name, "ofs")) {
- // Bounded above so a crafted value cannot force a walk over the
- // whole history. Negatives stop at -1 rather than at zero,
- // because the offset is overloaded, the stats page submits -1
- // for all authors, and the log skip loop floors a negative
- // itself.
+ // Bounded above so a crafted value cannot force a walk over
+ // the whole history. The floor is -1 rather than 0 because
+ // the stats page submits -1 for all authors.
ctx.qry.ofs = query_int(value, -1, MAX_QUERY_OFFSET);
} else if (!strcmp(name, "path")) {
ctx.qry.path = cgit_trim_end(value, '/');
@@ -847,10 +837,9 @@ static void authenticate_cookie(void)
}
/*
- * Only a full object id names content that can never change. The id parameter
- * accepts anything git can resolve, so a ref name or an abbreviation arrives
- * here just as marked as a real id, and a page pinned to one of those must
- * not be cached under the never-expiring static ttl.
+ * Only a full object id names content that can never change. The id
+ * parameter accepts anything git can resolve, so a page pinned to a ref
+ * name or abbreviation must not be cached under the static ttl.
*/
static int is_full_oid(const char *rev)
{
@@ -895,10 +884,9 @@ static int calc_ttl(void)
}
/*
- * The scheme and the host are folded in because the absolute urls a page
- * carries, its clone urls and atom links, are built from them, so a request
- * arriving with a spoofed Host must not poison the page served to a visitor
- * who came in on the real one.
+ * The scheme and host are folded in because the page's absolute urls, its
+ * clone urls and atom links, are built from them, so a spoofed Host must
+ * not poison the page served on the real one.
*/
static void build_cache_key(struct strbuf *key)
{
@@ -911,11 +899,9 @@ static void build_cache_key(struct strbuf *key)
};
size_t i;
- // Each part is written behind its own length, so nothing a value
- // contains can make two different requests spell one key. The path and
- // the query come from the environment rather than the query string cgit
- // rebuilds, since that rebuild folds the two together and would let the
- // PATH_INFO and QUERY_STRING forms of one request share a slot.
+ // Each part is written behind its own length so no value can make two
+ // requests spell one key, and the path and query come from the
+ // environment because cgit's rebuilt query string folds them together.
for (i = 0; i < ARRAY_SIZE(parts); i++)
strbuf_addf(key, "%zu|%s", strlen(parts[i]), parts[i]);
free(hosturl);
@@ -1013,7 +999,6 @@ static void choose_readme(struct cgit_repo *repo)
for_each_string_list_item(entry, &repo->readme) {
parse_readme(entry->string, &filename, &ref, repo);
if (!filename) {
- free(filename);
free(ref);
continue;
}
@@ -1041,8 +1026,6 @@ static void prepare_repo_env(int *nongit)
{
setenv("GIT_DIR", ctx.repo->path, 1);
- // Both read configuration out of the repository, with the user's own
- // git configuration already stripped by isolate_git_environment.
setup_git_directory_gently(the_repository, nongit);
load_display_notes(NULL);
}
@@ -1230,7 +1213,8 @@ void cgit_repo_config(struct cgit_repo *repo, const char *name, const char *valu
else if (!strcmp(name, "about-filter") || !strcmp(name, "commit-filter") ||
!strcmp(name, "source-filter") || !strcmp(name, "email-filter")) {
if (!ctx.cfg.enable_filter_overrides)
- fprintf(stderr, "[cgit] Ignoring repo %s: enable-filter-overrides is not set\n", name);
+ fprintf(stderr, "[cgit] Ignoring repo %s: "
+ "enable-filter-overrides is not set\n", name);
else if (!strcmp(name, "about-filter"))
repo->about_filter = cgit_new_filter(value, ABOUT);
else if (!strcmp(name, "commit-filter"))
@@ -1275,8 +1259,7 @@ int cmd_main(int argc, const char **argv)
// string keeps it part of the cache key.
path = ctx.env.path_info;
if (!ctx.qry.url && path) {
- // Stripped like the url parameter and for the same reason, so
- // a request for //example.com cannot turn into a link off site.
+ // Stripped like the url parameter and for the same reason.
while (*path == '/')
path++;
ctx.qry.url = xstrdup(path);
diff --git a/source/cgit.h b/source/cgit.h
index 8d2d686..308fda2 100644
--- a/source/cgit.h
+++ b/source/cgit.h
@@ -50,13 +50,12 @@
// converted on the way in.
#define PAGE_ENCODING "UTF-8"
-// The month is a double because a twelfth of a year is not a whole number of
-// seconds.
#define SECONDS_PER_MINUTE 60
#define SECONDS_PER_HOUR (SECONDS_PER_MINUTE * 60)
#define SECONDS_PER_DAY (SECONDS_PER_HOUR * 24)
#define SECONDS_PER_WEEK (SECONDS_PER_DAY * 7)
#define SECONDS_PER_YEAR (SECONDS_PER_DAY * 365)
+// A double, because a twelfth of a year is not a whole number of seconds.
#define SECONDS_PER_MONTH (SECONDS_PER_YEAR / 12.0)
typedef enum {
diff --git a/source/cgit.mk b/source/cgit.mk
index 0683cb7..1106b64 100644
--- a/source/cgit.mk
+++ b/source/cgit.mk
@@ -9,10 +9,10 @@
# ../../build.
include Makefile
-# TOOLSDIR and BUILDDIR are named relative to the project root, matching the
-# top level Makefile, because the version recipe changes into the root before
-# using them. CGIT_SRC and CGIT_BUILD lead to the sources and the output from
-# vendor/git, where everything else here runs.
+# TOOLSDIR and BUILDDIR are named relative to the project root because the
+# version recipe changes into the root before using them. CGIT_SRC and
+# CGIT_BUILD lead to the sources and the output from vendor/git, where
+# everything else here runs.
CGIT_ROOT = ../..
SRCDIR = source
TOOLSDIR = tools
@@ -24,8 +24,7 @@ CGIT_BUILD = $(CGIT_ROOT)/$(BUILDDIR)
# Makefile exports, which leaves out the build options this file reads.
-include $(CGIT_ROOT)/cgit.conf
-# CGIT_VERSION and the other CGIT_ values used below come from the top level
-# Makefile, which exports them, rather than being defined in this file.
+# The CGIT_ values used below are exported by the top level Makefile.
$(CGIT_BUILD)/VERSION: force-version
@mkdir -p $(CGIT_BUILD)/
@cd $(CGIT_ROOT) && '$(SHELL_PATH_SQ)' $(TOOLSDIR)/gen-version.sh "$(CGIT_VERSION)" $(BUILDDIR)/VERSION
@@ -42,15 +41,16 @@ $(CGIT_BUILD)/VERSION: force-version
# standard again.
CGIT_STD ?= gnu17
-# CGIT_CFLAGS is tracked separately so that changing it does not force a
-# rebuild of Git itself.
+# CGIT_CFLAGS is tracked separately so that changing it does not force a rebuild
+# of Git itself.
CGIT_CFLAGS += -std=$(CGIT_STD)
CGIT_CFLAGS += -DCGIT_CONFIG='"$(CGIT_CONFIG)"'
CGIT_CFLAGS += -DCGIT_SCRIPT_NAME='"$(CGIT_SCRIPT_NAME)"'
CGIT_CFLAGS += -DCGIT_CACHE_ROOT='"$(CACHE_ROOT)"'
-# Reaches only the cgit objects, so a caller can tighten the build, the way CI
-# passes -Werror, without holding git's own sources to the same standard.
+# Reaches only the cgit objects, so a caller can tighten the build, the way the
+# release build passes -Werror=format-security, without holding git's own
+# sources to the same standard.
CGIT_CFLAGS += $(CGIT_EXTRA_CFLAGS)
PKG_CONFIG ?= pkg-config
@@ -161,10 +161,12 @@ $(CGIT_BUILD)/CGIT-CFLAGS: FORCE
if test x"$$FLAGS" != x"`cat $(CGIT_BUILD)/CGIT-CFLAGS 2>/dev/null`" ; then \
echo 1>&2 " * new CGit build flags"; \
echo "$$FLAGS" >$(CGIT_BUILD)/CGIT-CFLAGS; \
- fi
+ fi
-$(CGIT_OBJS): $(CGIT_BUILD)/%.o: $(CGIT_SRC)/%.c GIT-CFLAGS $(CGIT_BUILD)/CGIT-CFLAGS $(missing_dep_dirs)
- $(QUIET_CC)$(CC) -o $@ -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) $(CGIT_CFLAGS) $<
+$(CGIT_OBJS): $(CGIT_BUILD)/%.o: $(CGIT_SRC)/%.c GIT-CFLAGS \
+ $(CGIT_BUILD)/CGIT-CFLAGS $(missing_dep_dirs)
+ $(QUIET_CC)$(CC) -o $@ -c $(dep_args) $(ALL_CFLAGS) $(EXTRA_CPPFLAGS) \
+ $(CGIT_CFLAGS) $<
$(CGIT_BUILD)/cgit: $(CGIT_OBJS) GIT-LDFLAGS $(GITLIBS)
@echo 1>&2 " * $(LUA_MESSAGE)"
diff --git a/source/config.c b/source/config.c
index 6a5d136..0ff8588 100644
--- a/source/config.c
+++ b/source/config.c
@@ -1,12 +1,9 @@
/*
- * The reader for cgit's config files, which are the main cgitrc, any file it
- * pulls in with an include line, the cgitrc that sits beside a scanned
- * repository, and the cached repolist. A file is a sequence of name=value
- * lines, and each pair is handed to a callback that decides what it means, so
- * nothing here knows a single key by name. A value runs to the end of its line
- * and keeps whatever spacing it has, there is no quoting. A line whose first
- * non blank character is a hash or a semicolon is a comment, and blank lines
- * are ignored.
+ * The reader for cgit's config files, which are the main cgitrc, any file
+ * it pulls in with an include line, the cgitrc beside a scanned repository,
+ * and the cached repolist. A file is a sequence of name=value lines, each
+ * handed to a callback that decides what it means, so nothing here knows a
+ * single key by name.
*/
#include "cgit.h"
@@ -95,9 +92,8 @@ int config_file_parse(const char *filename, config_file_value_fn fn)
struct strbuf value = STRBUF_INIT;
FILE *f;
- // An include line calls back into here, so a file that includes itself,
- // directly or round a longer loop, would recurse until the stack gave
- // out.
+ // An include line calls back into here, so an include cycle would
+ // recurse until the stack gave out.
if (nesting > MAX_INCLUDE_NESTING)
return -1;
if (!(f = fopen(filename, "r")))
diff --git a/source/filter.c b/source/filter.c
index 3c0c7e4..f5f971c 100644
--- a/source/filter.c
+++ b/source/filter.c
@@ -78,14 +78,10 @@ static void fprintf_exec_filter(struct cgit_filter *base, FILE *f,
static void cleanup_exec_filter(struct cgit_filter *base)
{
struct cgit_exec_filter *filter = (struct cgit_exec_filter *)base;
- if (filter->argv) {
- free(filter->argv);
- filter->argv = NULL;
- }
- if (filter->cmd) {
- free(filter->cmd);
- filter->cmd = NULL;
- }
+ free(filter->argv);
+ filter->argv = NULL;
+ free(filter->cmd);
+ filter->cmd = NULL;
}
static struct cgit_filter *new_exec_filter(const char *cmd, int argument_count)
@@ -175,11 +171,10 @@ static inline void unhook_write(void)
current_write_filter = NULL;
}
-static void die_lua_error(struct lua_filter *filter)
+static NORETURN void die_lua_error(struct lua_filter *filter)
{
die("Lua error in %s: %s", filter->script_file,
lua_tostring(filter->lua_state, -1));
- lua_pop(filter->lua_state, 1);
}
static ssize_t write_lua_filter(struct cgit_filter *base, const void *buf,
@@ -189,18 +184,15 @@ static ssize_t write_lua_filter(struct cgit_filter *base, const void *buf,
lua_getglobal(filter->lua_state, "filter_write");
lua_pushlstring(filter->lua_state, buf, count);
- if (lua_pcall(filter->lua_state, 1, 0, 0)) {
+ if (lua_pcall(filter->lua_state, 1, 0, 0))
die_lua_error(filter);
- errno = EIO;
- return -1;
- }
return count;
}
/*
- * Output a script asks for belongs on the page and not back in its own filter,
- * so the hook comes off around the call. The zero returned is Lua's count of
- * values pushed for the script, not a success code.
+ * Output a script asks for belongs on the page, not back in its own filter,
+ * so the hook comes off around the call. The zero returned is Lua's count
+ * of values pushed, not a success code.
*/
static inline int emit_unfiltered(lua_State *lua_state,
void (*emit)(const char *text))
@@ -295,12 +287,8 @@ static int init_lua_filter(struct lua_filter *filter)
lua_setglobal(filter->lua_state, script_globals[i].name);
}
- if (luaL_dofile(filter->lua_state, filter->script_file)) {
+ if (luaL_dofile(filter->lua_state, filter->script_file))
die_lua_error(filter);
- lua_close(filter->lua_state);
- filter->lua_state = NULL;
- return 1;
- }
return 0;
}
@@ -317,26 +305,21 @@ static int open_lua_filter(struct cgit_filter *base, va_list ap)
lua_getglobal(filter->lua_state, "filter_open");
for (i = 0; i < filter->base.argument_count; ++i)
lua_pushstring(filter->lua_state, va_arg(ap, char *));
- if (lua_pcall(filter->lua_state, filter->base.argument_count, 0, 0)) {
+ if (lua_pcall(filter->lua_state, filter->base.argument_count, 0, 0))
die_lua_error(filter);
- return 1;
- }
return 0;
}
static int close_lua_filter(struct cgit_filter *base)
{
struct lua_filter *filter = (struct lua_filter *)base;
- int ret = 0;
+ int ret;
lua_getglobal(filter->lua_state, "filter_close");
- if (lua_pcall(filter->lua_state, 0, 1, 0)) {
+ if (lua_pcall(filter->lua_state, 0, 1, 0))
die_lua_error(filter);
- ret = -1;
- } else {
- ret = lua_tonumber(filter->lua_state, -1);
- lua_pop(filter->lua_state, 1);
- }
+ ret = lua_tonumber(filter->lua_state, -1);
+ lua_pop(filter->lua_state, 1);
unhook_write();
return ret;
@@ -358,10 +341,8 @@ static void cleanup_lua_filter(struct cgit_filter *base)
lua_close(filter->lua_state);
filter->lua_state = NULL;
- if (filter->script_file) {
- free(filter->script_file);
- filter->script_file = NULL;
- }
+ free(filter->script_file);
+ filter->script_file = NULL;
}
static struct cgit_filter *new_lua_filter(const char *cmd, int argument_count)
diff --git a/source/html.c b/source/html.c
index 2e4ec66..2e3a3b7 100644
--- a/source/html.c
+++ b/source/html.c
@@ -3,10 +3,9 @@
* for page text, attribute values, URL paths and query arguments along with
* the small formatting helpers the rest of the code prints through. What is
* written here is gathered into one buffer and handed to stdout in whole
- * blocks, because a page is made of a great many small fragments and a write
- * apiece spent more time in the kernel than rendering the page did. cgit
- * shares stdout with the filters it runs and with git itself, so that buffer
- * has to be emptied wherever another writer takes over.
+ * blocks, since a page is made of a great many small fragments. cgit shares
+ * stdout with the filters it runs and with git itself, so that buffer has
+ * to be emptied wherever another writer takes over.
*/
#include "cgit.h"
@@ -57,9 +56,8 @@ static struct strbuf *capture;
static void write_out(const char *data, size_t size)
{
- // A blob, a snapshot or a patch reaches this with a size well past what
- // one write can move onto a pipe, so a short write is ordinary rather
- // than an error and has to be resumed instead of reported.
+ // A blob or snapshot is well past what one write can move onto a
+ // pipe, so short writes are resumed rather than reported.
if (write_in_full(STDOUT_FILENO, data, size) < 0)
die_errno("write error on html output");
}
@@ -256,11 +254,11 @@ void html_url_path(const char *txt)
const char *p = txt;
while (p && *p) {
unsigned char c = *p;
- // A raw ampersand or plus is legal in a URL path, but the
- // paths written here land in attribute values, where a bare
- // ampersand can start a character reference and quietly turn
- // "a&copy.txt" into a different filename. Encoding both keeps
- // the output byte-safe in every sink.
+ // A raw ampersand or plus is legal in a URL path, but this
+ // table is shared with html_url_arg, where a bare plus decodes
+ // back as a space, and the paths written here land in attribute
+ // values, where an ampersand can start a character reference
+ // and quietly turn "a&copy.txt" into a different filename.
const char *esc = url_escape_table[c];
if (esc) {
html_raw(txt, p - txt);
diff --git a/source/html.h b/source/html.h
index ecc7141..3bbb30e 100644
--- a/source/html.h
+++ b/source/html.h
@@ -14,8 +14,8 @@
// How much of a generated run to build before handing it to html_raw. Growing
// past this gains nothing, since html_raw gathers what it is given into a
-// buffer of its own, and a run built whole would instead be sized by the file
-// it came from, which the blob limits do not bound.
+// buffer of its own, and a run built whole would grow with the file it came
+// from, to many times the blob's size, which max-blob-size never measures.
#define HTML_BATCH (64 * 1024)
extern void html_raw(const char *txt, size_t size);
diff --git a/source/parsing.c b/source/parsing.c
index de2798a..745bbba 100644
--- a/source/parsing.c
+++ b/source/parsing.c
@@ -77,9 +77,6 @@ static const char *reencode(char **text, const char *from, const char *to)
{
char *converted;
- if (!text)
- return NULL;
-
if (!*text || !from || !to)
return *text;
@@ -160,7 +157,7 @@ struct commitinfo *cgit_parse_commit(struct commit *commit)
while (skip_prefix(p, "parent ", &p))
p += the_hash_algo->hexsz + 1;
- if (p && skip_prefix(p, "author ", &p)) {
+ if (skip_prefix(p, "author ", &p)) {
parse_user(p, &info->author, &info->author_email,
&info->author_date, &info->author_tz);
p = next_header_line(p);
@@ -197,10 +194,8 @@ struct commitinfo *cgit_parse_commit(struct commit *commit)
eol++;
info->msg = xstrdup(eol);
} else {
- // Reached when an object is truncated mid header, which
- // leaves nothing at all after them. Callers render subject
- // and msg as text without checking, so they get empty
- // strings rather than NULL.
+ // An object truncated mid header leaves nothing after it,
+ // and callers render subject and msg without NULL checks.
info->subject = xstrdup("");
info->msg = xstrdup("");
}
diff --git a/source/parsing.h b/source/parsing.h
index 2230eaa..b1dc9f1 100644
--- a/source/parsing.h
+++ b/source/parsing.h
@@ -10,8 +10,8 @@
#include "cgit.h"
-// Split PATH_INFO into the repository and the page it names, storing both in
-// ctx.qry.
+// Split a request url into the repository, the page and the path it names,
+// storing them in ctx.qry.
extern void cgit_parse_url(const char *url);
extern struct commitinfo *cgit_parse_commit(struct commit *commit);
diff --git a/source/scan-tree.c b/source/scan-tree.c
index ac74eb3..f72a5be 100644
--- a/source/scan-tree.c
+++ b/source/scan-tree.c
@@ -15,7 +15,9 @@
// Git writes this line into the description file of every repository it
// creates, so a repository still carrying it gets cgit's own default instead.
-static const char *default_git_desc = "Unnamed repository; edit this file 'description' to name the repository.";
+static const char *default_git_desc =
+ "Unnamed repository; edit this file 'description' to name the "
+ "repository.";
// The config callbacks are handed only a name and a value, so the repository
// being filled in waits here for the length of one add_repo call.
@@ -88,7 +90,7 @@ static char *section_slash(struct strbuf *relpath, int depth)
if (depth > 0) {
slash = relpath->buf - 1;
- while (slash && depth && (slash = strchr(slash + 1, '/')))
+ while (depth && (slash = strchr(slash + 1, '/')))
depth--;
} else {
slash = relpath->buf + relpath->len;
@@ -150,9 +152,8 @@ static void add_repo(const char *base, struct strbuf *path)
else
strbuf_addstr(&relpath, path->buf + strlen(base) + 1);
- // Drop the trailing slash added above before testing for "/.git", since
- // with it still attached the suffix never matches and every ordinary
- // working tree is named "repo/.git" instead of "repo".
+ // Drop the trailing slash added above, or the "/.git" suffix test
+ // below never matches and a working tree is named "repo/.git".
if (relpath.len && relpath.buf[relpath.len - 1] == '/')
strbuf_setlen(&relpath, relpath.len - 1);
if (relpath.len >= 5 && !strcmp(relpath.buf + relpath.len - 5, "/.git"))
diff --git a/source/shared.c b/source/shared.c
index 00d5605..fab5c13 100644
--- a/source/shared.c
+++ b/source/shared.c
@@ -89,9 +89,8 @@ static int load_mmfile(mmfile_t *file, const struct object_id *oid)
}
/*
- * The test is on the oid rather than on the size, because load_mmfile uses a
- * literal only for a null oid, and a real blob that happens to be empty does
- * own its buffer.
+ * The test is on the oid rather than the size, because load_mmfile uses a
+ * literal only for a null oid, while a real but empty blob owns its buffer.
*/
static void release_mmfile(mmfile_t *file, const struct object_id *oid)
{
@@ -101,9 +100,7 @@ static void release_mmfile(mmfile_t *file, const struct object_id *oid)
/*
* Xdiff emits buffers that need not end on a line boundary, so a trailing
- * fragment is held back and joined with whatever arrives next. Git's own
- * xdiff_outf keeps that fragment in a callback struct, which is not an option
- * here because priv already carries the caller's function.
+ * fragment is held back and joined with whatever arrives next.
*/
static int emit_line(void *priv, mmbuffer_t *mb, int nbuf)
{
@@ -138,9 +135,8 @@ static int emit_line(void *priv, mmbuffer_t *mb, int nbuf)
return 0;
}
-// Takes an unsigned char because a byte over 0x7f is negative in a plain
-// char wherever char is signed, and a negative one is not a value the ctype
-// tests are defined for.
+// Takes an unsigned char because a byte over 0x7f is negative where char
+// is signed, which the ctype tests are not defined for.
static int is_token_char(unsigned char c)
{
return isalnum(c) || c == '_';
@@ -466,9 +462,8 @@ void cgit_diff_commit(struct commit *commit, filepair_fn fn, const char *prefix)
}
/*
- * Git's parse_date_format dies on anything it does not recognize, which would
- * turn a typo in cgitrc into a failed request, so only the formats cgit
- * documents reach it.
+ * Git's parse_date_format dies on anything unknown, which would turn a
+ * cgitrc typo into a failed request, so only documented formats reach it.
*/
void cgit_parse_date_format(const char *format, struct date_mode *mode)
{
@@ -578,9 +573,8 @@ char *cgit_expand_macros(const char *text)
out = expand_macro(start, limit - start) - 1;
}
start = NULL;
- // Step back so the character that ended the
- // token is written again past the expansion,
- // where it may open a token of its own.
+ // Step back so the byte that ended the token
+ // is written again and may open a new one.
text--;
}
out++;
diff --git a/source/ui-atom.c b/source/ui-atom.c
index 09d3501..3eb4332 100644
--- a/source/ui-atom.c
+++ b/source/ui-atom.c
@@ -28,9 +28,9 @@ static const char *feed_date(timestamp_t when)
#define XML_REPLACEMENT "?"
/*
- * How many bytes the UTF-8 sequence at p holds, or 0 when the bytes there are
- * not a valid sequence. The lead-byte ranges fold in the overlong, surrogate
- * and out-of-range cases, so a 0 is the only error signal a caller needs.
+ * How many bytes the UTF-8 sequence at p holds, or 0 when invalid. The
+ * lead-byte ranges fold in the overlong, surrogate and out-of-range cases,
+ * so 0 is the only error signal a caller needs.
*/
static size_t utf8_seq_len(const unsigned char *p, size_t left)
{
@@ -61,10 +61,9 @@ static size_t utf8_seq_len(const unsigned char *p, size_t left)
}
/*
- * The XML counterpart of html_txt. Commit metadata is arbitrary bytes, and
- * where a browser shrugs at a stray control byte or a broken UTF-8 sequence,
- * an XML reader must reject the whole feed, so both are replaced instead of
- * passed through.
+ * The XML counterpart of html_txt. A browser shrugs at a stray control byte
+ * or broken UTF-8, but an XML reader must reject the whole feed, so both
+ * are replaced instead of passed through.
*/
static void xml_txt(const char *txt)
{
@@ -219,8 +218,7 @@ void cgit_print_atom(char *tip, const char *path, int max_count)
prepare_revision_walk(&rev);
// CGI guarantees a server name, so only a bare test run reaches the
- // fallback, and a placeholder there keeps the mandatory feed id and
- // the links present rather than dropping them.
+ // fallback, which keeps the mandatory feed id and links present.
host = cgit_hosturl();
if (!host)
host = xstrdup("localhost");
@@ -276,9 +274,8 @@ void cgit_print_atom(char *tip, const char *path, int max_count)
commit->parents = NULL;
}
if (need_updated) {
- // Atom makes a feed level updated mandatory, and an empty feed
- // has no commit to take one from, so the epoch stands in and
- // keeps the feed byte for byte stable.
+ // Atom makes a feed level updated mandatory, and an empty
+ // feed has no commit to take one from, so the epoch stands in.
html("<updated>");
xml_txt(feed_date(0));
html("</updated>\n");
diff --git a/source/ui-blame.c b/source/ui-blame.c
index ff3795e..8a7f8f0 100644
--- a/source/ui-blame.c
+++ b/source/ui-blame.c
@@ -17,9 +17,8 @@
#include "ui-blame.h"
#include "ui-shared.h"
-// A tab in the rendered source runs on to the next multiple of this. The
-// stylesheet leaves tab-size alone, so the measurement has to match what the
-// browser does on its own rather than anything cgit picks.
+// A tab in the rendered source runs on to the next multiple of this,
+// matching what the browser does on its own since tab-size is left alone.
#define TAB_WIDTH 8
enum blame_target {
@@ -225,9 +224,9 @@ static size_t line_width(struct blame_scoreboard *sb, int line)
}
/*
- * The stylesheet takes the source pre out of flow and positions it over these
- * blocks, so nothing else gives the cell a size and each block has to be
- * padded to the height and the width of the lines it stands behind.
+ * The stylesheet takes the source pre out of flow and positions it over
+ * these blocks, so each block has to be padded to the height and width of
+ * the lines it stands behind.
*/
static void emit_entry_background(struct blame_scoreboard *sb,
struct blame_entry *ent)
diff --git a/source/ui-blob.c b/source/ui-blob.c
index efe1596..67af675 100644
--- a/source/ui-blob.c
+++ b/source/ui-blob.c
@@ -72,9 +72,8 @@ static int find_path_oid(struct object_id *oid, char *path, int file_only)
}
/*
- * Callers ask before reading the object, because the point of the limit is to
- * keep a huge blob out of memory rather than to notice it once it is already
- * there.
+ * Callers ask before reading the object, so a huge blob stays out of
+ * memory rather than being noticed once already there.
*/
static int over_size_limit(unsigned long size)
{
diff --git a/source/ui-clone.c b/source/ui-clone.c
index 75e5f95..f5c4d59 100644
--- a/source/ui-clone.c
+++ b/source/ui-clone.c
@@ -5,7 +5,6 @@
* files under objects, and HEAD, each written as raw bytes rather than as a
* page. The two listings a clone starts from are built per request, so a
* repository serves without anyone having run git update-server-info over it.
- * The shape of it all follows git's own http-backend.
*/
#define USE_THE_REPOSITORY_VARIABLE
diff --git a/source/ui-diff.c b/source/ui-diff.c
index e08b096..3c7d8d2 100644
--- a/source/ui-diff.c
+++ b/source/ui-diff.c
@@ -17,12 +17,10 @@
#include "ui-shared.h"
#include "ui-ssdiff.h"
-// A file's body is collected while the walk still has that file open, because
-// the stat table above it has to be printed first and rendering the bodies
-// afterwards meant a second walk with its own rename detection and its own
-// xdiff of every file. This bounds what one request may hold that way, so it
-// is not something to configure, and once it is passed the collected bodies
-// are dropped and that second walk happens after all.
+// A file's body is collected while the walk still has that file open,
+// since the stat table above it has to be printed first. This bounds what
+// one request may hold that way. Past it the collected bodies are dropped
+// and a second walk renders the page instead.
#define BODY_BUDGET (8 * 1024 * 1024)
// What a context of zero means once the diff runs, mirroring the fallback in
@@ -81,9 +79,8 @@ static void release_bodies(void)
/*
* One bar segment of the per-file diffstat graph. The bar is a fixed-layout
- * table whose row always spans 1000 columns, so a segment takes its share
- * of the width through colspan rather than through an inline style, which
- * a Content-Security-Policy would have to allow.
+ * table whose row always spans 1000 columns, so a segment takes its width
+ * through colspan rather than an inline style a CSP would have to allow.
*/
static void print_graph_cell(const char *class, int span)
{
@@ -168,9 +165,8 @@ static void print_fileinfo(struct fileinfo *info)
}
/*
- * Counting is only half of what this does. It also renders each line, until
- * max-diff-lines is passed and the rest of the file is dropped, which is why
- * the two cannot be separated into a counting pass and a rendering one.
+ * Counting is only half of what this does. It also renders each line until
+ * max-diff-lines is passed, so the two cannot be split into separate passes.
*/
static void count_diff_lines(char *line, int len)
{
@@ -376,9 +372,9 @@ static void collect_body(struct diff_filepair *pair, struct fileinfo *item,
render_suppressed = 0;
if (S_ISGITLINK(pair->one->mode) || S_ISGITLINK(pair->two->mode)) {
- // The stat has always counted what a diff of the pair produces
- // rather than the two lines the body shows, so run that diff
- // for the count alone.
+ // The stat counts what a diff of the pair produces rather
+ // than the two lines the body shows, so run that diff for
+ // the count alone.
render_line_fn = NULL;
cgit_diff_files(&pair->one->oid, &pair->two->oid, old_size,
new_size, binary, 0, ctx.qry.ignorews,
@@ -398,10 +394,9 @@ static void collect_body(struct diff_filepair *pair, struct fileinfo *item,
cgit_ssdiff_footer();
if (render_suppressed) {
- // Setting the length back would leave the buffer holding
- // everything it grew to while rendering, which the budget below
- // cannot see because it only counts what is kept, so rebuild it
- // at the size actually kept.
+ // Setting the length back would keep the grown allocation,
+ // which the budget below cannot see because it only counts
+ // what is kept, so rebuild the buffer at the kept size.
char *header_text = xmemdupz(body->buf, header_len);
strbuf_release(body);
diff --git a/source/ui-log.c b/source/ui-log.c
index bbfeb67..5b5dd32 100644
--- a/source/ui-log.c
+++ b/source/ui-log.c
@@ -337,7 +337,7 @@ static char *next_token(char **src)
{
char *token;
- if (!src || !*src)
+ if (!*src)
return NULL;
while (isspace((unsigned char)**src))
(*src)++;
@@ -398,7 +398,6 @@ void cgit_print_commit_decorations(struct commit *commit)
const struct name_decoration *deco;
static char buf[1024];
- buf[sizeof(buf) - 1] = 0;
deco = get_name_decoration(&commit->object);
if (!deco)
return;
@@ -463,10 +462,9 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep,
tip = disambiguate_ref(tip, &must_free_tip);
if (tip && tip[0] == '-') {
// setup_revisions() reads a leading-dash argument as an
- // option, so a tip arriving as the id= value "--output=<path>"
- // would be handled by git as a request to write an arbitrary
- // file. No valid ref or object name begins with a dash, so
- // refuse it.
+ // option, so a tip like "--output=<path>" would become a
+ // request to write an arbitrary file. No valid ref or object
+ // name begins with a dash, so refuse it.
cgit_print_error_page(400, "Bad Request", "Invalid revision");
if (must_free_tip)
free((char *)tip);
@@ -484,10 +482,10 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep,
char *arg;
// Each whitespace separated token is taken as a
- // revision expression and nothing else, since anything
- // starting with a dash would reach setup_revisions as
- // a rev-list option. The tip pushed above goes away
- // because the range supersedes it.
+ // revision expression only, since a leading dash
+ // would reach setup_revisions as a rev-list option.
+ // The tip pushed above goes away, since the range
+ // supersedes it.
strvec_pop(&rev_argv);
while ((arg = next_token(&pattern))) {
if (*arg == '-') {
diff --git a/source/ui-patch.c b/source/ui-patch.c
index ef63d00..bc98f2e 100644
--- a/source/ui-patch.c
+++ b/source/ui-patch.c
@@ -1,11 +1,9 @@
/*
* The patch page, which serves a commit or a range of commits as plain text
* in the mail format git format-patch writes, so that a change read in cgit
- * can be fed straight to git am. It is one of the repository commands in
- * cmd.c, taking the newer revision from id, the older one from id2, and an
- * optional path that narrows the diff. A merge carries no single patch and so
- * drops out of a range, and max-patch-count bounds how many commits one
- * request may emit.
+ * can be fed straight to git am. A merge carries no single patch and drops
+ * out of a range, and max-patch-count bounds how many commits one request
+ * may emit.
*/
#define USE_THE_REPOSITORY_VARIABLE
diff --git a/source/ui-plain.c b/source/ui-plain.c
index b63b9c6..d3b4771 100644
--- a/source/ui-plain.c
+++ b/source/ui-plain.c
@@ -45,10 +45,10 @@ static int is_unsafe_type(const char *mimetype)
}
/*
- * A nonzero return says the response has been written, error pages included,
- * so the walk does not go on to report the path as missing.
+ * Writes the response for the object, error pages included, so the walk
+ * does not go on to report the path as missing.
*/
-static int print_object(const struct object_id *oid, const char *path)
+static void print_object(const struct object_id *oid, const char *path)
{
enum object_type type;
char *buf, *mimetype;
@@ -57,7 +57,7 @@ static int print_object(const struct object_id *oid, const char *path)
type = odb_read_object_info(the_repository->objects, oid, &size);
if (type == OBJ_BAD) {
cgit_print_error_page(404, "Not Found", "Not found");
- return 1;
+ return;
}
// The limit counts kilobytes and is checked before the read, so a huge
@@ -67,13 +67,13 @@ static int print_object(const struct object_id *oid, const char *path)
cgit_print_error_page(413, "Content Too Large",
"Object size (%luKB) exceeds limit (%dKB)",
size / 1024, ctx.cfg.max_blob_size);
- return 1;
+ return;
}
buf = odb_read_object(the_repository->objects, oid, &type, &size);
if (!buf) {
cgit_print_error_page(404, "Not Found", "Not found");
- return 1;
+ return;
}
mimetype = cgit_get_mimetype_for_filename(path);
@@ -99,7 +99,6 @@ static int print_object(const struct object_id *oid, const char *path)
html_raw(buf, size);
free(mimetype);
free(buf);
- return 1;
}
static char *build_path(const char *base, int baselen, const char *path)
@@ -110,8 +109,7 @@ static char *build_path(const char *base, int baselen, const char *path)
return cgit_fmtalloc("%.*s/", baselen, base);
}
-static void print_dir(const struct object_id *oid, const char *base,
- int baselen, const char *path)
+static void print_dir(const char *base, int baselen, const char *path)
{
char *fullpath;
const char *leading_slash;
@@ -120,9 +118,8 @@ static void print_dir(const struct object_id *oid, const char *base,
fullpath = build_path(base, baselen, path);
leading_slash = (fullpath[0] == '/' ? "" : "/");
cgit_print_http_headers();
- // The listing is a full document of its own, so it carries the same
- // doctype and charset as the layout pages or the browser would parse
- // it in quirks mode.
+ // A full document of its own, and without the doctype and charset
+ // the browser would parse it in quirks mode.
html("<!DOCTYPE html>\n<html lang='en'>\n<head>\n");
html("<meta charset='UTF-8'>\n");
htmlf("<title>%s", leading_slash);
@@ -186,10 +183,10 @@ static int walk_tree(const struct object_id *oid, struct strbuf *base,
if (walk->dir_len >= 0 && base->len == (size_t)walk->dir_len) {
if (S_ISREG(mode) || S_ISLNK(mode)) {
- if (print_object(oid, pathname))
- walk->response = RESPONSE_BLOB;
+ print_object(oid, pathname);
+ walk->response = RESPONSE_BLOB;
} else if (S_ISDIR(mode)) {
- print_dir(oid, base->buf, base->len, pathname);
+ print_dir(base->buf, base->len, pathname);
walk->response = RESPONSE_LISTING;
return READ_TREE_RECURSIVE;
}
@@ -217,10 +214,9 @@ void cgit_print_plain(void)
struct object_id oid;
struct commit *commit;
int path_len = ctx.qry.path ? strlen(ctx.qry.path) : 0;
- // A hand built pathspec leaves nowildcard_len at zero, which tells git
- // the match may be a glob. It would then hand this walk every entry a
- // pattern like * matches, and each one would be answered with its own
- // set of HTTP headers inside the body of the first.
+ // nowildcard_len matches len so git treats the path as literal. As a
+ // glob, every entry a pattern like * matches would be answered with
+ // its own HTTP headers inside the body of the first.
struct pathspec_item path_items = {
.match = ctx.qry.path,
.len = path_len,
@@ -251,7 +247,7 @@ void cgit_print_plain(void)
// itself, so the listing it would have opened is opened here.
path_items.match = "";
walk.dir_len = -1;
- print_dir(get_commit_tree_oid(commit), "", 0, "");
+ print_dir("", 0, "");
walk.response = RESPONSE_LISTING;
} else {
walk.dir_len = dir_prefix_len(path_items.match);
diff --git a/source/ui-repolist.c b/source/ui-repolist.c
index 39978ae..9f60228 100644
--- a/source/ui-repolist.c
+++ b/source/ui-repolist.c
@@ -267,7 +267,7 @@ static void print_repo_row(const char *currenturl, int sublevel)
static void print_pager(int total, int pagelen, char *search, char *sort)
{
int i, ofs;
- char *class = NULL;
+ char *class;
html("<ul class='pager'>\n");
for (i = 0, ofs = 0; ofs < total; i++, ofs = i * pagelen) {
@@ -356,8 +356,7 @@ static int cmp_section(const void *a, const void *b)
/*
* get_repo_modtime caches into the repository it is handed, but qsort moves
- * those structs around as it works, so a comparator left to fill the cache
- * loses most of what it stored and stats the same repository over and over.
+ * those structs as it works, so the cache is filled before sorting.
*/
static void resolve_modtimes(void)
{
diff --git a/source/ui-shared.c b/source/ui-shared.c
index a79c291..2ec9d0e 100644
--- a/source/ui-shared.c
+++ b/source/ui-shared.c
@@ -611,7 +611,8 @@ static void print_repo_tabs(void)
ctx.qry.oid, ctx.qry.vpath);
else
cgit_tree_link("tree",
- tab_title("Browse the tree at %s", "Browse the file tree", vpath),
+ tab_title("Browse the tree at %s",
+ "Browse the file tree", vpath),
tab_class("tree"), ctx.qry.head,
ctx.qry.oid, ctx.qry.vpath);
html("</li>\n<li>");
@@ -686,8 +687,6 @@ static void print_site_search(void)
free(currenturl);
}
-// The link is built out of the request in ctx.qry, so a caller that alters a
-// field of ctx.qry first gets a link differing in exactly that.
static void snapshot_link(const char *name, const char *title, const char *class,
const char *head, const char *rev,
const char *archivename)
@@ -695,6 +694,8 @@ static void snapshot_link(const char *name, const char *title, const char *class
reporevlink("snapshot", name, title, class, head, rev, archivename);
}
+// The link is built out of the request in ctx.qry, so a caller that alters a
+// field of ctx.qry first gets a link differing in exactly that.
static void self_link(const char *name, const char *title, const char *class)
{
if (!strcmp(ctx.qry.page, "repolist"))
@@ -1225,10 +1226,7 @@ static const struct forge *forge_for_host(const char *host, size_t len)
* Derives a submodule row's links from its .gitmodules entry. The url is
* matched against this instance's own repositories first, so ssh, file and
* relative urls still land on an internal page when their target is served
- * here, and the pinned commit gets a page of its own. A plain web url is
- * linked as it is, an ssh url to a known host is rewritten to its web form,
- * and anything else is left unlinked with the url as a tooltip, since a
- * scheme cgit cannot vouch for has no place in an href.
+ * here, and a scheme cgit cannot vouch for is left unlinked as a tooltip.
*/
static void gitmodules_link(const char *path, const char *rev,
char **module, char **commit,
@@ -1477,7 +1475,8 @@ void cgit_print_http_headers(void)
void cgit_redirect(const char *url, bool permanent)
{
- htmlf("Status: %d %s\n", permanent ? 301 : 302, permanent ? "Moved Permanently" : "Found");
+ htmlf("Status: %d %s\n", permanent ? 301 : 302,
+ permanent ? "Moved Permanently" : "Found");
html("Location: ");
html_url_path(url);
html("\n\n");
@@ -1500,8 +1499,10 @@ void cgit_print_docstart(void)
html("<meta charset='UTF-8'>\n");
html("<meta name='viewport' content='width=device-width, initial-scale=1'>\n");
html("<meta name='color-scheme' content='light dark'>\n");
- html("<meta name='theme-color' media='(prefers-color-scheme: light)' content='#ffffff'>\n");
- html("<meta name='theme-color' media='(prefers-color-scheme: dark)' content='#1b1b1b'>\n");
+ html("<meta name='theme-color' media='(prefers-color-scheme: light)'"
+ " content='#ffffff'>\n");
+ html("<meta name='theme-color' media='(prefers-color-scheme: dark)'"
+ " content='#1b1b1b'>\n");
html("<title>");
// An error page reached before a title was chosen still has to name
// itself, since an empty title element is not valid.
@@ -1585,7 +1586,8 @@ void cgit_print_docend(void)
if (ctx.cfg.footer)
html_include(ctx.cfg.footer);
else {
- htmlf("<footer class='footer'>generated by <a href='https://github.com/brycekwon/cgit'>cgit %s</a> "
+ htmlf("<footer class='footer'>generated by "
+ "<a href='https://github.com/brycekwon/cgit'>cgit %s</a> "
"(<a href='https://git-scm.com/'>git %s</a>)</footer>\n",
cgit_version, git_version_string);
}
@@ -1652,11 +1654,10 @@ static void capture_http_clone_url(const char *url)
}
/*
- * One row of the clone table. The url is shown as written, and every row is
- * a link, but a browser cannot follow the ssh, scp or git forms, so those
- * rows point at the first http url in the clone list, or at the repository's
- * own page when the list has none, which with http clone enabled is itself a
- * working clone url. A colspan of zero leaves the attribute out.
+ * One row of the clone table. Every row is a link, but a browser cannot
+ * follow the ssh, scp or git forms, so those rows point at the first http
+ * url in the clone list, or at the repository's own page when the list has
+ * none. A colspan of zero leaves the attribute out.
*/
void cgit_print_clone_row(const char *url, int colspan)
{
@@ -1858,7 +1859,8 @@ void cgit_print_snapshot_links(const struct cgit_repo *repo, const char *ref,
snapshot_link("sig", NULL, NULL, NULL, NULL,
filename.buf);
html(")");
- } else if (starts_with(f->suffix, ".tar") && cgit_snapshot_get_sig(ref, &cgit_snapshot_formats[0])) {
+ } else if (starts_with(f->suffix, ".tar") &&
+ cgit_snapshot_get_sig(ref, &cgit_snapshot_formats[0])) {
// A compressed tarball offers the signature made for
// the plain tar it expands to, which is the first
// format in the table.
diff --git a/source/ui-snapshot.c b/source/ui-snapshot.c
index 7da7252..af985f4 100644
--- a/source/ui-snapshot.c
+++ b/source/ui-snapshot.c
@@ -165,7 +165,7 @@ static const char *ref_from_filename(const struct cgit_repo *repo,
if (starts_with(rev.buf, repo_prefix)) {
const char *rest = rev.buf + strlen(repo_prefix);
- while (rest && (*rest == '-' || *rest == '_'))
+ while (*rest == '-' || *rest == '_')
rest++;
strbuf_splice(&rev, 0, rest - rev.buf, "", 0);
}
diff --git a/source/ui-snapshot.h b/source/ui-snapshot.h
index 9f1ec02..9d2910f 100644
--- a/source/ui-snapshot.h
+++ b/source/ui-snapshot.h
@@ -26,8 +26,9 @@ extern unsigned cgit_snapshot_format_bit(const struct cgit_snapshot_format *f);
/*
* Turn a cgitrc snapshots value into a mask over cgit_snapshot_formats. A
- * plain number is the legacy form meaning every format, as is the word all,
- * otherwise the value is a space separated list of suffixes.
+ * plain nonzero number is the legacy boolean form and enables plain tar
+ * alone, the word all enables every format, and otherwise the value is a
+ * space separated list of suffixes.
*/
extern int cgit_parse_snapshots_mask(const char *str);
diff --git a/source/ui-ssdiff.c b/source/ui-ssdiff.c
index 8651ce7..759a77b 100644
--- a/source/ui-ssdiff.c
+++ b/source/ui-ssdiff.c
@@ -33,8 +33,7 @@ static struct deferred_line *deferred_new, *deferred_new_last;
/*
* The table is reused by every comparison and nothing clears it in between,
* because the fill in longest_common_subsequence works back from the far
- * corner and writes every cell it goes on to read. Clearing it for each pair
- * of lines cost more than the comparison it was preparing for.
+ * corner and writes every cell it goes on to read.
*/
static void create_lcs_table(void)
{
@@ -107,9 +106,8 @@ static char *longest_common_subsequence(const char *old_line,
}
/*
- * The line with its tabs expanded, which the caller owns. Appending as the
- * line is walked replaces a loop that rescanned the rest of the input at every
- * tab, which made a tab heavy line quadratic in its own length.
+ * The line with its tabs expanded, which the caller owns. Built in one
+ * forward pass so a tab heavy line stays linear in its own length.
*/
static char *expand_tabs(const char *line)
{
@@ -135,9 +133,8 @@ static void flush_run(struct strbuf *run)
}
/*
- * A stretch that the other side does not share is escaped in one call because
- * escaping a character at a time sent every character of every changed line
- * through the output path on its own, which dominated this page.
+ * A stretch the other side does not share is escaped in one call, so a
+ * changed line does not go through the output path a byte at a time.
*/
static void print_line_with_lcs(const char *class, const char *line,
const char *lcs)
@@ -397,8 +394,7 @@ void cgit_ssdiff_line_cb(char *line, int len)
}
if (line[0] == ' ') {
- if (deferred_old || deferred_new)
- print_deferred_lines();
+ print_deferred_lines();
print_row("ctx", current_old_line, line,
current_new_line, line, 0);
current_old_line += 1;
@@ -438,7 +434,6 @@ void cgit_ssdiff_header_end(void)
void cgit_ssdiff_footer(void)
{
- if (deferred_old || deferred_new)
- print_deferred_lines();
+ print_deferred_lines();
html("<tr><td class='foot' colspan='4'></td></tr>\n");
}
diff --git a/source/ui-stats.c b/source/ui-stats.c
index 5b36f54..62aac56 100644
--- a/source/ui-stats.c
+++ b/source/ui-stats.c
@@ -149,10 +149,10 @@ static char *pretty_year(struct tm *tm)
* caps the page by storing an index into this table as its max-stats.
*/
static const struct cgit_period periods[] = {
- {'w', "week", 12, 4, trunc_week, dec_week, inc_week, pretty_week},
- {'m', "month", 12, 4, trunc_month, dec_month, inc_month, pretty_month},
- {'q', "quarter", 12, 4, trunc_quarter, dec_quarter, inc_quarter, pretty_quarter},
- {'y', "year", 12, 4, trunc_year, dec_year, inc_year, pretty_year},
+ {'w', "week", 4, trunc_week, dec_week, inc_week, pretty_week},
+ {'m', "month", 4, trunc_month, dec_month, inc_month, pretty_month},
+ {'q', "quarter", 4, trunc_quarter, dec_quarter, inc_quarter, pretty_quarter},
+ {'y', "year", 4, trunc_year, dec_year, inc_year, pretty_year},
};
static void window_start(const struct cgit_period *period, struct tm *tm)
diff --git a/source/ui-stats.h b/source/ui-stats.h
index ccb0598..1b20e6c 100644
--- a/source/ui-stats.h
+++ b/source/ui-stats.h
@@ -13,7 +13,6 @@
struct cgit_period {
const char code;
const char *name;
- int max_periods;
// How many periods a page shows side by side.
int count;
diff --git a/source/ui-summary.c b/source/ui-summary.c
index dacf0f7..197cd07 100644
--- a/source/ui-summary.c
+++ b/source/ui-summary.c
@@ -65,10 +65,9 @@ static int path_within(const char *base, const char *path)
/*
* Returns a path the caller must free, or NULL when the request cannot be
- * served. A null ref means the readme is a file on the server's disk rather
- * than a path inside a ref, and such a readme is confined to its own
- * directory, so one named without a directory has nothing to confine it to
- * and is refused.
+ * served. A null ref means the readme is a file on the server's disk, and
+ * such a readme is confined to its own directory, so one named without a
+ * directory is refused.
*/
static char *resolve_about_path(const char *filename, const char *ref,
const char *path)
@@ -158,10 +157,8 @@ void cgit_print_repo_readme(const char *path)
html("<div id='summary'>");
if (!ctx.repo->about_filter) {
- // With no about-filter configured there is nothing to turn the
- // readme source into safe HTML, so it is escaped rather than
- // served raw, which would let an untrusted repository put
- // script on this page.
+ // With no about-filter there is nothing to turn the readme
+ // into safe HTML, so it is escaped rather than served raw.
html("<pre class='plaintext'>");
if (ref) {
cgit_print_file(filename, ref, 1, 1);
diff --git a/source/ui-tree.c b/source/ui-tree.c
index cbf783f..26a3fd1 100644
--- a/source/ui-tree.c
+++ b/source/ui-tree.c
@@ -53,10 +53,8 @@ struct only_child {
};
/*
- * A formatted write per line meant a syscall and a temporary buffer for every
- * line of the file, so the anchors are handed over in batches. Building the
- * column whole was rejected because it would come to several times the size of
- * the blob.
+ * The anchors are handed over in batches rather than a write per line, and
+ * never built whole, which would come to several times the blob's size.
*/
static void print_linenumbers(const char *buf, unsigned long size)
{
@@ -109,8 +107,6 @@ static void print_text_buffer(const char *filename, char *buf,
return;
}
- // Syntax highlighting ships as one of the filters under
- // custom/extensions, which keeps knowledge of languages out of cgit.
html("<td class='lines'><pre><code>");
html_txt(buf);
html("</code></pre></td></tr></table>\n");
@@ -134,8 +130,7 @@ static void print_binary_buffer(char *buf, unsigned long size)
html("<table class='bin-blob'>\n");
html("<tr><th>ofs</th><th>hex dump</th><th>ascii</th></tr>\n");
- // At the default blob size limit a write per byte spent almost all of
- // its time in the kernel, so a row goes out in one write.
+ // A row goes out in one write rather than a write per byte.
for (offset = 0; offset < size;
offset += HEXDUMP_ROW_BYTES, buf += HEXDUMP_ROW_BYTES) {
strbuf_reset(&row);
@@ -424,7 +419,7 @@ static void ls_tail(void)
cgit_print_layout_end();
}
-static void ls_tree(const struct object_id *oid, const char *path,
+static void ls_tree(const struct object_id *oid,
struct walk_tree_context *walk)
{
struct tree *tree;
@@ -518,7 +513,7 @@ void cgit_print_tree(const char *rev, char *path)
walk.rev = xstrdup(rev);
if (path == NULL) {
- ls_tree(get_commit_tree_oid(commit), NULL, &walk);
+ ls_tree(get_commit_tree_oid(commit), &walk);
goto cleanup;
}
diff --git a/tests/extensions/harness.lua b/tests/extensions/harness.lua
index 9085010..d0299e3 100644
--- a/tests/extensions/harness.lua
+++ b/tests/extensions/harness.lua
@@ -118,9 +118,7 @@ end
-- Deterministic bytes standing in for a digest, built from djb2 style lanes
-- in plain arithmetic so they compute the same on every Lua version. Not
--- remotely cryptographic, and enough for what the checks assert, that equal
--- input hashes equal, different input hashes different and a tampered
--- payload no longer verifies.
+-- cryptographic, just stable and collision-shy enough for the checks.
local function fake_digest_bytes(text)
local lanes = { 5381, 52711, 1313, 7919 }
for i = 1, #text do
@@ -140,8 +138,6 @@ local function fake_digest_bytes(text)
return table.concat(bytes)
end
-harness.fake_digest_bytes = fake_digest_bytes
-
-- The slice of the luaossl digest interface the avatar filters use.
function harness.stub_digest()
harness.preload("openssl.digest", {
@@ -168,8 +164,6 @@ local function fake_crypt(password, setting)
return prefix .. password
end
-harness.fake_crypt = fake_crypt
-
-- The slices of luaossl and luaposix the auth filters use. The link and
-- unlink stubs serve the secret creation path, which the auth checks bypass
-- by replacing get_secret, so they only have to exist.
diff --git a/tests/extensions/lib.sh b/tests/extensions/lib.sh
index 1b31a4b..f472faf 100644
--- a/tests/extensions/lib.sh
+++ b/tests/extensions/lib.sh
@@ -15,9 +15,8 @@ ext_lua_version() {
}
# Prints the interpreters found on the path whose version falls between 5.1
-# and the given 5.x ceiling, one per line, since each extension states the
-# versions it runs on and a test must not fail a script on a version it never
-# claimed.
+# and the given 5.x ceiling, one per line, so a script is never failed on a
+# version it never claimed to run on.
ext_lua_interpreters() {
ext_lua_ceiling=$1
for ext_lua_bin in luajit lua5.1 lua5.2 lua5.3 lua5.4 lua5.5 lua
diff --git a/tests/filters/dump.lua b/tests/filters/dump.lua
index aa16dfd..d654621 100644
--- a/tests/filters/dump.lua
+++ b/tests/filters/dump.lua
@@ -1,7 +1,6 @@
-- Test fixture for the cgit Lua filter API, exercised by t0201-filters.sh.
--- It echoes the filter_open arguments and upper-cases the body, which lets the
--- test confirm that arguments and content flow through the lua: filter path. It
--- is not a production filter. Runs on Lua 5.1 through 5.4 and LuaJIT.
+-- It echoes the filter_open arguments and upper-cases the body, which lets
+-- the test confirm arguments and content flow through the lua: filter path.
function filter_open(...)
buffer = ""
diff --git a/tests/setup.sh b/tests/setup.sh
index 757ae04..de4fcc6 100755
--- a/tests/setup.sh
+++ b/tests/setup.sh
@@ -6,16 +6,13 @@
# CGIT_TEST_NO_CREATE_REPOS to get the helpers without paying for the fixtures.
# The Git test library would run every Git command under Valgrind if it saw
-# --valgrind, and only cgit itself is worth watching, so the option is taken out
-# here and acted on further down. The arguments are carried across as a newline
-# separated list, which keeps any other whitespace in them intact but assumes
-# that none holds a newline of its own.
+# --valgrind, and only cgit is worth watching, so the option is taken out
+# here and acted on further down.
LF='
'
-# Trash directories are collected under one trash/ rather than left beside
-# the scripts, which keeps the ignore and clean rules to a single plain
-# name. The option is seeded ahead of the real arguments so one given on
-# the command line still wins.
+# Trash directories are collected under one trash/, which keeps the ignore
+# and clean rules to a single name. Seeded ahead of the real arguments so
+# one given on the command line still wins.
test_argv="${LF}--root=trash"
while test $# != 0
@@ -45,17 +42,15 @@ TEST_NO_CREATE_REPO=YesPlease
. "$TEST_DIRECTORY"/test-lib.sh
# The library spells its results directory test-results and derives these
-# variables before it can be told otherwise, so they are re-pointed here and
-# every count lands under the plainer results/ instead. The rarely used
-# --tee and --stress options write their raw logs before this line and keep
-# the library's own name.
+# variables before it can be told otherwise, so they are re-pointed at the
+# plainer results/. The --tee and --stress raw logs write earlier and keep
+# the library's name.
TEST_RESULTS_DIR="$TEST_OUTPUT_DIRECTORY/results"
TEST_RESULTS_BASE="$TEST_RESULTS_DIR/$TEST_NAME$TEST_STRESS_JOB_SFX"
TEST_RESULTS_SAN_DIR="$TEST_RESULTS_BASE.$TEST_RESULTS_SAN_DIR_SFX"
-# The library has moved into the trash directory by now, so everything the
-# tests reach outside it is anchored to TEST_OUTPUT_DIRECTORY, which still
-# names this directory whatever depth the trash sits at.
+# The library has moved into the trash directory by now, so paths outside
+# it are anchored to TEST_OUTPUT_DIRECTORY.
# The tests run cgit by name, so the binary just built has to come ahead of any
# copy already installed. Under Valgrind the wrappers take that place instead.
@@ -138,9 +133,7 @@ enable-filter-overrides=1
repo.url=foo
repo.path=$PWD/repos/foo/.git
-# Do not specify a description for this repo, as it then will be assigned
-# the constant value "[no description]" (which actually used to cause a
-# segfault).
+# No repo.desc here, so the [no description] default gets exercised.
repo.url=bar
repo.path=$PWD/repos/bar/.git
diff --git a/tests/t0001-git-version.sh b/tests/t0001-git-version.sh
index 7dd9c40..dd49002 100755
--- a/tests/t0001-git-version.sh
+++ b/tests/t0001-git-version.sh
@@ -1,11 +1,9 @@
#!/bin/sh
# Checks that the Git version cgit says it is built for is the one it is
-# actually built against. The top-level Makefile names a version, the tree
-# under vendor/git records its own, and the submodule is pinned to a tag, so
-# all three have to agree or cgit is being built on something other than what
-# it claims. Set CGIT_TEST_NO_GIT_VERSION to YesPlease when Git comes from
-# elsewhere and the comparison has nothing to say.
+# built against, so the Makefile, vendor/git and the submodule pin must name
+# the same version. Set CGIT_TEST_NO_GIT_VERSION to YesPlease when Git comes
+# from elsewhere.
if test "$CGIT_TEST_NO_GIT_VERSION" = "YesPlease"
then
diff --git a/tests/t0002-html-validity.sh b/tests/t0002-html-validity.sh
index f22b2b6..0784092 100755
--- a/tests/t0002-html-validity.sh
+++ b/tests/t0002-html-validity.sh
@@ -1,11 +1,9 @@
#!/bin/sh
-# Runs the tidy checker over one page of each kind cgit renders, so that markup
-# broken enough to confuse a browser is caught here rather than in the browser.
-# Only the shape of the markup matters, since what the pages actually say is
-# the business of the t01xx scripts. Tidy is optional and old versions of it
-# predate the elements cgit uses, so the whole file steps aside when a usable
-# one cannot be found.
+# Runs the tidy checker over one page of each kind cgit renders, caring only
+# about the shape of the markup. What the pages say is the business of the
+# t01xx scripts. Tidy is optional and old versions predate the elements cgit
+# uses, so the file steps aside when a usable one cannot be found.
test_description='Validate html with tidy'
. ./setup.sh
diff --git a/tests/t0003-cache.sh b/tests/t0003-cache.sh
index 7ad2a79..61bf45c 100755
--- a/tests/t0003-cache.sh
+++ b/tests/t0003-cache.sh
@@ -1,11 +1,9 @@
#!/bin/sh
-# Exercises the cache, which keeps a rendered page in a slot on disk and
-# replays it for the next request that asks for the same thing. The first three
-# tests set cache-size to nothing, to one slot and to the full table in turn,
-# then count what the requests left behind. The rest cover the two ways a slot
-# can come out wrong, a page longer than the output buffer and a key too long
-# to be read back.
+# Exercises the cache. The first three tests set cache-size to nothing, one
+# slot and the full table in turn, then count what the requests left behind.
+# The rest cover a page longer than the output buffer and a key too long to
+# be read back.
test_description='Validate cache'
. ./setup.sh
diff --git a/tests/t0004-docs.sh b/tests/t0004-docs.sh
index ef12493..292223f 100755
--- a/tests/t0004-docs.sh
+++ b/tests/t0004-docs.sh
@@ -3,9 +3,7 @@
# Checks that the configuration documents stay consistent with each other.
# The manual documents every key the reference config sets, the reference
# config sets every key the manual documents, and both settings sections of
-# the manual keep their entries sorted so a reader can find a key by
-# scanning. An audit found the two files drifting apart, so this pins them
-# together.
+# the manual keep their entries sorted.
test_description='Check the configuration documents'
. ./setup.sh
diff --git a/tests/t0101-index.sh b/tests/t0101-index.sh
index be382ad..60f71e8 100755
--- a/tests/t0101-index.sh
+++ b/tests/t0101-index.sh
@@ -1,11 +1,9 @@
#!/bin/sh
-# The index page is what cgit serves at the root of a site, one row for every
-# repository named in cgitrc. These checks look for each repository the shared
-# setup builds along with its description, and for the escaping a name that
-# contains a plus or a space needs before it can go into a link. They also
-# confirm the index stays a plain list, without the tree and log links that
-# belong to a repository's own pages.
+# The index page, one row per repository in cgitrc. The checks look for each
+# fixture repository and its description, for the escaping a name with a
+# plus or a space needs in a link, and for the absence of the tree and log
+# links that belong to a repository's own pages.
test_description='Check content on index page'
. ./setup.sh
diff --git a/tests/t0102-summary.sh b/tests/t0102-summary.sh
index 5ce1fab..181040d 100755
--- a/tests/t0102-summary.sh
+++ b/tests/t0102-summary.sh
@@ -1,11 +1,9 @@
#!/bin/sh
-# The summary page is the landing page for a single repository, holding its
-# most recent commits together with its branches and its tags. The shared
-# setup caps that log at five entries, so the checks against the fifty commit
-# repository are really checking that the cut lands where it should. They also
-# confirm the clone url template from cgitrc has had the repository name
-# substituted into it.
+# The summary page for a single repository. The shared setup caps its log at
+# five entries, so the checks against the fifty commit repository prove the
+# cut lands where it should, and the clone url template has the repository
+# name substituted in.
test_description='Check content on summary page'
. ./setup.sh
diff --git a/tests/t0103-log.sh b/tests/t0103-log.sh
index dfb5176..16fabda 100755
--- a/tests/t0103-log.sh
+++ b/tests/t0103-log.sh
@@ -1,10 +1,8 @@
#!/bin/sh
-# The log page lists the commits on a branch and can narrow that list down
-# with a search. The searching checks run against the repository whose name
-# contains a space and search for a term containing a space, so every link
-# cgit writes back out has to escape both the path it points at and the query
-# it carries, and the two are escaped differently.
+# The log page and its search. The searching checks use the repository whose
+# name contains a space and a term containing a space, so every link cgit
+# writes back has to escape the path and the query, which escape differently.
test_description='Check content on log page'
. ./setup.sh
diff --git a/tests/t0104-tree.sh b/tests/t0104-tree.sh
index a30297f..66686c0 100755
--- a/tests/t0104-tree.sh
+++ b/tests/t0104-tree.sh
@@ -1,11 +1,9 @@
#!/bin/sh
-# The tree page browses a repository at one revision, either as a listing of a
-# directory or as a single file with an anchor on every line. The checks
-# against the repository named foo+bar cover a file name and a branch name
-# that both contain a plus, which cgit percent-encodes in a path as well as in
-# a query, since a bare plus in a served path would read back as a space when
-# the link is requested through a query string.
+# The tree page. The checks against foo+bar cover a file name and a branch
+# name that both contain a plus, which cgit percent-encodes in a path as
+# well as in a query, since a bare plus in a served path reads back as a
+# space through a query string.
test_description='Check content on tree page'
. ./setup.sh
diff --git a/tests/t0105-plain.sh b/tests/t0105-plain.sh
index b950098..2fbe87f 100755
--- a/tests/t0105-plain.sh
+++ b/tests/t0105-plain.sh
@@ -1,11 +1,9 @@
#!/bin/sh
-# The plain page hands over a repository's own bytes rather than a rendered
-# view of them, so these checks read the response headers and then compare
-# the body against what git says the blob holds. A file with no better guess
-# is served as text unless its bytes look binary, a directory answers with a
-# bare listing of links rather than one of the themed pages, and a path that
-# names nothing has to come back as a 404 rather than an empty document.
+# The plain page hands over a repository's own bytes. A file with no better
+# guess is served as text unless its bytes look binary, a directory answers
+# with a bare listing of links, and a path that names nothing comes back as
+# a 404 rather than an empty document.
test_description='Check content on plain page'
. ./setup.sh
diff --git a/tests/t0106-commit.sh b/tests/t0106-commit.sh
index ca41830..39f1822 100755
--- a/tests/t0106-commit.sh
+++ b/tests/t0106-commit.sh
@@ -1,10 +1,8 @@
#!/bin/sh
-# The commit page shows a single commit, its message, the files it touched and
-# the diff for them. Most of these checks read the markup cgit emits for the
-# tree link, the parent link, the subject and the diffstat. The last few ask
-# for the root commit of a repository, which has no parent and so goes through
-# the code that compares a commit against an empty tree.
+# The commit page. Most checks read the markup for the tree link, the parent
+# link, the subject and the diffstat. The last few use a root commit, which
+# has no parent and diffs against the empty tree.
test_description='Check content on commit page'
. ./setup.sh
diff --git a/tests/t0107-diff.sh b/tests/t0107-diff.sh
index 175f609..f058246 100755
--- a/tests/t0107-diff.sh
+++ b/tests/t0107-diff.sh
@@ -1,11 +1,10 @@
#!/bin/sh
-# The diff page renders the change a commit made, either as unified text or,
-# when dt=1 asks for it, as a side by side table. The first checks read the
-# markup for one added file in the repository the shared setup builds. The
-# rest build small repositories of their own, shaped so the side by side
-# renderer meets the two cases it used to get wrong, a hunk covering a single
-# line and a file where every line changed.
+# The diff page, unified or side by side under dt=1. The first checks read
+# the markup for one added file in the fixture repository. The rest build
+# repositories of their own, shaped for the side by side renderer's two
+# trickiest cases, a hunk covering a single line and a file where every
+# line changed.
test_description='Check content on diff page'
. ./setup.sh
diff --git a/tests/t0108-rawdiff.sh b/tests/t0108-rawdiff.sh
index c546993..7753bdb 100755
--- a/tests/t0108-rawdiff.sh
+++ b/tests/t0108-rawdiff.sh
@@ -1,10 +1,8 @@
#!/bin/sh
-# Checks the rawdiff page, which serves a diff as plain text with no markup
-# around it so that the result can be fed straight to patch. Every test runs
-# the git command the page is meant to mirror and compares the two byte for
-# byte, covering an ordinary commit, the initial commit that has no parent,
-# and a range spanning several commits.
+# The rawdiff page serves a diff as plain text fit for patch. Every test
+# runs the git command the page mirrors and compares the two byte for byte,
+# over an ordinary commit, the parentless initial commit and a range.
test_description='Check content on rawdiff page'
. ./setup.sh
diff --git a/tests/t0109-patch.sh b/tests/t0109-patch.sh
index ae4dc83..0982102 100755
--- a/tests/t0109-patch.sh
+++ b/tests/t0109-patch.sh
@@ -1,15 +1,22 @@
#!/bin/sh
-# The patch page serves a commit as a mail ready patch, so that a change read
-# from cgit can be fed straight to git am. The checks compare that output
-# against git format-patch for a single commit and for a range of them, once
-# the CGI headers have been stripped, which means the two have to agree line
-# for line. The last one sets max-patch-count so a range wider than the limit
-# comes back cut short.
+# The patch page serves mail ready patches, compared line for line against
+# git format-patch for a single commit and for a range, once the CGI headers
+# are stripped. The last check sets max-patch-count so a range wider than
+# the limit comes back cut short.
test_description='Check content on patch page'
. ./setup.sh
+# The signature sits on the second-to-last line, above the trailing blank.
+check_cgit_signature() {
+ tail -2 tmp | head -1 | grep "^cgit"
+}
+
+# The version the built binary signs its patches with.
+CGIT_VERSION=$(sed -n "s/CGIT_VERSION = //p" \
+ "$TEST_OUTPUT_DIRECTORY/../build/VERSION")
+
test_expect_success 'generate foo/patch' '
cgit_query "url=foo/patch" >tmp
'
@@ -27,26 +34,27 @@ test_expect_success 'find `Subject:` line' '
'
test_expect_success 'find `cgit` signature' '
- tail -2 tmp | head -1 | grep "^cgit"
+ check_cgit_signature
'
test_expect_success 'compare with output of git-format-patch(1)' '
- CGIT_VERSION=$(sed -n "s/CGIT_VERSION = //p" "$TEST_OUTPUT_DIRECTORY/../build/VERSION") &&
- git --git-dir="$PWD/repos/foo/.git" format-patch --subject-prefix="" --signature="cgit $CGIT_VERSION" --stdout HEAD^ >tmp2 &&
+ git --git-dir="$PWD/repos/foo/.git" format-patch --subject-prefix="" \
+ --signature="cgit $CGIT_VERSION" --stdout HEAD^ >tmp2 &&
strip_headers <tmp >tmp_ &&
test_cmp tmp_ tmp2
'
test_expect_success 'find initial commit' '
- root=$(git --git-dir="$PWD/repos/foo/.git" rev-list --max-parents=0 HEAD)
+ root=$(git --git-dir="$PWD/repos/foo/.git" \
+ rev-list --max-parents=0 HEAD)
'
test_expect_success 'generate patch for initial commit' '
cgit_query "url=foo/patch&id=$root" >tmp
'
-test_expect_success 'find `cgit` signature' '
- tail -2 tmp | head -1 | grep "^cgit"
+test_expect_success 'find `cgit` signature on the initial commit' '
+ check_cgit_signature
'
test_expect_success 'generate patches for multiple commits' '
@@ -55,13 +63,14 @@ test_expect_success 'generate patches for multiple commits' '
cgit_query "url=foo/patch&id=$id&id2=$id2" >tmp
'
-test_expect_success 'find `cgit` signature' '
- tail -2 tmp | head -1 | grep "^cgit"
+test_expect_success 'find `cgit` signature on the range' '
+ check_cgit_signature
'
-test_expect_success 'compare with output of git-format-patch(1)' '
- CGIT_VERSION=$(sed -n "s/CGIT_VERSION = //p" "$TEST_OUTPUT_DIRECTORY/../build/VERSION") &&
- git --git-dir="$PWD/repos/foo/.git" format-patch -N --subject-prefix="" --signature="cgit $CGIT_VERSION" --stdout HEAD~3..HEAD >tmp2 &&
+test_expect_success 'compare the range with git-format-patch(1)' '
+ git --git-dir="$PWD/repos/foo/.git" format-patch --subject-prefix="" \
+ -N --signature="cgit $CGIT_VERSION" --stdout \
+ HEAD~3..HEAD >tmp2 &&
strip_headers <tmp >tmp_ &&
test_cmp tmp_ tmp2
'
@@ -74,8 +83,10 @@ test_expect_success 'max-patch-count bounds a patch range' '
echo "repo.path=$PWD/repos/foo/.git"
} >patchcountrc &&
id=$(git --git-dir="$PWD/repos/foo/.git" rev-parse HEAD) &&
- root=$(git --git-dir="$PWD/repos/foo/.git" rev-list --max-parents=0 HEAD) &&
- CGIT_CONFIG="$PWD/patchcountrc" QUERY_STRING="url=foo/patch&id=$id&id2=$root" cgit >tmp &&
+ root=$(git --git-dir="$PWD/repos/foo/.git" \
+ rev-list --max-parents=0 HEAD) &&
+ CGIT_CONFIG="$PWD/patchcountrc" \
+ QUERY_STRING="url=foo/patch&id=$id&id2=$root" cgit >tmp &&
test $(grep -c "^From " tmp) -eq 2
'
diff --git a/tests/t0110-snapshot.sh b/tests/t0110-snapshot.sh
index 9dc177f..9c8ce35 100755
--- a/tests/t0110-snapshot.sh
+++ b/tests/t0110-snapshot.sh
@@ -1,13 +1,10 @@
#!/bin/sh
-# The snapshot page hands a branch back as an archive. Every tar based format
-# goes through the same motions, fetch the archive, read its headers, prove
-# the compression is genuine, then unpack it and compare the files inside
-# against the repository the shared setup built, so one function below
-# registers those checks per format. cgit pipes each format through the
-# matching compressor on the server and this test needs the same program to
-# unpack, so one missing tool skips that format on both grounds at once. The
-# zip format follows at the end, since unzip shares no flags with the rest.
+# The snapshot page hands a branch back as an archive. One function below
+# registers the same checks for every tar based format, and each format
+# needs the same compressor cgit pipes through on the server, so one missing
+# tool skips that format on both grounds at once. zip follows at the end,
+# since unzip shares no flags with the rest.
test_description='Verify snapshot'
. ./setup.sh
diff --git a/tests/t0111-atom.sh b/tests/t0111-atom.sh
index d2a678b..6ffb5b0 100755
--- a/tests/t0111-atom.sh
+++ b/tests/t0111-atom.sh
@@ -1,11 +1,8 @@
#!/bin/sh
-# The atom page serves a repository's recent history as a feed, XML rather
-# than a page, so a reader can follow the project without polling the
-# browsable log. These checks read the content type, count the entries
-# against the max-atom-items cap, which defaults to ten, and hand the feed to
-# xmllint where one is installed, since a reader is far stricter about
-# well-formedness than any of the greps here.
+# The atom page serves recent history as a feed. The checks read the content
+# type, count the entries against the max-atom-items cap, and hand the feed
+# to xmllint where installed, a far stricter reader than any grep here.
test_description='Check the atom feed'
. ./setup.sh
diff --git a/tests/t0201-filters.sh b/tests/t0201-filters.sh
index 971ec36..a8341aa 100755
--- a/tests/t0201-filters.sh
+++ b/tests/t0201-filters.sh
@@ -49,13 +49,10 @@ do
grep "<committer@example.com> commit C O MITTER &LT;COMMITTER@EXAMPLE.COM&GT;" tmp
'
- # Page output is buffered, so whatever was written before a filter
- # opens has to leave the buffer before the filter takes over stdout,
- # and whatever was written while it was open has to leave before
- # stdout is handed back, since those bytes are meant for the filter.
- # A missed flush reorders the page rather than losing any of it,
- # so the two tests below confirm that the markup around the filtered
- # text is still on the side of it that it belongs on.
+ # Page output is buffered and has to be flushed as stdout is handed
+ # to a filter and back. A missed flush reorders the page rather than
+ # losing any of it, so the two tests below watch which side of the
+ # filtered text the surrounding markup lands on.
test_expect_success "the $prefix source filter output stays inside its cell" "
cgit_url 'filter-$prefix/tree/a%2bb' >tmp &&
tr -d '\n' <tmp >flat.out &&
diff --git a/tests/t0202-submodule-links.sh b/tests/t0202-submodule-links.sh
index bbd99b4..6db164f 100755
--- a/tests/t0202-submodule-links.sh
+++ b/tests/t0202-submodule-links.sh
@@ -1,11 +1,9 @@
#!/bin/sh
-# Submodule rows can derive their links from the .gitmodules entry at the
-# shown revision once enable-gitmodules-links is set. The url is matched
-# against the repositories this instance serves first, so ssh and relative
-# urls still land on an internal page, a plain web url is linked directly,
-# an ssh url to a known host is rewritten to its web form, and anything
-# else stays unlinked with the url offered as a tooltip.
+# Submodule rows derive their links from the .gitmodules entry at the shown
+# revision once enable-gitmodules-links is set, landing on an internal page,
+# a plain or rewritten web url, or an unlinked tooltip depending on the url.
+# Each of those outcomes is checked against a fixture .gitmodules.
test_description='Check submodule links derived from .gitmodules'
. ./setup.sh
diff --git a/tests/t0204-limits.sh b/tests/t0204-limits.sh
index 6591106..1195c93 100755
--- a/tests/t0204-limits.sh
+++ b/tests/t0204-limits.sh
@@ -1,13 +1,11 @@
#!/bin/sh
-# Checks the ceilings a config can put on a page, that is the caps on refs
-# listed, on the lines and the files a diff renders inline, and on the size
-# of a blob any view will inflate, along with the clamp on how long an index
-# query may be. Crossing one of these has to trim the page or point the
-# reader at somewhere better suited, never drop the request, so each case
-# watches what survives as closely as what is left out. The last case is the
-# same idea applied to a filter, which degrades to escaped text rather than
-# failing when its highlighting library is absent.
+# Checks the ceilings a config can put on a page, the caps on refs listed,
+# on the lines and files a diff renders inline, on the size of a blob any
+# view will inflate, and the clamp on index query length. Crossing one has
+# to trim the page or point somewhere better suited, never drop the request.
+# The last case is the same idea applied to a filter, which degrades to
+# escaped text when its highlighting library is absent.
test_description='Check the ref listing and diff size limits'
. ./setup.sh
diff --git a/tests/t0301-security.sh b/tests/t0301-security.sh
index 9a3af3c..2e5127c 100755
--- a/tests/t0301-security.sh
+++ b/tests/t0301-security.sh
@@ -2,10 +2,8 @@
# Collects the regression tests for the security fixes and for the behaviour
# this fork adds on top of upstream cgit. Each case builds the smallest
-# repository and config that reproduce the original problem and then asks for
-# the page that used to mishandle it. The comment above a case says what the
-# page is being defended against, because a request that looks ordinary is
-# usually the whole point of the attack.
+# repository and config that reproduce the original problem and then asks
+# for the page that used to mishandle it.
test_description='Check security fixes and fork-specific behavior'
. ./setup.sh
diff --git a/tests/t0502-syntax-highlight.sh b/tests/t0502-syntax-highlight.sh
index c7cbf89..a6e3fcb 100755
--- a/tests/t0502-syntax-highlight.sh
+++ b/tests/t0502-syntax-highlight.sh
@@ -1,13 +1,13 @@
#!/bin/sh
-# Checks syntax-highlight.lua, the shipped source-filter. The real
-# Scintillua collection is not assumed anywhere, because the fake lexer
-# module under extensions/fake-lexers drives every path through the
-# filter deterministically. The unit checks run twice per interpreter, once
-# with the fake lexers found and once with an empty directory so the escaped
-# fallback is what everything renders through. The run through cgit itself
-# places the fake lexers beside the config file, which is the probe the
-# filter documents for a scintillua directory next to cgitrc.
+# Checks syntax-highlight.lua, the shipped source-filter. The real Scintillua
+# collection is not assumed anywhere, because the fake lexer module under
+# extensions/fake-lexers drives every path through the filter
+# deterministically. The unit checks run twice per interpreter, once with the
+# fake lexers found and once with an empty directory so the escaped fallback
+# is what everything renders through. The run through cgit itself places the
+# fake lexers beside the config file, which is the probe the filter documents
+# for a scintillua directory next to cgitrc.
test_description='Check the shipped syntax-highlight extension'
CGIT_TEST_NO_CREATE_REPOS=YesPlease
diff --git a/tests/t0505-auth.sh b/tests/t0505-auth.sh
index d4dcd52..ca379de 100755
--- a/tests/t0505-auth.sh
+++ b/tests/t0505-auth.sh
@@ -1,15 +1,12 @@
#!/bin/sh
# Checks auth-file.lua and auth-inline.lua, the shipped auth filters, which
-# share their cookie signing, redirect vetting and action flows and differ
-# only in where accounts live. The unit checks under a standalone Lua meet
-# luaossl and luaposix with deterministic stand-ins from the harness, so
-# they prove this script's own logic on any machine, tampered and expired
-# cookies turned away, header injection stripped, unsafe redirects refused
-# and the login flows answering as documented. The run through cgit itself
-# needs the real modules inside the binary's own Lua, so it is probed for,
-# and an unedited copy protects nothing, which is itself the behaviour worth
-# proving end to end.
+# differ only in where accounts live. The unit checks meet luaossl and
+# luaposix with deterministic stand-ins from the harness, proving tampered
+# and expired cookies turned away, header injection stripped, unsafe
+# redirects refused and the login flows answering as documented. The run
+# through cgit itself needs the real modules inside the binary's own Lua, so
+# it is probed for, and proves an unedited copy protects nothing.
test_description='Check the shipped auth extensions'
CGIT_TEST_NO_CREATE_REPOS=YesPlease
diff --git a/tools/release-build.sh b/tools/release-build.sh
index 12f4260..0d9008f 100755
--- a/tools/release-build.sh
+++ b/tools/release-build.sh
@@ -1,17 +1,13 @@
#!/bin/sh
-# Build cgit for a release with Linux hardening flags. These are ELF and GCC
-# or Clang specific, so this targets a Linux deploy rather than local macOS
-# development, where a plain make is enough. The flags add a stack protector,
-# fortified libc calls, a position independent executable, and full RELRO. By
-# default Lua is pinned off so the binary needs no Lua at runtime, and running
-# it as ./tools/release-build.sh lua links in the backend behind the "lua:"
-# filter prefix instead, which needs a Lua dev package installed.
+# Build cgit for a release with Linux hardening flags, which are ELF and GCC or
+# Clang specific. The flags add a stack protector, fortified libc calls, a
+# position independent executable, and full RELRO. By default Lua is pinned off
+# so the binary needs no Lua at runtime, and running it as
+# ./tools/release-build.sh lua links in the backend behind the "lua:" filter
+# prefix instead, which needs a Lua dev package installed.
set -eu
-# The argument is checked rather than assumed, since anything unrecognised
-# would otherwise fall through to a quiet Lua-less build that looks like it
-# worked.
if [ "$#" -gt 1 ]; then
echo "usage: $0 [lua]" >&2
exit 2
@@ -23,8 +19,7 @@ lua) set -- ;;
exit 2 ;;
esac
-# Every make target below is written relative to the repository root, so go
-# there rather than requiring the caller to.
+# Every make target below is written relative to the repository root.
cd "$(dirname "$0")/.."
CC=${CC:-cc}
@@ -68,11 +63,9 @@ LDFLAGS="-pie \
# These reach only the cgit objects, so git's own sources are not held to them.
# -Wformat-security is an error because a non-literal format with no arguments
-# is never intentional. The shape that let a repository supply its own format
-# string through module-link was the other one, a non-literal that does take
-# arguments, and only -Wformat-nonliteral reports that, and that one is left out because it also fires
-# on forwarding a va_list and on local format constants, so it cannot be an
-# error without false positives. It is still worth running by hand when
+# is never intentional. -Wformat-nonliteral would catch the module-link shape,
+# a non-literal that does take arguments, but it also fires on va_list
+# forwarding and on local format constants, so it is left to manual runs when
# touching anything that formats.
#
# make cgit CGIT_EXTRA_CFLAGS=-Wformat-nonliteral
diff --git a/tools/serve.py b/tools/serve.py
index 2b2f045..a39d03f 100755
--- a/tools/serve.py
+++ b/tools/serve.py
@@ -29,8 +29,20 @@ REPO_ROOT = Path(__file__).resolve().parent.parent
MAX_BODY_BYTES = 8 * 1024 * 1024
CGI_TIMEOUT = 60
-STATIC_SUFFIXES = (".css", ".js", ".png", ".ico", ".gif", ".jpg", ".jpeg",
- ".svg", ".webp", ".txt", ".woff", ".woff2")
+STATIC_SUFFIXES = (
+ ".css",
+ ".js",
+ ".png",
+ ".ico",
+ ".gif",
+ ".jpg",
+ ".jpeg",
+ ".svg",
+ ".webp",
+ ".txt",
+ ".woff",
+ ".woff2",
+)
# The request headers cgit looks at, paired with the CGI variable each one
# has to arrive as.
@@ -273,8 +285,11 @@ def main() -> None:
config = Path(options.config).resolve()
cgit = Path(options.cgit).resolve()
data_dir = Path(options.data).resolve()
- for label, path in (("config", config), ("cgit binary", cgit),
- ("data directory", data_dir)):
+ for label, path in (
+ ("config", config),
+ ("cgit binary", cgit),
+ ("data directory", data_dir),
+ ):
if not path.exists():
sys.exit(f"error: {label} not found: {path}")