diff options
| -rw-r--r-- | cgit/cgitrc | 32 | ||||
| -rwxr-xr-x | cgit/filters/about.sh | 5 | ||||
| -rwxr-xr-x | cgit/filters/html-transform.py | 83 | ||||
| -rw-r--r-- | cgit/nginx.conf | 35 | ||||
| -rw-r--r-- | cgit/static/cgit.css | 54 | ||||
| -rw-r--r-- | docker-compose.yml | 89 |
6 files changed, 237 insertions, 61 deletions
diff --git a/cgit/cgitrc b/cgit/cgitrc index bed622c..935192c 100644 --- a/cgit/cgitrc +++ b/cgit/cgitrc @@ -5,10 +5,24 @@ root-readme=/usr/share/webapps/cgit/ediblemonad/README.md # Theme css=/ediblemonad/cgit.css logo=/ediblemonad/logo.png -head-include=/usr/share/webapps/cgit/ediblemonad/head.html +favicon=/favicon.ico +head-include=/usr/share/webapps/cgit/ediblemonad/header.html +# footer= TODO: override footer + +# TODO: submodule links +# module-link=/cgit/submodule/%s/commit?id=%s source-filter=/usr/lib/cgit/filters/syntax-highlighting.py -about-filter=/usr/lib/cgit/filters/about-formatting.sh +about-filter=/usr/lib/cgit/filters/ediblemonad/about.sh + +# Mimetypes for plain files +mimetype.gif=image/gif +mimetype.html=text/html +mimetype.jpg=image/jpeg +mimetype.jpeg=image/jpeg +mimetype.pdf=application/pdf +mimetype.png=image/png +mimetype.svg=image/svg+xml # Search for these files in the root of the default branch of repositories # for coming up with the about page: @@ -43,17 +57,25 @@ readme=:install # Cache cache-root=/var/cache/cgit -cache-size=2000 +cache-size=0 -enable-index-links=1 +enable-index-links=0 enable-index-owner=0 enable-remote-branches=1 enable-log-filecount=1 enable-log-linecount=1 +enable-tree-linenumbers=1 enable-git-config=1 +enable-commit-graph=1 +enable-follow-links=1 +enable-http-clone=1 +enable-html-serving=1 snapshots=tar.xz zip +remove-suffix=1 +repository-sort=age +# side-by-side-diffs=1 -robots=noindex, nofollow +robots=index, nofollow virtual-root=/ section-from-path=0 max-repo-count=50 diff --git a/cgit/filters/about.sh b/cgit/filters/about.sh new file mode 100755 index 0000000..e8554b0 --- /dev/null +++ b/cgit/filters/about.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env sh +# About content filter + +/usr/lib/cgit/filters/about-formatting.sh "$@" | /usr/lib/cgit/filters/ediblemonad/html-transform.py + diff --git a/cgit/filters/html-transform.py b/cgit/filters/html-transform.py new file mode 100755 index 0000000..9fc7aec --- /dev/null +++ b/cgit/filters/html-transform.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 +# Rewrite image urls in about section + +import sys +from html.parser import HTMLParser +import html +from urllib.parse import urljoin, urlparse +import re + +def is_absolute_url(url): + if not url: return False + parsed = urlparse(url) + return bool(parsed.netloc or parsed.scheme) + +def is_relative_path(url): + if not url: return False + return not url.startswith("/") and not is_absolute_url(url) + +def linkify(text, make_link): + url_pattern = r'(?<!\S)(https?://\S+?)([.,!?;:]?(?=\s|$))' + def replace(m): + url, trail = m.group(1), m.group(2) + return make_link(url) + trail + return re.sub(url_pattern, replace, text) + +class LinkRewriter(HTMLParser): + def __init__(self): + super().__init__(convert_charrefs=False) + self.output = [] + + def get_html(self): + return "".join(self.output) + + def _build_tag(self, tag, attrs, self_closing = False): + new_tag = tag + attr_map = {} + for name, value in attrs: + if name in ("href", "src") and is_relative_path(value) and not value.startswith('#'): + if tag == 'a': + value = "../" + urljoin("tree/", value) + else: + value = "../" + urljoin("plain/", value) + attr_map[name] = value + # Open in new tab + if tag == "a" and name == "href" and is_absolute_url(value): + if not 'target' in attr_map: attr_map['target'] = '_blank _parent' + if not 'rel' in attr_map: attr_map['rel'] = 'noopener' + + attr_str = "".join( + f' {name}="{html.escape(value, quote=True)}"' if value is not None else f" {name}" + for name, value in attr_map.items() + ) + return f"<{new_tag}{attr_str}{' /' if self_closing else ''}>" + + def handle_starttag(self, tag, attrs): + self.output.append(self._build_tag(tag, attrs)) + + def handle_startendtag(self, tag, attrs): + self.output.append(self._build_tag(tag, attrs, self_closing=True)) + + def handle_endtag(self, tag): + self.output.append(f"</{tag}>") + + def handle_data(self, data): + data_with_links = linkify(data, + lambda url: self._build_tag("a", [('href', url)]) + html.escape(url) + "</a>") + self.output.append(data_with_links) + + def handle_entityref(self, name): + self.output.append(f"&{name};") + + def handle_charref(self, name): + self.output.append(f"&#{name};") + + def handle_comment(self, data): + self.output.append(f"<!--{data}-->") + +html_in = sys.stdin.read() + +parser = LinkRewriter() +parser.feed(html_in) + +print(parser.get_html()) diff --git a/cgit/nginx.conf b/cgit/nginx.conf new file mode 100644 index 0000000..a850744 --- /dev/null +++ b/cgit/nginx.conf @@ -0,0 +1,35 @@ +server { + listen 80; + server_name localhost; + root /usr/share/webapps/cgit; + + location / { + try_files $uri @cgit; + } + + location ~* ^.+(favicon.ico|robots.txt) { + root /usr/share/webapps/cgit; + expires 30d; + } + + location @cgit { + include /etc/nginx/fastcgi_params; + fastcgi_param SCRIPT_FILENAME $document_root/cgit.cgi; + fastcgi_param PATH_INFO $uri; + fastcgi_param QUERY_STRING $args; + fastcgi_param HTTP_HOST $server_name; + fastcgi_pass unix:/var/run/fcgiwrap.sock; + } + + error_page 404 /404.html; + error_page 401 /401.html; + + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } + + location ~ /\.ht { + deny all; + } +} diff --git a/cgit/static/cgit.css b/cgit/static/cgit.css index a57fa9a..8da6a9e 100644 --- a/cgit/static/cgit.css +++ b/cgit/static/cgit.css @@ -9,9 +9,12 @@ html, body { input[type=search], input[type=text], select { background-color: #111; - color: var(--color-accent); + color: #eee; border: 1px solid #333; } +select { + color: var(--color-accent); +} div#cgit button, div#cgit input[type=submit] { background-color: #111; @@ -978,6 +981,15 @@ div#cgit table.ssdiff td.space div { #cgit a.toclink { color: white !important; } +#cgit .markdown-body h1, +#cgit .markdown-body h2, +#cgit .markdown-body h3, +#cgit .markdown-body h4, +#cgit .markdown-body h5, +#cgit .markdown-body h6 { + /*border-bottom: 1px solid #222;*/ + border: none; +} #cgit .markdown-body pre { background: #111; border: 1px solid #222; @@ -989,20 +1001,40 @@ div#cgit table.ssdiff td.space div { background: #222; border: none; } +#cgit .markdown-body table tr, +#cgit .markdown-body table th, +#cgit .markdown-body table td { + background: transparent; + border: 1px solid #333; +} +#cgit .markdown-body table img { + display: block; + margin: 0 auto; +} -#cgit .markdown-body pre code > span { +#cgit .highlight pre span { background: transparent !important; } +#cgit .markdown-body hr { + background: none; + border-top: 1px solid #222; + height: 1rem; + margin: 1rem 1rem 0; +} /* BuiltIn */ -#cgit .highlight span.cp { +#cgit .highlight span[class^=c] { color: #006060; font-weight: bold; } -#cgit .highlight span.k, #cgit .highlight span.kr { +#cgit .highlight span[class^=k] { color: #006060; font-weight: bold; } +#cgit .highlight span[class^=b] { + color: #bbeeee; + font-weight: bold; +} /* Err */ #cgit .highlight span.err { @@ -1010,23 +1042,15 @@ div#cgit table.ssdiff td.space div { } /* Variables */ -#cgit .highlight span.n { - color: #eee; -} - -/* Func */ -#cgit .highlight span.nb { - color: #eee; -} -#cgit .highlight span.nf { +#cgit .highlight span[class^=n] { color: #eee; } /* Literal */ -#cgit .highlight span.mi, #cgit .highlight span.mf { /* Num */ +#cgit .highlight span[class^=m] { /* Num */ color: #607020; } -#cgit .highlight span.s { /* Str */ +#cgit .highlight span[class^=s] { /* Str */ color: #71d2ae; background-color: transparent; } diff --git a/docker-compose.yml b/docker-compose.yml index 0216d9d..f8316af 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,37 +1,4 @@ services: - nginx-proxy: - profiles: [core] - container_name: nginx-proxy - image: 'jwilder/nginx-proxy:alpine' - restart: always - ports: - - '80:80' - - '443:443' - environment: - - DEFAULT_HOST=ediblemonad.dev - - HSTS=off - volumes: - - /var/run/docker.sock:/tmp/docker.sock:ro - - proxy-certs:/etc/nginx/certs:ro - - proxy-vhost:/etc/nginx/vhost.d - - proxy-html:/usr/share/nginx/html - - proxy-letsencrypt: - profiles: [core] - image: 'nginxproxy/acme-companion' - restart: always - environment: - - DEFAULT_EMAIL=ediblemonad@gmail.com - - NGINX_PROXY_CONTAINER=nginx-proxy - - NGINX_DOCKER_GEN_CONTAINER=nginx-proxy - - ACME_CA_URI=https://acme-staging-v02.api.letsencrypt.org/directory - volumes: - - /var/run/docker.sock:/var/run/docker.sock:ro - - proxy-certs:/etc/nginx/certs - - proxy-vhost:/etc/nginx/vhost.d - - proxy-html:/usr/share/nginx/html - - acme:/etc/acme.sh - send: profiles: [services] image: 'registry.gitlab.com/timvisee/send:v3.4.27' @@ -39,7 +6,7 @@ services: ports: - '1234:1234' volumes: - - ./uploads:/uploads + - /uploads:/uploads environment: - VIRTUAL_PORT=1234 - VIRTUAL_HOST=send.ediblemonad.dev @@ -60,27 +27,67 @@ services: depends_on: - redis - redis: - profiles: [services] - image: 'redis:alpine' - restart: always - volumes: - - redis:/data - cgit: profiles: [services] image: 'joseluisq/alpine-cgit:2.9' + restart: always ports: - 8080:80 environment: + - VIRTUAL_PORT=80 + - VIRTUAL_HOST=git.ediblemonad.dev + - LETSENCRYPT_HOST=git.ediblemonad.dev + - DHPARAM_GENERATION=false - USE_CUSTOM_CONFIG=true volumes: - cgit-cache:/var/cache/cgit - /home/imsohexy/dev/projects:/srv/git:ro - ./cgit/cgitrc:/etc/cgitrc:ro - ./cgit/static:/usr/share/webapps/cgit/ediblemonad:ro + - ./cgit/nginx.conf:/etc/nginx/conf.d/default.conf:ro + - ./cgit/filters:/usr/lib/cgit/filters/ediblemonad:ro - ./favicon.ico:/usr/share/webapps/cgit/favicon.ico:ro + nginx-proxy: + profiles: [core] + container_name: nginx-proxy + image: 'jwilder/nginx-proxy:alpine' + restart: always + ports: + - '80:80' + - '443:443' + environment: + - DEFAULT_HOST=ediblemonad.dev + - HSTS=off + volumes: + - /var/run/docker.sock:/tmp/docker.sock:ro + - proxy-certs:/etc/nginx/certs:ro + - proxy-vhost:/etc/nginx/vhost.d + - proxy-html:/usr/share/nginx/html + + proxy-letsencrypt: + profiles: [core] + image: 'nginxproxy/acme-companion' + restart: always + environment: + - DEFAULT_EMAIL=ediblemonad@gmail.com + - NGINX_PROXY_CONTAINER=nginx-proxy + - NGINX_DOCKER_GEN_CONTAINER=nginx-proxy + - ACME_CA_URI=https://acme-staging-v02.api.letsencrypt.org/directory + volumes: + - /var/run/docker.sock:/var/run/docker.sock:ro + - proxy-certs:/etc/nginx/certs + - proxy-vhost:/etc/nginx/vhost.d + - proxy-html:/usr/share/nginx/html + - acme:/etc/acme.sh + + redis: + profiles: [services] + image: 'redis:alpine' + restart: always + volumes: + - redis:/data + volumes: redis: cgit-cache: |
