aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore5
-rw-r--r--Makefile58
-rw-r--r--README.md68
-rw-r--r--config.example.scfg40
-rw-r--r--contrib/Dockerfile35
-rw-r--r--contrib/config.docker.scfg7
-rw-r--r--contrib/docker-compose.yaml14
-rw-r--r--go.mod44
-rw-r--r--go.sum179
-rw-r--r--main.go71
-rw-r--r--pkg/config/config.go219
-rw-r--r--pkg/config/config_test.go53
-rw-r--r--pkg/ext/auth.go85
-rw-r--r--pkg/ext/compression.go31
-rw-r--r--pkg/ext/log.go4
-rw-r--r--pkg/ext/request.go14
-rw-r--r--pkg/ext/router.go42
-rw-r--r--pkg/git/git.go265
-rw-r--r--pkg/handler/about/handler.go5
-rw-r--r--pkg/handler/auth/login.go97
-rw-r--r--pkg/handler/config/handler.go63
-rw-r--r--pkg/handler/git/handler.go193
-rw-r--r--pkg/handler/router.go23
-rw-r--r--pkg/handler/static/handler.go4
-rw-r--r--pkg/humanize/times.go141
-rw-r--r--pkg/service/auth.go123
-rw-r--r--pkg/service/auth_test.go119
-rw-r--r--pkg/service/git.go87
-rw-r--r--pkg/u/list.go22
-rw-r--r--scss/main.scss204
-rw-r--r--scss/tree.scss134
-rw-r--r--templates/about.qtpl11
-rw-r--r--templates/about.qtpl.go180
-rw-r--r--templates/base.qtpl39
-rw-r--r--templates/base.qtpl.go156
-rw-r--r--templates/commit.qtpl24
-rw-r--r--templates/commit.qtpl.go204
-rw-r--r--templates/config.qtpl19
-rw-r--r--templates/config.qtpl.go165
-rw-r--r--templates/error.qtpl10
-rw-r--r--templates/error.qtpl.go177
-rw-r--r--templates/gititem.qtpl10
-rw-r--r--templates/gititem.qtpl.go199
-rw-r--r--templates/gititemabout.qtpl.go72
-rw-r--r--templates/gititemblob.qtpl.go110
-rw-r--r--templates/gititemcommit.qtpl8
-rw-r--r--templates/gititemcommit.qtpl.go86
-rw-r--r--templates/gititemlog.qtpl8
-rw-r--r--templates/gititemlog.qtpl.go112
-rw-r--r--templates/gititemref.qtpl34
-rw-r--r--templates/gititemref.qtpl.go171
-rw-r--r--templates/gititemrefs.qtpl.go112
-rw-r--r--templates/gititemsummary.qtpl5
-rw-r--r--templates/gititemsummary.qtpl.go143
-rw-r--r--templates/gititemtree.qtpl7
-rw-r--r--templates/gititemtree.qtpl.go189
-rw-r--r--templates/gitlist.qtpl37
-rw-r--r--templates/gitlist.qtpl.go286
-rw-r--r--templates/login.qtpl46
-rw-r--r--templates/login.qtpl.go217
-rw-r--r--templates/navbar.qtpl19
-rw-r--r--templates/navbar.qtpl.go234
-rw-r--r--templates/tags.qtpl2
-rw-r--r--templates/tags.qtpl.go114
64 files changed, 3871 insertions, 1784 deletions
diff --git a/.gitignore b/.gitignore
index 776d7a2..541ad56 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,5 @@
-bin/
+# css output
static/*.css
+
+# bin output
+cerrado
diff --git a/Makefile b/Makefile
index 068f872..d214a85 100644
--- a/Makefile
+++ b/Makefile
@@ -1,31 +1,47 @@
-SLUG ?= $(shell git rev-parse --short HEAD)
-LDFLAGS := "-X 'git.gabrielgio.me/cerrado/templates.Slug=.$(SLUG)' -s -w"
+GIT_COMMIT ?= $(shell git rev-parse --short HEAD)
+LDFLAGS := "-X 'git.gabrielgio.me/cerrado/templates.Slug=.$(GIT_COMMIT)' -s -w"
+GO_SRC := $(shell find . -name '*.go')
-build: sass-slug tmpl
- go build \
- -ldflags=$(LDFLAGS) \
- -o bin/cerrado
+BIN ?= cerrado
+PREFIX ?= /usr/local
+BINDIR ?= $(PREFIX)/bin
+
+TEMPLATES_DIR := templates
+TEMPLATES := $(wildcard $(TEMPLATES_DIR)/*.qtpl)
+GO_TEMPLATES_FILES := $(TEMPLATES:.qtpl=.qtpl.go)
+
+SASS_DIR := scss
+CSS_DIR := static
+OUTPUT_CSS := $(CSS_DIR)/main.$(GIT_COMMIT).css
+SASS_FILES := $(wildcard $(SASS_DIR)/*.scss)
+
+build: $(BIN)
+
+$(BIN): $(GO_SRC) $(OUTPUT_CSS) $(GO_TEMPLATES_FILES)
+ go build -ldflags=$(LDFLAGS) -o $(BIN)
+
+install:
+ install -Dm755 $(BIN) $(BINDIR)/$(BIN)
run: sass tmpl
- go run .
+ go run -ldflags=$(LDFLAGS) .
test:
go test -v --tags=unit ./...
-# this is meant for "prod" build
-sass-slug:
- mkdir -p static
- sassc \
- --style compressed \
- -I scss scss/main.scss static/main.$(SLUG).css
+sass: $(OUTPUT_CSS)
+
+$(OUTPUT_CSS): $(SASS_FILES)
+ @mkdir -p $(CSS_DIR)
+ sassc --style compressed $(SASS_DIR)/main.scss $(OUTPUT_CSS)
+
+tmpl: $(GO_TEMPLATES_FILES)
-sass:
- mkdir -p static
- sassc \
- -I scss scss/main.scss static/main.css
+$(TEMPLATES_DIR)/%.qtpl.go: $(TEMPLATES_DIR)/%.qtpl
+ qtc $(TEMPLATES_DIR)/$*.qtpl
-tmpl:
- cd ./templates && \
- qtc *
+clean:
+ -rm $(OUTPUT_CSS)
+ -rm $(BIN)
-.PHONY: sass
+.PHONY: sass tmpl
diff --git a/README.md b/README.md
index f6e202a..0954b92 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,10 @@
### Cerrado
-Self host single user mail based forge.
+Self host single user forge.
+
+You can find a running instance here:
+
+https://beta.gabrielgio.me
### Goals
@@ -17,24 +21,64 @@ Easy to read code is better than clever.
The deployment process should be easy to wrap the head around and
straightforward to set up. To achieve that it uses a simple file format[^1] to
configure everything. Also to reduce the moving parts the whole application,
-including its statics file, is bundled into a single binary.
+including its statics files, is bundled into a single binary.
+
+To run the project you just need to `make run`.
+
+### Installations
+
+One installation process available is through my apk repository[^2][^3].
+
+You could also run:
+
+```sh
+make
+make install
+```
+
+Or you could also pick another prefix:
-To run the project you just need to do a make run.
+```sh
+PREFIX=$HOME/.local/ make install
+```
-### TODO
+You can check openrc files for the details how it is run with a init system,
+but in general you'd need the cerrado binary and scfg file, which can easily be
+integrated with systemd.
-- Impove diff display
-- Add log pagination
-- Fix submodule link on tree view
+### Contributing
-### Milestone
-- Mail patch / mailing list
+To discuss about the project send me a email or write an issue on codeberg[^4].
+To avoid duplicated work or to work something I might not take in, I'd
+recommend to reach me before doing something.
+
+To contribute code feel free to create a PR on codeberg or send me an
+email-patch[^5].
+
+My email:
+
+mail@gabrielgio.me
+
+### Missing for 1.0
+
+- Git clone support: that is very important feature for a git forge.
+- Dark mode support: in the same way as mobile support this should be supported
+ from the get go. I have slacked on this one but it should be done before 1.0.
+- Some rework on summary page: it is feels a bit crude as it is.
+
+### Ideas
- Code snippet support
- Setup manual (man feature perhaps?)
-- Add authentication
- - Enforce public property
- Add metrics
- Add reference based cache system. Cerrado should be able to cache the whole
- page based on its reference hash.
+ page based on its reference hash
+
+### Future
+- Mail patch / mailing list. This is very complex endeavour. In a distant
+ future I might do it, but for now I will focus on the features listed above.
[^1]: https://git.sr.ht/~emersion/scfg
+[^2]: https://apkdoc.gabrielgio.me/
+[^3]: https://git.gabrielgio.me/apkbuilds/
+[^4]: https://codeberg.org/gabrielgio/cerrado/issues
+[^5]: https://git-send-email.io/
diff --git a/config.example.scfg b/config.example.scfg
index 9de249b..5e47548 100644
--- a/config.example.scfg
+++ b/config.example.scfg
@@ -3,17 +3,51 @@
listen-addr unix://var/run/cerrado.sock
root-readme /srv/git/README.md
+syntax-highlight monokailight
-scan /srv/git/ {
- public true
-}
+# full hostname address plus protocol.
+# This is going to be used to display full link (e.g.: clone link)
+hostname https://domain.tld
+
+# if passphrase is empty the whole authentication, private/public repository
+# and login UI will be disabled, and only public repository will be displayed.
+passphrase $2a$14$VnB/ZcB1DUDkMnosRA6Y7.dj8h5eroslDxTeXlLwfQX/x86mh6WAq
+aes-key 8XHptZxSWCGs1m7QzztX5zNQ7D9NiQevVX0DaUTNMbDpRwFzoJiB0U7K6O/kqIt01jJVgzBUfiR8ES46ZLLb4w==
+
+# order of the list of repository, values:
+# unordered
+# alphabetical-asc
+# alphabetical-desc
+# lastcommit-asc
+# lastcommit-desc
+# default: unordered
+order-by lastcommit-asc
+
+# removes ".git" suffix from the name of the repository.
+# default: false
+remove-suffix true
+# repository section is order dependent where the first repository has priority
+# in case of conflict. Repository has also priority over scan. The order
+# between scan and repository is irrelevant which means that all repository
+# sections will be read first then all the scans.
repository /srv/git/cerrado.git {
name cerrado
description "Self host single person forge"
public true
}
+# scan is order dependent where first scan has priority in case of conflict. So
+# if you add another scan section bellow that scan the same folders it will be
+# ignored.
+scan /srv/git/private {
+ public false
+}
+
+scan /srv/git/ {
+ public true
+}
+
# TBD
#user admin:iKlvHe1g0UoXE
#
diff --git a/contrib/Dockerfile b/contrib/Dockerfile
new file mode 100644
index 0000000..d2e3056
--- /dev/null
+++ b/contrib/Dockerfile
@@ -0,0 +1,35 @@
+# syntax=docker/dockerfile:1
+
+FROM golang:1.22-alpine AS builder
+RUN apk add --no-cache git make sassc
+
+WORKDIR /build
+
+# Download Git submodules
+COPY .git ./.git
+RUN git submodule update --init --recursive
+
+# Download Go modules
+COPY go.mod go.sum ./
+RUN go mod download
+RUN go mod verify
+
+# Transfer source code
+COPY Makefile .
+COPY scss ./scss
+COPY static ./static
+COPY templates ./templates
+COPY *.go ./
+COPY pkg ./pkg
+
+# Build
+RUN make
+
+FROM scratch AS build-release-stage
+
+WORKDIR /app
+
+COPY --from=builder /build/cerrado .
+COPY contrib/config.docker.scfg /etc/cerrado.scfg
+
+ENTRYPOINT ["./cerrado"]
diff --git a/contrib/config.docker.scfg b/contrib/config.docker.scfg
new file mode 100644
index 0000000..64b1bff
--- /dev/null
+++ b/contrib/config.docker.scfg
@@ -0,0 +1,7 @@
+listen-addr tcp://:8080
+
+root-readme /srv/git/README.md
+
+scan /srv/git/ {
+ public true
+}
diff --git a/contrib/docker-compose.yaml b/contrib/docker-compose.yaml
new file mode 100644
index 0000000..5de7863
--- /dev/null
+++ b/contrib/docker-compose.yaml
@@ -0,0 +1,14 @@
+name: cerrado
+
+services:
+ app:
+ container_name: cerrado
+ restart: unless-stopped
+ build:
+ context: ../
+ dockerfile: contrib/Dockerfile
+ ports:
+ - "8080:8080"
+ volumes:
+ - /srv/git:/srv/git # set your scan folder here
+ # - ./config.scfg:/etc/cerrado.scfg:ro # load a custom config file
diff --git a/go.mod b/go.mod
index cc63e5d..3ba555f 100644
--- a/go.mod
+++ b/go.mod
@@ -3,39 +3,37 @@ module git.gabrielgio.me/cerrado
go 1.22.2
require (
- git.sr.ht/~emersion/go-scfg v0.0.0-20240128091534-2ae16e782082
- github.com/alecthomas/chroma/v2 v2.13.0
- github.com/andybalholm/brotli v1.1.0
- github.com/go-git/go-git/v5 v5.12.0
- github.com/gomarkdown/markdown v0.0.0-20240419095408-642f0ee99ae2
+ git.sr.ht/~emersion/go-scfg v0.0.0-20250102010123-2f3fb2d5d50e
+ github.com/alecthomas/chroma/v2 v2.15.0
+ github.com/andybalholm/brotli v1.1.1
+ github.com/go-git/go-git/v5 v5.13.2
+ github.com/gomarkdown/markdown v0.0.0-20250207164621-7a1f277a159e
github.com/google/go-cmp v0.6.0
- github.com/klauspost/compress v1.17.8
- github.com/valyala/quicktemplate v1.7.0
- golang.org/x/sync v0.7.0
+ github.com/klauspost/compress v1.17.11
+ github.com/valyala/quicktemplate v1.8.0
+ golang.org/x/crypto v0.33.0
+ golang.org/x/sync v0.11.0
)
require (
- dario.cat/mergo v1.0.0 // indirect
- github.com/Microsoft/go-winio v0.6.1 // indirect
- github.com/ProtonMail/go-crypto v1.0.0 // indirect
- github.com/cloudflare/circl v1.3.7 // indirect
- github.com/cyphar/filepath-securejoin v0.2.4 // indirect
- github.com/dlclark/regexp2 v1.11.0 // indirect
+ dario.cat/mergo v1.0.1 // indirect
+ github.com/Microsoft/go-winio v0.6.2 // indirect
+ github.com/ProtonMail/go-crypto v1.1.5 // indirect
+ github.com/cloudflare/circl v1.6.0 // indirect
+ github.com/cyphar/filepath-securejoin v0.4.1 // indirect
+ github.com/dlclark/regexp2 v1.11.4 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
- github.com/go-git/go-billy/v5 v5.5.0 // indirect
- github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
+ github.com/go-git/go-billy/v5 v5.6.2 // indirect
+ github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
- github.com/pjbgf/sha1cd v0.3.0 // indirect
+ github.com/pjbgf/sha1cd v0.3.2 // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
- github.com/skeema/knownhosts v1.2.2 // indirect
+ github.com/skeema/knownhosts v1.3.1 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
- golang.org/x/crypto v0.21.0 // indirect
- golang.org/x/mod v0.12.0 // indirect
- golang.org/x/net v0.22.0 // indirect
- golang.org/x/sys v0.18.0 // indirect
- golang.org/x/tools v0.13.0 // indirect
+ golang.org/x/net v0.34.0 // indirect
+ golang.org/x/sys v0.30.0 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
)
diff --git a/go.sum b/go.sum
index f010dc9..59c8d96 100644
--- a/go.sum
+++ b/go.sum
@@ -1,56 +1,70 @@
-dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
-dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
+dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
+dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
git.sr.ht/~emersion/go-scfg v0.0.0-20240128091534-2ae16e782082 h1:9Udx5fm4vRtmgDIBjy2ef5QioHbzpw5oHabbhpAUyEw=
git.sr.ht/~emersion/go-scfg v0.0.0-20240128091534-2ae16e782082/go.mod h1:ybgvEJTIx5XbaspSviB3KNa6OdPmAZqDoSud7z8fFlw=
+git.sr.ht/~emersion/go-scfg v0.0.0-20250102010123-2f3fb2d5d50e h1:dKdXdn8yhldnz8ynz/HNmLPk40tvTwDBsTdQcHddesg=
+git.sr.ht/~emersion/go-scfg v0.0.0-20250102010123-2f3fb2d5d50e/go.mod h1:7eWdbNLaP10M+QMSmmHYmYd8q86NHZy12Cq9TiZ9LC8=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
-github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow=
-github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM=
-github.com/ProtonMail/go-crypto v1.0.0 h1:LRuvITjQWX+WIfr930YHG2HNfjR1uOfyf5vE0kC2U78=
-github.com/ProtonMail/go-crypto v1.0.0/go.mod h1:EjAoLdwvbIOoOQr3ihjnSoLZRtE8azugULFRteWMNc0=
-github.com/alecthomas/assert/v2 v2.6.0 h1:o3WJwILtexrEUk3cUVal3oiQY2tfgr/FHWiz/v2n4FU=
-github.com/alecthomas/assert/v2 v2.6.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
-github.com/alecthomas/chroma/v2 v2.13.0 h1:VP72+99Fb2zEcYM0MeaWJmV+xQvz5v5cxRHd+ooU1lI=
-github.com/alecthomas/chroma/v2 v2.13.0/go.mod h1:BUGjjsD+ndS6eX37YgTchSEG+Jg9Jv1GiZs9sqPqztk=
+github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
+github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
+github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk=
+github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
+github.com/ProtonMail/go-crypto v1.1.5 h1:eoAQfK2dwL+tFSFpr7TbOaPNUbPiJj4fLYwwGE1FQO4=
+github.com/ProtonMail/go-crypto v1.1.5/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE=
+github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE=
+github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
+github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
+github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E=
+github.com/alecthomas/chroma/v2 v2.14.0/go.mod h1:QolEbTfmUHIMVpBqxeDnNBj2uoeI4EbYP4i6n68SG4I=
+github.com/alecthomas/chroma/v2 v2.15.0 h1:LxXTQHFoYrstG2nnV9y2X5O94sOBzf0CIUpSTbpxvMc=
+github.com/alecthomas/chroma/v2 v2.15.0/go.mod h1:gUhVLrPDXPtp/f+L1jo9xepo9gL4eLwRuGAunSZMkio=
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
-github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
-github.com/andybalholm/brotli v1.0.3/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
-github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
-github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
+github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
+github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
-github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
-github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
-github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
-github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
-github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53EtKeQYTC3kyg=
-github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
+github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys=
+github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
+github.com/cloudflare/circl v1.6.0 h1:cr5JKic4HI+LkINy2lg3W2jF8sHCVTBncJr5gIIq7qk=
+github.com/cloudflare/circl v1.6.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs=
+github.com/cyphar/filepath-securejoin v0.3.5 h1:L81NHjquoQmcPgXcttUS9qTSR/+bXry6pbSINQGpjj4=
+github.com/cyphar/filepath-securejoin v0.3.5/go.mod h1:edhVd3c6OXKjUmSrVa/tGJRS9joFTxlslFCAyaxigkE=
+github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s=
+github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
-github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
+github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo=
+github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a h1:mATvB/9r/3gvcejNsXKSkQ6lcIaNec2nyfOdlTBR2lU=
github.com/elazarl/goproxy v0.0.0-20230808193330-2592e75ae04a/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
+github.com/elazarl/goproxy v1.4.0 h1:4GyuSbFa+s26+3rmYNSuUVsx+HgPrV1bk1jXI0l9wjM=
github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE=
github.com/gliderlabs/ssh v0.3.7/go.mod h1:zpHEXBstFnQYtGnB8k8kQLol82umzn/2/snG7alWVD8=
+github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
-github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU=
-github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow=
+github.com/go-git/go-billy/v5 v5.6.0 h1:w2hPNtoehvJIxR00Vb4xX94qHQi/ApZfX+nBE2Cjio8=
+github.com/go-git/go-billy/v5 v5.6.0/go.mod h1:sFDq7xD3fn3E0GOwUSZqHo9lrkmx8xJhA0ZrfvjBRGM=
+github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM=
+github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4=
github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII=
github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
-github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
-github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
-github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/gomarkdown/markdown v0.0.0-20240419095408-642f0ee99ae2 h1:yEt5djSYb4iNtmV9iJGVday+i4e9u6Mrn5iP64HH5QM=
-github.com/gomarkdown/markdown v0.0.0-20240419095408-642f0ee99ae2/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
+github.com/go-git/go-git/v5 v5.13.2 h1:7O7xvsK7K+rZPKW6AQR1YyNhfywkv7B8/FsP3ki6Zv0=
+github.com/go-git/go-git/v5 v5.13.2/go.mod h1:hWdW5P4YZRjmpGHwRH2v3zkWcNl6HeXaXQEMGb3NJ9A=
+github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
+github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
+github.com/gomarkdown/markdown v0.0.0-20241205020045-f7e15b2f3e62 h1:pbAFUZisjG4s6sxvRJvf2N7vhpCvx2Oxb3PmS6pDO1g=
+github.com/gomarkdown/markdown v0.0.0-20241205020045-f7e15b2f3e62/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
+github.com/gomarkdown/markdown v0.0.0-20250207164621-7a1f277a159e h1:ESHlT0RVZphh4JGBz49I5R6nTdC8Qyc08vU25GQHzzQ=
+github.com/gomarkdown/markdown v0.0.0-20250207164621-7a1f277a159e/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
@@ -59,10 +73,8 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
-github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
-github.com/klauspost/compress v1.13.5/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
-github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU=
-github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
+github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
+github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
@@ -70,21 +82,26 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/onsi/gomega v1.27.10 h1:naR28SdDFlqrG6kScpT8VWpu1xWY5nJRCF3XaYyBjhI=
-github.com/onsi/gomega v1.27.10/go.mod h1:RsS8tutOdbdgzbPtzzATp12yT7kM5I5aElG3evPbQ0M=
+github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k=
+github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY=
github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
+github.com/pjbgf/sha1cd v0.3.2 h1:a9wb0bp1oC2TGwStyn0Umc/IGKQnEgF0vVaZ8QF8eo4=
+github.com/pjbgf/sha1cd v0.3.2/go.mod h1:zQWigSxVmsHEZow5qaLtPYxpcKMMQpa09ixqBxuCS6A=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
+github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8=
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A=
-github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo=
+github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY=
+github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M=
+github.com/skeema/knownhosts v1.3.1 h1:X2osQ+RAjK76shCbvhHHHVl3ZlgDm8apHEHFqRjnBY8=
+github.com/skeema/knownhosts v1.3.1/go.mod h1:r7KTdC8l4uxWRyK2TpQZ/1o5HaSzh06ePQNxPwTcfiY=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -92,79 +109,47 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus=
-github.com/valyala/quicktemplate v1.7.0 h1:LUPTJmlVcb46OOUY3IeD9DojFpAVbsG+5WFTcjMJzCM=
-github.com/valyala/quicktemplate v1.7.0/go.mod h1:sqKJnoaOF88V07vkO+9FL8fb9uZg/VPSJnLYn+LmLk8=
-github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
+github.com/valyala/quicktemplate v1.8.0 h1:zU0tjbIqTRgKQzFY1L42zq0qR3eh4WoQQdIdqCysW5k=
+github.com/valyala/quicktemplate v1.8.0/go.mod h1:qIqW8/igXt8fdrUln5kOSb+KWMaJ4Y8QUsfd1k6L2jM=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
-github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
-golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
+github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
-golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
-golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
-golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
-golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
-golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/crypto v0.30.0 h1:RwoQn3GkWiMkzlX562cLB7OxWvjH1L8xutO2WoJcRoY=
+golang.org/x/crypto v0.30.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
+golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
+golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
+golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
+golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
-golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
-golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
-golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
-golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
-golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
+golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
+golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
+golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
+golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
+golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
+golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
-golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
+golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
-golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
-golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
-golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
-golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
-golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
+golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
+golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
+golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
-golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
-golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
diff --git a/main.go b/main.go
index 18b73ff..797ebea 100644
--- a/main.go
+++ b/main.go
@@ -3,11 +3,14 @@ package main
import (
"context"
"flag"
+ "fmt"
"log/slog"
"os"
"os/signal"
"time"
+ "github.com/alecthomas/chroma/v2/styles"
+
"git.gabrielgio.me/cerrado/pkg/config"
"git.gabrielgio.me/cerrado/pkg/handler"
"git.gabrielgio.me/cerrado/pkg/service"
@@ -15,18 +18,53 @@ import (
)
func main() {
- ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
- defer stop()
- if err := run(ctx); err != nil {
- slog.Error("Error", "error", err)
+ if len(os.Args) == 4 && os.Args[1] == "hash" {
+ err := hash(os.Args[2], os.Args[3])
+ if err != nil {
+ slog.Error("Hash", "error", err)
+ os.Exit(1)
+ }
+ return
+ }
+
+ if len(os.Args) == 2 && os.Args[1] == "key" {
+ err := key()
+ if err != nil {
+ slog.Error("Key", "error", err)
+ os.Exit(1)
+ }
+ return
+ }
+
+ if err := run(); err != nil {
+ slog.Error("Server", "error", err)
os.Exit(1)
}
}
-func run(ctx context.Context) error {
- var (
- configPath = flag.String("config", "/etc/cerrado.scfg", "File path for the configuration file")
- )
+func hash(username string, password string) error {
+ hash, err := service.GenerateHash(username, password)
+ if err != nil {
+ return err
+ }
+ fmt.Println(hash)
+ return nil
+}
+
+func key() error {
+ en, err := service.GenerateAesKey()
+ if err != nil {
+ return err
+ }
+ fmt.Println(en)
+ return nil
+}
+
+func run() error {
+ ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill)
+ defer stop()
+
+ configPath := flag.String("config", "/etc/cerrado.scfg", "File path for the configuration file")
flag.Parse()
@@ -36,10 +74,25 @@ func run(ctx context.Context) error {
return err
}
+ // checking chroma configuration
+ if _, ok := styles.Registry[configRepo.GetSyntaxHighlight()]; !ok {
+ slog.Warn(
+ "Invalid Syntax highlight selected",
+ "invalid-style", configRepo.GetSyntaxHighlight(),
+ "using", "monokailight",
+ )
+ styles.Fallback = styles.Registry["monokailight"]
+ }
+
// services
gitService := service.NewGitService(configRepo)
+ authService := service.NewAuthService(configRepo)
- handler, err := handler.MountHandler(gitService, configRepo)
+ handler, err := handler.MountHandler(
+ gitService,
+ authService,
+ configRepo,
+ )
if err != nil {
return err
}
diff --git a/pkg/config/config.go b/pkg/config/config.go
index fd19808..c00586b 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -4,10 +4,12 @@ import (
"errors"
"fmt"
"io"
+ "log/slog"
"os"
"path"
"path/filepath"
"strconv"
+ "strings"
"git.gabrielgio.me/cerrado/pkg/u"
"git.sr.ht/~emersion/go-scfg"
@@ -19,6 +21,16 @@ var (
ErrInvalidProperty = errors.New("Invalid property")
)
+type OrderBy int
+
+const (
+ Unordered OrderBy = iota
+ AlphabeticalAsc
+ AlphabeticalDesc
+ LastCommitAsc
+ LastCommitDesc
+)
+
type (
// scan represents piece of the scan from the configuration file.
@@ -30,10 +42,16 @@ type (
// configuration represents file configuration.
// fields needs to be exported to cmp to work
configuration struct {
- Scan *scan
- RootReadme string
- ListenAddr string
- Repositories []*GitRepositoryConfiguration
+ AESKey string
+ ListenAddr string
+ OrderBy string
+ Passphrase string
+ RemoveSuffix bool
+ Repositories []*GitRepositoryConfiguration
+ RootReadme string
+ Scans []*scan
+ SyntaxHighlight string
+ Hostname string
}
// This is a per repository configuration.
@@ -50,9 +68,15 @@ type (
// This holds all the function necessary to ask for configuration
// information.
ConfigurationRepository struct {
- rootReadme string
- listenAddr string
- repositories []*GitRepositoryConfiguration
+ aesKey []byte
+ listenAddr string
+ orderBy OrderBy
+ passphrase []byte
+ removeSuffix bool
+ repositories []*GitRepositoryConfiguration
+ rootReadme string
+ syntaxHighlight string
+ hostname string
}
)
@@ -68,20 +92,27 @@ func LoadConfigurationRepository(configPath string) (*ConfigurationRepository, e
}
repo := &ConfigurationRepository{
- rootReadme: config.RootReadme,
- listenAddr: config.ListenAddr,
- repositories: config.Repositories,
+ aesKey: []byte(config.AESKey),
+ listenAddr: config.ListenAddr,
+ passphrase: []byte(config.Passphrase),
+ repositories: config.Repositories,
+ rootReadme: config.RootReadme,
+ hostname: config.Hostname,
+ syntaxHighlight: config.SyntaxHighlight,
+ removeSuffix: config.RemoveSuffix,
+ orderBy: parseOrderBy(config.OrderBy),
}
- if config.Scan.Path != "" {
- err = repo.expandOnScanPath(config.Scan.Path, config.Scan.Public)
- if err != nil {
- return nil, err
+ for _, scan := range config.Scans {
+ if scan.Path != "" {
+ err = repo.expandOnScanPath(scan.Path, scan.Public)
+ if err != nil {
+ return nil, err
+ }
}
}
return repo, nil
-
}
// GetRootReadme returns root read path
@@ -89,10 +120,34 @@ func (c *ConfigurationRepository) GetRootReadme() string {
return c.rootReadme
}
+func (c *ConfigurationRepository) GetHostname() string {
+ return c.hostname
+}
+
+func (c *ConfigurationRepository) GetOrderBy() OrderBy {
+ return c.orderBy
+}
+
+func (c *ConfigurationRepository) GetSyntaxHighlight() string {
+ return c.syntaxHighlight
+}
+
func (c *ConfigurationRepository) GetListenAddr() string {
return c.listenAddr
}
+func (c *ConfigurationRepository) GetPassphrase() []byte {
+ return c.passphrase
+}
+
+func (c *ConfigurationRepository) GetBase64AesKey() []byte {
+ return c.aesKey
+}
+
+func (c *ConfigurationRepository) IsAuthEnabled() bool {
+ return len(c.passphrase) != 0
+}
+
// GetByName returns configuration of repository for a given name.
// It returns nil if there is not match for it.
func (c *ConfigurationRepository) GetByName(name string) *GitRepositoryConfiguration {
@@ -128,8 +183,14 @@ func (c *ConfigurationRepository) expandOnScanPath(scanPath string, public bool)
fullPath := path.Join(scanPath, e.Name())
if !c.repoExits(fullPath) {
+
+ name := e.Name()
+ if c.removeSuffix {
+ name = strings.TrimSuffix(name, ".git")
+ }
+
c.repositories = append(c.repositories, &GitRepositoryConfiguration{
- Name: e.Name(),
+ Name: name,
Path: fullPath,
Public: public,
})
@@ -155,7 +216,7 @@ func parse(r io.Reader) (*configuration, error) {
config := defaultConfiguration()
- err = setScan(block, config.Scan)
+ err = setScan(block, &config.Scans)
if err != nil {
return nil, err
}
@@ -165,11 +226,41 @@ func parse(r io.Reader) (*configuration, error) {
return nil, err
}
+ err = setHostname(block, &config.Hostname)
+ if err != nil {
+ return nil, err
+ }
+
err = setListenAddr(block, &config.ListenAddr)
if err != nil {
return nil, err
}
+ err = setPassphrase(block, &config.Passphrase)
+ if err != nil {
+ return nil, err
+ }
+
+ err = setAESKey(block, &config.AESKey)
+ if err != nil {
+ return nil, err
+ }
+
+ err = setSyntaxHighlight(block, &config.SyntaxHighlight)
+ if err != nil {
+ return nil, err
+ }
+
+ err = setOrderby(block, &config.OrderBy)
+ if err != nil {
+ return nil, err
+ }
+
+ err = setRemoveSuffix(block, &config.RemoveSuffix)
+ if err != nil {
+ return nil, err
+ }
+
err = setRepositories(block, &config.Repositories)
if err != nil {
return nil, err
@@ -230,18 +321,20 @@ func setRepositories(block scfg.Block, repositories *[]*GitRepositoryConfigurati
func defaultConfiguration() *configuration {
return &configuration{
- Scan: defaultScan(),
+ Scans: defaultScans(),
RootReadme: "",
+ Hostname: defaultHostname(),
ListenAddr: defaultAddr(),
Repositories: make([]*GitRepositoryConfiguration, 0),
}
}
-func defaultScan() *scan {
- return &scan{
- Public: false,
- Path: "",
- }
+func defaultHostname() string {
+ return "https://localhost:8080"
+}
+
+func defaultScans() []*scan {
+ return []*scan{}
}
func defaultAddr() string {
@@ -263,23 +356,62 @@ func setRootReadme(block scfg.Block, readme *string) error {
return setString(scanDir, readme)
}
+func setHostname(block scfg.Block, hostname *string) error {
+ scanDir := block.Get("hostname")
+ return setString(scanDir, hostname)
+}
+
+func setPassphrase(block scfg.Block, listenAddr *string) error {
+ scanDir := block.Get("passphrase")
+ return setString(scanDir, listenAddr)
+}
+
+func setAESKey(block scfg.Block, listenAddr *string) error {
+ scanDir := block.Get("aes-key")
+ return setString(scanDir, listenAddr)
+}
+
+func setSyntaxHighlight(block scfg.Block, listenAddr *string) error {
+ scanDir := block.Get("syntax-highlight")
+ return setString(scanDir, listenAddr)
+}
+
+func setOrderby(block scfg.Block, orderBy *string) error {
+ scanDir := block.Get("order-by")
+ return setString(scanDir, orderBy)
+}
+
func setListenAddr(block scfg.Block, listenAddr *string) error {
scanDir := block.Get("listen-addr")
return setString(scanDir, listenAddr)
}
-func setScan(block scfg.Block, scan *scan) error {
- scanDir := block.Get("scan")
- if scanDir == nil {
- return nil
- }
- err := setString(scanDir, &scan.Path)
- if err != nil {
- return err
+func setRemoveSuffix(block scfg.Block, remove *bool) error {
+ scanDir := block.Get("remove-suffix")
+ return setBool(scanDir, remove)
+}
+
+func setScan(block scfg.Block, scans *[]*scan) error {
+ for _, scanDir := range block.GetAll("scan") {
+ s := &scan{}
+ if scanDir == nil {
+ return nil
+ }
+ err := setString(scanDir, &s.Path)
+ if err != nil {
+ return err
+ }
+
+ public := scanDir.Children.Get("public")
+ err = setBool(public, &s.Public)
+ if err != nil {
+ return err
+ }
+
+ *scans = append(*scans, s)
}
- public := scanDir.Children.Get("public")
- return setBool(public, &scan.Public)
+ return nil
}
func setBool(dir *scfg.Directive, field *bool) error {
@@ -301,3 +433,24 @@ func setString(dir *scfg.Directive, field *string) error {
}
return nil
}
+
+func parseOrderBy(s string) OrderBy {
+ switch s {
+ case "":
+ return LastCommitAsc
+ case "unordered":
+ return Unordered
+ case "alphabetical-asc":
+ return AlphabeticalAsc
+ case "alphabetical-desc":
+ return AlphabeticalDesc
+ case "lastcommit-asc":
+ return LastCommitAsc
+ case "lastcommit-desc":
+ return LastCommitDesc
+ default:
+ slog.Warn("Invalid order-by using default unordered")
+ return LastCommitAsc
+
+ }
+}
diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go
index 8c1d27e..31cf1c0 100644
--- a/pkg/config/config_test.go
+++ b/pkg/config/config_test.go
@@ -18,11 +18,14 @@ func TestFileParsing(t *testing.T) {
name: "minimal scan",
config: `scan "/srv/git"`,
expectedConfig: &configuration{
- Scan: &scan{
- Public: false,
- Path: "/srv/git",
+ Scans: []*scan{
+ {
+ Public: false,
+ Path: "/srv/git",
+ },
},
ListenAddr: defaultAddr(),
+ Hostname: defaultHostname(),
Repositories: []*GitRepositoryConfiguration{},
},
},
@@ -33,11 +36,14 @@ scan "/srv/git" {
public true
}`,
expectedConfig: &configuration{
- Scan: &scan{
- Public: true,
- Path: "/srv/git",
+ Scans: []*scan{
+ {
+ Public: true,
+ Path: "/srv/git",
+ },
},
ListenAddr: defaultAddr(),
+ Hostname: defaultHostname(),
Repositories: []*GitRepositoryConfiguration{},
},
},
@@ -45,8 +51,9 @@ scan "/srv/git" {
name: "minimal repository",
config: `repository /srv/git/cerrado.git`,
expectedConfig: &configuration{
- Scan: defaultScan(),
+ Scans: defaultScans(),
ListenAddr: defaultAddr(),
+ Hostname: defaultHostname(),
Repositories: []*GitRepositoryConfiguration{
{
Name: "cerrado.git",
@@ -68,8 +75,9 @@ repository /srv/git/cerrado.git {
about readme.txt
}`,
expectedConfig: &configuration{
- Scan: defaultScan(),
+ Scans: defaultScans(),
ListenAddr: defaultAddr(),
+ Hostname: defaultHostname(),
Repositories: []*GitRepositoryConfiguration{
{
Name: "cerrado",
@@ -85,8 +93,9 @@ repository /srv/git/cerrado.git {
name: "minimal listen",
config: ``,
expectedConfig: &configuration{
- Scan: defaultScan(),
+ Scans: defaultScans(),
ListenAddr: defaultAddr(),
+ Hostname: defaultHostname(),
Repositories: []*GitRepositoryConfiguration{},
},
},
@@ -94,7 +103,8 @@ repository /srv/git/cerrado.git {
name: "complete listen",
config: `listen-addr unix://var/run/cerrado/cerrado.sock`,
expectedConfig: &configuration{
- Scan: defaultScan(),
+ Scans: defaultScans(),
+ Hostname: defaultHostname(),
ListenAddr: "unix://var/run/cerrado/cerrado.sock",
Repositories: []*GitRepositoryConfiguration{},
},
@@ -103,6 +113,12 @@ repository /srv/git/cerrado.git {
name: "complete",
config: `
listen-addr unix://var/run/cerrado/cerrado.sock
+passphrase $2a$14$VnB/ZcB1DUDkMnosRA6Y7.dj8h5eroslDxTeXlLwfQX/x86mh6WAq
+aes-key 8XHptZxSWCGs1m7QzztX5zNQ7D9NiQevVX0DaUTNMbDpRwFzoJiB0U7K6O/kqIt01jJVgzBUfiR8ES46ZLLb4w==
+syntax-highlight monokailight
+order-by lastcommit-desc
+remove-suffix true
+hostname https://domain.tld
scan "/srv/git" {
public true
@@ -117,11 +133,19 @@ repository /srv/git/cerrado.git {
about readme.txt
}`,
expectedConfig: &configuration{
- Scan: &scan{
- Public: true,
- Path: "/srv/git",
+ Scans: []*scan{
+ {
+ Public: true,
+ Path: "/srv/git",
+ },
},
- ListenAddr: "unix://var/run/cerrado/cerrado.sock",
+ ListenAddr: "unix://var/run/cerrado/cerrado.sock",
+ Passphrase: "$2a$14$VnB/ZcB1DUDkMnosRA6Y7.dj8h5eroslDxTeXlLwfQX/x86mh6WAq",
+ AESKey: "8XHptZxSWCGs1m7QzztX5zNQ7D9NiQevVX0DaUTNMbDpRwFzoJiB0U7K6O/kqIt01jJVgzBUfiR8ES46ZLLb4w==",
+ SyntaxHighlight: "monokailight",
+ OrderBy: "lastcommit-desc",
+ RemoveSuffix: true,
+ Hostname: "https://domain.tld",
Repositories: []*GitRepositoryConfiguration{
{
Name: "linux.git",
@@ -154,6 +178,5 @@ repository /srv/git/cerrado.git {
t.Errorf("Wrong result given - wanted + got\n %s", diff)
}
})
-
}
}
diff --git a/pkg/ext/auth.go b/pkg/ext/auth.go
new file mode 100644
index 0000000..ef126ec
--- /dev/null
+++ b/pkg/ext/auth.go
@@ -0,0 +1,85 @@
+package ext
+
+import (
+ "context"
+ "encoding/base64"
+ "errors"
+ "log/slog"
+ "net/http"
+
+ serverconfig "git.gabrielgio.me/cerrado/pkg/config"
+)
+
+type authService interface {
+ ValidateToken(token []byte) (bool, error)
+}
+
+func DisableAuthentication(next HandlerFunc) HandlerFunc {
+ return func(w http.ResponseWriter, r *Request) {
+ ctx := r.Context()
+ ctx = context.WithValue(ctx, "disableAuthentication", true)
+ r.Request = r.WithContext(ctx)
+ next(w, r)
+ }
+}
+
+func VerifyRespository(
+ config *serverconfig.ConfigurationRepository,
+) func(next HandlerFunc) HandlerFunc {
+ return func(next HandlerFunc) HandlerFunc {
+ return func(w http.ResponseWriter, r *Request) {
+ name := r.PathValue("name")
+ if name != "" {
+ repo := config.GetByName(name)
+ if repo != nil && !repo.Public && !IsLoggedIn(r.Context()) {
+ NotFound(w, r)
+ return
+ }
+ }
+
+ next(w, r)
+ }
+ }
+}
+
+func Authenticate(auth authService) func(next HandlerFunc) HandlerFunc {
+ return func(next HandlerFunc) HandlerFunc {
+ return func(w http.ResponseWriter, r *Request) {
+ cookie, err := r.Cookie("auth")
+ if err != nil {
+ if !errors.Is(err, http.ErrNoCookie) {
+ slog.Error("Error loading cookie", "error", err)
+ }
+
+ next(w, r)
+ return
+ }
+
+ value, err := base64.StdEncoding.DecodeString(cookie.Value)
+ if err != nil {
+ slog.Error("Error decoding", "error", err)
+ next(w, r)
+ return
+ }
+
+ valid, err := auth.ValidateToken(value)
+ if err != nil {
+ slog.Error("Error validating token", "error", err, "cookie", cookie.Value)
+ next(w, r)
+ return
+ }
+
+ ctx := r.Context()
+ ctx = context.WithValue(ctx, "logged", valid)
+ r.Request = r.WithContext(ctx)
+
+ slog.Info("Validated token", "valid?", valid)
+ next(w, r)
+ }
+ }
+}
+
+func IsLoggedIn(ctx context.Context) bool {
+ t, ok := ctx.Value("logged").(bool)
+ return ok && t
+}
diff --git a/pkg/ext/compression.go b/pkg/ext/compression.go
index 6c7a219..d3a3df1 100644
--- a/pkg/ext/compression.go
+++ b/pkg/ext/compression.go
@@ -15,18 +15,37 @@ import (
"github.com/klauspost/compress/zstd"
)
-var (
- errInvalidParam = errors.New("Invalid weighted param")
-)
+var errInvalidParam = errors.New("Invalid weighted param")
type CompressionResponseWriter struct {
innerWriter http.ResponseWriter
compressWriter io.Writer
}
-func Compress(next http.HandlerFunc) http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
+func Compress(next HandlerFunc) HandlerFunc {
+ return func(w http.ResponseWriter, r *Request) {
+ // TODO: hand this better
+ if strings.HasSuffix(r.URL.Path, ".tar.gz") {
+ next(w, r)
+ return
+ }
+
+ if accept, ok := r.Header["Accept-Encoding"]; ok {
+ if compress, algo := GetCompressionWriter(u.FirstOrZero(accept), w); algo != "" {
+ defer compress.Close()
+ w.Header().Add("Content-Encoding", algo)
+ w = &CompressionResponseWriter{
+ innerWriter: w,
+ compressWriter: compress,
+ }
+ }
+ }
+ next(w, r)
+ }
+}
+func Decompress(next http.HandlerFunc) http.HandlerFunc {
+ return func(w http.ResponseWriter, r *http.Request) {
// TODO: hand this better
if strings.HasSuffix(r.URL.Path, ".tar.gz") {
next(w, r)
@@ -61,12 +80,12 @@ func GetCompressionWriter(header string, inner io.Writer) (io.WriteCloser, strin
default:
return nil, ""
}
-
}
func (c *CompressionResponseWriter) Header() http.Header {
return c.innerWriter.Header()
}
+
func (c *CompressionResponseWriter) Write(b []byte) (int, error) {
return c.compressWriter.Write(b)
}
diff --git a/pkg/ext/log.go b/pkg/ext/log.go
index 8e68134..e0ad89f 100644
--- a/pkg/ext/log.go
+++ b/pkg/ext/log.go
@@ -39,8 +39,8 @@ func wrap(w http.ResponseWriter) *statusWraper {
}
}
-func Log(next http.HandlerFunc) http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
+func Log(next HandlerFunc) HandlerFunc {
+ return func(w http.ResponseWriter, r *Request) {
t := time.Now()
s := wrap(w)
next(s, r)
diff --git a/pkg/ext/request.go b/pkg/ext/request.go
new file mode 100644
index 0000000..d1593b2
--- /dev/null
+++ b/pkg/ext/request.go
@@ -0,0 +1,14 @@
+package ext
+
+import (
+ "io"
+ "net/http"
+)
+
+type Request struct {
+ *http.Request
+}
+
+func (r *Request) ReadBody() io.ReadCloser {
+ return r.Body
+}
diff --git a/pkg/ext/router.go b/pkg/ext/router.go
index 96da1c9..bbbffa1 100644
--- a/pkg/ext/router.go
+++ b/pkg/ext/router.go
@@ -3,10 +3,12 @@ package ext
import (
"errors"
"fmt"
+ "log/slog"
"net/http"
"git.gabrielgio.me/cerrado/pkg/service"
"git.gabrielgio.me/cerrado/templates"
+ "github.com/go-git/go-git/v5/plumbing"
)
type (
@@ -14,8 +16,9 @@ type (
middlewares []Middleware
router *http.ServeMux
}
- Middleware func(next http.HandlerFunc) http.HandlerFunc
- ErrorRequestHandler func(w http.ResponseWriter, r *http.Request) error
+ HandlerFunc func(http.ResponseWriter, *Request)
+ Middleware func(next HandlerFunc) HandlerFunc
+ ErrorRequestHandler func(w http.ResponseWriter, r *Request) error
)
func NewRouter() *Router {
@@ -23,6 +26,7 @@ func NewRouter() *Router {
router: http.NewServeMux(),
}
}
+
func (r *Router) Handler() http.Handler {
return r.router
}
@@ -31,13 +35,15 @@ func (r *Router) AddMiddleware(middleware Middleware) {
r.middlewares = append(r.middlewares, middleware)
}
-func wrapError(next ErrorRequestHandler) http.HandlerFunc {
- return func(w http.ResponseWriter, r *http.Request) {
+func wrapError(next ErrorRequestHandler) HandlerFunc {
+ return func(w http.ResponseWriter, r *Request) {
if err := next(w, r); err != nil {
- if errors.Is(err, service.ErrRepositoryNotFound) {
- NotFound(w)
+ if errors.Is(err, service.ErrRepositoryNotFound) ||
+ errors.Is(err, plumbing.ErrReferenceNotFound) {
+ NotFound(w, r)
} else {
- InternalServerError(w, err)
+ slog.Error("Internal Server Error", "error", err)
+ InternalServerError(w, r, err)
}
}
}
@@ -49,7 +55,7 @@ func (r *Router) run(next ErrorRequestHandler) http.HandlerFunc {
for _, r := range r.middlewares {
req = r(req)
}
- req(w, re)
+ req(w, &Request{Request: re})
}
}
@@ -57,16 +63,28 @@ func (r *Router) HandleFunc(path string, handler ErrorRequestHandler) {
r.router.HandleFunc(path, r.run(handler))
}
-func NotFound(w http.ResponseWriter) {
+func NotFound(w http.ResponseWriter, r *Request) {
w.WriteHeader(http.StatusNotFound)
templates.WritePageTemplate(w, &templates.ErrorPage{
Message: "Not Found",
- })
+ }, r.Context())
+}
+
+func BadRequest(w http.ResponseWriter, r *Request, msg string) {
+ w.WriteHeader(http.StatusBadRequest)
+ templates.WritePageTemplate(w, &templates.ErrorPage{
+ Message: msg,
+ }, r.Context())
+}
+
+func Redirect(w http.ResponseWriter, location string) {
+ w.Header().Add("location", location)
+ w.WriteHeader(http.StatusTemporaryRedirect)
}
-func InternalServerError(w http.ResponseWriter, err error) {
+func InternalServerError(w http.ResponseWriter, r *Request, err error) {
w.WriteHeader(http.StatusInternalServerError)
templates.WritePageTemplate(w, &templates.ErrorPage{
Message: fmt.Sprintf("Internal Server Error:\n%s", err.Error()),
- })
+ }, r.Context())
}
diff --git a/pkg/git/git.go b/pkg/git/git.go
index 6221e33..83f3f93 100644
--- a/pkg/git/git.go
+++ b/pkg/git/git.go
@@ -3,10 +3,13 @@ package git
import (
"archive/tar"
"bytes"
+ "context"
"errors"
"fmt"
"io"
"io/fs"
+ "log/slog"
+ "os/exec"
"path"
"sort"
"time"
@@ -16,11 +19,10 @@ import (
"github.com/go-git/go-git/v5/plumbing/object"
)
-var ()
-
var (
MissingRefErr = errors.New("Reference not found")
TreeForFileErr = errors.New("Trying to get tree of a file")
+ eofIter = errors.New("End of a iterator")
)
type (
@@ -34,6 +36,10 @@ type (
ref *plumbing.Reference
tag *object.Tag
}
+ CommitReference struct {
+ commit *object.Commit
+ refs []*plumbing.Reference
+ }
infoWrapper struct {
name string
size int64
@@ -83,7 +89,7 @@ func (g *GitRepository) Path() string {
return g.path
}
-func (g *GitRepository) LastCommit() (*object.Commit, error) {
+func (g *GitRepository) LastCommit() (*CommitReference, error) {
err := g.validateRef()
if err != nil {
return nil, err
@@ -93,39 +99,157 @@ func (g *GitRepository) LastCommit() (*object.Commit, error) {
if err != nil {
return nil, err
}
- return c, nil
+
+ iter, err := g.repository.Tags()
+ if err != nil {
+ return nil, err
+ }
+
+ commitRef := &CommitReference{commit: c}
+ if err := iter.ForEach(func(ref *plumbing.Reference) error {
+ obj, err := g.repository.TagObject(ref.Hash())
+ switch err {
+ case nil:
+ if obj.Target == commitRef.commit.Hash {
+ commitRef.AddReference(ref)
+ }
+ case plumbing.ErrObjectNotFound:
+ if commitRef.commit.Hash == ref.Hash() {
+ commitRef.AddReference(ref)
+ }
+ default:
+ return err
+ }
+
+ return nil
+ }); err != nil {
+ return nil, err
+ }
+
+ return commitRef, nil
}
-func (g *GitRepository) Commits(count int) ([]*object.Commit, error) {
+func (g *GitRepository) Commits(count int, from string) ([]*CommitReference, *object.Commit, error) {
err := g.validateRef()
if err != nil {
- return nil, err
+ return nil, nil, err
+ }
+
+ opts := &git.LogOptions{Order: git.LogOrderCommitterTime}
+
+ if from != "" {
+ hash, err := g.repository.ResolveRevision(plumbing.Revision(from))
+ if err != nil {
+ return nil, nil, errors.Join(MissingRefErr, err)
+ }
+ opts.From = *hash
}
- ci, err := g.repository.Log(&git.LogOptions{From: g.ref})
+ ci, err := g.repository.Log(opts)
if err != nil {
- return nil, fmt.Errorf("commits from ref: %w", err)
+ return nil, nil, fmt.Errorf("commits from ref: %w", err)
}
- commits := []*object.Commit{}
- // TODO: for now only load first 1000
- for x := 0; x < count; x++ {
+ commitRefs := []*CommitReference{}
+ var next *object.Commit
+
+ // iterate one more item so we can fetch the next commit
+ for x := 0; x < (count + 1); x++ {
c, err := ci.Next()
if err != nil && errors.Is(err, io.EOF) {
break
} else if err != nil {
- return nil, err
+ return nil, nil, err
}
- commits = append(commits, c)
+ if x == count {
+ next = c
+ } else {
+ commitRefs = append(commitRefs, &CommitReference{commit: c})
+ }
+ }
+
+ // new we fetch for possible tags for each commit
+ iter, err := g.repository.References()
+ if err != nil {
+ return nil, nil, err
+ }
+
+ if err := iter.ForEach(func(ref *plumbing.Reference) error {
+ for _, c := range commitRefs {
+ obj, err := g.repository.TagObject(ref.Hash())
+ switch err {
+ case nil:
+ if obj.Target == c.commit.Hash {
+ c.AddReference(ref)
+ }
+ case plumbing.ErrObjectNotFound:
+ if c.commit.Hash == ref.Hash() {
+ c.AddReference(ref)
+ }
+ default:
+ return err
+ }
+ }
+ return nil
+ }); err != nil {
+ return nil, nil, err
}
- return commits, nil
+ return commitRefs, next, nil
}
func (g *GitRepository) Head() (*plumbing.Reference, error) {
return g.repository.Head()
}
+func (g *GitRepository) Tag() (*object.Commit, *TagReference, error) {
+ err := g.validateRef()
+ if err != nil {
+ return nil, nil, err
+ }
+
+ c, err := g.repository.CommitObject(g.ref)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ var tagReference *TagReference
+
+ iter, err := g.repository.Tags()
+ if err != nil {
+ return nil, nil, err
+ }
+
+ if err := iter.ForEach(func(ref *plumbing.Reference) error {
+ obj, err := g.repository.TagObject(ref.Hash())
+ switch err {
+ case nil:
+ if obj.Target == c.Hash {
+ tagReference = &TagReference{
+ ref: ref,
+ tag: obj,
+ }
+ return eofIter
+ }
+ return nil
+ case plumbing.ErrObjectNotFound:
+ if c.Hash == ref.Hash() {
+ tagReference = &TagReference{
+ ref: ref,
+ }
+ return eofIter
+ }
+ return nil
+ default:
+ return err
+ }
+ }); err != nil && !errors.Is(eofIter, err) {
+ return nil, nil, err
+ }
+
+ return c, tagReference, nil
+}
+
func (g *GitRepository) Tags() ([]*TagReference, error) {
iter, err := g.repository.Tags()
if err != nil {
@@ -311,6 +435,68 @@ func (g *GitRepository) FileContent(path string) ([]byte, error) {
return buf.Bytes(), nil
}
+func (g *GitRepository) WriteInfoRefs(ctx context.Context, w io.Writer) error {
+ cmd := exec.CommandContext(
+ ctx,
+ "git-upload-pack",
+ "--stateless-rpc",
+ "--advertise-refs",
+ ".",
+ )
+
+ cmd.Dir = g.path
+ cmd.Env = []string{
+ // TODO: get this from header.
+ "GIT_PROTOCOL=version=2",
+ }
+
+ var errBuff bytes.Buffer
+ cmd.Stderr = &errBuff
+ cmd.Stdout = w
+
+ err := packLine(w, "# service=git-upload-pack\n")
+ if err != nil {
+ return err
+ }
+
+ err = packFlush(w)
+ if err != nil {
+ return err
+ }
+
+ err = cmd.Run()
+ if err != nil {
+ slog.Error("Error upload pack refs", "message", errBuff.String())
+ return err
+ }
+ return nil
+}
+
+func (g *GitRepository) WriteUploadPack(ctx context.Context, r io.Reader, w io.Writer) error {
+ cmd := exec.CommandContext(
+ ctx,
+ "git-upload-pack",
+ "--stateless-rpc",
+ ".",
+ )
+ cmd.Dir = g.Path()
+ cmd.Env = []string{
+ // TODO: get this from header.
+ "GIT_PROTOCOL=version=2",
+ }
+ var errBuff bytes.Buffer
+ cmd.Stderr = &errBuff
+ cmd.Stdout = w
+ cmd.Stdin = r
+
+ if err := cmd.Run(); err != nil {
+ slog.ErrorContext(ctx, "Git upload pack failed", "error", err, "message", errBuff.String())
+ return err
+ }
+
+ return nil
+}
+
func (g *GitRepository) WriteTar(w io.Writer, prefix string) error {
tw := tar.NewWriter(w)
defer tw.Close()
@@ -438,7 +624,22 @@ func (t *TagReference) Message() string {
return t.tag.Message
}
return ""
+}
+
+func (c *CommitReference) Commit() *object.Commit {
+ return c.commit
+}
+
+func (c *CommitReference) HasReference() bool {
+ return len(c.refs) > 0
+}
+
+func (c *CommitReference) References() []*plumbing.Reference {
+ return c.refs
+}
+func (c *CommitReference) AddReference(ref *plumbing.Reference) {
+ c.refs = append(c.refs, ref)
}
func (self *tagList) Len() int {
@@ -477,3 +678,39 @@ func (self *tagList) Less(i, j int) bool {
return dateI.After(dateJ)
}
+
+func packLine(w io.Writer, s string) error {
+ _, err := fmt.Fprintf(w, "%04x%s", len(s)+4, s)
+ return err
+}
+
+func packFlush(w io.Writer) error {
+ _, err := fmt.Fprint(w, "0000")
+ return err
+}
+
+type debugReader struct {
+ r io.Reader
+}
+
+func (d *debugReader) Read(p []byte) (n int, err error) {
+ r, err := d.r.Read(p)
+ if err != nil {
+ if errors.Is(io.EOF, err) {
+ fmt.Printf("READ: EOF\n")
+ }
+ return r, err
+ }
+
+ fmt.Printf("READ: %s\n", p[:r])
+ return r, nil
+}
+
+type debugWriter struct {
+ w io.Writer
+}
+
+func (d *debugWriter) Write(p []byte) (n int, err error) {
+ fmt.Printf("WRITE: %s\n", p)
+ return d.w.Write(p)
+}
diff --git a/pkg/handler/about/handler.go b/pkg/handler/about/handler.go
index ac3d314..b3a1593 100644
--- a/pkg/handler/about/handler.go
+++ b/pkg/handler/about/handler.go
@@ -9,6 +9,7 @@ import (
"github.com/gomarkdown/markdown/html"
"github.com/gomarkdown/markdown/parser"
+ "git.gabrielgio.me/cerrado/pkg/ext"
"git.gabrielgio.me/cerrado/templates"
)
@@ -26,7 +27,7 @@ func NewAboutHandler(configRepo configurationRepository) *AboutHandler {
return &AboutHandler{configRepo.GetRootReadme()}
}
-func (g *AboutHandler) About(w http.ResponseWriter, _ *http.Request) error {
+func (g *AboutHandler) About(w http.ResponseWriter, r *ext.Request) error {
f, err := os.Open(g.readmePath)
if err != nil {
return err
@@ -50,6 +51,6 @@ func (g *AboutHandler) About(w http.ResponseWriter, _ *http.Request) error {
gitList := &templates.AboutPage{
Body: bs,
}
- templates.WritePageTemplate(w, gitList)
+ templates.WritePageTemplate(w, gitList, r.Context())
return nil
}
diff --git a/pkg/handler/auth/login.go b/pkg/handler/auth/login.go
new file mode 100644
index 0000000..9cc13cc
--- /dev/null
+++ b/pkg/handler/auth/login.go
@@ -0,0 +1,97 @@
+package auth
+
+import (
+ "encoding/base64"
+ "net/http"
+ "time"
+
+ "git.gabrielgio.me/cerrado/pkg/ext"
+ "git.gabrielgio.me/cerrado/templates"
+)
+
+type (
+ LoginHandler struct {
+ auth authService
+ }
+
+ authService interface {
+ CheckAuth(username, password string) bool
+ IssueToken() ([]byte, error)
+ }
+)
+
+func NewLoginHandler(auth authService) *LoginHandler {
+ return &LoginHandler{
+ auth: auth,
+ }
+}
+
+func (g *LoginHandler) Logout(w http.ResponseWriter, r *ext.Request) error {
+ cookie := &http.Cookie{
+ Name: "auth",
+ Value: "",
+ Path: "/",
+ Expires: time.Unix(0, 0),
+ }
+
+ referer := r.Header.Get("Referer")
+ if referer == "" {
+ referer = "/"
+ }
+
+ http.SetCookie(w, cookie)
+ ext.Redirect(w, referer)
+ return nil
+}
+
+func (g *LoginHandler) Login(w http.ResponseWriter, r *ext.Request) error {
+ referer := r.URL.Query().Get("referer")
+
+ // if query value is empty tries to get from header
+ if referer == "" {
+ referer = r.Header.Get("Referer")
+ }
+
+ if r.Method == "GET" {
+ ext.SetHTML(w)
+
+ login := &templates.LoginPage{
+ Referer: referer,
+ }
+ templates.WritePageTemplate(w, login, r.Context())
+ } else if r.Method == "POST" {
+
+ username := r.FormValue("username")
+ password := r.FormValue("password")
+
+ if !g.auth.CheckAuth(username, password) {
+ login := &templates.LoginPage{
+ Referer: referer,
+ ErrorMessage: "Invalid login",
+ }
+ templates.WritePageTemplate(w, login, r.Context())
+ } else {
+
+ bytes, err := g.auth.IssueToken()
+ if err != nil {
+ return err
+ }
+
+ cookie := &http.Cookie{
+ Name: "auth",
+ Value: base64.StdEncoding.EncodeToString(bytes),
+ Path: "/",
+ MaxAge: 3600,
+ HttpOnly: true,
+ Secure: true,
+ SameSite: http.SameSiteStrictMode,
+ }
+
+ http.SetCookie(w, cookie)
+ ext.Redirect(w, referer)
+ }
+
+ }
+
+ return nil
+}
diff --git a/pkg/handler/config/handler.go b/pkg/handler/config/handler.go
deleted file mode 100644
index c43b54d..0000000
--- a/pkg/handler/config/handler.go
+++ /dev/null
@@ -1,63 +0,0 @@
-package config
-
-import (
- "bytes"
- "encoding/json"
- "net/http"
-
- "github.com/alecthomas/chroma/v2/formatters/html"
- "github.com/alecthomas/chroma/v2/lexers"
- "github.com/alecthomas/chroma/v2/styles"
-
- "git.gabrielgio.me/cerrado/pkg/config"
- "git.gabrielgio.me/cerrado/pkg/ext"
- "git.gabrielgio.me/cerrado/templates"
-)
-
-type (
- configurationRepository interface {
- GetRootReadme() string
- List() []*config.GitRepositoryConfiguration
- }
-)
-
-func ConfigFile(configRepo configurationRepository) ext.ErrorRequestHandler {
- return func(w http.ResponseWriter, _ *http.Request) error {
-
- config := struct {
- RootReadme string
- Repositories []*config.GitRepositoryConfiguration
- }{
- RootReadme: configRepo.GetRootReadme(),
- Repositories: configRepo.List(),
- }
-
- b, err := json.MarshalIndent(config, "", " ")
- if err != nil {
- return err
- }
-
- lexer := lexers.Get("json")
- style := styles.Get("monokailight")
- formatter := html.New(
- html.WithLineNumbers(true),
- )
- iterator, err := lexer.Tokenise(nil, string(b))
- if err != nil {
- return err
- }
-
- var code bytes.Buffer
- err = formatter.Format(&code, style, iterator)
- if err != nil {
- return err
- }
-
- hello := &templates.ConfigPage{
- Body: code.Bytes(),
- }
-
- templates.WritePageTemplate(w, hello)
- return nil
- }
-}
diff --git a/pkg/handler/git/handler.go b/pkg/handler/git/handler.go
index 40fae24..cb202a2 100644
--- a/pkg/handler/git/handler.go
+++ b/pkg/handler/git/handler.go
@@ -2,6 +2,7 @@ package git
import (
"bytes"
+ "compress/gzip"
"errors"
"fmt"
"io"
@@ -9,10 +10,13 @@ import (
"net/http"
"os"
"path/filepath"
+ "sort"
"strings"
+ "git.gabrielgio.me/cerrado/pkg/config"
"git.gabrielgio.me/cerrado/pkg/ext"
"git.gabrielgio.me/cerrado/pkg/service"
+ "git.gabrielgio.me/cerrado/pkg/u"
"git.gabrielgio.me/cerrado/templates"
"github.com/alecthomas/chroma/v2"
"github.com/alecthomas/chroma/v2/formatters/html"
@@ -27,28 +31,38 @@ import (
type (
GitHandler struct {
gitService *service.GitService
- readmePath string
+ config configurationRepository
}
configurationRepository interface {
GetRootReadme() string
+ GetSyntaxHighlight() string
+ GetOrderBy() config.OrderBy
}
)
func NewGitHandler(gitService *service.GitService, confRepo configurationRepository) *GitHandler {
return &GitHandler{
gitService: gitService,
- readmePath: confRepo.GetRootReadme(),
+ config: confRepo,
}
}
-func (g *GitHandler) List(w http.ResponseWriter, _ *http.Request) error {
+func (g *GitHandler) List(w http.ResponseWriter, r *ext.Request) error {
+ // this is the only handler that needs to handle authentication itself.
+ // everything else relay on name path parameter
+ logged := ext.IsLoggedIn(r.Context())
+
repos, err := g.gitService.ListRepositories()
if err != nil {
return err
}
- f, err := os.Open(g.readmePath)
+ if !logged {
+ repos = u.Filter(repos, isPublic)
+ }
+
+ f, err := os.Open(g.config.GetRootReadme())
if err != nil {
return err
}
@@ -69,14 +83,14 @@ func (g *GitHandler) List(w http.ResponseWriter, _ *http.Request) error {
bs = markdown.Render(doc, renderer)
gitList := &templates.GitListPage{
- Respositories: repos,
+ Respositories: orderBy(repos, g.config.GetOrderBy()),
About: bs,
}
- templates.WritePageTemplate(w, gitList)
+ templates.WritePageTemplate(w, gitList, r.Context())
return nil
}
-func (g *GitHandler) Archive(w http.ResponseWriter, r *http.Request) error {
+func (g *GitHandler) Archive(w http.ResponseWriter, r *ext.Request) error {
ext.SetGZip(w)
name := r.PathValue("name")
file := r.PathValue("file")
@@ -84,7 +98,7 @@ func (g *GitHandler) Archive(w http.ResponseWriter, r *http.Request) error {
// TODO: remove it once we can support more than gzip
if !strings.HasSuffix(file, ".tar.gz") {
- ext.NotFound(w)
+ ext.NotFound(w, r)
return nil
}
@@ -102,7 +116,51 @@ func (g *GitHandler) Archive(w http.ResponseWriter, r *http.Request) error {
return nil
}
-func (g *GitHandler) Summary(w http.ResponseWriter, r *http.Request) error {
+func (g *GitHandler) Multiplex(w http.ResponseWriter, r *ext.Request) error {
+ path := r.PathValue("rest")
+ name := r.PathValue("name")
+
+ if r.URL.RawQuery == "service=git-receive-pack" {
+ ext.BadRequest(w, r, "no pushing allowed")
+ return nil
+ }
+
+ if path == "info/refs" && r.URL.RawQuery == "service=git-upload-pack" && r.Method == "GET" {
+ w.Header().Set("content-type", "application/x-git-upload-pack-advertisement")
+
+ err := g.gitService.WriteInfoRefs(r.Context(), name, w)
+ if err != nil {
+ slog.Error("Error WriteInfoRefs", "error", err)
+ }
+ } else if path == "git-upload-pack" && r.Method == "POST" {
+ w.Header().Set("content-type", "application/x-git-upload-pack-result")
+ w.Header().Set("Connection", "Keep-Alive")
+ w.Header().Set("Transfer-Encoding", "chunked")
+ w.WriteHeader(http.StatusOK)
+
+ reader := r.Body
+
+ if r.Header.Get("Content-Encoding") == "gzip" {
+ var err error
+ reader, err = gzip.NewReader(r.Body)
+ if err != nil {
+ return err
+ }
+ defer reader.Close()
+ }
+
+ err := g.gitService.WriteUploadPack(r.Context(), name, reader, w)
+ if err != nil {
+ slog.Error("Error WriteUploadPack", "error", err)
+ }
+ } else if r.Method == "GET" {
+ return g.Summary(w, r)
+ }
+
+ return nil
+}
+
+func (g *GitHandler) Summary(w http.ResponseWriter, r *ext.Request) error {
ext.SetHTML(w)
name := r.PathValue("name")
ref, err := g.gitService.GetHead(name)
@@ -120,11 +178,15 @@ func (g *GitHandler) Summary(w http.ResponseWriter, r *http.Request) error {
return err
}
- commits, err := g.gitService.ListCommits(name, "", 10)
+ commits, _, err := g.gitService.ListCommits(name, "", "", 10)
if err != nil {
return err
}
+ if len(tags) > 3 {
+ tags = tags[:3]
+ }
+
gitList := &templates.GitItemPage{
Name: name,
Ref: ref.Name().Short(),
@@ -134,11 +196,11 @@ func (g *GitHandler) Summary(w http.ResponseWriter, r *http.Request) error {
Commits: commits,
},
}
- templates.WritePageTemplate(w, gitList)
+ templates.WritePageTemplate(w, gitList, r.Context())
return nil
}
-func (g *GitHandler) About(w http.ResponseWriter, r *http.Request) error {
+func (g *GitHandler) About(w http.ResponseWriter, r *ext.Request) error {
ext.SetHTML(w)
name := r.PathValue("name")
ref, err := g.gitService.GetHead(name)
@@ -154,7 +216,7 @@ func (g *GitHandler) About(w http.ResponseWriter, r *http.Request) error {
GitItemBase: &templates.GitItemAboutPage{
About: []byte("About file not configured properly"),
},
- })
+ }, r.Context())
return nil
}
if err != nil {
@@ -178,11 +240,11 @@ func (g *GitHandler) About(w http.ResponseWriter, r *http.Request) error {
About: bs,
},
}
- templates.WritePageTemplate(w, gitList)
+ templates.WritePageTemplate(w, gitList, r.Context())
return nil
}
-func (g *GitHandler) Refs(w http.ResponseWriter, r *http.Request) error {
+func (g *GitHandler) Refs(w http.ResponseWriter, r *ext.Request) error {
ext.SetHTML(w)
name := r.PathValue("name")
@@ -209,11 +271,11 @@ func (g *GitHandler) Refs(w http.ResponseWriter, r *http.Request) error {
Branches: branches,
},
}
- templates.WritePageTemplate(w, gitList)
+ templates.WritePageTemplate(w, gitList, r.Context())
return nil
}
-func (g *GitHandler) Tree(w http.ResponseWriter, r *http.Request) error {
+func (g *GitHandler) Tree(w http.ResponseWriter, r *ext.Request) error {
ext.SetHTML(w)
name := r.PathValue("name")
ref := r.PathValue("ref")
@@ -238,11 +300,11 @@ func (g *GitHandler) Tree(w http.ResponseWriter, r *http.Request) error {
Tree: tree,
},
}
- templates.WritePageTemplate(w, gitList)
+ templates.WritePageTemplate(w, gitList, r.Context())
return nil
}
-func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) error {
+func (g *GitHandler) Blob(w http.ResponseWriter, r *ext.Request) error {
ext.SetHTML(w)
name := r.PathValue("name")
ref := r.PathValue("ref")
@@ -269,7 +331,7 @@ func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) error {
Content: []byte("Binary file"),
},
}
- templates.WritePageTemplate(w, gitList)
+ templates.WritePageTemplate(w, gitList, r.Context())
return nil
}
@@ -280,7 +342,8 @@ func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) error {
filename := filepath.Base(rest)
lexer := GetLexers(filename)
- style := styles.Get("xcode")
+ style := styles.Get(g.config.GetSyntaxHighlight())
+
formatter := html.New(
html.WithLineNumbers(true),
html.WithLinkableLineNumbers(true, "L"),
@@ -305,16 +368,17 @@ func (g *GitHandler) Blob(w http.ResponseWriter, r *http.Request) error {
Content: code.Bytes(),
},
}
- templates.WritePageTemplate(w, gitList)
+ templates.WritePageTemplate(w, gitList, r.Context())
return nil
}
-func (g *GitHandler) Log(w http.ResponseWriter, r *http.Request) error {
+func (g *GitHandler) Log(w http.ResponseWriter, r *ext.Request) error {
ext.SetHTML(w)
name := r.PathValue("name")
ref := r.PathValue("ref")
+ from := r.URL.Query().Get("from")
- commits, err := g.gitService.ListCommits(name, ref, 1000)
+ commits, next, err := g.gitService.ListCommits(name, ref, from, 100)
if err != nil {
return err
}
@@ -324,13 +388,36 @@ func (g *GitHandler) Log(w http.ResponseWriter, r *http.Request) error {
Ref: ref,
GitItemBase: &templates.GitItemLogPage{
Commits: commits,
+ Next: next,
+ },
+ }
+ templates.WritePageTemplate(w, gitList, r.Context())
+ return nil
+}
+
+func (g *GitHandler) Ref(w http.ResponseWriter, r *ext.Request) error {
+ ext.SetHTML(w)
+ name := r.PathValue("name")
+ ref := r.PathValue("ref")
+
+ commit, tag, err := g.gitService.GetTag(ref, name)
+ if err != nil {
+ return err
+ }
+
+ gitList := &templates.GitItemPage{
+ Name: name,
+ Ref: ref,
+ GitItemBase: &templates.GitItemRefPage{
+ Commit: commit,
+ Reference: tag,
},
}
- templates.WritePageTemplate(w, gitList)
+ templates.WritePageTemplate(w, gitList, r.Context())
return nil
}
-func (g *GitHandler) Commit(w http.ResponseWriter, r *http.Request) error {
+func (g *GitHandler) Commit(w http.ResponseWriter, r *ext.Request) error {
ext.SetHTML(w)
name := r.PathValue("name")
ref := r.PathValue("ref")
@@ -345,15 +432,34 @@ func (g *GitHandler) Commit(w http.ResponseWriter, r *http.Request) error {
return err
}
+ lexer := lexers.Get("diff")
+ style := styles.Get(g.config.GetSyntaxHighlight())
+
+ formatter := html.New(
+ html.WithLineNumbers(true),
+ html.WithLinkableLineNumbers(true, "L"),
+ )
+
+ iterator, err := lexer.Tokenise(nil, diff)
+ if err != nil {
+ return err
+ }
+
+ var code bytes.Buffer
+ err = formatter.Format(&code, style, iterator)
+ if err != nil {
+ return err
+ }
+
gitList := &templates.GitItemPage{
Name: name,
Ref: ref,
GitItemBase: &templates.GitItemCommitPage{
Commit: commit,
- Diff: diff,
+ Diff: code.Bytes(),
},
}
- templates.WritePageTemplate(w, gitList)
+ templates.WritePageTemplate(w, gitList, r.Context())
return nil
}
@@ -362,6 +468,10 @@ func GetLexers(filename string) chroma.Lexer {
return lexers.Get("sh")
}
+ if strings.HasSuffix(filename, ".qtpl") {
+ return lexers.Get("html")
+ }
+
lexer := lexers.Get(filename)
if lexer == nil {
@@ -369,3 +479,30 @@ func GetLexers(filename string) chroma.Lexer {
}
return lexer
}
+
+func isPublic(r *service.Repository) bool {
+ return r.Public
+}
+
+func orderBy(repos []*service.Repository, order config.OrderBy) []*service.Repository {
+ switch order {
+ case config.AlphabeticalAsc:
+ sort.Slice(repos, func(i, j int) bool {
+ return repos[i].Name < repos[j].Name
+ })
+ case config.AlphabeticalDesc:
+ sort.Slice(repos, func(i, j int) bool {
+ return repos[i].Name > repos[j].Name
+ })
+ case config.LastCommitAsc:
+ sort.Slice(repos, func(i, j int) bool {
+ return repos[i].LastCommit.Commit().Committer.When.Before(repos[j].LastCommit.Commit().Committer.When)
+ })
+ case config.LastCommitDesc:
+ sort.Slice(repos, func(i, j int) bool {
+ return repos[i].LastCommit.Commit().Committer.When.After(repos[j].LastCommit.Commit().Committer.When)
+ })
+ }
+
+ return repos
+}
diff --git a/pkg/handler/router.go b/pkg/handler/router.go
index f464ac2..fea8827 100644
--- a/pkg/handler/router.go
+++ b/pkg/handler/router.go
@@ -6,7 +6,7 @@ import (
serverconfig "git.gabrielgio.me/cerrado/pkg/config"
"git.gabrielgio.me/cerrado/pkg/ext"
"git.gabrielgio.me/cerrado/pkg/handler/about"
- "git.gabrielgio.me/cerrado/pkg/handler/config"
+ "git.gabrielgio.me/cerrado/pkg/handler/auth"
"git.gabrielgio.me/cerrado/pkg/handler/git"
"git.gabrielgio.me/cerrado/pkg/handler/static"
"git.gabrielgio.me/cerrado/pkg/service"
@@ -17,12 +17,13 @@ import (
// its sub package don't leak in other places.
func MountHandler(
gitService *service.GitService,
+ authService *service.AuthService,
configRepo *serverconfig.ConfigurationRepository,
) (http.Handler, error) {
var (
- gitHandler = git.NewGitHandler(gitService, configRepo)
- aboutHandler = about.NewAboutHandler(configRepo)
- configHandler = config.ConfigFile(configRepo)
+ gitHandler = git.NewGitHandler(gitService, configRepo)
+ aboutHandler = about.NewAboutHandler(configRepo)
+ loginHandler = auth.NewLoginHandler(authService)
)
staticHandler, err := static.ServeStaticHandler()
@@ -33,17 +34,27 @@ func MountHandler(
mux := ext.NewRouter()
mux.AddMiddleware(ext.Compress)
mux.AddMiddleware(ext.Log)
+ mux.AddMiddleware(ext.VerifyRespository(configRepo))
+
+ if configRepo.IsAuthEnabled() {
+ mux.AddMiddleware(ext.Authenticate(authService))
+ mux.HandleFunc("/login/{$}", loginHandler.Login)
+ mux.HandleFunc("/logout/{$}", loginHandler.Logout)
+ } else {
+ mux.AddMiddleware(ext.DisableAuthentication)
+ }
mux.HandleFunc("/static/{file}", staticHandler)
mux.HandleFunc("/{name}/about/{$}", gitHandler.About)
- mux.HandleFunc("/{name}/", gitHandler.Summary)
+ mux.HandleFunc("/{name}", gitHandler.Multiplex)
+ mux.HandleFunc("/{name}/{rest...}", gitHandler.Multiplex)
mux.HandleFunc("/{name}/refs/{$}", gitHandler.Refs)
mux.HandleFunc("/{name}/tree/{ref}/{rest...}", gitHandler.Tree)
mux.HandleFunc("/{name}/blob/{ref}/{rest...}", gitHandler.Blob)
mux.HandleFunc("/{name}/log/{ref}/", gitHandler.Log)
mux.HandleFunc("/{name}/commit/{ref}/", gitHandler.Commit)
+ mux.HandleFunc("/{name}/ref/{ref}/", gitHandler.Ref)
mux.HandleFunc("/{name}/archive/{file}", gitHandler.Archive)
- mux.HandleFunc("/config", configHandler)
mux.HandleFunc("/about", aboutHandler.About)
mux.HandleFunc("/", gitHandler.List)
return mux.Handler(), nil
diff --git a/pkg/handler/static/handler.go b/pkg/handler/static/handler.go
index 361f690..cdb2ae6 100644
--- a/pkg/handler/static/handler.go
+++ b/pkg/handler/static/handler.go
@@ -16,7 +16,7 @@ func ServeStaticHandler() (ext.ErrorRequestHandler, error) {
return nil, err
}
- return func(w http.ResponseWriter, r *http.Request) error {
+ return func(w http.ResponseWriter, r *ext.Request) error {
var (
f = r.PathValue("file")
e = filepath.Ext(f)
@@ -24,7 +24,7 @@ func ServeStaticHandler() (ext.ErrorRequestHandler, error) {
)
ext.SetMIME(w, m)
w.Header().Add("Cache-Control", "max-age=31536000")
- http.ServeFileFS(w, r, staticFs, f)
+ http.ServeFileFS(w, r.Request, staticFs, f)
return nil
}, nil
}
diff --git a/pkg/humanize/times.go b/pkg/humanize/times.go
new file mode 100644
index 0000000..1bd5166
--- /dev/null
+++ b/pkg/humanize/times.go
@@ -0,0 +1,141 @@
+// This code includes software originally developed by Dustin Sallings.
+//
+// Copyright (c) 2005-2008 Dustin Sallings <dustin@spy.net>
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+//
+//<http://www.opensource.org/licenses/mit-license.php>
+
+package humanize
+
+import (
+ "fmt"
+ "math"
+ "sort"
+ "time"
+)
+
+// Seconds-based time units
+const (
+ Day = 24 * time.Hour
+ Week = 7 * Day
+ Month = 30 * Day
+ Year = 12 * Month
+ LongTime = 37 * Year
+)
+
+// Time formats a time into a relative string.
+//
+// Time(someT) -> "3 weeks ago"
+func Time(then time.Time) string {
+ return RelTime(then, time.Now(), "ago", "from now")
+}
+
+// A RelTimeMagnitude struct contains a relative time point at which
+// the relative format of time will switch to a new format string. A
+// slice of these in ascending order by their "D" field is passed to
+// CustomRelTime to format durations.
+//
+// The Format field is a string that may contain a "%s" which will be
+// replaced with the appropriate signed label (e.g. "ago" or "from
+// now") and a "%d" that will be replaced by the quantity.
+//
+// The DivBy field is the amount of time the time difference must be
+// divided by in order to display correctly.
+//
+// e.g. if D is 2*time.Minute and you want to display "%d minutes %s"
+// DivBy should be time.Minute so whatever the duration is will be
+// expressed in minutes.
+type RelTimeMagnitude struct {
+ D time.Duration
+ Format string
+ DivBy time.Duration
+}
+
+var defaultMagnitudes = []RelTimeMagnitude{
+ {time.Second, "now", time.Second},
+ {2 * time.Second, "1 second %s", 1},
+ {time.Minute, "%d seconds %s", time.Second},
+ {2 * time.Minute, "1 minute %s", 1},
+ {time.Hour, "%d minutes %s", time.Minute},
+ {2 * time.Hour, "1 hour %s", 1},
+ {Day, "%d hours %s", time.Hour},
+ {2 * Day, "1 day %s", 1},
+ {Week, "%d days %s", Day},
+ {2 * Week, "1 week %s", 1},
+ {Month, "%d weeks %s", Week},
+ {2 * Month, "1 month %s", 1},
+ {Year, "%d months %s", Month},
+ {18 * Month, "1 year %s", 1},
+ {2 * Year, "2 years %s", 1},
+ {LongTime, "%d years %s", Year},
+ {math.MaxInt64, "a long while %s", 1},
+}
+
+// RelTime formats a time into a relative string.
+//
+// It takes two times and two labels. In addition to the generic time
+// delta string (e.g. 5 minutes), the labels are used applied so that
+// the label corresponding to the smaller time is applied.
+//
+// RelTime(timeInPast, timeInFuture, "earlier", "later") -> "3 weeks earlier"
+func RelTime(a, b time.Time, albl, blbl string) string {
+ return CustomRelTime(a, b, albl, blbl, defaultMagnitudes)
+}
+
+// CustomRelTime formats a time into a relative string.
+//
+// It takes two times two labels and a table of relative time formats.
+// In addition to the generic time delta string (e.g. 5 minutes), the
+// labels are used applied so that the label corresponding to the
+// smaller time is applied.
+func CustomRelTime(a, b time.Time, albl, blbl string, magnitudes []RelTimeMagnitude) string {
+ lbl := albl
+ diff := b.Sub(a)
+
+ if a.After(b) {
+ lbl = blbl
+ diff = a.Sub(b)
+ }
+
+ n := sort.Search(len(magnitudes), func(i int) bool {
+ return magnitudes[i].D > diff
+ })
+
+ if n >= len(magnitudes) {
+ n = len(magnitudes) - 1
+ }
+ mag := magnitudes[n]
+ args := []interface{}{}
+ escaped := false
+ for _, ch := range mag.Format {
+ if escaped {
+ switch ch {
+ case 's':
+ args = append(args, lbl)
+ case 'd':
+ args = append(args, diff/mag.DivBy)
+ }
+ escaped = false
+ } else {
+ escaped = ch == '%'
+ }
+ }
+ return fmt.Sprintf(mag.Format, args...)
+}
diff --git a/pkg/service/auth.go b/pkg/service/auth.go
new file mode 100644
index 0000000..0dbd960
--- /dev/null
+++ b/pkg/service/auth.go
@@ -0,0 +1,123 @@
+package service
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/rand"
+ "encoding/base64"
+ "fmt"
+ "io"
+
+ "golang.org/x/crypto/bcrypt"
+)
+
+type (
+ AuthService struct {
+ authRepository authRepository
+ }
+
+ authRepository interface {
+ GetPassphrase() []byte
+ GetBase64AesKey() []byte
+ }
+)
+
+var tokenSeed = []byte("this is a token for cerrado")
+
+func NewAuthService(repostiory authRepository) *AuthService {
+ return &AuthService{
+ authRepository: repostiory,
+ }
+}
+
+func (a *AuthService) CheckAuth(username, password string) bool {
+ passphrase := a.authRepository.GetPassphrase()
+ pass := []byte(fmt.Sprintf("%s:%s", username, password))
+
+ err := bcrypt.CompareHashAndPassword(passphrase, pass)
+
+ return err == nil
+}
+
+func (a *AuthService) IssueToken() ([]byte, error) {
+ // TODO: do this block only once
+ base := a.authRepository.GetBase64AesKey()
+
+ dbuf, err := base64.StdEncoding.DecodeString(string(base))
+ if err != nil {
+ return nil, err
+ }
+
+ block, err := aes.NewCipher(dbuf)
+ if err != nil {
+ return nil, err
+ }
+
+ gcm, err := cipher.NewGCM(block)
+ if err != nil {
+ return nil, err
+ }
+
+ nonce := make([]byte, gcm.NonceSize())
+ if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
+ return nil, err
+ }
+
+ ciphertext := gcm.Seal(nonce, nonce, tokenSeed, nil)
+
+ return ciphertext, nil
+}
+
+func (a *AuthService) ValidateToken(token []byte) (bool, error) {
+ base := a.authRepository.GetBase64AesKey()
+
+ dbuf, err := base64.StdEncoding.DecodeString(string(base))
+ if err != nil {
+ return false, err
+ }
+
+ block, err := aes.NewCipher(dbuf)
+ if err != nil {
+ return false, err
+ }
+
+ gcm, err := cipher.NewGCM(block)
+ if err != nil {
+ return false, err
+ }
+
+ nonceSize := gcm.NonceSize()
+ if len(token) < nonceSize {
+ return false, fmt.Errorf("ciphertext too short")
+ }
+
+ nonce, ciphertext := token[:nonceSize], token[nonceSize:]
+ plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
+ if err != nil {
+ return false, err
+ }
+
+ return bytes.Equal(tokenSeed, plaintext), nil
+}
+
+func GenerateHash(username, password string) (string, error) {
+ passphrase := fmt.Sprintf("%s:%s", username, password)
+ bytes, err := bcrypt.GenerateFromPassword([]byte(passphrase), 14)
+ if err != nil {
+ return "", err
+ }
+
+ return string(bytes), nil
+}
+
+func GenerateAesKey() (string, error) {
+ key := make([]byte, 32)
+
+ _, err := rand.Read(key)
+ if err != nil {
+ return "", err
+ }
+
+ return base64.StdEncoding.EncodeToString(key), nil
+}
diff --git a/pkg/service/auth_test.go b/pkg/service/auth_test.go
new file mode 100644
index 0000000..06bf76f
--- /dev/null
+++ b/pkg/service/auth_test.go
@@ -0,0 +1,119 @@
+// go:build unit
+
+package service
+
+import (
+ "testing"
+)
+
+func TestCheck(t *testing.T) {
+ testCases := []struct {
+ name string
+ passphrase []byte
+ username string
+ password string
+ wantError bool
+ }{
+ {
+ name: "generated",
+ passphrase: nil,
+ username: "gabrielgio",
+ password: "adminadmin",
+ wantError: false,
+ },
+ {
+ name: "static",
+ passphrase: []byte("$2a$14$W2yT0E6Zm8nTecqipHUQGOLC6PvNjIQqpQTW/MZmD5oqDfaBJnBV6"),
+ username: "gabrielgio",
+ password: "adminadmin",
+ wantError: false,
+ },
+ {
+ name: "error",
+ passphrase: []byte("This is not a valid hash"),
+ username: "gabrielgio",
+ password: "adminadmin",
+ wantError: true,
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ mock := &mockAuthRepository{
+ username: tc.username,
+ password: tc.password,
+ passphrase: tc.passphrase,
+ }
+
+ service := AuthService{authRepository: mock}
+
+ if service.CheckAuth(tc.username, tc.password) == tc.wantError {
+ t.Errorf("Invalid result, wanted %t got %t", tc.wantError, !tc.wantError)
+ }
+ })
+ }
+}
+
+func TestValidate(t *testing.T) {
+ testCases := []struct {
+ name string
+ aesKey []byte
+ }{
+ {
+ name: "generated",
+ aesKey: nil,
+ },
+ {
+ name: "static",
+ aesKey: []byte("RTGkmunKmi5agh7jaqENunG2zI/godnkqhHaHyX/AVg="),
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ mock := &mockAuthRepository{
+ aesKey: tc.aesKey,
+ }
+
+ service := AuthService{authRepository: mock}
+
+ token, err := service.IssueToken()
+ if err != nil {
+ t.Fatalf("Error issuing token: %s", err.Error())
+ }
+
+ v, err := service.ValidateToken(token)
+ if err != nil {
+ t.Fatalf("Error validating token: %s", err.Error())
+ }
+
+ if !v {
+ t.Error("Invalid token generated")
+ }
+ })
+ }
+}
+
+type mockAuthRepository struct {
+ username string
+ password string
+ passphrase []byte
+
+ aesKey []byte
+}
+
+func (m *mockAuthRepository) GetPassphrase() []byte {
+ if m.passphrase == nil {
+ hash, _ := GenerateHash(m.username, m.password)
+ m.passphrase = []byte(hash)
+ }
+ return m.passphrase
+}
+
+func (m *mockAuthRepository) GetBase64AesKey() []byte {
+ if m.aesKey == nil {
+ key, _ := GenerateAesKey()
+ m.aesKey = []byte(key)
+ }
+ return m.aesKey
+}
diff --git a/pkg/service/git.go b/pkg/service/git.go
index f03ba42..6aa5cd6 100644
--- a/pkg/service/git.go
+++ b/pkg/service/git.go
@@ -2,22 +2,25 @@ package service
import (
"compress/gzip"
+ "context"
"errors"
"io"
"log/slog"
"git.gabrielgio.me/cerrado/pkg/config"
"git.gabrielgio.me/cerrado/pkg/git"
+ gogit "github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"github.com/go-git/go-git/v5/plumbing/object"
)
type (
Repository struct {
- Name string
- Description string
- LastCommitDate string
- Ref string
+ Name string
+ Description string
+ Public bool
+ LastCommit *git.CommitReference
+ Ref string
}
GitService struct {
@@ -30,9 +33,7 @@ type (
}
)
-var (
- ErrRepositoryNotFound = errors.New("Repository not found")
-)
+var ErrRepositoryNotFound = errors.New("Repository not found")
// TODO: make it configurable
const timeFormat = "2006.01.02 15:04:05"
@@ -50,6 +51,10 @@ func (g *GitService) ListRepositories() ([]*Repository, error) {
for _, r := range rs {
repo, err := git.OpenRepository(r.Path)
if err != nil {
+ if errors.Is(err, gogit.ErrRepositoryNotExists) {
+ slog.Info("Path does not contain a repository", "path", r.Path)
+ continue
+ }
return nil, err
}
@@ -66,35 +71,36 @@ func (g *GitService) ListRepositories() ([]*Repository, error) {
}
repos = append(repos, &Repository{
- Name: r.Name,
- Description: r.Description,
- LastCommitDate: obj.Author.When.Format(timeFormat),
- Ref: head.Name().Short(),
+ Name: r.Name,
+ Description: r.Description,
+ Public: r.Public,
+ LastCommit: obj,
+ Ref: head.Name().Short(),
})
}
return repos, nil
}
-func (g *GitService) ListCommits(name, ref string, count int) ([]*object.Commit, error) {
+func (g *GitService) ListCommits(name, ref, from string, count int) ([]*git.CommitReference, *object.Commit, error) {
r := g.configRepo.GetByName(name)
if r == nil {
- return nil, ErrRepositoryNotFound
+ return nil, nil, ErrRepositoryNotFound
}
repo, err := git.OpenRepository(r.Path)
if err != nil {
- return nil, err
+ return nil, nil, err
}
err = repo.SetRef(ref)
if err != nil {
- return nil, err
+ return nil, nil, err
}
- return repo.Commits(count)
+ return repo.Commits(count, from)
}
-func (g *GitService) LastCommit(name, ref string) (*object.Commit, error) {
+func (g *GitService) LastCommit(name, ref string) (*git.CommitReference, error) {
r := g.configRepo.GetByName(name)
if r == nil {
return nil, ErrRepositoryNotFound
@@ -236,6 +242,25 @@ func (g *GitService) GetAbout(name string) ([]byte, error) {
return file, nil
}
+func (g *GitService) GetTag(ref, name string) (*object.Commit, *git.TagReference, error) {
+ r := g.configRepo.GetByName(name)
+ if r == nil {
+ return nil, nil, ErrRepositoryNotFound
+ }
+
+ repo, err := git.OpenRepository(r.Path)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ err = repo.SetRef(ref)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ return repo.Tag()
+}
+
func (g *GitService) ListTags(name string) ([]*git.TagReference, error) {
r := g.configRepo.GetByName(name)
if r == nil {
@@ -275,3 +300,31 @@ func (g *GitService) GetHead(name string) (*plumbing.Reference, error) {
return repo.Head()
}
+
+func (g *GitService) WriteInfoRefs(ctx context.Context, name string, w io.Writer) error {
+ r := g.configRepo.GetByName(name)
+ if r == nil {
+ return ErrRepositoryNotFound
+ }
+
+ repo, err := git.OpenRepository(r.Path)
+ if err != nil {
+ return err
+ }
+
+ return repo.WriteInfoRefs(ctx, w)
+}
+
+func (g *GitService) WriteUploadPack(ctx context.Context, name string, re io.Reader, w io.Writer) error {
+ r := g.configRepo.GetByName(name)
+ if r == nil {
+ return ErrRepositoryNotFound
+ }
+
+ repo, err := git.OpenRepository(r.Path)
+ if err != nil {
+ return err
+ }
+
+ return repo.WriteUploadPack(ctx, re, w)
+}
diff --git a/pkg/u/list.go b/pkg/u/list.go
index 39d7b11..1cffbd5 100644
--- a/pkg/u/list.go
+++ b/pkg/u/list.go
@@ -1,5 +1,25 @@
package u
+func Filter[T any](v []T, f func(T) bool) []T {
+ var result []T
+
+ for _, s := range v {
+ if f(s) {
+ result = append(result, s)
+ }
+ }
+
+ return result
+}
+
+func Map[T any, V any](a []T, f func(T) V) []V {
+ result := make([]V, len(a))
+ for i, v := range a {
+ result[i] = f(v)
+ }
+ return result
+}
+
func First[T any](v []T) (T, bool) {
if len(v) == 0 {
var zero T
@@ -25,7 +45,7 @@ func LastOrZero[T any](v []T) T {
}
func ChunkBy[T any](items []T, chunkSize int) [][]T {
- var chunks = make([][]T, 0, (len(items)/chunkSize)+1)
+ chunks := make([][]T, 0, (len(items)/chunkSize)+1)
for chunkSize < len(items) {
items, chunks = items[chunkSize:], append(chunks, items[0:chunkSize:chunkSize])
}
diff --git a/scss/main.scss b/scss/main.scss
index 0766f82..e0fecf1 100644
--- a/scss/main.scss
+++ b/scss/main.scss
@@ -5,6 +5,10 @@ $base-font-size: 1rem;
$font-family-monospace: monospace;
$headings-margin-bottom: 0;
+$input-border-radius: 0;
+
+$btn-border-radius: 0;
+
// basic functionality
@import "bootstrap/scss/_functions.scss";
@import "bootstrap/scss/_variables.scss";
@@ -21,73 +25,79 @@ $navbar-nav-link-padding-x: $spacer;
@import "bootstrap/scss/_nav.scss";
@import "bootstrap/scss/_navbar.scss";
@import "bootstrap/scss/_grid.scss";
+@import "bootstrap/scss/_forms.scss";
+@import "bootstrap/scss/_buttons.scss";
@import "tree.scss";
-// TODO remove once is not needed
-$alert-border-radius: 0;
-@import "bootstrap/scss/_alert.scss";
-
// overwrite to reduce the ammount of css generated by loading all utilities
$utilities: (
- "order": (
- responsive: true,
- property: order,
- values: (
- first: -1,
- 0: 0,
- 1: 1,
- 2: 2,
- 3: 3,
- 4: 4,
- 5: 5,
- last: 6,
+ "order": (responsive: true,
+ property: order,
+ values: (first: -1,
+ 0: 0,
+ 1: 1,
+ 2: 2,
+ 3: 3,
+ 4: 4,
+ 5: 5,
+ last: 6,
+ ),
),
- ),
- "float": (
- responsive: true,
- property: float,
- values: (
- start: left,
- end: right,
- none: none,
- )
- ),
- "text-align": (
- responsive: true,
- property: text-align,
- class: text,
- values: (
- start: left,
- end: right,
- center: center,
- )
- ),
- "margin": (
- responsive: true,
- property: margin,
- class: m,
- values: map-merge($spacers, (auto: auto))
- ),
- "margin-end": (
- responsive: true,
- property: margin-right,
- class: me,
- values: map-merge($spacers, (auto: auto))
- ),
+ "float": (responsive: true,
+ property: float,
+ values: (start: left,
+ end: right,
+ none: none,
+ )),
+ "text-align": (responsive: true,
+ property: text-align,
+ class: text,
+ values: (start: left,
+ end: right,
+ center: center,
+ )),
+ "margin": (responsive: true,
+ property: margin,
+ class: m,
+ values: map-merge($spacers, (auto: auto))),
+ "margin-end": (responsive: true,
+ property: margin-right,
+ class: me,
+ values: map-merge($spacers, (auto: auto))),
+ "margin-start": (responsive: true,
+ property: margin-left,
+ class: ms,
+ values: map-merge($spacers, (auto: auto))),
);
@import "bootstrap/scss/utilities/_api.scss";
+// prevents wierd font resizing on overflow
body {
- // prevents wierd font resizing on overflow
-webkit-text-size-adjust: 100%;
font-family: $font-family-monospace;
font-size: $base-font-size;
margin: 0;
}
+// prevert wierd input overflowing 100%
+input {
+ width: 100%;
+ box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+}
+
+a[href]:not([href=""]):not(.nav-link) {
+ text-decoration: none;
+
+ &:hover {
+ text-decoration: underline;
+ }
+}
+
.navbar-nav {
- margin-top: 0px
+ margin-top: 0px
}
.event-list {
@@ -106,29 +116,50 @@ body {
background: #f8f9fa;
}
+.event-commit {
+ background: #dadada;
+ padding: 5px;
+
+ a {
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ }
+}
+
+.event-commit a:nth-child(3) {
+ text-align: end;
+
+ @include media-breakpoint-down(xl) {
+ text-align: start;
+ }
+}
+
+
.selected {
- text-decoration: underline;
+ text-decoration: underline;
}
-.event > h4 {
- margin: 0;
+.event>h4 {
+ margin: 0;
}
-.event > p {
- margin: 0.5rem 0;
+
+.event>p {
+ margin: 0.5rem 0;
}
.code-view {
display: grid;
overflow-x: auto;
- > pre {
- margin: 0;
+ >pre {
+ margin: 0;
}
}
-.pathing{
- margin-left: $spacer;
- display: inline-block
+.pathing {
+ margin-left: $spacer;
+ display: inline-block
}
pre {
@@ -137,21 +168,48 @@ pre {
}
#name {
- text-overflow: ellipsis;
- overflow: hidden;
- white-space: nowrap;
- padding-left: $spacer;
- max-width: calc(100% - calc(2 * #{$spacer}));
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+ padding-left: $spacer;
+ max-width: calc(100% - calc(2 * #{$spacer}));
}
#about {
- padding: 0 $spacer $spacer $spacer;
- > p:first-child {
- margin-top: 0
- }
+ padding: 0 $spacer $spacer $spacer;
- @include media-breakpoint-down(md) {
- padding: $spacer;
- max-width: calc(100% - calc(2 * #{$spacer}));
- }
+ >p:first-child {
+ margin-top: 0
+ }
+
+ @include media-breakpoint-down(md) {
+ padding: $spacer;
+ max-width: calc(100% - calc(2 * #{$spacer}));
+ }
+}
+
+.ref {
+ padding: 2px;
+ margin: 2px;
+ color: white;
+ text-decoration: none;
+
+ &.branch {
+ background: #25a525;
+ }
+
+ &.tag {
+ background: #5874e2;
+
+ }
+}
+
+.more {
+ margin: -15px 4px 10px 0;
+ padding: 5px 0 5px 0;
+ text-decoration: none;
+
+ &:hover {
+ text-decoration: underline;
+ }
}
diff --git a/scss/tree.scss b/scss/tree.scss
index bbca162..05828dc 100644
--- a/scss/tree.scss
+++ b/scss/tree.scss
@@ -1,59 +1,91 @@
-// TODO: refer to sourcehut code AGPL
+// This code includes software originally developed by Drew DeVault.
+//
+// Copyright 2017 Drew DeVault <sir@cmpwn.com>
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+// list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+// this list of conditions and the following disclaimer in the documentation
+// and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its contributors
+// may be used to endorse or promote products derived from this software without
+// specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
.tree-list {
- display: grid;
- // mode name
- grid-template-columns: auto 1fr fit-content(40em) auto auto;
- font-family: $font-family-monospace;
-
- svg {
- color: #777;
- }
-
- .size {
- text-align: right;
- }
-
- .name.blob a {
- color: $gray-900;
- }
-
- .mode, .commit, .commit a, .date, .size {
- color: $gray-700;
- }
-
- .name.blob {
- text-overflow: ellipsis;
- white-space: nowrap;
- overflow: hidden;
- }
-
- .commit {
- text-overflow: ellipsis;
- white-space: nowrap;
- overflow: hidden;
- }
-
- & > div {
- padding: 0.1rem 0.5rem;
- background: transparent;
-
- &.id {
- text-align: right;
+ display: grid;
+ // mode name
+ grid-template-columns: auto 1fr fit-content(40em) auto auto;
+ font-family: $font-family-monospace;
+
+ svg {
+ color: #777;
+ }
+
+ .size {
+ text-align: right;
}
- &.comments {
- text-align: center;
+ .name.blob a {
+ color: $gray-900;
}
- @for $i from 1 through 5 {
- &:nth-child(5n+#{$i}) {
- grid-column-start: $i;
- }
+ .mode,
+ .commit,
+ .commit a,
+ .date,
+ .size {
+ color: $gray-700;
+ }
+
+ .name.blob {
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ }
+
+ .commit {
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ }
+
+ &>div {
+ padding: 0.1rem 0.5rem;
+ background: transparent;
+
+ &.id {
+ text-align: right;
+ }
+
+ &.comments {
+ text-align: center;
+ }
+
+ @for $i from 1 through 5 {
+ &:nth-child(5n+#{$i}) {
+ grid-column-start: $i;
+ }
- // Striped rows
- &:nth-child(10n+#{$i}) {
- background: rgba(0,0,0,.05);
- }
+ // Striped rows
+ &:nth-child(10n+#{$i}) {
+ background: rgba(0, 0, 0, .05);
+ }
+ }
}
- }
}
diff --git a/templates/about.qtpl b/templates/about.qtpl
index faee50e..cfbf0d9 100644
--- a/templates/about.qtpl
+++ b/templates/about.qtpl
@@ -1,16 +1,19 @@
+{% import "context" %}
+
{% code
type AboutPage struct {
+ LoggedIn bool
Body []byte
}
%}
-{% func (p *AboutPage) Title() %}Hello{% endfunc %}
+{% func (p *AboutPage) Title(ctx context.Context) %}Hello{% endfunc %}
-{% func (p *AboutPage) Navbar() %}{%= Navbar(About) %}{% endfunc %}
+{% func (p *AboutPage) Navbar(ctx context.Context) %}{%= Navbar(ctx, About) %}{% endfunc %}
-{% func (p *AboutPage) Content() %}
+{% func (p *AboutPage) Content(ctx context.Context) %}
{%z= p.Body %}
{% endfunc %}
-{% func (p *AboutPage) Script() %}
+{% func (p *AboutPage) Script(ctx context.Context) %}
{% endfunc %}
diff --git a/templates/about.qtpl.go b/templates/about.qtpl.go
index aaa2514..a640f7e 100644
--- a/templates/about.qtpl.go
+++ b/templates/about.qtpl.go
@@ -1,162 +1,166 @@
// Code generated by qtc from "about.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
-//line about.qtpl:1
+//line templates/about.qtpl:1
package templates
-//line about.qtpl:1
+//line templates/about.qtpl:1
+import "context"
+
+//line templates/about.qtpl:3
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
-//line about.qtpl:1
+//line templates/about.qtpl:3
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
-//line about.qtpl:2
+//line templates/about.qtpl:4
type AboutPage struct {
- Body []byte
+ LoggedIn bool
+ Body []byte
}
-//line about.qtpl:7
-func (p *AboutPage) StreamTitle(qw422016 *qt422016.Writer) {
-//line about.qtpl:7
+//line templates/about.qtpl:10
+func (p *AboutPage) StreamTitle(qw422016 *qt422016.Writer, ctx context.Context) {
+//line templates/about.qtpl:10
qw422016.N().S(`Hello`)
-//line about.qtpl:7
+//line templates/about.qtpl:10
}
-//line about.qtpl:7
-func (p *AboutPage) WriteTitle(qq422016 qtio422016.Writer) {
-//line about.qtpl:7
+//line templates/about.qtpl:10
+func (p *AboutPage) WriteTitle(qq422016 qtio422016.Writer, ctx context.Context) {
+//line templates/about.qtpl:10
qw422016 := qt422016.AcquireWriter(qq422016)
-//line about.qtpl:7
- p.StreamTitle(qw422016)
-//line about.qtpl:7
+//line templates/about.qtpl:10
+ p.StreamTitle(qw422016, ctx)
+//line templates/about.qtpl:10
qt422016.ReleaseWriter(qw422016)
-//line about.qtpl:7
+//line templates/about.qtpl:10
}
-//line about.qtpl:7
-func (p *AboutPage) Title() string {
-//line about.qtpl:7
+//line templates/about.qtpl:10
+func (p *AboutPage) Title(ctx context.Context) string {
+//line templates/about.qtpl:10
qb422016 := qt422016.AcquireByteBuffer()
-//line about.qtpl:7
- p.WriteTitle(qb422016)
-//line about.qtpl:7
+//line templates/about.qtpl:10
+ p.WriteTitle(qb422016, ctx)
+//line templates/about.qtpl:10
qs422016 := string(qb422016.B)
-//line about.qtpl:7
+//line templates/about.qtpl:10
qt422016.ReleaseByteBuffer(qb422016)
-//line about.qtpl:7
+//line templates/about.qtpl:10
return qs422016
-//line about.qtpl:7
+//line templates/about.qtpl:10
}
-//line about.qtpl:9
-func (p *AboutPage) StreamNavbar(qw422016 *qt422016.Writer) {
-//line about.qtpl:9
- StreamNavbar(qw422016, About)
-//line about.qtpl:9
+//line templates/about.qtpl:12
+func (p *AboutPage) StreamNavbar(qw422016 *qt422016.Writer, ctx context.Context) {
+//line templates/about.qtpl:12
+ StreamNavbar(qw422016, ctx, About)
+//line templates/about.qtpl:12
}
-//line about.qtpl:9
-func (p *AboutPage) WriteNavbar(qq422016 qtio422016.Writer) {
-//line about.qtpl:9
+//line templates/about.qtpl:12
+func (p *AboutPage) WriteNavbar(qq422016 qtio422016.Writer, ctx context.Context) {
+//line templates/about.qtpl:12
qw422016 := qt422016.AcquireWriter(qq422016)
-//line about.qtpl:9
- p.StreamNavbar(qw422016)
-//line about.qtpl:9
+//line templates/about.qtpl:12
+ p.StreamNavbar(qw422016, ctx)
+//line templates/about.qtpl:12
qt422016.ReleaseWriter(qw422016)
-//line about.qtpl:9
+//line templates/about.qtpl:12
}
-//line about.qtpl:9
-func (p *AboutPage) Navbar() string {
-//line about.qtpl:9
+//line templates/about.qtpl:12
+func (p *AboutPage) Navbar(ctx context.Context) string {
+//line templates/about.qtpl:12
qb422016 := qt422016.AcquireByteBuffer()
-//line about.qtpl:9
- p.WriteNavbar(qb422016)
-//line about.qtpl:9
+//line templates/about.qtpl:12
+ p.WriteNavbar(qb422016, ctx)
+//line templates/about.qtpl:12
qs422016 := string(qb422016.B)
-//line about.qtpl:9
+//line templates/about.qtpl:12
qt422016.ReleaseByteBuffer(qb422016)
-//line about.qtpl:9
+//line templates/about.qtpl:12
return qs422016
-//line about.qtpl:9
+//line templates/about.qtpl:12
}
-//line about.qtpl:11
-func (p *AboutPage) StreamContent(qw422016 *qt422016.Writer) {
-//line about.qtpl:11
+//line templates/about.qtpl:14
+func (p *AboutPage) StreamContent(qw422016 *qt422016.Writer, ctx context.Context) {
+//line templates/about.qtpl:14
qw422016.N().S(`
`)
-//line about.qtpl:12
+//line templates/about.qtpl:15
qw422016.N().Z(p.Body)
-//line about.qtpl:12
+//line templates/about.qtpl:15
qw422016.N().S(`
`)
-//line about.qtpl:13
+//line templates/about.qtpl:16
}
-//line about.qtpl:13
-func (p *AboutPage) WriteContent(qq422016 qtio422016.Writer) {
-//line about.qtpl:13
+//line templates/about.qtpl:16
+func (p *AboutPage) WriteContent(qq422016 qtio422016.Writer, ctx context.Context) {
+//line templates/about.qtpl:16
qw422016 := qt422016.AcquireWriter(qq422016)
-//line about.qtpl:13
- p.StreamContent(qw422016)
-//line about.qtpl:13
+//line templates/about.qtpl:16
+ p.StreamContent(qw422016, ctx)
+//line templates/about.qtpl:16
qt422016.ReleaseWriter(qw422016)
-//line about.qtpl:13
+//line templates/about.qtpl:16
}
-//line about.qtpl:13
-func (p *AboutPage) Content() string {
-//line about.qtpl:13
+//line templates/about.qtpl:16
+func (p *AboutPage) Content(ctx context.Context) string {
+//line templates/about.qtpl:16
qb422016 := qt422016.AcquireByteBuffer()
-//line about.qtpl:13
- p.WriteContent(qb422016)
-//line about.qtpl:13
+//line templates/about.qtpl:16
+ p.WriteContent(qb422016, ctx)
+//line templates/about.qtpl:16
qs422016 := string(qb422016.B)
-//line about.qtpl:13
+//line templates/about.qtpl:16
qt422016.ReleaseByteBuffer(qb422016)
-//line about.qtpl:13
+//line templates/about.qtpl:16
return qs422016
-//line about.qtpl:13
+//line templates/about.qtpl:16
}
-//line about.qtpl:15
-func (p *AboutPage) StreamScript(qw422016 *qt422016.Writer) {
-//line about.qtpl:15
+//line templates/about.qtpl:18
+func (p *AboutPage) StreamScript(qw422016 *qt422016.Writer, ctx context.Context) {
+//line templates/about.qtpl:18
qw422016.N().S(`
`)
-//line about.qtpl:16
+//line templates/about.qtpl:19
}
-//line about.qtpl:16
-func (p *AboutPage) WriteScript(qq422016 qtio422016.Writer) {
-//line about.qtpl:16
+//line templates/about.qtpl:19
+func (p *AboutPage) WriteScript(qq422016 qtio422016.Writer, ctx context.Context) {
+//line templates/about.qtpl:19
qw422016 := qt422016.AcquireWriter(qq422016)
-//line about.qtpl:16
- p.StreamScript(qw422016)
-//line about.qtpl:16
+//line templates/about.qtpl:19
+ p.StreamScript(qw422016, ctx)
+//line templates/about.qtpl:19
qt422016.ReleaseWriter(qw422016)
-//line about.qtpl:16
+//line templates/about.qtpl:19
}
-//line about.qtpl:16
-func (p *AboutPage) Script() string {
-//line about.qtpl:16
+//line templates/about.qtpl:19
+func (p *AboutPage) Script(ctx context.Context) string {
+//line templates/about.qtpl:19
qb422016 := qt422016.AcquireByteBuffer()
-//line about.qtpl:16
- p.WriteScript(qb422016)
-//line about.qtpl:16
+//line templates/about.qtpl:19
+ p.WriteScript(qb422016, ctx)
+//line templates/about.qtpl:19
qs422016 := string(qb422016.B)
-//line about.qtpl:16
+//line templates/about.qtpl:19
qt422016.ReleaseByteBuffer(qb422016)
-//line about.qtpl:16
+//line templates/about.qtpl:19
return qs422016
-//line about.qtpl:16
+//line templates/about.qtpl:19
}
diff --git a/templates/base.qtpl b/templates/base.qtpl
index 9e2e6ac..db9deee 100644
--- a/templates/base.qtpl
+++ b/templates/base.qtpl
@@ -1,5 +1,6 @@
This is a base page template. All the other template pages implement this interface.
+{% import "context" %}
{% import "strconv" %}
{% import "time" %}
@@ -9,10 +10,10 @@ This is a base page template. All the other template pages implement this interf
{% interface
Page {
- Title()
- Content()
- Script()
- Navbar()
+ Title(ctx context.Context)
+ Content(ctx context.Context)
+ Script(ctx context.Context)
+ Navbar(ctx context.Context)
}
%}
@@ -25,6 +26,8 @@ Page {
}
%}
+
+
{% code func TimeFormat(t time.Time) string {
return t.Format("02.01.2006")
}
@@ -35,27 +38,37 @@ Page {
}
%}
+
+{% code func IsAuthenticationDisabled(ctx context.Context) bool {
+ t, ok := ctx.Value("disableAuthentication").(bool)
+ return ok && t
+ }
+%}
+
+{% code func IsLoggedIn(ctx context.Context) bool {
+ t, ok := ctx.Value("logged").(bool)
+ return ok && t
+ }
+%}
+
Page prints a page implementing Page interface.
-{% func PageTemplate(p Page) %}
+{% func PageTemplate(p Page, ctx context.Context) %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="icon" href="data:,">
- <title>{%= p.Title() %}</title>
- <link rel="stylesheet" href="/static/main{%s Slug%}.css">
+ <title>{%= p.Title(ctx) %}</title>
+ <link rel="stylesheet" href="/static/main{%s Slug %}.css">
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
- <div class="alert alert-warning text-center" role="alert">
- This project is under development, things may be broken or incomplete.
- </div>
- {%= p.Navbar() %}
+ {%= p.Navbar(ctx) %}
<div class="container">
- {%= p.Content() %}
+ {%= p.Content(ctx) %}
</div>
</body>
- {%= p.Script() %}
+ {%= p.Script(ctx) %}
</html>
{% endfunc %}
diff --git a/templates/base.qtpl.go b/templates/base.qtpl.go
index b2356fe..796538e 100644
--- a/templates/base.qtpl.go
+++ b/templates/base.qtpl.go
@@ -4,61 +4,64 @@
// This is a base page template. All the other template pages implement this interface.
//
-//line base.qtpl:3
+//line templates/base.qtpl:3
package templates
-//line base.qtpl:3
+//line templates/base.qtpl:3
+import "context"
+
+//line templates/base.qtpl:4
import "strconv"
-//line base.qtpl:4
+//line templates/base.qtpl:5
import "time"
-//line base.qtpl:6
+//line templates/base.qtpl:7
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
-//line base.qtpl:6
+//line templates/base.qtpl:7
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
-//line base.qtpl:7
+//line templates/base.qtpl:8
var Slug = ""
-//line base.qtpl:11
+//line templates/base.qtpl:12
type Page interface {
-//line base.qtpl:11
- Title() string
-//line base.qtpl:11
- StreamTitle(qw422016 *qt422016.Writer)
-//line base.qtpl:11
- WriteTitle(qq422016 qtio422016.Writer)
-//line base.qtpl:11
- Content() string
-//line base.qtpl:11
- StreamContent(qw422016 *qt422016.Writer)
-//line base.qtpl:11
- WriteContent(qq422016 qtio422016.Writer)
-//line base.qtpl:11
- Script() string
-//line base.qtpl:11
- StreamScript(qw422016 *qt422016.Writer)
-//line base.qtpl:11
- WriteScript(qq422016 qtio422016.Writer)
-//line base.qtpl:11
- Navbar() string
-//line base.qtpl:11
- StreamNavbar(qw422016 *qt422016.Writer)
-//line base.qtpl:11
- WriteNavbar(qq422016 qtio422016.Writer)
-//line base.qtpl:11
+//line templates/base.qtpl:12
+ Title(ctx context.Context) string
+//line templates/base.qtpl:12
+ StreamTitle(qw422016 *qt422016.Writer, ctx context.Context)
+//line templates/base.qtpl:12
+ WriteTitle(qq422016 qtio422016.Writer, ctx context.Context)
+//line templates/base.qtpl:12
+ Content(ctx context.Context) string
+//line templates/base.qtpl:12
+ StreamContent(qw422016 *qt422016.Writer, ctx context.Context)
+//line templates/base.qtpl:12
+ WriteContent(qq422016 qtio422016.Writer, ctx context.Context)
+//line templates/base.qtpl:12
+ Script(ctx context.Context) string
+//line templates/base.qtpl:12
+ StreamScript(qw422016 *qt422016.Writer, ctx context.Context)
+//line templates/base.qtpl:12
+ WriteScript(qq422016 qtio422016.Writer, ctx context.Context)
+//line templates/base.qtpl:12
+ Navbar(ctx context.Context) string
+//line templates/base.qtpl:12
+ StreamNavbar(qw422016 *qt422016.Writer, ctx context.Context)
+//line templates/base.qtpl:12
+ WriteNavbar(qq422016 qtio422016.Writer, ctx context.Context)
+//line templates/base.qtpl:12
}
-//line base.qtpl:20
+//line templates/base.qtpl:21
func FromUInttoString(u *uint) string {
if u != nil {
return strconv.FormatUint(uint64(*u), 10)
@@ -66,21 +69,33 @@ func FromUInttoString(u *uint) string {
return ""
}
-//line base.qtpl:28
+//line templates/base.qtpl:31
func TimeFormat(t time.Time) string {
return t.Format("02.01.2006")
}
-//line base.qtpl:33
+//line templates/base.qtpl:36
func Ignore[T any](v T, _ error) T {
return v
}
+//line templates/base.qtpl:42
+func IsAuthenticationDisabled(ctx context.Context) bool {
+ t, ok := ctx.Value("disableAuthentication").(bool)
+ return ok && t
+}
+
+//line templates/base.qtpl:48
+func IsLoggedIn(ctx context.Context) bool {
+ t, ok := ctx.Value("logged").(bool)
+ return ok && t
+}
+
// Page prints a page implementing Page interface.
-//line base.qtpl:39
-func StreamPageTemplate(qw422016 *qt422016.Writer, p Page) {
-//line base.qtpl:39
+//line templates/base.qtpl:55
+func StreamPageTemplate(qw422016 *qt422016.Writer, p Page, ctx context.Context) {
+//line templates/base.qtpl:55
qw422016.N().S(`
<!DOCTYPE html>
<html lang="en">
@@ -88,67 +103,64 @@ func StreamPageTemplate(qw422016 *qt422016.Writer, p Page) {
<meta charset="utf-8">
<link rel="icon" href="data:,">
<title>`)
-//line base.qtpl:45
- p.StreamTitle(qw422016)
-//line base.qtpl:45
+//line templates/base.qtpl:61
+ p.StreamTitle(qw422016, ctx)
+//line templates/base.qtpl:61
qw422016.N().S(`</title>
<link rel="stylesheet" href="/static/main`)
-//line base.qtpl:46
+//line templates/base.qtpl:62
qw422016.E().S(Slug)
-//line base.qtpl:46
+//line templates/base.qtpl:62
qw422016.N().S(`.css">
<meta content="text/html;charset=utf-8" http-equiv="Content-Type">
<meta name="viewport" content="width=device-width, initial-scale=1" />
</head>
<body>
- <div class="alert alert-warning text-center" role="alert">
- This project is under development, things may be broken or incomplete.
- </div>
`)
-//line base.qtpl:54
- p.StreamNavbar(qw422016)
-//line base.qtpl:54
+//line templates/base.qtpl:67
+ p.StreamNavbar(qw422016, ctx)
+//line templates/base.qtpl:67
qw422016.N().S(`
<div class="container">
`)
-//line base.qtpl:56
- p.StreamContent(qw422016)
-//line base.qtpl:56
+//line templates/base.qtpl:69
+ p.StreamContent(qw422016, ctx)
+//line templates/base.qtpl:69
qw422016.N().S(`
</div>
</body>
`)
-//line base.qtpl:59
- p.StreamScript(qw422016)
-//line base.qtpl:59
+//line templates/base.qtpl:72
+ p.StreamScript(qw422016, ctx)
+//line templates/base.qtpl:72
qw422016.N().S(`
</html>
`)
-//line base.qtpl:61
+//line templates/base.qtpl:74
}
-//line base.qtpl:61
-func WritePageTemplate(qq422016 qtio422016.Writer, p Page) {
-//line base.qtpl:61
+//line templates/base.qtpl:74
+func WritePageTemplate(qq422016 qtio422016.Writer, p Page, ctx context.Context) {
+//line templates/base.qtpl:74
qw422016 := qt422016.AcquireWriter(qq422016)
-//line base.qtpl:61
- StreamPageTemplate(qw422016, p)
-//line base.qtpl:61
+//line templates/base.qtpl:74
+ StreamPageTemplate(qw422016, p, ctx)
+//line templates/base.qtpl:74
qt422016.ReleaseWriter(qw422016)
-//line base.qtpl:61
+//line templates/base.qtpl:74
}
-//line base.qtpl:61
-func PageTemplate(p Page) string {
-//line base.qtpl:61
+//line templates/base.qtpl:74
+func PageTemplate(p Page, ctx context.Context) string {
+//line templates/base.qtpl:74
qb422016 := qt422016.AcquireByteBuffer()
-//line base.qtpl:61
- WritePageTemplate(qb422016, p)
-//line base.qtpl:61
+//line templates/base.qtpl:74
+ WritePageTemplate(qb422016, p, ctx)
+//line templates/base.qtpl:74
qs422016 := string(qb422016.B)
-//line base.qtpl:61
+//line templates/base.qtpl:74
qt422016.ReleaseByteBuffer(qb422016)
-//line base.qtpl:61
+//line templates/base.qtpl:74
return qs422016
-//line base.qtpl:61
+//line templates/base.qtpl:74
}
diff --git a/templates/commit.qtpl b/templates/commit.qtpl
index 2b58864..4fe92e9 100644
--- a/templates/commit.qtpl
+++ b/templates/commit.qtpl
@@ -1,22 +1,34 @@
-{% import "github.com/go-git/go-git/v5/plumbing/object" %}
+{% import "git.gabrielgio.me/cerrado/pkg/git" %}
+{% import "git.gabrielgio.me/cerrado/pkg/humanize" %}
-{% func Commit(name string, c *object.Commit, showTar bool) %}
+{% func Commit(name string, c *git.CommitReference, showTar bool) %}
<div class="row event">
<div class="row">
<div class="col-md">
- <a title="{%s c.Hash.String() %}" href="/{%s name %}/commit/{%s c.Hash.String() %}">{%s c.Hash.String()[0:8] %}</a>
+ <a title="{%s c.Commit().Hash.String() %}" href="/{%s name %}/commit/{%s c.Commit().Hash.String() %}/">{%s c.Commit().Hash.String()[0:8] %}</a> —
+ <a title="{%s c.Commit().Committer.Email %}" href="mailto:{%s c.Commit().Author.Email %}">{%s c.Commit().Author.Name %}</a>
+ {% if c.HasReference() %}
+ —
+ {% for _, r := range c.References() %}
+ {% if r.Name().IsBranch() %}
+ <a class="ref branch" title="{%s c.Commit().Hash.String() %}" href="/{%s name %}/tree/{%s r.Name().Short() %}/">{%s r.Name().Short() %}</a>
+ {% else %}
+ <a class="ref tag" title="{%s c.Commit().Hash.String() %}" href="/{%s name %}/ref/{%s r.Name().Short() %}/">{%s r.Name().Short() %}</a>
+ {% endif %}
+ {% endfor %}
+ {%endif%}
</div>
{% if showTar %}
<div class="col-md text-md-center">
- <a title="tar.gz for {%s c.Hash.String() %}" href="/{%s name %}/archive/{%s c.Hash.String() %}.tar.gz">tar.gz</a>
+ <a title="tar.gz for {%s c.Commit().Hash.String() %}" href="/{%s name %}/archive/{%s c.Commit().Hash.String() %}.tar.gz">tar.gz</a>
</div>
{% endif %}
<div class="col-md text-md-end">
- <a title="{%s c.Committer.Email %}" href="mailto:{%s c.Committer.Email %}">{%s c.Committer.Name %}</a>
+ <a title="{%s c.Commit().Author.When.UTC().Format("2006-01-02 15:04:05")%} UTC">{%s humanize.Time(c.Commit().Author.When) %}</a>
</div>
</div>
<div class="code-view">
- <pre>{%s c.Message %}</pre>
+ <pre>{%s c.Commit().Message %}</pre>
</div>
</div>
{% endfunc %}
diff --git a/templates/commit.qtpl.go b/templates/commit.qtpl.go
index 04d1c9c..0aefbb8 100644
--- a/templates/commit.qtpl.go
+++ b/templates/commit.qtpl.go
@@ -1,125 +1,207 @@
// Code generated by qtc from "commit.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
-//line commit.qtpl:1
+//line templates/commit.qtpl:1
package templates
-//line commit.qtpl:1
-import "github.com/go-git/go-git/v5/plumbing/object"
+//line templates/commit.qtpl:1
+import "git.gabrielgio.me/cerrado/pkg/git"
-//line commit.qtpl:3
+//line templates/commit.qtpl:2
+import "git.gabrielgio.me/cerrado/pkg/humanize"
+
+//line templates/commit.qtpl:4
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
-//line commit.qtpl:3
+//line templates/commit.qtpl:4
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
-//line commit.qtpl:3
-func StreamCommit(qw422016 *qt422016.Writer, name string, c *object.Commit, showTar bool) {
-//line commit.qtpl:3
+//line templates/commit.qtpl:4
+func StreamCommit(qw422016 *qt422016.Writer, name string, c *git.CommitReference, showTar bool) {
+//line templates/commit.qtpl:4
qw422016.N().S(`
<div class="row event">
<div class="row">
<div class="col-md">
<a title="`)
-//line commit.qtpl:7
- qw422016.E().S(c.Hash.String())
-//line commit.qtpl:7
+//line templates/commit.qtpl:8
+ qw422016.E().S(c.Commit().Hash.String())
+//line templates/commit.qtpl:8
qw422016.N().S(`" href="/`)
-//line commit.qtpl:7
+//line templates/commit.qtpl:8
qw422016.E().S(name)
-//line commit.qtpl:7
+//line templates/commit.qtpl:8
qw422016.N().S(`/commit/`)
-//line commit.qtpl:7
- qw422016.E().S(c.Hash.String())
-//line commit.qtpl:7
+//line templates/commit.qtpl:8
+ qw422016.E().S(c.Commit().Hash.String())
+//line templates/commit.qtpl:8
+ qw422016.N().S(`/">`)
+//line templates/commit.qtpl:8
+ qw422016.E().S(c.Commit().Hash.String()[0:8])
+//line templates/commit.qtpl:8
+ qw422016.N().S(`</a> —
+ <a title="`)
+//line templates/commit.qtpl:9
+ qw422016.E().S(c.Commit().Committer.Email)
+//line templates/commit.qtpl:9
+ qw422016.N().S(`" href="mailto:`)
+//line templates/commit.qtpl:9
+ qw422016.E().S(c.Commit().Author.Email)
+//line templates/commit.qtpl:9
qw422016.N().S(`">`)
-//line commit.qtpl:7
- qw422016.E().S(c.Hash.String()[0:8])
-//line commit.qtpl:7
+//line templates/commit.qtpl:9
+ qw422016.E().S(c.Commit().Author.Name)
+//line templates/commit.qtpl:9
qw422016.N().S(`</a>
+ `)
+//line templates/commit.qtpl:10
+ if c.HasReference() {
+//line templates/commit.qtpl:10
+ qw422016.N().S(`
+ —
+ `)
+//line templates/commit.qtpl:12
+ for _, r := range c.References() {
+//line templates/commit.qtpl:12
+ qw422016.N().S(`
+ `)
+//line templates/commit.qtpl:13
+ if r.Name().IsBranch() {
+//line templates/commit.qtpl:13
+ qw422016.N().S(`
+ <a class="ref branch" title="`)
+//line templates/commit.qtpl:14
+ qw422016.E().S(c.Commit().Hash.String())
+//line templates/commit.qtpl:14
+ qw422016.N().S(`" href="/`)
+//line templates/commit.qtpl:14
+ qw422016.E().S(name)
+//line templates/commit.qtpl:14
+ qw422016.N().S(`/tree/`)
+//line templates/commit.qtpl:14
+ qw422016.E().S(r.Name().Short())
+//line templates/commit.qtpl:14
+ qw422016.N().S(`/">`)
+//line templates/commit.qtpl:14
+ qw422016.E().S(r.Name().Short())
+//line templates/commit.qtpl:14
+ qw422016.N().S(`</a>
+ `)
+//line templates/commit.qtpl:15
+ } else {
+//line templates/commit.qtpl:15
+ qw422016.N().S(`
+ <a class="ref tag" title="`)
+//line templates/commit.qtpl:16
+ qw422016.E().S(c.Commit().Hash.String())
+//line templates/commit.qtpl:16
+ qw422016.N().S(`" href="/`)
+//line templates/commit.qtpl:16
+ qw422016.E().S(name)
+//line templates/commit.qtpl:16
+ qw422016.N().S(`/ref/`)
+//line templates/commit.qtpl:16
+ qw422016.E().S(r.Name().Short())
+//line templates/commit.qtpl:16
+ qw422016.N().S(`/">`)
+//line templates/commit.qtpl:16
+ qw422016.E().S(r.Name().Short())
+//line templates/commit.qtpl:16
+ qw422016.N().S(`</a>
+ `)
+//line templates/commit.qtpl:17
+ }
+//line templates/commit.qtpl:17
+ qw422016.N().S(`
+ `)
+//line templates/commit.qtpl:18
+ }
+//line templates/commit.qtpl:18
+ qw422016.N().S(`
+ `)
+//line templates/commit.qtpl:19
+ }
+//line templates/commit.qtpl:19
+ qw422016.N().S(`
</div>
`)
-//line commit.qtpl:9
+//line templates/commit.qtpl:21
if showTar {
-//line commit.qtpl:9
+//line templates/commit.qtpl:21
qw422016.N().S(`
<div class="col-md text-md-center">
<a title="tar.gz for `)
-//line commit.qtpl:11
- qw422016.E().S(c.Hash.String())
-//line commit.qtpl:11
+//line templates/commit.qtpl:23
+ qw422016.E().S(c.Commit().Hash.String())
+//line templates/commit.qtpl:23
qw422016.N().S(`" href="/`)
-//line commit.qtpl:11
+//line templates/commit.qtpl:23
qw422016.E().S(name)
-//line commit.qtpl:11
+//line templates/commit.qtpl:23
qw422016.N().S(`/archive/`)
-//line commit.qtpl:11
- qw422016.E().S(c.Hash.String())
-//line commit.qtpl:11
+//line templates/commit.qtpl:23
+ qw422016.E().S(c.Commit().Hash.String())
+//line templates/commit.qtpl:23
qw422016.N().S(`.tar.gz">tar.gz</a>
</div>
`)
-//line commit.qtpl:13
+//line templates/commit.qtpl:25
}
-//line commit.qtpl:13
+//line templates/commit.qtpl:25
qw422016.N().S(`
<div class="col-md text-md-end">
- <a title="`)
-//line commit.qtpl:15
- qw422016.E().S(c.Committer.Email)
-//line commit.qtpl:15
- qw422016.N().S(`" href="mailto:`)
-//line commit.qtpl:15
- qw422016.E().S(c.Committer.Email)
-//line commit.qtpl:15
- qw422016.N().S(`">`)
-//line commit.qtpl:15
- qw422016.E().S(c.Committer.Name)
-//line commit.qtpl:15
+ <a title="`)
+//line templates/commit.qtpl:27
+ qw422016.E().S(c.Commit().Author.When.UTC().Format("2006-01-02 15:04:05"))
+//line templates/commit.qtpl:27
+ qw422016.N().S(` UTC">`)
+//line templates/commit.qtpl:27
+ qw422016.E().S(humanize.Time(c.Commit().Author.When))
+//line templates/commit.qtpl:27
qw422016.N().S(`</a>
</div>
</div>
<div class="code-view">
<pre>`)
-//line commit.qtpl:19
- qw422016.E().S(c.Message)
-//line commit.qtpl:19
+//line templates/commit.qtpl:31
+ qw422016.E().S(c.Commit().Message)
+//line templates/commit.qtpl:31
qw422016.N().S(`</pre>
</div>
</div>
`)
-//line commit.qtpl:22
+//line templates/commit.qtpl:34
}
-//line commit.qtpl:22
-func WriteCommit(qq422016 qtio422016.Writer, name string, c *object.Commit, showTar bool) {
-//line commit.qtpl:22
+//line templates/commit.qtpl:34
+func WriteCommit(qq422016 qtio422016.Writer, name string, c *git.CommitReference, showTar bool) {
+//line templates/commit.qtpl:34
qw422016 := qt422016.AcquireWriter(qq422016)
-//line commit.qtpl:22
+//line templates/commit.qtpl:34
StreamCommit(qw422016, name, c, showTar)
-//line commit.qtpl:22
+//line templates/commit.qtpl:34
qt422016.ReleaseWriter(qw422016)
-//line commit.qtpl:22
+//line templates/commit.qtpl:34
}
-//line commit.qtpl:22
-func Commit(name string, c *object.Commit, showTar bool) string {
-//line commit.qtpl:22
+//line templates/commit.qtpl:34
+func Commit(name string, c *git.CommitReference, showTar bool) string {
+//line templates/commit.qtpl:34
qb422016 := qt422016.AcquireByteBuffer()
-//line commit.qtpl:22
+//line templates/commit.qtpl:34
WriteCommit(qb422016, name, c, showTar)
-//line commit.qtpl:22
+//line templates/commit.qtpl:34
qs422016 := string(qb422016.B)
-//line commit.qtpl:22
+//line templates/commit.qtpl:34
qt422016.ReleaseByteBuffer(qb422016)
-//line commit.qtpl:22
+//line templates/commit.qtpl:34
return qs422016
-//line commit.qtpl:22
+//line templates/commit.qtpl:34
}
diff --git a/templates/config.qtpl b/templates/config.qtpl
deleted file mode 100644
index b3df50e..0000000
--- a/templates/config.qtpl
+++ /dev/null
@@ -1,19 +0,0 @@
-{% code
-type ConfigPage struct {
- Body []byte
-}
-%}
-
-{% func (p *ConfigPage) Title() %}Hello{% endfunc %}
-
-{% func (p *ConfigPage) Navbar() %}{%= Navbar(Config) %}{% endfunc %}
-
-{% func (p *ConfigPage) Content() %}
-<p>This is the configuration that is currently loaded</p>
-<div class="code-view">
-{%z= p.Body %}
-</div>
-{% endfunc %}
-
-{% func (p *ConfigPage) Script() %}
-{% endfunc %}
diff --git a/templates/config.qtpl.go b/templates/config.qtpl.go
deleted file mode 100644
index 58b3881..0000000
--- a/templates/config.qtpl.go
+++ /dev/null
@@ -1,165 +0,0 @@
-// Code generated by qtc from "config.qtpl". DO NOT EDIT.
-// See https://github.com/valyala/quicktemplate for details.
-
-//line config.qtpl:1
-package templates
-
-//line config.qtpl:1
-import (
- qtio422016 "io"
-
- qt422016 "github.com/valyala/quicktemplate"
-)
-
-//line config.qtpl:1
-var (
- _ = qtio422016.Copy
- _ = qt422016.AcquireByteBuffer
-)
-
-//line config.qtpl:2
-type ConfigPage struct {
- Body []byte
-}
-
-//line config.qtpl:7
-func (p *ConfigPage) StreamTitle(qw422016 *qt422016.Writer) {
-//line config.qtpl:7
- qw422016.N().S(`Hello`)
-//line config.qtpl:7
-}
-
-//line config.qtpl:7
-func (p *ConfigPage) WriteTitle(qq422016 qtio422016.Writer) {
-//line config.qtpl:7
- qw422016 := qt422016.AcquireWriter(qq422016)
-//line config.qtpl:7
- p.StreamTitle(qw422016)
-//line config.qtpl:7
- qt422016.ReleaseWriter(qw422016)
-//line config.qtpl:7
-}
-
-//line config.qtpl:7
-func (p *ConfigPage) Title() string {
-//line config.qtpl:7
- qb422016 := qt422016.AcquireByteBuffer()
-//line config.qtpl:7
- p.WriteTitle(qb422016)
-//line config.qtpl:7
- qs422016 := string(qb422016.B)
-//line config.qtpl:7
- qt422016.ReleaseByteBuffer(qb422016)
-//line config.qtpl:7
- return qs422016
-//line config.qtpl:7
-}
-
-//line config.qtpl:9
-func (p *ConfigPage) StreamNavbar(qw422016 *qt422016.Writer) {
-//line config.qtpl:9
- StreamNavbar(qw422016, Config)
-//line config.qtpl:9
-}
-
-//line config.qtpl:9
-func (p *ConfigPage) WriteNavbar(qq422016 qtio422016.Writer) {
-//line config.qtpl:9
- qw422016 := qt422016.AcquireWriter(qq422016)
-//line config.qtpl:9
- p.StreamNavbar(qw422016)
-//line config.qtpl:9
- qt422016.ReleaseWriter(qw422016)
-//line config.qtpl:9
-}
-
-//line config.qtpl:9
-func (p *ConfigPage) Navbar() string {
-//line config.qtpl:9
- qb422016 := qt422016.AcquireByteBuffer()
-//line config.qtpl:9
- p.WriteNavbar(qb422016)
-//line config.qtpl:9
- qs422016 := string(qb422016.B)
-//line config.qtpl:9
- qt422016.ReleaseByteBuffer(qb422016)
-//line config.qtpl:9
- return qs422016
-//line config.qtpl:9
-}
-
-//line config.qtpl:11
-func (p *ConfigPage) StreamContent(qw422016 *qt422016.Writer) {
-//line config.qtpl:11
- qw422016.N().S(`
-<p>This is the configuration that is currently loaded</p>
-<div class="code-view">
-`)
-//line config.qtpl:14
- qw422016.N().Z(p.Body)
-//line config.qtpl:14
- qw422016.N().S(`
-</div>
-`)
-//line config.qtpl:16
-}
-
-//line config.qtpl:16
-func (p *ConfigPage) WriteContent(qq422016 qtio422016.Writer) {
-//line config.qtpl:16
- qw422016 := qt422016.AcquireWriter(qq422016)
-//line config.qtpl:16
- p.StreamContent(qw422016)
-//line config.qtpl:16
- qt422016.ReleaseWriter(qw422016)
-//line config.qtpl:16
-}
-
-//line config.qtpl:16
-func (p *ConfigPage) Content() string {
-//line config.qtpl:16
- qb422016 := qt422016.AcquireByteBuffer()
-//line config.qtpl:16
- p.WriteContent(qb422016)
-//line config.qtpl:16
- qs422016 := string(qb422016.B)
-//line config.qtpl:16
- qt422016.ReleaseByteBuffer(qb422016)
-//line config.qtpl:16
- return qs422016
-//line config.qtpl:16
-}
-
-//line config.qtpl:18
-func (p *ConfigPage) StreamScript(qw422016 *qt422016.Writer) {
-//line config.qtpl:18
- qw422016.N().S(`
-`)
-//line config.qtpl:19
-}
-
-//line config.qtpl:19
-func (p *ConfigPage) WriteScript(qq422016 qtio422016.Writer) {
-//line config.qtpl:19
- qw422016 := qt422016.AcquireWriter(qq422016)
-//line config.qtpl:19
- p.StreamScript(qw422016)
-//line config.qtpl:19
- qt422016.ReleaseWriter(qw422016)
-//line config.qtpl:19
-}
-
-//line config.qtpl:19
-func (p *ConfigPage) Script() string {
-//line config.qtpl:19
- qb422016 := qt422016.AcquireByteBuffer()
-//line config.qtpl:19
- p.WriteScript(qb422016)
-//line config.qtpl:19
- qs422016 := string(qb422016.B)
-//line config.qtpl:19
- qt422016.ReleaseByteBuffer(qb422016)
-//line config.qtpl:19
- return qs422016
-//line config.qtpl:19
-}
diff --git a/templates/error.qtpl b/templates/error.qtpl
index 771d533..65e1321 100644
--- a/templates/error.qtpl
+++ b/templates/error.qtpl
@@ -1,16 +1,18 @@
+{% import "context" %}
+
{% code
type ErrorPage struct {
Message string
}
%}
-{% func (p *ErrorPage) Title() %}Error{% endfunc %}
+{% func (p *ErrorPage) Title(ctx context.Context) %}Error{% endfunc %}
-{% func (p *ErrorPage) Navbar() %}{%= Navbar(Git) %}{% endfunc %}
+{% func (p *ErrorPage) Navbar(ctx context.Context) %}{%= Navbar(ctx, Git) %}{% endfunc %}
-{% func (p *ErrorPage) Content() %}
+{% func (p *ErrorPage) Content(ctx context.Context) %}
{%s p.Message %}
{% endfunc %}
-{% func (p *ErrorPage) Script() %}
+{% func (p *ErrorPage) Script(ctx context.Context) %}
{% endfunc %}
diff --git a/templates/error.qtpl.go b/templates/error.qtpl.go
index 099395f..d4732c5 100644
--- a/templates/error.qtpl.go
+++ b/templates/error.qtpl.go
@@ -1,162 +1,165 @@
// Code generated by qtc from "error.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
-//line error.qtpl:1
+//line templates/error.qtpl:1
package templates
-//line error.qtpl:1
+//line templates/error.qtpl:1
+import "context"
+
+//line templates/error.qtpl:3
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
-//line error.qtpl:1
+//line templates/error.qtpl:3
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
-//line error.qtpl:2
+//line templates/error.qtpl:4
type ErrorPage struct {
Message string
}
-//line error.qtpl:7
-func (p *ErrorPage) StreamTitle(qw422016 *qt422016.Writer) {
-//line error.qtpl:7
+//line templates/error.qtpl:9
+func (p *ErrorPage) StreamTitle(qw422016 *qt422016.Writer, ctx context.Context) {
+//line templates/error.qtpl:9
qw422016.N().S(`Error`)
-//line error.qtpl:7
+//line templates/error.qtpl:9
}
-//line error.qtpl:7
-func (p *ErrorPage) WriteTitle(qq422016 qtio422016.Writer) {
-//line error.qtpl:7
+//line templates/error.qtpl:9
+func (p *ErrorPage) WriteTitle(qq422016 qtio422016.Writer, ctx context.Context) {
+//line templates/error.qtpl:9
qw422016 := qt422016.AcquireWriter(qq422016)
-//line error.qtpl:7
- p.StreamTitle(qw422016)
-//line error.qtpl:7
+//line templates/error.qtpl:9
+ p.StreamTitle(qw422016, ctx)
+//line templates/error.qtpl:9
qt422016.ReleaseWriter(qw422016)
-//line error.qtpl:7
+//line templates/error.qtpl:9
}
-//line error.qtpl:7
-func (p *ErrorPage) Title() string {
-//line error.qtpl:7
+//line templates/error.qtpl:9
+func (p *ErrorPage) Title(ctx context.Context) string {
+//line templates/error.qtpl:9
qb422016 := qt422016.AcquireByteBuffer()
-//line error.qtpl:7
- p.WriteTitle(qb422016)
-//line error.qtpl:7
+//line templates/error.qtpl:9
+ p.WriteTitle(qb422016, ctx)
+//line templates/error.qtpl:9
qs422016 := string(qb422016.B)
-//line error.qtpl:7
+//line templates/error.qtpl:9
qt422016.ReleaseByteBuffer(qb422016)
-//line error.qtpl:7
+//line templates/error.qtpl:9
return qs422016
-//line error.qtpl:7
+//line templates/error.qtpl:9
}
-//line error.qtpl:9
-func (p *ErrorPage) StreamNavbar(qw422016 *qt422016.Writer) {
-//line error.qtpl:9
- StreamNavbar(qw422016, Git)
-//line error.qtpl:9
+//line templates/error.qtpl:11
+func (p *ErrorPage) StreamNavbar(qw422016 *qt422016.Writer, ctx context.Context) {
+//line templates/error.qtpl:11
+ StreamNavbar(qw422016, ctx, Git)
+//line templates/error.qtpl:11
}
-//line error.qtpl:9
-func (p *ErrorPage) WriteNavbar(qq422016 qtio422016.Writer) {
-//line error.qtpl:9
+//line templates/error.qtpl:11
+func (p *ErrorPage) WriteNavbar(qq422016 qtio422016.Writer, ctx context.Context) {
+//line templates/error.qtpl:11
qw422016 := qt422016.AcquireWriter(qq422016)
-//line error.qtpl:9
- p.StreamNavbar(qw422016)
-//line error.qtpl:9
+//line templates/error.qtpl:11
+ p.StreamNavbar(qw422016, ctx)
+//line templates/error.qtpl:11
qt422016.ReleaseWriter(qw422016)
-//line error.qtpl:9
+//line templates/error.qtpl:11
}
-//line error.qtpl:9
-func (p *ErrorPage) Navbar() string {
-//line error.qtpl:9
+//line templates/error.qtpl:11
+func (p *ErrorPage) Navbar(ctx context.Context) string {
+//line templates/error.qtpl:11
qb422016 := qt422016.AcquireByteBuffer()
-//line error.qtpl:9
- p.WriteNavbar(qb422016)
-//line error.qtpl:9
+//line templates/error.qtpl:11
+ p.WriteNavbar(qb422016, ctx)
+//line templates/error.qtpl:11
qs422016 := string(qb422016.B)
-//line error.qtpl:9
+//line templates/error.qtpl:11
qt422016.ReleaseByteBuffer(qb422016)
-//line error.qtpl:9
+//line templates/error.qtpl:11
return qs422016
-//line error.qtpl:9
+//line templates/error.qtpl:11
}
-//line error.qtpl:11
-func (p *ErrorPage) StreamContent(qw422016 *qt422016.Writer) {
-//line error.qtpl:11
+//line templates/error.qtpl:13
+func (p *ErrorPage) StreamContent(qw422016 *qt422016.Writer, ctx context.Context) {
+//line templates/error.qtpl:13
qw422016.N().S(`
`)
-//line error.qtpl:12
+//line templates/error.qtpl:14
qw422016.E().S(p.Message)
-//line error.qtpl:12
+//line templates/error.qtpl:14
qw422016.N().S(`
`)
-//line error.qtpl:13
+//line templates/error.qtpl:15
}
-//line error.qtpl:13
-func (p *ErrorPage) WriteContent(qq422016 qtio422016.Writer) {
-//line error.qtpl:13
+//line templates/error.qtpl:15
+func (p *ErrorPage) WriteContent(qq422016 qtio422016.Writer, ctx context.Context) {
+//line templates/error.qtpl:15
qw422016 := qt422016.AcquireWriter(qq422016)
-//line error.qtpl:13
- p.StreamContent(qw422016)
-//line error.qtpl:13
+//line templates/error.qtpl:15
+ p.StreamContent(qw422016, ctx)
+//line templates/error.qtpl:15
qt422016.ReleaseWriter(qw422016)
-//line error.qtpl:13
+//line templates/error.qtpl:15
}
-//line error.qtpl:13
-func (p *ErrorPage) Content() string {
-//line error.qtpl:13
+//line templates/error.qtpl:15
+func (p *ErrorPage) Content(ctx context.Context) string {
+//line templates/error.qtpl:15
qb422016 := qt422016.AcquireByteBuffer()
-//line error.qtpl:13
- p.WriteContent(qb422016)
-//line error.qtpl:13
+//line templates/error.qtpl:15
+ p.WriteContent(qb422016, ctx)
+//line templates/error.qtpl:15
qs422016 := string(qb422016.B)
-//line error.qtpl:13
+//line templates/error.qtpl:15
qt422016.ReleaseByteBuffer(qb422016)
-//line error.qtpl:13
+//line templates/error.qtpl:15
return qs422016
-//line error.qtpl:13
+//line templates/error.qtpl:15
}
-//line error.qtpl:15
-func (p *ErrorPage) StreamScript(qw422016 *qt422016.Writer) {
-//line error.qtpl:15
+//line templates/error.qtpl:17
+func (p *ErrorPage) StreamScript(qw422016 *qt422016.Writer, ctx context.Context) {
+//line templates/error.qtpl:17
qw422016.N().S(`
`)
-//line error.qtpl:16
+//line templates/error.qtpl:18
}
-//line error.qtpl:16
-func (p *ErrorPage) WriteScript(qq422016 qtio422016.Writer) {
-//line error.qtpl:16
+//line templates/error.qtpl:18
+func (p *ErrorPage) WriteScript(qq422016 qtio422016.Writer, ctx context.Context) {
+//line templates/error.qtpl:18
qw422016 := qt422016.AcquireWriter(qq422016)
-//line error.qtpl:16
- p.StreamScript(qw422016)
-//line error.qtpl:16
+//line templates/error.qtpl:18
+ p.StreamScript(qw422016, ctx)
+//line templates/error.qtpl:18
qt422016.ReleaseWriter(qw422016)
-//line error.qtpl:16
+//line templates/error.qtpl:18
}
-//line error.qtpl:16
-func (p *ErrorPage) Script() string {
-//line error.qtpl:16
+//line templates/error.qtpl:18
+func (p *ErrorPage) Script(ctx context.Context) string {
+//line templates/error.qtpl:18
qb422016 := qt422016.AcquireByteBuffer()
-//line error.qtpl:16
- p.WriteScript(qb422016)
-//line error.qtpl:16
+//line templates/error.qtpl:18
+ p.WriteScript(qb422016, ctx)
+//line templates/error.qtpl:18
qs422016 := string(qb422016.B)
-//line error.qtpl:16
+//line templates/error.qtpl:18
qt422016.ReleaseByteBuffer(qb422016)
-//line error.qtpl:16
+//line templates/error.qtpl:18
return qs422016
-//line error.qtpl:16
+//line templates/error.qtpl:18
}
diff --git a/templates/gititem.qtpl b/templates/gititem.qtpl
index a6a312d..c43bbfd 100644
--- a/templates/gititem.qtpl
+++ b/templates/gititem.qtpl
@@ -1,3 +1,5 @@
+{% import "context" %}
+
{% interface
GitItemBase {
Nav(name, ref string)
@@ -13,16 +15,16 @@ type GitItemPage struct {
}
%}
-{% func (p *GitItemPage) Title() %}Git | {%s p.Name %}{% endfunc %}
+{% func (p *GitItemPage) Title(ctx context.Context) %}Git | {%s p.Name %}{% endfunc %}
-{% func (p *GitItemPage) Navbar() %}{%= Navbar(Git) %}{% endfunc %}
+{% func (p *GitItemPage) Navbar(ctx context.Context) %}{%= Navbar(ctx, Git) %}{% endfunc %}
-{% func (p *GitItemPage) Content() %}
+{% func (p *GitItemPage) Content(ctx context.Context) %}
{%= p.Nav(p.Name, p.Ref) %}
<div class="container">
{%= p.GitContent(p.Name, p.Ref) %}
</div>
{% endfunc %}
-{% func (p *GitItemPage) Script() %}
+{% func (p *GitItemPage) Script(ctx context.Context) %}
{% endfunc %}
diff --git a/templates/gititem.qtpl.go b/templates/gititem.qtpl.go
index 7cfeeb4..5292e44 100644
--- a/templates/gititem.qtpl.go
+++ b/templates/gititem.qtpl.go
@@ -1,190 +1,193 @@
// Code generated by qtc from "gititem.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
-//line gititem.qtpl:1
+//line templates/gititem.qtpl:1
package templates
-//line gititem.qtpl:1
+//line templates/gititem.qtpl:1
+import "context"
+
+//line templates/gititem.qtpl:3
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
-//line gititem.qtpl:1
+//line templates/gititem.qtpl:3
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
-//line gititem.qtpl:2
+//line templates/gititem.qtpl:4
type GitItemBase interface {
-//line gititem.qtpl:2
+//line templates/gititem.qtpl:4
Nav(name, ref string) string
-//line gititem.qtpl:2
+//line templates/gititem.qtpl:4
StreamNav(qw422016 *qt422016.Writer, name, ref string)
-//line gititem.qtpl:2
+//line templates/gititem.qtpl:4
WriteNav(qq422016 qtio422016.Writer, name, ref string)
-//line gititem.qtpl:2
+//line templates/gititem.qtpl:4
GitContent(name, ref string) string
-//line gititem.qtpl:2
+//line templates/gititem.qtpl:4
StreamGitContent(qw422016 *qt422016.Writer, name, ref string)
-//line gititem.qtpl:2
+//line templates/gititem.qtpl:4
WriteGitContent(qq422016 qtio422016.Writer, name, ref string)
-//line gititem.qtpl:2
+//line templates/gititem.qtpl:4
}
-//line gititem.qtpl:9
+//line templates/gititem.qtpl:11
type GitItemPage struct {
Name string
Ref string
GitItemBase
}
-//line gititem.qtpl:16
-func (p *GitItemPage) StreamTitle(qw422016 *qt422016.Writer) {
-//line gititem.qtpl:16
+//line templates/gititem.qtpl:18
+func (p *GitItemPage) StreamTitle(qw422016 *qt422016.Writer, ctx context.Context) {
+//line templates/gititem.qtpl:18
qw422016.N().S(`Git | `)
-//line gititem.qtpl:16
+//line templates/gititem.qtpl:18
qw422016.E().S(p.Name)
-//line gititem.qtpl:16
+//line templates/gititem.qtpl:18
}
-//line gititem.qtpl:16
-func (p *GitItemPage) WriteTitle(qq422016 qtio422016.Writer) {
-//line gititem.qtpl:16
+//line templates/gititem.qtpl:18
+func (p *GitItemPage) WriteTitle(qq422016 qtio422016.Writer, ctx context.Context) {
+//line templates/gititem.qtpl:18
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gititem.qtpl:16
- p.StreamTitle(qw422016)
-//line gititem.qtpl:16
+//line templates/gititem.qtpl:18
+ p.StreamTitle(qw422016, ctx)
+//line templates/gititem.qtpl:18
qt422016.ReleaseWriter(qw422016)
-//line gititem.qtpl:16
+//line templates/gititem.qtpl:18
}
-//line gititem.qtpl:16
-func (p *GitItemPage) Title() string {
-//line gititem.qtpl:16
+//line templates/gititem.qtpl:18
+func (p *GitItemPage) Title(ctx context.Context) string {
+//line templates/gititem.qtpl:18
qb422016 := qt422016.AcquireByteBuffer()
-//line gititem.qtpl:16
- p.WriteTitle(qb422016)
-//line gititem.qtpl:16
+//line templates/gititem.qtpl:18
+ p.WriteTitle(qb422016, ctx)
+//line templates/gititem.qtpl:18
qs422016 := string(qb422016.B)
-//line gititem.qtpl:16
+//line templates/gititem.qtpl:18
qt422016.ReleaseByteBuffer(qb422016)
-//line gititem.qtpl:16
+//line templates/gititem.qtpl:18
return qs422016
-//line gititem.qtpl:16
+//line templates/gititem.qtpl:18
}
-//line gititem.qtpl:18
-func (p *GitItemPage) StreamNavbar(qw422016 *qt422016.Writer) {
-//line gititem.qtpl:18
- StreamNavbar(qw422016, Git)
-//line gititem.qtpl:18
+//line templates/gititem.qtpl:20
+func (p *GitItemPage) StreamNavbar(qw422016 *qt422016.Writer, ctx context.Context) {
+//line templates/gititem.qtpl:20
+ StreamNavbar(qw422016, ctx, Git)
+//line templates/gititem.qtpl:20
}
-//line gititem.qtpl:18
-func (p *GitItemPage) WriteNavbar(qq422016 qtio422016.Writer) {
-//line gititem.qtpl:18
+//line templates/gititem.qtpl:20
+func (p *GitItemPage) WriteNavbar(qq422016 qtio422016.Writer, ctx context.Context) {
+//line templates/gititem.qtpl:20
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gititem.qtpl:18
- p.StreamNavbar(qw422016)
-//line gititem.qtpl:18
+//line templates/gititem.qtpl:20
+ p.StreamNavbar(qw422016, ctx)
+//line templates/gititem.qtpl:20
qt422016.ReleaseWriter(qw422016)
-//line gititem.qtpl:18
+//line templates/gititem.qtpl:20
}
-//line gititem.qtpl:18
-func (p *GitItemPage) Navbar() string {
-//line gititem.qtpl:18
+//line templates/gititem.qtpl:20
+func (p *GitItemPage) Navbar(ctx context.Context) string {
+//line templates/gititem.qtpl:20
qb422016 := qt422016.AcquireByteBuffer()
-//line gititem.qtpl:18
- p.WriteNavbar(qb422016)
-//line gititem.qtpl:18
+//line templates/gititem.qtpl:20
+ p.WriteNavbar(qb422016, ctx)
+//line templates/gititem.qtpl:20
qs422016 := string(qb422016.B)
-//line gititem.qtpl:18
+//line templates/gititem.qtpl:20
qt422016.ReleaseByteBuffer(qb422016)
-//line gititem.qtpl:18
+//line templates/gititem.qtpl:20
return qs422016
-//line gititem.qtpl:18
+//line templates/gititem.qtpl:20
}
-//line gititem.qtpl:20
-func (p *GitItemPage) StreamContent(qw422016 *qt422016.Writer) {
-//line gititem.qtpl:20
+//line templates/gititem.qtpl:22
+func (p *GitItemPage) StreamContent(qw422016 *qt422016.Writer, ctx context.Context) {
+//line templates/gititem.qtpl:22
qw422016.N().S(`
`)
-//line gititem.qtpl:21
+//line templates/gititem.qtpl:23
p.StreamNav(qw422016, p.Name, p.Ref)
-//line gititem.qtpl:21
+//line templates/gititem.qtpl:23
qw422016.N().S(`
<div class="container">
`)
-//line gititem.qtpl:23
+//line templates/gititem.qtpl:25
p.StreamGitContent(qw422016, p.Name, p.Ref)
-//line gititem.qtpl:23
+//line templates/gititem.qtpl:25
qw422016.N().S(`
</div>
`)
-//line gititem.qtpl:25
+//line templates/gititem.qtpl:27
}
-//line gititem.qtpl:25
-func (p *GitItemPage) WriteContent(qq422016 qtio422016.Writer) {
-//line gititem.qtpl:25
+//line templates/gititem.qtpl:27
+func (p *GitItemPage) WriteContent(qq422016 qtio422016.Writer, ctx context.Context) {
+//line templates/gititem.qtpl:27
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gititem.qtpl:25
- p.StreamContent(qw422016)
-//line gititem.qtpl:25
+//line templates/gititem.qtpl:27
+ p.StreamContent(qw422016, ctx)
+//line templates/gititem.qtpl:27
qt422016.ReleaseWriter(qw422016)
-//line gititem.qtpl:25
+//line templates/gititem.qtpl:27
}
-//line gititem.qtpl:25
-func (p *GitItemPage) Content() string {
-//line gititem.qtpl:25
+//line templates/gititem.qtpl:27
+func (p *GitItemPage) Content(ctx context.Context) string {
+//line templates/gititem.qtpl:27
qb422016 := qt422016.AcquireByteBuffer()
-//line gititem.qtpl:25
- p.WriteContent(qb422016)
-//line gititem.qtpl:25
+//line templates/gititem.qtpl:27
+ p.WriteContent(qb422016, ctx)
+//line templates/gititem.qtpl:27
qs422016 := string(qb422016.B)
-//line gititem.qtpl:25
+//line templates/gititem.qtpl:27
qt422016.ReleaseByteBuffer(qb422016)
-//line gititem.qtpl:25
+//line templates/gititem.qtpl:27
return qs422016
-//line gititem.qtpl:25
+//line templates/gititem.qtpl:27
}
-//line gititem.qtpl:27
-func (p *GitItemPage) StreamScript(qw422016 *qt422016.Writer) {
-//line gititem.qtpl:27
+//line templates/gititem.qtpl:29
+func (p *GitItemPage) StreamScript(qw422016 *qt422016.Writer, ctx context.Context) {
+//line templates/gititem.qtpl:29
qw422016.N().S(`
`)
-//line gititem.qtpl:28
+//line templates/gititem.qtpl:30
}
-//line gititem.qtpl:28
-func (p *GitItemPage) WriteScript(qq422016 qtio422016.Writer) {
-//line gititem.qtpl:28
+//line templates/gititem.qtpl:30
+func (p *GitItemPage) WriteScript(qq422016 qtio422016.Writer, ctx context.Context) {
+//line templates/gititem.qtpl:30
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gititem.qtpl:28
- p.StreamScript(qw422016)
-//line gititem.qtpl:28
+//line templates/gititem.qtpl:30
+ p.StreamScript(qw422016, ctx)
+//line templates/gititem.qtpl:30
qt422016.ReleaseWriter(qw422016)
-//line gititem.qtpl:28
+//line templates/gititem.qtpl:30
}
-//line gititem.qtpl:28
-func (p *GitItemPage) Script() string {
-//line gititem.qtpl:28
+//line templates/gititem.qtpl:30
+func (p *GitItemPage) Script(ctx context.Context) string {
+//line templates/gititem.qtpl:30
qb422016 := qt422016.AcquireByteBuffer()
-//line gititem.qtpl:28
- p.WriteScript(qb422016)
-//line gititem.qtpl:28
+//line templates/gititem.qtpl:30
+ p.WriteScript(qb422016, ctx)
+//line templates/gititem.qtpl:30
qs422016 := string(qb422016.B)
-//line gititem.qtpl:28
+//line templates/gititem.qtpl:30
qt422016.ReleaseByteBuffer(qb422016)
-//line gititem.qtpl:28
+//line templates/gititem.qtpl:30
return qs422016
-//line gititem.qtpl:28
+//line templates/gititem.qtpl:30
}
diff --git a/templates/gititemabout.qtpl.go b/templates/gititemabout.qtpl.go
index e1c1db4..12b4be9 100644
--- a/templates/gititemabout.qtpl.go
+++ b/templates/gititemabout.qtpl.go
@@ -1,97 +1,97 @@
// Code generated by qtc from "gititemabout.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
-//line gititemabout.qtpl:1
+//line templates/gititemabout.qtpl:1
package templates
-//line gititemabout.qtpl:1
+//line templates/gititemabout.qtpl:1
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
-//line gititemabout.qtpl:1
+//line templates/gititemabout.qtpl:1
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
-//line gititemabout.qtpl:2
+//line templates/gititemabout.qtpl:2
type GitItemAboutPage struct {
About []byte
}
-//line gititemabout.qtpl:7
+//line templates/gititemabout.qtpl:7
func (g *GitItemAboutPage) StreamNav(qw422016 *qt422016.Writer, name, ref string) {
-//line gititemabout.qtpl:7
+//line templates/gititemabout.qtpl:7
StreamGitItemNav(qw422016, name, ref, Readme)
-//line gititemabout.qtpl:7
+//line templates/gititemabout.qtpl:7
}
-//line gititemabout.qtpl:7
+//line templates/gititemabout.qtpl:7
func (g *GitItemAboutPage) WriteNav(qq422016 qtio422016.Writer, name, ref string) {
-//line gititemabout.qtpl:7
+//line templates/gititemabout.qtpl:7
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gititemabout.qtpl:7
+//line templates/gititemabout.qtpl:7
g.StreamNav(qw422016, name, ref)
-//line gititemabout.qtpl:7
+//line templates/gititemabout.qtpl:7
qt422016.ReleaseWriter(qw422016)
-//line gititemabout.qtpl:7
+//line templates/gititemabout.qtpl:7
}
-//line gititemabout.qtpl:7
+//line templates/gititemabout.qtpl:7
func (g *GitItemAboutPage) Nav(name, ref string) string {
-//line gititemabout.qtpl:7
+//line templates/gititemabout.qtpl:7
qb422016 := qt422016.AcquireByteBuffer()
-//line gititemabout.qtpl:7
+//line templates/gititemabout.qtpl:7
g.WriteNav(qb422016, name, ref)
-//line gititemabout.qtpl:7
+//line templates/gititemabout.qtpl:7
qs422016 := string(qb422016.B)
-//line gititemabout.qtpl:7
+//line templates/gititemabout.qtpl:7
qt422016.ReleaseByteBuffer(qb422016)
-//line gititemabout.qtpl:7
+//line templates/gititemabout.qtpl:7
return qs422016
-//line gititemabout.qtpl:7
+//line templates/gititemabout.qtpl:7
}
-//line gititemabout.qtpl:9
+//line templates/gititemabout.qtpl:9
func (g *GitItemAboutPage) StreamGitContent(qw422016 *qt422016.Writer, name, ref string) {
-//line gititemabout.qtpl:9
+//line templates/gititemabout.qtpl:9
qw422016.N().S(`
<div class="m-2">
`)
-//line gititemabout.qtpl:11
+//line templates/gititemabout.qtpl:11
qw422016.N().Z(g.About)
-//line gititemabout.qtpl:11
+//line templates/gititemabout.qtpl:11
qw422016.N().S(`
</div>
`)
-//line gititemabout.qtpl:13
+//line templates/gititemabout.qtpl:13
}
-//line gititemabout.qtpl:13
+//line templates/gititemabout.qtpl:13
func (g *GitItemAboutPage) WriteGitContent(qq422016 qtio422016.Writer, name, ref string) {
-//line gititemabout.qtpl:13
+//line templates/gititemabout.qtpl:13
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gititemabout.qtpl:13
+//line templates/gititemabout.qtpl:13
g.StreamGitContent(qw422016, name, ref)
-//line gititemabout.qtpl:13
+//line templates/gititemabout.qtpl:13
qt422016.ReleaseWriter(qw422016)
-//line gititemabout.qtpl:13
+//line templates/gititemabout.qtpl:13
}
-//line gititemabout.qtpl:13
+//line templates/gititemabout.qtpl:13
func (g *GitItemAboutPage) GitContent(name, ref string) string {
-//line gititemabout.qtpl:13
+//line templates/gititemabout.qtpl:13
qb422016 := qt422016.AcquireByteBuffer()
-//line gititemabout.qtpl:13
+//line templates/gititemabout.qtpl:13
g.WriteGitContent(qb422016, name, ref)
-//line gititemabout.qtpl:13
+//line templates/gititemabout.qtpl:13
qs422016 := string(qb422016.B)
-//line gititemabout.qtpl:13
+//line templates/gititemabout.qtpl:13
qt422016.ReleaseByteBuffer(qb422016)
-//line gititemabout.qtpl:13
+//line templates/gititemabout.qtpl:13
return qs422016
-//line gititemabout.qtpl:13
+//line templates/gititemabout.qtpl:13
}
diff --git a/templates/gititemblob.qtpl.go b/templates/gititemblob.qtpl.go
index 5d986b4..73742f6 100644
--- a/templates/gititemblob.qtpl.go
+++ b/templates/gititemblob.qtpl.go
@@ -1,140 +1,140 @@
// Code generated by qtc from "gititemblob.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
-//line gititemblob.qtpl:1
+//line templates/gititemblob.qtpl:1
package templates
-//line gititemblob.qtpl:1
+//line templates/gititemblob.qtpl:1
import "git.gabrielgio.me/cerrado/pkg/u"
-//line gititemblob.qtpl:3
+//line templates/gititemblob.qtpl:3
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
-//line gititemblob.qtpl:3
+//line templates/gititemblob.qtpl:3
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
-//line gititemblob.qtpl:4
+//line templates/gititemblob.qtpl:4
type GitItemBlobPage struct {
Path []string
Content []byte
}
-//line gititemblob.qtpl:10
+//line templates/gititemblob.qtpl:10
func (g *GitItemBlobPage) StreamNav(qw422016 *qt422016.Writer, name, ref string) {
-//line gititemblob.qtpl:10
+//line templates/gititemblob.qtpl:10
StreamGitItemNav(qw422016, name, ref, Tree)
-//line gititemblob.qtpl:10
+//line templates/gititemblob.qtpl:10
}
-//line gititemblob.qtpl:10
+//line templates/gititemblob.qtpl:10
func (g *GitItemBlobPage) WriteNav(qq422016 qtio422016.Writer, name, ref string) {
-//line gititemblob.qtpl:10
+//line templates/gititemblob.qtpl:10
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gititemblob.qtpl:10
+//line templates/gititemblob.qtpl:10
g.StreamNav(qw422016, name, ref)
-//line gititemblob.qtpl:10
+//line templates/gititemblob.qtpl:10
qt422016.ReleaseWriter(qw422016)
-//line gititemblob.qtpl:10
+//line templates/gititemblob.qtpl:10
}
-//line gititemblob.qtpl:10
+//line templates/gititemblob.qtpl:10
func (g *GitItemBlobPage) Nav(name, ref string) string {
-//line gititemblob.qtpl:10
+//line templates/gititemblob.qtpl:10
qb422016 := qt422016.AcquireByteBuffer()
-//line gititemblob.qtpl:10
+//line templates/gititemblob.qtpl:10
g.WriteNav(qb422016, name, ref)
-//line gititemblob.qtpl:10
+//line templates/gititemblob.qtpl:10
qs422016 := string(qb422016.B)
-//line gititemblob.qtpl:10
+//line templates/gititemblob.qtpl:10
qt422016.ReleaseByteBuffer(qb422016)
-//line gititemblob.qtpl:10
+//line templates/gititemblob.qtpl:10
return qs422016
-//line gititemblob.qtpl:10
+//line templates/gititemblob.qtpl:10
}
-//line gititemblob.qtpl:12
+//line templates/gititemblob.qtpl:12
func (g *GitItemBlobPage) StreamGitContent(qw422016 *qt422016.Writer, name, ref string) {
-//line gititemblob.qtpl:12
+//line templates/gititemblob.qtpl:12
qw422016.N().S(`
<div class="pathing">
`)
-//line gititemblob.qtpl:15
+//line templates/gititemblob.qtpl:15
if len(g.Path) != 0 {
-//line gititemblob.qtpl:15
+//line templates/gititemblob.qtpl:15
qw422016.N().S(`<a href="`)
-//line gititemblob.qtpl:16
+//line templates/gititemblob.qtpl:16
qw422016.E().S(url(name, Folder, ref, Root, []string{}))
-//line gititemblob.qtpl:16
+//line templates/gititemblob.qtpl:16
qw422016.N().S(`">root/</a>`)
-//line gititemblob.qtpl:17
+//line templates/gititemblob.qtpl:17
for i, e := range g.Path[:len(g.Path)-1] {
-//line gititemblob.qtpl:17
+//line templates/gititemblob.qtpl:17
qw422016.N().S(`<a href="`)
-//line gititemblob.qtpl:18
+//line templates/gititemblob.qtpl:18
qw422016.E().S(url(name, Folder, ref, Root, g.Path[:1+i]))
-//line gititemblob.qtpl:18
+//line templates/gititemblob.qtpl:18
qw422016.N().S(`">`)
-//line gititemblob.qtpl:18
+//line templates/gititemblob.qtpl:18
qw422016.E().S(e)
-//line gititemblob.qtpl:18
+//line templates/gititemblob.qtpl:18
qw422016.N().S(`/</a>`)
-//line gititemblob.qtpl:19
+//line templates/gititemblob.qtpl:19
}
-//line gititemblob.qtpl:19
+//line templates/gititemblob.qtpl:19
qw422016.N().S(`<a>`)
-//line gititemblob.qtpl:20
+//line templates/gititemblob.qtpl:20
qw422016.E().S(u.LastOrZero(g.Path))
-//line gititemblob.qtpl:20
+//line templates/gititemblob.qtpl:20
qw422016.N().S(`</a>`)
-//line gititemblob.qtpl:21
+//line templates/gititemblob.qtpl:21
} else {
-//line gititemblob.qtpl:21
+//line templates/gititemblob.qtpl:21
qw422016.N().S(`<a>root/</a>`)
-//line gititemblob.qtpl:23
+//line templates/gititemblob.qtpl:23
}
-//line gititemblob.qtpl:24
+//line templates/gititemblob.qtpl:24
qw422016.N().S(`
</div>
<div class="code-view">
`)
-//line gititemblob.qtpl:27
+//line templates/gititemblob.qtpl:27
qw422016.N().Z(g.Content)
-//line gititemblob.qtpl:27
+//line templates/gititemblob.qtpl:27
qw422016.N().S(`
</div>
`)
-//line gititemblob.qtpl:29
+//line templates/gititemblob.qtpl:29
}
-//line gititemblob.qtpl:29
+//line templates/gititemblob.qtpl:29
func (g *GitItemBlobPage) WriteGitContent(qq422016 qtio422016.Writer, name, ref string) {
-//line gititemblob.qtpl:29
+//line templates/gititemblob.qtpl:29
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gititemblob.qtpl:29
+//line templates/gititemblob.qtpl:29
g.StreamGitContent(qw422016, name, ref)
-//line gititemblob.qtpl:29
+//line templates/gititemblob.qtpl:29
qt422016.ReleaseWriter(qw422016)
-//line gititemblob.qtpl:29
+//line templates/gititemblob.qtpl:29
}
-//line gititemblob.qtpl:29
+//line templates/gititemblob.qtpl:29
func (g *GitItemBlobPage) GitContent(name, ref string) string {
-//line gititemblob.qtpl:29
+//line templates/gititemblob.qtpl:29
qb422016 := qt422016.AcquireByteBuffer()
-//line gititemblob.qtpl:29
+//line templates/gititemblob.qtpl:29
g.WriteGitContent(qb422016, name, ref)
-//line gititemblob.qtpl:29
+//line templates/gititemblob.qtpl:29
qs422016 := string(qb422016.B)
-//line gititemblob.qtpl:29
+//line templates/gititemblob.qtpl:29
qt422016.ReleaseByteBuffer(qb422016)
-//line gititemblob.qtpl:29
+//line templates/gititemblob.qtpl:29
return qs422016
-//line gititemblob.qtpl:29
+//line templates/gititemblob.qtpl:29
}
diff --git a/templates/gititemcommit.qtpl b/templates/gititemcommit.qtpl
index d223315..7de1bdb 100644
--- a/templates/gititemcommit.qtpl
+++ b/templates/gititemcommit.qtpl
@@ -1,9 +1,9 @@
-{% import "github.com/go-git/go-git/v5/plumbing/object" %}
+{% import "git.gabrielgio.me/cerrado/pkg/git" %}
{% code
type GitItemCommitPage struct {
- Commit *object.Commit
- Diff string
+ Commit *git.CommitReference
+ Diff []byte
}
%}
@@ -14,6 +14,6 @@ type GitItemCommitPage struct {
{%= Commit(name, g.Commit, true) %}
</div>
<div class="code-view">
-<pre>{%s g.Diff %}</pre>
+<pre>{%z= g.Diff %}</pre>
</div>
{% endfunc %}
diff --git a/templates/gititemcommit.qtpl.go b/templates/gititemcommit.qtpl.go
index 39348ee..b790220 100644
--- a/templates/gititemcommit.qtpl.go
+++ b/templates/gititemcommit.qtpl.go
@@ -1,108 +1,108 @@
// Code generated by qtc from "gititemcommit.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
-//line gititemcommit.qtpl:1
+//line templates/gititemcommit.qtpl:1
package templates
-//line gititemcommit.qtpl:1
-import "github.com/go-git/go-git/v5/plumbing/object"
+//line templates/gititemcommit.qtpl:1
+import "git.gabrielgio.me/cerrado/pkg/git"
-//line gititemcommit.qtpl:3
+//line templates/gititemcommit.qtpl:3
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
-//line gititemcommit.qtpl:3
+//line templates/gititemcommit.qtpl:3
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
-//line gititemcommit.qtpl:4
+//line templates/gititemcommit.qtpl:4
type GitItemCommitPage struct {
- Commit *object.Commit
- Diff string
+ Commit *git.CommitReference
+ Diff []byte
}
-//line gititemcommit.qtpl:10
+//line templates/gititemcommit.qtpl:10
func (g *GitItemCommitPage) StreamNav(qw422016 *qt422016.Writer, name, ref string) {
-//line gititemcommit.qtpl:10
+//line templates/gititemcommit.qtpl:10
StreamGitItemNav(qw422016, name, ref, Log)
-//line gititemcommit.qtpl:10
+//line templates/gititemcommit.qtpl:10
}
-//line gititemcommit.qtpl:10
+//line templates/gititemcommit.qtpl:10
func (g *GitItemCommitPage) WriteNav(qq422016 qtio422016.Writer, name, ref string) {
-//line gititemcommit.qtpl:10
+//line templates/gititemcommit.qtpl:10
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gititemcommit.qtpl:10
+//line templates/gititemcommit.qtpl:10
g.StreamNav(qw422016, name, ref)
-//line gititemcommit.qtpl:10
+//line templates/gititemcommit.qtpl:10
qt422016.ReleaseWriter(qw422016)
-//line gititemcommit.qtpl:10
+//line templates/gititemcommit.qtpl:10
}
-//line gititemcommit.qtpl:10
+//line templates/gititemcommit.qtpl:10
func (g *GitItemCommitPage) Nav(name, ref string) string {
-//line gititemcommit.qtpl:10
+//line templates/gititemcommit.qtpl:10
qb422016 := qt422016.AcquireByteBuffer()
-//line gititemcommit.qtpl:10
+//line templates/gititemcommit.qtpl:10
g.WriteNav(qb422016, name, ref)
-//line gititemcommit.qtpl:10
+//line templates/gititemcommit.qtpl:10
qs422016 := string(qb422016.B)
-//line gititemcommit.qtpl:10
+//line templates/gititemcommit.qtpl:10
qt422016.ReleaseByteBuffer(qb422016)
-//line gititemcommit.qtpl:10
+//line templates/gititemcommit.qtpl:10
return qs422016
-//line gititemcommit.qtpl:10
+//line templates/gititemcommit.qtpl:10
}
-//line gititemcommit.qtpl:12
+//line templates/gititemcommit.qtpl:12
func (g *GitItemCommitPage) StreamGitContent(qw422016 *qt422016.Writer, name, ref string) {
-//line gititemcommit.qtpl:12
+//line templates/gititemcommit.qtpl:12
qw422016.N().S(`
<div class="event-list">
`)
-//line gititemcommit.qtpl:14
+//line templates/gititemcommit.qtpl:14
StreamCommit(qw422016, name, g.Commit, true)
-//line gititemcommit.qtpl:14
+//line templates/gititemcommit.qtpl:14
qw422016.N().S(`
</div>
<div class="code-view">
<pre>`)
-//line gititemcommit.qtpl:17
- qw422016.E().S(g.Diff)
-//line gititemcommit.qtpl:17
+//line templates/gititemcommit.qtpl:17
+ qw422016.N().Z(g.Diff)
+//line templates/gititemcommit.qtpl:17
qw422016.N().S(`</pre>
</div>
`)
-//line gititemcommit.qtpl:19
+//line templates/gititemcommit.qtpl:19
}
-//line gititemcommit.qtpl:19
+//line templates/gititemcommit.qtpl:19
func (g *GitItemCommitPage) WriteGitContent(qq422016 qtio422016.Writer, name, ref string) {
-//line gititemcommit.qtpl:19
+//line templates/gititemcommit.qtpl:19
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gititemcommit.qtpl:19
+//line templates/gititemcommit.qtpl:19
g.StreamGitContent(qw422016, name, ref)
-//line gititemcommit.qtpl:19
+//line templates/gititemcommit.qtpl:19
qt422016.ReleaseWriter(qw422016)
-//line gititemcommit.qtpl:19
+//line templates/gititemcommit.qtpl:19
}
-//line gititemcommit.qtpl:19
+//line templates/gititemcommit.qtpl:19
func (g *GitItemCommitPage) GitContent(name, ref string) string {
-//line gititemcommit.qtpl:19
+//line templates/gititemcommit.qtpl:19
qb422016 := qt422016.AcquireByteBuffer()
-//line gititemcommit.qtpl:19
+//line templates/gititemcommit.qtpl:19
g.WriteGitContent(qb422016, name, ref)
-//line gititemcommit.qtpl:19
+//line templates/gititemcommit.qtpl:19
qs422016 := string(qb422016.B)
-//line gititemcommit.qtpl:19
+//line templates/gititemcommit.qtpl:19
qt422016.ReleaseByteBuffer(qb422016)
-//line gititemcommit.qtpl:19
+//line templates/gititemcommit.qtpl:19
return qs422016
-//line gititemcommit.qtpl:19
+//line templates/gititemcommit.qtpl:19
}
diff --git a/templates/gititemlog.qtpl b/templates/gititemlog.qtpl
index e5bfc1b..391de53 100644
--- a/templates/gititemlog.qtpl
+++ b/templates/gititemlog.qtpl
@@ -1,8 +1,10 @@
+{% import "git.gabrielgio.me/cerrado/pkg/git" %}
{% import "github.com/go-git/go-git/v5/plumbing/object" %}
{% code
type GitItemLogPage struct {
- Commits []*object.Commit
+ Commits []*git.CommitReference
+ Next *object.Commit
}
%}
@@ -13,5 +15,9 @@ type GitItemLogPage struct {
{% for _, c := range g.Commits %}
{%= Commit(name, c, false) %}
{% endfor %}
+ {% if g.Next != nil %}
+ <a href="/{%s name %}/log/{%s ref %}/?from={%s g.Next.Hash.String() %}" class="btn btn-primary">Next</a>
+ {% endif %}
+
</div>
{% endfunc %}
diff --git a/templates/gititemlog.qtpl.go b/templates/gititemlog.qtpl.go
index bb37a08..2c9ce93 100644
--- a/templates/gititemlog.qtpl.go
+++ b/templates/gititemlog.qtpl.go
@@ -1,110 +1,138 @@
// Code generated by qtc from "gititemlog.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
-//line gititemlog.qtpl:1
+//line templates/gititemlog.qtpl:1
package templates
-//line gititemlog.qtpl:1
+//line templates/gititemlog.qtpl:1
+import "git.gabrielgio.me/cerrado/pkg/git"
+
+//line templates/gititemlog.qtpl:2
import "github.com/go-git/go-git/v5/plumbing/object"
-//line gititemlog.qtpl:3
+//line templates/gititemlog.qtpl:4
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
-//line gititemlog.qtpl:3
+//line templates/gititemlog.qtpl:4
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
-//line gititemlog.qtpl:4
+//line templates/gititemlog.qtpl:5
type GitItemLogPage struct {
- Commits []*object.Commit
+ Commits []*git.CommitReference
+ Next *object.Commit
}
-//line gititemlog.qtpl:9
+//line templates/gititemlog.qtpl:11
func (g *GitItemLogPage) StreamNav(qw422016 *qt422016.Writer, name, ref string) {
-//line gititemlog.qtpl:9
+//line templates/gititemlog.qtpl:11
StreamGitItemNav(qw422016, name, ref, Log)
-//line gititemlog.qtpl:9
+//line templates/gititemlog.qtpl:11
}
-//line gititemlog.qtpl:9
+//line templates/gititemlog.qtpl:11
func (g *GitItemLogPage) WriteNav(qq422016 qtio422016.Writer, name, ref string) {
-//line gititemlog.qtpl:9
+//line templates/gititemlog.qtpl:11
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gititemlog.qtpl:9
+//line templates/gititemlog.qtpl:11
g.StreamNav(qw422016, name, ref)
-//line gititemlog.qtpl:9
+//line templates/gititemlog.qtpl:11
qt422016.ReleaseWriter(qw422016)
-//line gititemlog.qtpl:9
+//line templates/gititemlog.qtpl:11
}
-//line gititemlog.qtpl:9
+//line templates/gititemlog.qtpl:11
func (g *GitItemLogPage) Nav(name, ref string) string {
-//line gititemlog.qtpl:9
+//line templates/gititemlog.qtpl:11
qb422016 := qt422016.AcquireByteBuffer()
-//line gititemlog.qtpl:9
+//line templates/gititemlog.qtpl:11
g.WriteNav(qb422016, name, ref)
-//line gititemlog.qtpl:9
+//line templates/gititemlog.qtpl:11
qs422016 := string(qb422016.B)
-//line gititemlog.qtpl:9
+//line templates/gititemlog.qtpl:11
qt422016.ReleaseByteBuffer(qb422016)
-//line gititemlog.qtpl:9
+//line templates/gititemlog.qtpl:11
return qs422016
-//line gititemlog.qtpl:9
+//line templates/gititemlog.qtpl:11
}
-//line gititemlog.qtpl:11
+//line templates/gititemlog.qtpl:13
func (g *GitItemLogPage) StreamGitContent(qw422016 *qt422016.Writer, name, ref string) {
-//line gititemlog.qtpl:11
+//line templates/gititemlog.qtpl:13
qw422016.N().S(`
<div class="event-list">
`)
-//line gititemlog.qtpl:13
+//line templates/gititemlog.qtpl:15
for _, c := range g.Commits {
-//line gititemlog.qtpl:13
+//line templates/gititemlog.qtpl:15
qw422016.N().S(`
`)
-//line gititemlog.qtpl:14
+//line templates/gititemlog.qtpl:16
StreamCommit(qw422016, name, c, false)
-//line gititemlog.qtpl:14
+//line templates/gititemlog.qtpl:16
qw422016.N().S(`
`)
-//line gititemlog.qtpl:15
+//line templates/gititemlog.qtpl:17
}
-//line gititemlog.qtpl:15
+//line templates/gititemlog.qtpl:17
qw422016.N().S(`
+ `)
+//line templates/gititemlog.qtpl:18
+ if g.Next != nil {
+//line templates/gititemlog.qtpl:18
+ qw422016.N().S(`
+ <a href="/`)
+//line templates/gititemlog.qtpl:19
+ qw422016.E().S(name)
+//line templates/gititemlog.qtpl:19
+ qw422016.N().S(`/log/`)
+//line templates/gititemlog.qtpl:19
+ qw422016.E().S(ref)
+//line templates/gititemlog.qtpl:19
+ qw422016.N().S(`/?from=`)
+//line templates/gititemlog.qtpl:19
+ qw422016.E().S(g.Next.Hash.String())
+//line templates/gititemlog.qtpl:19
+ qw422016.N().S(`" class="btn btn-primary">Next</a>
+ `)
+//line templates/gititemlog.qtpl:20
+ }
+//line templates/gititemlog.qtpl:20
+ qw422016.N().S(`
+
</div>
`)
-//line gititemlog.qtpl:17
+//line templates/gititemlog.qtpl:23
}
-//line gititemlog.qtpl:17
+//line templates/gititemlog.qtpl:23
func (g *GitItemLogPage) WriteGitContent(qq422016 qtio422016.Writer, name, ref string) {
-//line gititemlog.qtpl:17
+//line templates/gititemlog.qtpl:23
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gititemlog.qtpl:17
+//line templates/gititemlog.qtpl:23
g.StreamGitContent(qw422016, name, ref)
-//line gititemlog.qtpl:17
+//line templates/gititemlog.qtpl:23
qt422016.ReleaseWriter(qw422016)
-//line gititemlog.qtpl:17
+//line templates/gititemlog.qtpl:23
}
-//line gititemlog.qtpl:17
+//line templates/gititemlog.qtpl:23
func (g *GitItemLogPage) GitContent(name, ref string) string {
-//line gititemlog.qtpl:17
+//line templates/gititemlog.qtpl:23
qb422016 := qt422016.AcquireByteBuffer()
-//line gititemlog.qtpl:17
+//line templates/gititemlog.qtpl:23
g.WriteGitContent(qb422016, name, ref)
-//line gititemlog.qtpl:17
+//line templates/gititemlog.qtpl:23
qs422016 := string(qb422016.B)
-//line gititemlog.qtpl:17
+//line templates/gititemlog.qtpl:23
qt422016.ReleaseByteBuffer(qb422016)
-//line gititemlog.qtpl:17
+//line templates/gititemlog.qtpl:23
return qs422016
-//line gititemlog.qtpl:17
+//line templates/gititemlog.qtpl:23
}
diff --git a/templates/gititemref.qtpl b/templates/gititemref.qtpl
new file mode 100644
index 0000000..9e1c776
--- /dev/null
+++ b/templates/gititemref.qtpl
@@ -0,0 +1,34 @@
+{% import "git.gabrielgio.me/cerrado/pkg/git" %}
+{% import "git.gabrielgio.me/cerrado/pkg/humanize" %}
+{% import "github.com/go-git/go-git/v5/plumbing/object" %}
+
+{% code
+type GitItemRefPage struct {
+ Reference *git.TagReference
+ Commit *object.Commit
+}
+%}
+
+{% func (g *GitItemRefPage) Nav(name, ref string) %}{%= GitItemNav(name, ref, Refs) %}{% endfunc %}
+
+{% func (g *GitItemRefPage) GitContent(name, ref string) %}
+<div class="event-list">
+ <div class="row event">
+ <div class="row">
+ <div class="col-md">
+ <a title="{%s g.Commit.Hash.String() %}" href="/{%s name %}/commit/{%s g.Commit.Hash.String() %}/">{%s g.Commit.Hash.String()[0:8] %}</a> —
+ <a title="{%s g.Commit.Committer.Email %}" href="mailto:{%s g.Commit.Author.Email %}">{%s g.Commit.Author.Name %}</a>
+ </div>
+ <div class="col-md text-md-center">
+ <a title="tar.gz for {%s g.Reference.ShortName() %}" href="/{%s name %}/archive/{%s g.Reference.ShortName() %}.tar.gz">tar.gz</a>
+ </div>
+ <div class="col-md text-md-end">
+ <a title="{%s g.Commit.Author.When.UTC().Format("2006-01-02 15:04:05")%} UTC">{%s humanize.Time(g.Commit.Author.When) %}</a>
+ </div>
+ </div>
+ <div class="code-view">
+ <pre>{%s g.Reference.Message() %}</pre>
+ </div>
+ </div>
+</div>
+{% endfunc %}
diff --git a/templates/gititemref.qtpl.go b/templates/gititemref.qtpl.go
new file mode 100644
index 0000000..53ca1ec
--- /dev/null
+++ b/templates/gititemref.qtpl.go
@@ -0,0 +1,171 @@
+// Code generated by qtc from "gititemref.qtpl". DO NOT EDIT.
+// See https://github.com/valyala/quicktemplate for details.
+
+//line templates/gititemref.qtpl:1
+package templates
+
+//line templates/gititemref.qtpl:1
+import "git.gabrielgio.me/cerrado/pkg/git"
+
+//line templates/gititemref.qtpl:2
+import "git.gabrielgio.me/cerrado/pkg/humanize"
+
+//line templates/gititemref.qtpl:3
+import "github.com/go-git/go-git/v5/plumbing/object"
+
+//line templates/gititemref.qtpl:5
+import (
+ qtio422016 "io"
+
+ qt422016 "github.com/valyala/quicktemplate"
+)
+
+//line templates/gititemref.qtpl:5
+var (
+ _ = qtio422016.Copy
+ _ = qt422016.AcquireByteBuffer
+)
+
+//line templates/gititemref.qtpl:6
+type GitItemRefPage struct {
+ Reference *git.TagReference
+ Commit *object.Commit
+}
+
+//line templates/gititemref.qtpl:12
+func (g *GitItemRefPage) StreamNav(qw422016 *qt422016.Writer, name, ref string) {
+//line templates/gititemref.qtpl:12
+ StreamGitItemNav(qw422016, name, ref, Refs)
+//line templates/gititemref.qtpl:12
+}
+
+//line templates/gititemref.qtpl:12
+func (g *GitItemRefPage) WriteNav(qq422016 qtio422016.Writer, name, ref string) {
+//line templates/gititemref.qtpl:12
+ qw422016 := qt422016.AcquireWriter(qq422016)
+//line templates/gititemref.qtpl:12
+ g.StreamNav(qw422016, name, ref)
+//line templates/gititemref.qtpl:12
+ qt422016.ReleaseWriter(qw422016)
+//line templates/gititemref.qtpl:12
+}
+
+//line templates/gititemref.qtpl:12
+func (g *GitItemRefPage) Nav(name, ref string) string {
+//line templates/gititemref.qtpl:12
+ qb422016 := qt422016.AcquireByteBuffer()
+//line templates/gititemref.qtpl:12
+ g.WriteNav(qb422016, name, ref)
+//line templates/gititemref.qtpl:12
+ qs422016 := string(qb422016.B)
+//line templates/gititemref.qtpl:12
+ qt422016.ReleaseByteBuffer(qb422016)
+//line templates/gititemref.qtpl:12
+ return qs422016
+//line templates/gititemref.qtpl:12
+}
+
+//line templates/gititemref.qtpl:14
+func (g *GitItemRefPage) StreamGitContent(qw422016 *qt422016.Writer, name, ref string) {
+//line templates/gititemref.qtpl:14
+ qw422016.N().S(`
+<div class="event-list">
+ <div class="row event">
+ <div class="row">
+ <div class="col-md">
+ <a title="`)
+//line templates/gititemref.qtpl:19
+ qw422016.E().S(g.Commit.Hash.String())
+//line templates/gititemref.qtpl:19
+ qw422016.N().S(`" href="/`)
+//line templates/gititemref.qtpl:19
+ qw422016.E().S(name)
+//line templates/gititemref.qtpl:19
+ qw422016.N().S(`/commit/`)
+//line templates/gititemref.qtpl:19
+ qw422016.E().S(g.Commit.Hash.String())
+//line templates/gititemref.qtpl:19
+ qw422016.N().S(`/">`)
+//line templates/gititemref.qtpl:19
+ qw422016.E().S(g.Commit.Hash.String()[0:8])
+//line templates/gititemref.qtpl:19
+ qw422016.N().S(`</a> —
+ <a title="`)
+//line templates/gititemref.qtpl:20
+ qw422016.E().S(g.Commit.Committer.Email)
+//line templates/gititemref.qtpl:20
+ qw422016.N().S(`" href="mailto:`)
+//line templates/gititemref.qtpl:20
+ qw422016.E().S(g.Commit.Author.Email)
+//line templates/gititemref.qtpl:20
+ qw422016.N().S(`">`)
+//line templates/gititemref.qtpl:20
+ qw422016.E().S(g.Commit.Author.Name)
+//line templates/gititemref.qtpl:20
+ qw422016.N().S(`</a>
+ </div>
+ <div class="col-md text-md-center">
+ <a title="tar.gz for `)
+//line templates/gititemref.qtpl:23
+ qw422016.E().S(g.Reference.ShortName())
+//line templates/gititemref.qtpl:23
+ qw422016.N().S(`" href="/`)
+//line templates/gititemref.qtpl:23
+ qw422016.E().S(name)
+//line templates/gititemref.qtpl:23
+ qw422016.N().S(`/archive/`)
+//line templates/gititemref.qtpl:23
+ qw422016.E().S(g.Reference.ShortName())
+//line templates/gititemref.qtpl:23
+ qw422016.N().S(`.tar.gz">tar.gz</a>
+ </div>
+ <div class="col-md text-md-end">
+ <a title="`)
+//line templates/gititemref.qtpl:26
+ qw422016.E().S(g.Commit.Author.When.UTC().Format("2006-01-02 15:04:05"))
+//line templates/gititemref.qtpl:26
+ qw422016.N().S(` UTC">`)
+//line templates/gititemref.qtpl:26
+ qw422016.E().S(humanize.Time(g.Commit.Author.When))
+//line templates/gititemref.qtpl:26
+ qw422016.N().S(`</a>
+ </div>
+ </div>
+ <div class="code-view">
+ <pre>`)
+//line templates/gititemref.qtpl:30
+ qw422016.E().S(g.Reference.Message())
+//line templates/gititemref.qtpl:30
+ qw422016.N().S(`</pre>
+ </div>
+ </div>
+</div>
+`)
+//line templates/gititemref.qtpl:34
+}
+
+//line templates/gititemref.qtpl:34
+func (g *GitItemRefPage) WriteGitContent(qq422016 qtio422016.Writer, name, ref string) {
+//line templates/gititemref.qtpl:34
+ qw422016 := qt422016.AcquireWriter(qq422016)
+//line templates/gititemref.qtpl:34
+ g.StreamGitContent(qw422016, name, ref)
+//line templates/gititemref.qtpl:34
+ qt422016.ReleaseWriter(qw422016)
+//line templates/gititemref.qtpl:34
+}
+
+//line templates/gititemref.qtpl:34
+func (g *GitItemRefPage) GitContent(name, ref string) string {
+//line templates/gititemref.qtpl:34
+ qb422016 := qt422016.AcquireByteBuffer()
+//line templates/gititemref.qtpl:34
+ g.WriteGitContent(qb422016, name, ref)
+//line templates/gititemref.qtpl:34
+ qs422016 := string(qb422016.B)
+//line templates/gititemref.qtpl:34
+ qt422016.ReleaseByteBuffer(qb422016)
+//line templates/gititemref.qtpl:34
+ return qs422016
+//line templates/gititemref.qtpl:34
+}
diff --git a/templates/gititemrefs.qtpl.go b/templates/gititemrefs.qtpl.go
index d54301d..eb1b657 100644
--- a/templates/gititemrefs.qtpl.go
+++ b/templates/gititemrefs.qtpl.go
@@ -1,160 +1,160 @@
// Code generated by qtc from "gititemrefs.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
-//line gititemrefs.qtpl:1
+//line templates/gititemrefs.qtpl:1
package templates
-//line gititemrefs.qtpl:1
+//line templates/gititemrefs.qtpl:1
import "github.com/go-git/go-git/v5/plumbing"
-//line gititemrefs.qtpl:2
+//line templates/gititemrefs.qtpl:2
import "git.gabrielgio.me/cerrado/pkg/git"
-//line gititemrefs.qtpl:4
+//line templates/gititemrefs.qtpl:4
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
-//line gititemrefs.qtpl:4
+//line templates/gititemrefs.qtpl:4
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
-//line gititemrefs.qtpl:5
+//line templates/gititemrefs.qtpl:5
type GitItemRefsPage struct {
Tags []*git.TagReference
Branches []*plumbing.Reference
}
-//line gititemrefs.qtpl:11
+//line templates/gititemrefs.qtpl:11
func (g *GitItemRefsPage) StreamNav(qw422016 *qt422016.Writer, name, ref string) {
-//line gititemrefs.qtpl:11
+//line templates/gititemrefs.qtpl:11
StreamGitItemNav(qw422016, name, ref, Refs)
-//line gititemrefs.qtpl:11
+//line templates/gititemrefs.qtpl:11
}
-//line gititemrefs.qtpl:11
+//line templates/gititemrefs.qtpl:11
func (g *GitItemRefsPage) WriteNav(qq422016 qtio422016.Writer, name, ref string) {
-//line gititemrefs.qtpl:11
+//line templates/gititemrefs.qtpl:11
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gititemrefs.qtpl:11
+//line templates/gititemrefs.qtpl:11
g.StreamNav(qw422016, name, ref)
-//line gititemrefs.qtpl:11
+//line templates/gititemrefs.qtpl:11
qt422016.ReleaseWriter(qw422016)
-//line gititemrefs.qtpl:11
+//line templates/gititemrefs.qtpl:11
}
-//line gititemrefs.qtpl:11
+//line templates/gititemrefs.qtpl:11
func (g *GitItemRefsPage) Nav(name, ref string) string {
-//line gititemrefs.qtpl:11
+//line templates/gititemrefs.qtpl:11
qb422016 := qt422016.AcquireByteBuffer()
-//line gititemrefs.qtpl:11
+//line templates/gititemrefs.qtpl:11
g.WriteNav(qb422016, name, ref)
-//line gititemrefs.qtpl:11
+//line templates/gititemrefs.qtpl:11
qs422016 := string(qb422016.B)
-//line gititemrefs.qtpl:11
+//line templates/gititemrefs.qtpl:11
qt422016.ReleaseByteBuffer(qb422016)
-//line gititemrefs.qtpl:11
+//line templates/gititemrefs.qtpl:11
return qs422016
-//line gititemrefs.qtpl:11
+//line templates/gititemrefs.qtpl:11
}
-//line gititemrefs.qtpl:13
+//line templates/gititemrefs.qtpl:13
func (g *GitItemRefsPage) StreamGitContent(qw422016 *qt422016.Writer, name, ref string) {
-//line gititemrefs.qtpl:13
+//line templates/gititemrefs.qtpl:13
qw422016.N().S(`
<div class="row">
<div class="col-md-8">
`)
-//line gititemrefs.qtpl:16
+//line templates/gititemrefs.qtpl:16
StreamListTags(qw422016, name, g.Tags)
-//line gititemrefs.qtpl:16
+//line templates/gititemrefs.qtpl:16
qw422016.N().S(`
</div>
<div class="col-md-4">
<div class="event-list">
`)
-//line gititemrefs.qtpl:20
+//line templates/gititemrefs.qtpl:20
for _, b := range g.Branches {
-//line gititemrefs.qtpl:20
+//line templates/gititemrefs.qtpl:20
qw422016.N().S(`
<div class="row event">
<div class="col-4">
`)
-//line gititemrefs.qtpl:23
+//line templates/gititemrefs.qtpl:23
qw422016.E().S(b.Name().Short())
-//line gititemrefs.qtpl:23
+//line templates/gititemrefs.qtpl:23
qw422016.N().S(`
</div>
<div class="col-8">
<div class="float-end">
<a href="/`)
-//line gititemrefs.qtpl:27
+//line templates/gititemrefs.qtpl:27
qw422016.E().S(name)
-//line gititemrefs.qtpl:27
+//line templates/gititemrefs.qtpl:27
qw422016.N().S(`/archive/`)
-//line gititemrefs.qtpl:27
+//line templates/gititemrefs.qtpl:27
qw422016.E().S(b.Name().Short())
-//line gititemrefs.qtpl:27
+//line templates/gititemrefs.qtpl:27
qw422016.N().S(`.tar.gz">tar.gz</a>
<a href="/`)
-//line gititemrefs.qtpl:28
+//line templates/gititemrefs.qtpl:28
qw422016.E().S(name)
-//line gititemrefs.qtpl:28
+//line templates/gititemrefs.qtpl:28
qw422016.N().S(`/tree/`)
-//line gititemrefs.qtpl:28
+//line templates/gititemrefs.qtpl:28
qw422016.E().S(b.Name().Short())
-//line gititemrefs.qtpl:28
+//line templates/gititemrefs.qtpl:28
qw422016.N().S(`/">tree</a>
<a href="/`)
-//line gititemrefs.qtpl:29
+//line templates/gititemrefs.qtpl:29
qw422016.E().S(name)
-//line gititemrefs.qtpl:29
+//line templates/gititemrefs.qtpl:29
qw422016.N().S(`/log/`)
-//line gititemrefs.qtpl:29
+//line templates/gititemrefs.qtpl:29
qw422016.E().S(b.Name().Short())
-//line gititemrefs.qtpl:29
+//line templates/gititemrefs.qtpl:29
qw422016.N().S(`/">log</a>
</div>
</div>
</div>
`)
-//line gititemrefs.qtpl:33
+//line templates/gititemrefs.qtpl:33
}
-//line gititemrefs.qtpl:33
+//line templates/gititemrefs.qtpl:33
qw422016.N().S(`
</div>
</div>
</div>
`)
-//line gititemrefs.qtpl:37
+//line templates/gititemrefs.qtpl:37
}
-//line gititemrefs.qtpl:37
+//line templates/gititemrefs.qtpl:37
func (g *GitItemRefsPage) WriteGitContent(qq422016 qtio422016.Writer, name, ref string) {
-//line gititemrefs.qtpl:37
+//line templates/gititemrefs.qtpl:37
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gititemrefs.qtpl:37
+//line templates/gititemrefs.qtpl:37
g.StreamGitContent(qw422016, name, ref)
-//line gititemrefs.qtpl:37
+//line templates/gititemrefs.qtpl:37
qt422016.ReleaseWriter(qw422016)
-//line gititemrefs.qtpl:37
+//line templates/gititemrefs.qtpl:37
}
-//line gititemrefs.qtpl:37
+//line templates/gititemrefs.qtpl:37
func (g *GitItemRefsPage) GitContent(name, ref string) string {
-//line gititemrefs.qtpl:37
+//line templates/gititemrefs.qtpl:37
qb422016 := qt422016.AcquireByteBuffer()
-//line gititemrefs.qtpl:37
+//line templates/gititemrefs.qtpl:37
g.WriteGitContent(qb422016, name, ref)
-//line gititemrefs.qtpl:37
+//line templates/gititemrefs.qtpl:37
qs422016 := string(qb422016.B)
-//line gititemrefs.qtpl:37
+//line templates/gititemrefs.qtpl:37
qt422016.ReleaseByteBuffer(qb422016)
-//line gititemrefs.qtpl:37
+//line templates/gititemrefs.qtpl:37
return qs422016
-//line gititemrefs.qtpl:37
+//line templates/gititemrefs.qtpl:37
}
diff --git a/templates/gititemsummary.qtpl b/templates/gititemsummary.qtpl
index f2de5be..f39a613 100644
--- a/templates/gititemsummary.qtpl
+++ b/templates/gititemsummary.qtpl
@@ -1,12 +1,11 @@
{% import "github.com/go-git/go-git/v5/plumbing" %}
-{% import "github.com/go-git/go-git/v5/plumbing/object" %}
{% import "git.gabrielgio.me/cerrado/pkg/git" %}
{% code
type GitItemSummaryPage struct {
Tags []*git.TagReference
Branches []*plumbing.Reference
- Commits []*object.Commit
+ Commits []*git.CommitReference
}
%}
@@ -35,6 +34,7 @@ type GitItemSummaryPage struct {
{% endfor %}
</div>
</div>
+ <a class="more" href="/{%s name %}/refs/">[ see refs... ]</a>
</div>
<div class="row">
<div class="event-list">
@@ -42,5 +42,6 @@ type GitItemSummaryPage struct {
{%= Commit(name, c, false) %}
{% endfor %}
</div>
+ <a class="more" href="/{%s name %}/log/{%s ref %}/">[ see log... ]</a>
</div>
{% endfunc %}
diff --git a/templates/gititemsummary.qtpl.go b/templates/gititemsummary.qtpl.go
index d70823e..d6d20cb 100644
--- a/templates/gititemsummary.qtpl.go
+++ b/templates/gititemsummary.qtpl.go
@@ -1,183 +1,194 @@
// Code generated by qtc from "gititemsummary.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
-//line gititemsummary.qtpl:1
+//line templates/gititemsummary.qtpl:1
package templates
-//line gititemsummary.qtpl:1
+//line templates/gititemsummary.qtpl:1
import "github.com/go-git/go-git/v5/plumbing"
-//line gititemsummary.qtpl:2
-import "github.com/go-git/go-git/v5/plumbing/object"
-
-//line gititemsummary.qtpl:3
+//line templates/gititemsummary.qtpl:2
import "git.gabrielgio.me/cerrado/pkg/git"
-//line gititemsummary.qtpl:5
+//line templates/gititemsummary.qtpl:4
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
-//line gititemsummary.qtpl:5
+//line templates/gititemsummary.qtpl:4
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
-//line gititemsummary.qtpl:6
+//line templates/gititemsummary.qtpl:5
type GitItemSummaryPage struct {
Tags []*git.TagReference
Branches []*plumbing.Reference
- Commits []*object.Commit
+ Commits []*git.CommitReference
}
-//line gititemsummary.qtpl:13
+//line templates/gititemsummary.qtpl:12
func (g *GitItemSummaryPage) StreamNav(qw422016 *qt422016.Writer, name, ref string) {
-//line gititemsummary.qtpl:13
+//line templates/gititemsummary.qtpl:12
StreamGitItemNav(qw422016, name, ref, Summary)
-//line gititemsummary.qtpl:13
+//line templates/gititemsummary.qtpl:12
}
-//line gititemsummary.qtpl:13
+//line templates/gititemsummary.qtpl:12
func (g *GitItemSummaryPage) WriteNav(qq422016 qtio422016.Writer, name, ref string) {
-//line gititemsummary.qtpl:13
+//line templates/gititemsummary.qtpl:12
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gititemsummary.qtpl:13
+//line templates/gititemsummary.qtpl:12
g.StreamNav(qw422016, name, ref)
-//line gititemsummary.qtpl:13
+//line templates/gititemsummary.qtpl:12
qt422016.ReleaseWriter(qw422016)
-//line gititemsummary.qtpl:13
+//line templates/gititemsummary.qtpl:12
}
-//line gititemsummary.qtpl:13
+//line templates/gititemsummary.qtpl:12
func (g *GitItemSummaryPage) Nav(name, ref string) string {
-//line gititemsummary.qtpl:13
+//line templates/gititemsummary.qtpl:12
qb422016 := qt422016.AcquireByteBuffer()
-//line gititemsummary.qtpl:13
+//line templates/gititemsummary.qtpl:12
g.WriteNav(qb422016, name, ref)
-//line gititemsummary.qtpl:13
+//line templates/gititemsummary.qtpl:12
qs422016 := string(qb422016.B)
-//line gititemsummary.qtpl:13
+//line templates/gititemsummary.qtpl:12
qt422016.ReleaseByteBuffer(qb422016)
-//line gititemsummary.qtpl:13
+//line templates/gititemsummary.qtpl:12
return qs422016
-//line gititemsummary.qtpl:13
+//line templates/gititemsummary.qtpl:12
}
-//line gititemsummary.qtpl:15
+//line templates/gititemsummary.qtpl:14
func (g *GitItemSummaryPage) StreamGitContent(qw422016 *qt422016.Writer, name, ref string) {
-//line gititemsummary.qtpl:15
+//line templates/gititemsummary.qtpl:14
qw422016.N().S(`
<div class="row">
<div class="col-md-8">
`)
-//line gititemsummary.qtpl:18
+//line templates/gititemsummary.qtpl:17
StreamListTags(qw422016, name, g.Tags)
-//line gititemsummary.qtpl:18
+//line templates/gititemsummary.qtpl:17
qw422016.N().S(`
</div>
<div class="col-md-4">
<div class="event-list">
`)
-//line gititemsummary.qtpl:22
+//line templates/gititemsummary.qtpl:21
for _, b := range g.Branches {
-//line gititemsummary.qtpl:22
+//line templates/gititemsummary.qtpl:21
qw422016.N().S(`
<div class="row event">
<div class="col-4">
`)
-//line gititemsummary.qtpl:25
+//line templates/gititemsummary.qtpl:24
qw422016.E().S(b.Name().Short())
-//line gititemsummary.qtpl:25
+//line templates/gititemsummary.qtpl:24
qw422016.N().S(`
</div>
<div class="col-8">
<div class="float-end">
<a href="/`)
-//line gititemsummary.qtpl:29
+//line templates/gititemsummary.qtpl:28
qw422016.E().S(name)
-//line gititemsummary.qtpl:29
+//line templates/gititemsummary.qtpl:28
qw422016.N().S(`/archive/`)
-//line gititemsummary.qtpl:29
+//line templates/gititemsummary.qtpl:28
qw422016.E().S(b.Name().Short())
-//line gititemsummary.qtpl:29
+//line templates/gititemsummary.qtpl:28
qw422016.N().S(`.tar.gz">tar.gz</a>
<a href="/`)
-//line gititemsummary.qtpl:30
+//line templates/gititemsummary.qtpl:29
qw422016.E().S(name)
-//line gititemsummary.qtpl:30
+//line templates/gititemsummary.qtpl:29
qw422016.N().S(`/tree/`)
-//line gititemsummary.qtpl:30
+//line templates/gititemsummary.qtpl:29
qw422016.E().S(b.Name().Short())
-//line gititemsummary.qtpl:30
+//line templates/gititemsummary.qtpl:29
qw422016.N().S(`/">tree</a>
<a href="/`)
-//line gititemsummary.qtpl:31
+//line templates/gititemsummary.qtpl:30
qw422016.E().S(name)
-//line gititemsummary.qtpl:31
+//line templates/gititemsummary.qtpl:30
qw422016.N().S(`/log/`)
-//line gititemsummary.qtpl:31
+//line templates/gititemsummary.qtpl:30
qw422016.E().S(b.Name().Short())
-//line gititemsummary.qtpl:31
+//line templates/gititemsummary.qtpl:30
qw422016.N().S(`/">log</a>
</div>
</div>
</div>
`)
-//line gititemsummary.qtpl:35
+//line templates/gititemsummary.qtpl:34
}
-//line gititemsummary.qtpl:35
+//line templates/gititemsummary.qtpl:34
qw422016.N().S(`
</div>
</div>
+ <a class="more" href="/`)
+//line templates/gititemsummary.qtpl:37
+ qw422016.E().S(name)
+//line templates/gititemsummary.qtpl:37
+ qw422016.N().S(`/refs/">[ see refs... ]</a>
</div>
<div class="row">
<div class="event-list">
`)
-//line gititemsummary.qtpl:41
+//line templates/gititemsummary.qtpl:41
for _, c := range g.Commits {
-//line gititemsummary.qtpl:41
+//line templates/gititemsummary.qtpl:41
qw422016.N().S(`
`)
-//line gititemsummary.qtpl:42
+//line templates/gititemsummary.qtpl:42
StreamCommit(qw422016, name, c, false)
-//line gititemsummary.qtpl:42
+//line templates/gititemsummary.qtpl:42
qw422016.N().S(`
`)
-//line gititemsummary.qtpl:43
+//line templates/gititemsummary.qtpl:43
}
-//line gititemsummary.qtpl:43
+//line templates/gititemsummary.qtpl:43
qw422016.N().S(`
</div>
+ <a class="more" href="/`)
+//line templates/gititemsummary.qtpl:45
+ qw422016.E().S(name)
+//line templates/gititemsummary.qtpl:45
+ qw422016.N().S(`/log/`)
+//line templates/gititemsummary.qtpl:45
+ qw422016.E().S(ref)
+//line templates/gititemsummary.qtpl:45
+ qw422016.N().S(`/">[ see log... ]</a>
</div>
`)
-//line gititemsummary.qtpl:46
+//line templates/gititemsummary.qtpl:47
}
-//line gititemsummary.qtpl:46
+//line templates/gititemsummary.qtpl:47
func (g *GitItemSummaryPage) WriteGitContent(qq422016 qtio422016.Writer, name, ref string) {
-//line gititemsummary.qtpl:46
+//line templates/gititemsummary.qtpl:47
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gititemsummary.qtpl:46
+//line templates/gititemsummary.qtpl:47
g.StreamGitContent(qw422016, name, ref)
-//line gititemsummary.qtpl:46
+//line templates/gititemsummary.qtpl:47
qt422016.ReleaseWriter(qw422016)
-//line gititemsummary.qtpl:46
+//line templates/gititemsummary.qtpl:47
}
-//line gititemsummary.qtpl:46
+//line templates/gititemsummary.qtpl:47
func (g *GitItemSummaryPage) GitContent(name, ref string) string {
-//line gititemsummary.qtpl:46
+//line templates/gititemsummary.qtpl:47
qb422016 := qt422016.AcquireByteBuffer()
-//line gititemsummary.qtpl:46
+//line templates/gititemsummary.qtpl:47
g.WriteGitContent(qb422016, name, ref)
-//line gititemsummary.qtpl:46
+//line templates/gititemsummary.qtpl:47
qs422016 := string(qb422016.B)
-//line gititemsummary.qtpl:46
+//line templates/gititemsummary.qtpl:47
qt422016.ReleaseByteBuffer(qb422016)
-//line gititemsummary.qtpl:46
+//line templates/gititemsummary.qtpl:47
return qs422016
-//line gititemsummary.qtpl:46
+//line templates/gititemsummary.qtpl:47
}
diff --git a/templates/gititemtree.qtpl b/templates/gititemtree.qtpl
index 5898506..2753e24 100644
--- a/templates/gititemtree.qtpl
+++ b/templates/gititemtree.qtpl
@@ -1,5 +1,6 @@
{% import "git.gabrielgio.me/cerrado/pkg/u" %}
{% import "github.com/go-git/go-git/v5/plumbing/object" %}
+{% import "github.com/go-git/go-git/v5/plumbing/filemode" %}
{% code type GitItemTreePage struct {
Path []string
@@ -52,10 +53,14 @@
<div class="size"></div>
{% endif %}
{% for _, e := range g.Tree.Entries %}
- <div class="mode">{%s Ignore(e.Mode.ToOSFileMode()).String() %}</div>
{% if e.Mode.IsFile() %}
+ <div class="mode">{%s Ignore(e.Mode.ToOSFileMode()).String() %}</div>
<div class="name blob"><a href="{%s url(name, Blob, ref, e.Name, g.Path) %}">{%s e.Name %}</a></div>
+ {% elseif e.Mode == filemode.Submodule %}
+ <div class="mode">m---------</div>
+ <div class="name tree">{%s e.Name %} (submodule)</div>
{% else %}
+ <div class="mode">d---------</div>
<div class="name tree"><a href="{%s url(name, Folder, ref, e.Name, g.Path) %}">{%s e.Name %}</a></div>
{% endif %}
<div class="commit"></div>
diff --git a/templates/gititemtree.qtpl.go b/templates/gititemtree.qtpl.go
index f8d1fd2..9116cd7 100644
--- a/templates/gititemtree.qtpl.go
+++ b/templates/gititemtree.qtpl.go
@@ -1,42 +1,45 @@
// Code generated by qtc from "gititemtree.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
-//line gititemtree.qtpl:1
+//line templates/gititemtree.qtpl:1
package templates
-//line gititemtree.qtpl:1
+//line templates/gititemtree.qtpl:1
import "git.gabrielgio.me/cerrado/pkg/u"
-//line gititemtree.qtpl:2
+//line templates/gititemtree.qtpl:2
import "github.com/go-git/go-git/v5/plumbing/object"
-//line gititemtree.qtpl:4
+//line templates/gititemtree.qtpl:3
+import "github.com/go-git/go-git/v5/plumbing/filemode"
+
+//line templates/gititemtree.qtpl:5
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
-//line gititemtree.qtpl:4
+//line templates/gititemtree.qtpl:5
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
-//line gititemtree.qtpl:4
+//line templates/gititemtree.qtpl:5
type GitItemTreePage struct {
Path []string
Tree *object.Tree
}
-//line gititemtree.qtpl:10
+//line templates/gititemtree.qtpl:11
const (
Folder = "tree"
Blob = "blob"
Root = ""
)
-//line gititemtree.qtpl:17
+//line templates/gititemtree.qtpl:18
func url(name, mode, ref, filename string, path []string) string {
return u.NewPathing().
AddPath(name).
@@ -47,188 +50,200 @@ func url(name, mode, ref, filename string, path []string) string {
Done()
}
-//line gititemtree.qtpl:28
+//line templates/gititemtree.qtpl:29
func (g *GitItemTreePage) StreamNav(qw422016 *qt422016.Writer, name, ref string) {
-//line gititemtree.qtpl:28
+//line templates/gititemtree.qtpl:29
StreamGitItemNav(qw422016, name, ref, Tree)
-//line gititemtree.qtpl:28
+//line templates/gititemtree.qtpl:29
}
-//line gititemtree.qtpl:28
+//line templates/gititemtree.qtpl:29
func (g *GitItemTreePage) WriteNav(qq422016 qtio422016.Writer, name, ref string) {
-//line gititemtree.qtpl:28
+//line templates/gititemtree.qtpl:29
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gititemtree.qtpl:28
+//line templates/gititemtree.qtpl:29
g.StreamNav(qw422016, name, ref)
-//line gititemtree.qtpl:28
+//line templates/gititemtree.qtpl:29
qt422016.ReleaseWriter(qw422016)
-//line gititemtree.qtpl:28
+//line templates/gititemtree.qtpl:29
}
-//line gititemtree.qtpl:28
+//line templates/gititemtree.qtpl:29
func (g *GitItemTreePage) Nav(name, ref string) string {
-//line gititemtree.qtpl:28
+//line templates/gititemtree.qtpl:29
qb422016 := qt422016.AcquireByteBuffer()
-//line gititemtree.qtpl:28
+//line templates/gititemtree.qtpl:29
g.WriteNav(qb422016, name, ref)
-//line gititemtree.qtpl:28
+//line templates/gititemtree.qtpl:29
qs422016 := string(qb422016.B)
-//line gititemtree.qtpl:28
+//line templates/gititemtree.qtpl:29
qt422016.ReleaseByteBuffer(qb422016)
-//line gititemtree.qtpl:28
+//line templates/gititemtree.qtpl:29
return qs422016
-//line gititemtree.qtpl:28
+//line templates/gititemtree.qtpl:29
}
-//line gititemtree.qtpl:30
+//line templates/gititemtree.qtpl:31
func (g *GitItemTreePage) StreamGitContent(qw422016 *qt422016.Writer, name, ref string) {
-//line gititemtree.qtpl:30
+//line templates/gititemtree.qtpl:31
qw422016.N().S(`
<div class="pathing">
`)
-//line gititemtree.qtpl:33
+//line templates/gititemtree.qtpl:34
if len(g.Path) != 0 {
-//line gititemtree.qtpl:33
+//line templates/gititemtree.qtpl:34
qw422016.N().S(`<a href="`)
-//line gititemtree.qtpl:34
+//line templates/gititemtree.qtpl:35
qw422016.E().S(url(name, Folder, ref, Root, []string{}))
-//line gititemtree.qtpl:34
+//line templates/gititemtree.qtpl:35
qw422016.N().S(`">root/</a>`)
-//line gititemtree.qtpl:35
+//line templates/gititemtree.qtpl:36
for i, e := range g.Path[:len(g.Path)-1] {
-//line gititemtree.qtpl:35
+//line templates/gititemtree.qtpl:36
qw422016.N().S(`<a href="`)
-//line gititemtree.qtpl:36
+//line templates/gititemtree.qtpl:37
qw422016.E().S(url(name, Folder, ref, Root, g.Path[:1+i]))
-//line gititemtree.qtpl:36
+//line templates/gititemtree.qtpl:37
qw422016.N().S(`">`)
-//line gititemtree.qtpl:36
+//line templates/gititemtree.qtpl:37
qw422016.E().S(e)
-//line gititemtree.qtpl:36
+//line templates/gititemtree.qtpl:37
qw422016.N().S(`/</a>`)
-//line gititemtree.qtpl:37
+//line templates/gititemtree.qtpl:38
}
-//line gititemtree.qtpl:37
+//line templates/gititemtree.qtpl:38
qw422016.N().S(`<a>`)
-//line gititemtree.qtpl:38
+//line templates/gititemtree.qtpl:39
qw422016.E().S(u.LastOrZero(g.Path))
-//line gititemtree.qtpl:38
+//line templates/gititemtree.qtpl:39
qw422016.N().S(`</a>`)
-//line gititemtree.qtpl:39
+//line templates/gititemtree.qtpl:40
} else {
-//line gititemtree.qtpl:39
+//line templates/gititemtree.qtpl:40
qw422016.N().S(`<a>root/</a>`)
-//line gititemtree.qtpl:41
+//line templates/gititemtree.qtpl:42
}
-//line gititemtree.qtpl:42
+//line templates/gititemtree.qtpl:43
qw422016.N().S(`
</div>
<div class="row">
<div class="col-md-12">
<div class="tree-list">
`)
-//line gititemtree.qtpl:47
+//line templates/gititemtree.qtpl:48
if len(g.Path) != 0 {
-//line gititemtree.qtpl:47
+//line templates/gititemtree.qtpl:48
qw422016.N().S(`
<div class="mode"><a href="`)
-//line gititemtree.qtpl:48
+//line templates/gititemtree.qtpl:49
qw422016.E().S(url(name, Folder, ref, g.Path[len(g.Path)-1], g.Path[:len(g.Path)-1]))
-//line gititemtree.qtpl:48
+//line templates/gititemtree.qtpl:49
qw422016.N().S(`">..</a></div>
<div class="name tree"></div>
<div class="commit"></div>
<div class="date"></div>
<div class="size"></div>
`)
-//line gititemtree.qtpl:53
+//line templates/gititemtree.qtpl:54
}
-//line gititemtree.qtpl:53
+//line templates/gititemtree.qtpl:54
qw422016.N().S(`
`)
-//line gititemtree.qtpl:54
+//line templates/gititemtree.qtpl:55
for _, e := range g.Tree.Entries {
-//line gititemtree.qtpl:54
+//line templates/gititemtree.qtpl:55
qw422016.N().S(`
- <div class="mode">`)
-//line gititemtree.qtpl:55
- qw422016.E().S(Ignore(e.Mode.ToOSFileMode()).String())
-//line gititemtree.qtpl:55
- qw422016.N().S(`</div>
`)
-//line gititemtree.qtpl:56
+//line templates/gititemtree.qtpl:56
if e.Mode.IsFile() {
-//line gititemtree.qtpl:56
+//line templates/gititemtree.qtpl:56
qw422016.N().S(`
+ <div class="mode">`)
+//line templates/gititemtree.qtpl:57
+ qw422016.E().S(Ignore(e.Mode.ToOSFileMode()).String())
+//line templates/gititemtree.qtpl:57
+ qw422016.N().S(`</div>
<div class="name blob"><a href="`)
-//line gititemtree.qtpl:57
+//line templates/gititemtree.qtpl:58
qw422016.E().S(url(name, Blob, ref, e.Name, g.Path))
-//line gititemtree.qtpl:57
+//line templates/gititemtree.qtpl:58
qw422016.N().S(`">`)
-//line gititemtree.qtpl:57
+//line templates/gititemtree.qtpl:58
qw422016.E().S(e.Name)
-//line gititemtree.qtpl:57
+//line templates/gititemtree.qtpl:58
qw422016.N().S(`</a></div>
`)
-//line gititemtree.qtpl:58
+//line templates/gititemtree.qtpl:59
+ } else if e.Mode == filemode.Submodule {
+//line templates/gititemtree.qtpl:59
+ qw422016.N().S(`
+ <div class="mode">m---------</div>
+ <div class="name tree">`)
+//line templates/gititemtree.qtpl:61
+ qw422016.E().S(e.Name)
+//line templates/gititemtree.qtpl:61
+ qw422016.N().S(` (submodule)</div>
+ `)
+//line templates/gititemtree.qtpl:62
} else {
-//line gititemtree.qtpl:58
+//line templates/gititemtree.qtpl:62
qw422016.N().S(`
+ <div class="mode">d---------</div>
<div class="name tree"><a href="`)
-//line gititemtree.qtpl:59
+//line templates/gititemtree.qtpl:64
qw422016.E().S(url(name, Folder, ref, e.Name, g.Path))
-//line gititemtree.qtpl:59
+//line templates/gititemtree.qtpl:64
qw422016.N().S(`">`)
-//line gititemtree.qtpl:59
+//line templates/gititemtree.qtpl:64
qw422016.E().S(e.Name)
-//line gititemtree.qtpl:59
+//line templates/gititemtree.qtpl:64
qw422016.N().S(`</a></div>
`)
-//line gititemtree.qtpl:60
+//line templates/gititemtree.qtpl:65
}
-//line gititemtree.qtpl:60
+//line templates/gititemtree.qtpl:65
qw422016.N().S(`
<div class="commit"></div>
<div class="date"></div>
<div class="size">`)
-//line gititemtree.qtpl:63
+//line templates/gititemtree.qtpl:68
qw422016.N().DL(Ignore(g.Tree.Size(e.Name)))
-//line gititemtree.qtpl:63
+//line templates/gititemtree.qtpl:68
qw422016.N().S(` KiB</div>
`)
-//line gititemtree.qtpl:64
+//line templates/gititemtree.qtpl:69
}
-//line gititemtree.qtpl:64
+//line templates/gititemtree.qtpl:69
qw422016.N().S(`
</div>
</div>
</div>
`)
-//line gititemtree.qtpl:68
+//line templates/gititemtree.qtpl:73
}
-//line gititemtree.qtpl:68
+//line templates/gititemtree.qtpl:73
func (g *GitItemTreePage) WriteGitContent(qq422016 qtio422016.Writer, name, ref string) {
-//line gititemtree.qtpl:68
+//line templates/gititemtree.qtpl:73
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gititemtree.qtpl:68
+//line templates/gititemtree.qtpl:73
g.StreamGitContent(qw422016, name, ref)
-//line gititemtree.qtpl:68
+//line templates/gititemtree.qtpl:73
qt422016.ReleaseWriter(qw422016)
-//line gititemtree.qtpl:68
+//line templates/gititemtree.qtpl:73
}
-//line gititemtree.qtpl:68
+//line templates/gititemtree.qtpl:73
func (g *GitItemTreePage) GitContent(name, ref string) string {
-//line gititemtree.qtpl:68
+//line templates/gititemtree.qtpl:73
qb422016 := qt422016.AcquireByteBuffer()
-//line gititemtree.qtpl:68
+//line templates/gititemtree.qtpl:73
g.WriteGitContent(qb422016, name, ref)
-//line gititemtree.qtpl:68
+//line templates/gititemtree.qtpl:73
qs422016 := string(qb422016.B)
-//line gititemtree.qtpl:68
+//line templates/gititemtree.qtpl:73
qt422016.ReleaseByteBuffer(qb422016)
-//line gititemtree.qtpl:68
+//line templates/gititemtree.qtpl:73
return qs422016
-//line gititemtree.qtpl:68
+//line templates/gititemtree.qtpl:73
}
diff --git a/templates/gitlist.qtpl b/templates/gitlist.qtpl
index ff2eca9..9756eb7 100644
--- a/templates/gitlist.qtpl
+++ b/templates/gitlist.qtpl
@@ -1,4 +1,7 @@
+{% import "git.gabrielgio.me/cerrado/pkg/humanize" %}
{% import "git.gabrielgio.me/cerrado/pkg/service" %}
+{% import "context" %}
+{% import "strings" %}
{% code
type GitListPage struct {
@@ -7,21 +10,41 @@ type GitListPage struct {
}
%}
-{% func (p *GitListPage) Title() %}Git | List{% endfunc %}
-{% func (p *GitListPage) Navbar() %}{%= Navbar(Git) %}{% endfunc %}
+{% code func firstLine(text string) string {
+ lines := strings.Split(text, "\n")
+ if len(lines) > 0 {
+ return lines[0]
+ }
+ return ""
+}
+%}
+
+{% func (p *GitListPage) Title(ctx context.Context) %}Git | List{% endfunc %}
+
+{% func (p *GitListPage) Navbar(ctx context.Context) %}{%= Navbar(ctx, Git) %}{% endfunc %}
-{% func (p *GitListPage) Content() %}
+{% func (p *GitListPage) Content(ctx context.Context) %}
<div class="row">
<div class="col-md-6 order-last order-md-first">
<div class="event-list">
{% for _, r := range p.Respositories %}
<div class="event">
- <h4>
- <a href="/{%s r.Name %}/">{%s r.Name %}</a>
- </h4>
+ <div class="row">
+ <div class="col-md">
+ <a href="/{%s r.Name %}/">{%s r.Name %}</a>
+ </div>
+ <div class="col-md text-md-end">
+ <small>{% if !r.Public %}private{% endif %}</small>
+ </div>
+ </div>
</hr>
<p>{%s r.Description %}</p>
+ <div class="event-commit row">
+ <a class="col-xl-2" title="{%s r.LastCommit.Commit().Hash.String() %}" href="/{%s r.Name %}/commit/{%s r.LastCommit.Commit().Hash.String() %}/">{%s r.LastCommit.Commit().Hash.String()[0:8] %}</a>
+ <a class="col-xl-7"> {%s firstLine(r.LastCommit.Commit().Message) %}</a>
+ <a class="col-xl-3" title="{%s r.LastCommit.Commit().Author.When.UTC().Format("2006-01-02 15:04:05")%} UTC">{%s humanize.Time(r.LastCommit.Commit().Author.When) %}</a>
+ </div>
<p>
<a href="/{%s r.Name %}/log/{%s r.Ref %}/">log</a>
<a href="/{%s r.Name %}/tree/{%s r.Ref %}/">tree</a>
@@ -37,5 +60,5 @@ type GitListPage struct {
</div>
{% endfunc %}
-{% func (p *GitListPage) Script() %}
+{% func (p *GitListPage) Script(ctx context.Context) %}
{% endfunc %}
diff --git a/templates/gitlist.qtpl.go b/templates/gitlist.qtpl.go
index f38c404..97b570b 100644
--- a/templates/gitlist.qtpl.go
+++ b/templates/gitlist.qtpl.go
@@ -1,228 +1,292 @@
// Code generated by qtc from "gitlist.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
-//line gitlist.qtpl:1
+//line templates/gitlist.qtpl:1
package templates
-//line gitlist.qtpl:1
+//line templates/gitlist.qtpl:1
+import "git.gabrielgio.me/cerrado/pkg/humanize"
+
+//line templates/gitlist.qtpl:2
import "git.gabrielgio.me/cerrado/pkg/service"
-//line gitlist.qtpl:3
+//line templates/gitlist.qtpl:3
+import "context"
+
+//line templates/gitlist.qtpl:4
+import "strings"
+
+//line templates/gitlist.qtpl:6
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
-//line gitlist.qtpl:3
+//line templates/gitlist.qtpl:6
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
-//line gitlist.qtpl:4
+//line templates/gitlist.qtpl:7
type GitListPage struct {
Respositories []*service.Repository
About []byte
}
-//line gitlist.qtpl:10
-func (p *GitListPage) StreamTitle(qw422016 *qt422016.Writer) {
-//line gitlist.qtpl:10
+//line templates/gitlist.qtpl:14
+func firstLine(text string) string {
+ lines := strings.Split(text, "\n")
+ if len(lines) > 0 {
+ return lines[0]
+ }
+ return ""
+}
+
+//line templates/gitlist.qtpl:23
+func (p *GitListPage) StreamTitle(qw422016 *qt422016.Writer, ctx context.Context) {
+//line templates/gitlist.qtpl:23
qw422016.N().S(`Git | List`)
-//line gitlist.qtpl:10
+//line templates/gitlist.qtpl:23
}
-//line gitlist.qtpl:10
-func (p *GitListPage) WriteTitle(qq422016 qtio422016.Writer) {
-//line gitlist.qtpl:10
+//line templates/gitlist.qtpl:23
+func (p *GitListPage) WriteTitle(qq422016 qtio422016.Writer, ctx context.Context) {
+//line templates/gitlist.qtpl:23
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gitlist.qtpl:10
- p.StreamTitle(qw422016)
-//line gitlist.qtpl:10
+//line templates/gitlist.qtpl:23
+ p.StreamTitle(qw422016, ctx)
+//line templates/gitlist.qtpl:23
qt422016.ReleaseWriter(qw422016)
-//line gitlist.qtpl:10
+//line templates/gitlist.qtpl:23
}
-//line gitlist.qtpl:10
-func (p *GitListPage) Title() string {
-//line gitlist.qtpl:10
+//line templates/gitlist.qtpl:23
+func (p *GitListPage) Title(ctx context.Context) string {
+//line templates/gitlist.qtpl:23
qb422016 := qt422016.AcquireByteBuffer()
-//line gitlist.qtpl:10
- p.WriteTitle(qb422016)
-//line gitlist.qtpl:10
+//line templates/gitlist.qtpl:23
+ p.WriteTitle(qb422016, ctx)
+//line templates/gitlist.qtpl:23
qs422016 := string(qb422016.B)
-//line gitlist.qtpl:10
+//line templates/gitlist.qtpl:23
qt422016.ReleaseByteBuffer(qb422016)
-//line gitlist.qtpl:10
+//line templates/gitlist.qtpl:23
return qs422016
-//line gitlist.qtpl:10
+//line templates/gitlist.qtpl:23
}
-//line gitlist.qtpl:12
-func (p *GitListPage) StreamNavbar(qw422016 *qt422016.Writer) {
-//line gitlist.qtpl:12
- StreamNavbar(qw422016, Git)
-//line gitlist.qtpl:12
+//line templates/gitlist.qtpl:25
+func (p *GitListPage) StreamNavbar(qw422016 *qt422016.Writer, ctx context.Context) {
+//line templates/gitlist.qtpl:25
+ StreamNavbar(qw422016, ctx, Git)
+//line templates/gitlist.qtpl:25
}
-//line gitlist.qtpl:12
-func (p *GitListPage) WriteNavbar(qq422016 qtio422016.Writer) {
-//line gitlist.qtpl:12
+//line templates/gitlist.qtpl:25
+func (p *GitListPage) WriteNavbar(qq422016 qtio422016.Writer, ctx context.Context) {
+//line templates/gitlist.qtpl:25
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gitlist.qtpl:12
- p.StreamNavbar(qw422016)
-//line gitlist.qtpl:12
+//line templates/gitlist.qtpl:25
+ p.StreamNavbar(qw422016, ctx)
+//line templates/gitlist.qtpl:25
qt422016.ReleaseWriter(qw422016)
-//line gitlist.qtpl:12
+//line templates/gitlist.qtpl:25
}
-//line gitlist.qtpl:12
-func (p *GitListPage) Navbar() string {
-//line gitlist.qtpl:12
+//line templates/gitlist.qtpl:25
+func (p *GitListPage) Navbar(ctx context.Context) string {
+//line templates/gitlist.qtpl:25
qb422016 := qt422016.AcquireByteBuffer()
-//line gitlist.qtpl:12
- p.WriteNavbar(qb422016)
-//line gitlist.qtpl:12
+//line templates/gitlist.qtpl:25
+ p.WriteNavbar(qb422016, ctx)
+//line templates/gitlist.qtpl:25
qs422016 := string(qb422016.B)
-//line gitlist.qtpl:12
+//line templates/gitlist.qtpl:25
qt422016.ReleaseByteBuffer(qb422016)
-//line gitlist.qtpl:12
+//line templates/gitlist.qtpl:25
return qs422016
-//line gitlist.qtpl:12
+//line templates/gitlist.qtpl:25
}
-//line gitlist.qtpl:14
-func (p *GitListPage) StreamContent(qw422016 *qt422016.Writer) {
-//line gitlist.qtpl:14
+//line templates/gitlist.qtpl:27
+func (p *GitListPage) StreamContent(qw422016 *qt422016.Writer, ctx context.Context) {
+//line templates/gitlist.qtpl:27
qw422016.N().S(`
<div class="row">
<div class="col-md-6 order-last order-md-first">
<div class="event-list">
`)
-//line gitlist.qtpl:18
+//line templates/gitlist.qtpl:31
for _, r := range p.Respositories {
-//line gitlist.qtpl:18
+//line templates/gitlist.qtpl:31
qw422016.N().S(`
<div class="event">
- <h4>
- <a href="/`)
-//line gitlist.qtpl:21
+ <div class="row">
+ <div class="col-md">
+ <a href="/`)
+//line templates/gitlist.qtpl:35
qw422016.E().S(r.Name)
-//line gitlist.qtpl:21
+//line templates/gitlist.qtpl:35
qw422016.N().S(`/">`)
-//line gitlist.qtpl:21
+//line templates/gitlist.qtpl:35
qw422016.E().S(r.Name)
-//line gitlist.qtpl:21
+//line templates/gitlist.qtpl:35
qw422016.N().S(`</a>
- </h4>
+ </div>
+ <div class="col-md text-md-end">
+ <small>`)
+//line templates/gitlist.qtpl:38
+ if !r.Public {
+//line templates/gitlist.qtpl:38
+ qw422016.N().S(`private`)
+//line templates/gitlist.qtpl:38
+ }
+//line templates/gitlist.qtpl:38
+ qw422016.N().S(`</small>
+ </div>
+ </div>
</hr>
<p>`)
-//line gitlist.qtpl:24
+//line templates/gitlist.qtpl:42
qw422016.E().S(r.Description)
-//line gitlist.qtpl:24
+//line templates/gitlist.qtpl:42
qw422016.N().S(`</p>
+ <div class="event-commit row">
+ <a class="col-xl-2" title="`)
+//line templates/gitlist.qtpl:44
+ qw422016.E().S(r.LastCommit.Commit().Hash.String())
+//line templates/gitlist.qtpl:44
+ qw422016.N().S(`" href="/`)
+//line templates/gitlist.qtpl:44
+ qw422016.E().S(r.Name)
+//line templates/gitlist.qtpl:44
+ qw422016.N().S(`/commit/`)
+//line templates/gitlist.qtpl:44
+ qw422016.E().S(r.LastCommit.Commit().Hash.String())
+//line templates/gitlist.qtpl:44
+ qw422016.N().S(`/">`)
+//line templates/gitlist.qtpl:44
+ qw422016.E().S(r.LastCommit.Commit().Hash.String()[0:8])
+//line templates/gitlist.qtpl:44
+ qw422016.N().S(`</a>
+ <a class="col-xl-7"> `)
+//line templates/gitlist.qtpl:45
+ qw422016.E().S(firstLine(r.LastCommit.Commit().Message))
+//line templates/gitlist.qtpl:45
+ qw422016.N().S(`</a>
+ <a class="col-xl-3" title="`)
+//line templates/gitlist.qtpl:46
+ qw422016.E().S(r.LastCommit.Commit().Author.When.UTC().Format("2006-01-02 15:04:05"))
+//line templates/gitlist.qtpl:46
+ qw422016.N().S(` UTC">`)
+//line templates/gitlist.qtpl:46
+ qw422016.E().S(humanize.Time(r.LastCommit.Commit().Author.When))
+//line templates/gitlist.qtpl:46
+ qw422016.N().S(`</a>
+ </div>
<p>
<a href="/`)
-//line gitlist.qtpl:26
+//line templates/gitlist.qtpl:49
qw422016.E().S(r.Name)
-//line gitlist.qtpl:26
+//line templates/gitlist.qtpl:49
qw422016.N().S(`/log/`)
-//line gitlist.qtpl:26
+//line templates/gitlist.qtpl:49
qw422016.E().S(r.Ref)
-//line gitlist.qtpl:26
+//line templates/gitlist.qtpl:49
qw422016.N().S(`/">log</a>
<a href="/`)
-//line gitlist.qtpl:27
+//line templates/gitlist.qtpl:50
qw422016.E().S(r.Name)
-//line gitlist.qtpl:27
+//line templates/gitlist.qtpl:50
qw422016.N().S(`/tree/`)
-//line gitlist.qtpl:27
+//line templates/gitlist.qtpl:50
qw422016.E().S(r.Ref)
-//line gitlist.qtpl:27
+//line templates/gitlist.qtpl:50
qw422016.N().S(`/">tree</a>
<a href="/`)
-//line gitlist.qtpl:28
+//line templates/gitlist.qtpl:51
qw422016.E().S(r.Name)
-//line gitlist.qtpl:28
+//line templates/gitlist.qtpl:51
qw422016.N().S(`/refs/">refs</a>
</p>
</div>
`)
-//line gitlist.qtpl:31
+//line templates/gitlist.qtpl:54
}
-//line gitlist.qtpl:31
+//line templates/gitlist.qtpl:54
qw422016.N().S(`
</div>
</div>
<div id="about" class="col-md-4 order-first order-md-last">
`)
-//line gitlist.qtpl:35
+//line templates/gitlist.qtpl:58
qw422016.N().Z(p.About)
-//line gitlist.qtpl:35
+//line templates/gitlist.qtpl:58
qw422016.N().S(`
</div>
</div>
`)
-//line gitlist.qtpl:38
+//line templates/gitlist.qtpl:61
}
-//line gitlist.qtpl:38
-func (p *GitListPage) WriteContent(qq422016 qtio422016.Writer) {
-//line gitlist.qtpl:38
+//line templates/gitlist.qtpl:61
+func (p *GitListPage) WriteContent(qq422016 qtio422016.Writer, ctx context.Context) {
+//line templates/gitlist.qtpl:61
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gitlist.qtpl:38
- p.StreamContent(qw422016)
-//line gitlist.qtpl:38
+//line templates/gitlist.qtpl:61
+ p.StreamContent(qw422016, ctx)
+//line templates/gitlist.qtpl:61
qt422016.ReleaseWriter(qw422016)
-//line gitlist.qtpl:38
+//line templates/gitlist.qtpl:61
}
-//line gitlist.qtpl:38
-func (p *GitListPage) Content() string {
-//line gitlist.qtpl:38
+//line templates/gitlist.qtpl:61
+func (p *GitListPage) Content(ctx context.Context) string {
+//line templates/gitlist.qtpl:61
qb422016 := qt422016.AcquireByteBuffer()
-//line gitlist.qtpl:38
- p.WriteContent(qb422016)
-//line gitlist.qtpl:38
+//line templates/gitlist.qtpl:61
+ p.WriteContent(qb422016, ctx)
+//line templates/gitlist.qtpl:61
qs422016 := string(qb422016.B)
-//line gitlist.qtpl:38
+//line templates/gitlist.qtpl:61
qt422016.ReleaseByteBuffer(qb422016)
-//line gitlist.qtpl:38
+//line templates/gitlist.qtpl:61
return qs422016
-//line gitlist.qtpl:38
+//line templates/gitlist.qtpl:61
}
-//line gitlist.qtpl:40
-func (p *GitListPage) StreamScript(qw422016 *qt422016.Writer) {
-//line gitlist.qtpl:40
+//line templates/gitlist.qtpl:63
+func (p *GitListPage) StreamScript(qw422016 *qt422016.Writer, ctx context.Context) {
+//line templates/gitlist.qtpl:63
qw422016.N().S(`
`)
-//line gitlist.qtpl:41
+//line templates/gitlist.qtpl:64
}
-//line gitlist.qtpl:41
-func (p *GitListPage) WriteScript(qq422016 qtio422016.Writer) {
-//line gitlist.qtpl:41
+//line templates/gitlist.qtpl:64
+func (p *GitListPage) WriteScript(qq422016 qtio422016.Writer, ctx context.Context) {
+//line templates/gitlist.qtpl:64
qw422016 := qt422016.AcquireWriter(qq422016)
-//line gitlist.qtpl:41
- p.StreamScript(qw422016)
-//line gitlist.qtpl:41
+//line templates/gitlist.qtpl:64
+ p.StreamScript(qw422016, ctx)
+//line templates/gitlist.qtpl:64
qt422016.ReleaseWriter(qw422016)
-//line gitlist.qtpl:41
+//line templates/gitlist.qtpl:64
}
-//line gitlist.qtpl:41
-func (p *GitListPage) Script() string {
-//line gitlist.qtpl:41
+//line templates/gitlist.qtpl:64
+func (p *GitListPage) Script(ctx context.Context) string {
+//line templates/gitlist.qtpl:64
qb422016 := qt422016.AcquireByteBuffer()
-//line gitlist.qtpl:41
- p.WriteScript(qb422016)
-//line gitlist.qtpl:41
+//line templates/gitlist.qtpl:64
+ p.WriteScript(qb422016, ctx)
+//line templates/gitlist.qtpl:64
qs422016 := string(qb422016.B)
-//line gitlist.qtpl:41
+//line templates/gitlist.qtpl:64
qt422016.ReleaseByteBuffer(qb422016)
-//line gitlist.qtpl:41
+//line templates/gitlist.qtpl:64
return qs422016
-//line gitlist.qtpl:41
+//line templates/gitlist.qtpl:64
}
diff --git a/templates/login.qtpl b/templates/login.qtpl
new file mode 100644
index 0000000..efaf329
--- /dev/null
+++ b/templates/login.qtpl
@@ -0,0 +1,46 @@
+{% import "context" %}
+
+{% code
+type LoginPage struct {
+ Referer string
+ ErrorMessage string
+}
+%}
+
+{% func (p *LoginPage) Title(ctx context.Context) %}Hello{% endfunc %}
+
+{% func (p *LoginPage) Navbar(ctx context.Context) %}{%= Navbar(ctx, Login) %}{% endfunc %}
+
+{% func (p *LoginPage) Content(ctx context.Context) %}
+<div class="row">
+ <div class="col-md-6 offset-md-3">
+ {% if p.Referer == "" %}
+ <form action="/login/" method="POST">
+ {% else %}
+ <form action="/login/?referer={%s p.Referer %}" method="POST">
+ {% endif %}
+ <div class="form-group m-3">
+ <label for="username" class="form-label">Username</label>
+ <input type="text" class="form-control" name="username" id="username">
+ </div>
+ <div class="form-group m-3">
+ <label for="password" class="form-label">Password</label>
+ <input type="password" class="form-control" name="password" id="password">
+ </div>
+ <div class="form-group m-3">
+ <button type="submit" class="btn btn-primary">Login</button>
+ </div>
+ </form>
+ </div>
+ {% if p.ErrorMessage != "" %}
+ <div class="col-md-6 offset-md-3">
+ <div class="alert alert-warning text-center" >
+ {%s p.ErrorMessage %}
+ </div>
+ </div>
+ {% endif %}
+</div>
+{% endfunc %}
+
+{% func (p *LoginPage) Script(ctx context.Context) %}
+{% endfunc %}
diff --git a/templates/login.qtpl.go b/templates/login.qtpl.go
new file mode 100644
index 0000000..1a1b6d7
--- /dev/null
+++ b/templates/login.qtpl.go
@@ -0,0 +1,217 @@
+// Code generated by qtc from "login.qtpl". DO NOT EDIT.
+// See https://github.com/valyala/quicktemplate for details.
+
+//line templates/login.qtpl:1
+package templates
+
+//line templates/login.qtpl:1
+import "context"
+
+//line templates/login.qtpl:3
+import (
+ qtio422016 "io"
+
+ qt422016 "github.com/valyala/quicktemplate"
+)
+
+//line templates/login.qtpl:3
+var (
+ _ = qtio422016.Copy
+ _ = qt422016.AcquireByteBuffer
+)
+
+//line templates/login.qtpl:4
+type LoginPage struct {
+ Referer string
+ ErrorMessage string
+}
+
+//line templates/login.qtpl:10
+func (p *LoginPage) StreamTitle(qw422016 *qt422016.Writer, ctx context.Context) {
+//line templates/login.qtpl:10
+ qw422016.N().S(`Hello`)
+//line templates/login.qtpl:10
+}
+
+//line templates/login.qtpl:10
+func (p *LoginPage) WriteTitle(qq422016 qtio422016.Writer, ctx context.Context) {
+//line templates/login.qtpl:10
+ qw422016 := qt422016.AcquireWriter(qq422016)
+//line templates/login.qtpl:10
+ p.StreamTitle(qw422016, ctx)
+//line templates/login.qtpl:10
+ qt422016.ReleaseWriter(qw422016)
+//line templates/login.qtpl:10
+}
+
+//line templates/login.qtpl:10
+func (p *LoginPage) Title(ctx context.Context) string {
+//line templates/login.qtpl:10
+ qb422016 := qt422016.AcquireByteBuffer()
+//line templates/login.qtpl:10
+ p.WriteTitle(qb422016, ctx)
+//line templates/login.qtpl:10
+ qs422016 := string(qb422016.B)
+//line templates/login.qtpl:10
+ qt422016.ReleaseByteBuffer(qb422016)
+//line templates/login.qtpl:10
+ return qs422016
+//line templates/login.qtpl:10
+}
+
+//line templates/login.qtpl:12
+func (p *LoginPage) StreamNavbar(qw422016 *qt422016.Writer, ctx context.Context) {
+//line templates/login.qtpl:12
+ StreamNavbar(qw422016, ctx, Login)
+//line templates/login.qtpl:12
+}
+
+//line templates/login.qtpl:12
+func (p *LoginPage) WriteNavbar(qq422016 qtio422016.Writer, ctx context.Context) {
+//line templates/login.qtpl:12
+ qw422016 := qt422016.AcquireWriter(qq422016)
+//line templates/login.qtpl:12
+ p.StreamNavbar(qw422016, ctx)
+//line templates/login.qtpl:12
+ qt422016.ReleaseWriter(qw422016)
+//line templates/login.qtpl:12
+}
+
+//line templates/login.qtpl:12
+func (p *LoginPage) Navbar(ctx context.Context) string {
+//line templates/login.qtpl:12
+ qb422016 := qt422016.AcquireByteBuffer()
+//line templates/login.qtpl:12
+ p.WriteNavbar(qb422016, ctx)
+//line templates/login.qtpl:12
+ qs422016 := string(qb422016.B)
+//line templates/login.qtpl:12
+ qt422016.ReleaseByteBuffer(qb422016)
+//line templates/login.qtpl:12
+ return qs422016
+//line templates/login.qtpl:12
+}
+
+//line templates/login.qtpl:14
+func (p *LoginPage) StreamContent(qw422016 *qt422016.Writer, ctx context.Context) {
+//line templates/login.qtpl:14
+ qw422016.N().S(`
+<div class="row">
+ <div class="col-md-6 offset-md-3">
+ `)
+//line templates/login.qtpl:17
+ if p.Referer == "" {
+//line templates/login.qtpl:17
+ qw422016.N().S(`
+ <form action="/login/" method="POST">
+ `)
+//line templates/login.qtpl:19
+ } else {
+//line templates/login.qtpl:19
+ qw422016.N().S(`
+ <form action="/login/?referer=`)
+//line templates/login.qtpl:20
+ qw422016.E().S(p.Referer)
+//line templates/login.qtpl:20
+ qw422016.N().S(`" method="POST">
+ `)
+//line templates/login.qtpl:21
+ }
+//line templates/login.qtpl:21
+ qw422016.N().S(`
+ <div class="form-group m-3">
+ <label for="username" class="form-label">Username</label>
+ <input type="text" class="form-control" name="username" id="username">
+ </div>
+ <div class="form-group m-3">
+ <label for="password" class="form-label">Password</label>
+ <input type="password" class="form-control" name="password" id="password">
+ </div>
+ <div class="form-group m-3">
+ <button type="submit" class="btn btn-primary">Login</button>
+ </div>
+ </form>
+ </div>
+ `)
+//line templates/login.qtpl:35
+ if p.ErrorMessage != "" {
+//line templates/login.qtpl:35
+ qw422016.N().S(`
+ <div class="col-md-6 offset-md-3">
+ <div class="alert alert-warning text-center" >
+ `)
+//line templates/login.qtpl:38
+ qw422016.E().S(p.ErrorMessage)
+//line templates/login.qtpl:38
+ qw422016.N().S(`
+ </div>
+ </div>
+ `)
+//line templates/login.qtpl:41
+ }
+//line templates/login.qtpl:41
+ qw422016.N().S(`
+</div>
+`)
+//line templates/login.qtpl:43
+}
+
+//line templates/login.qtpl:43
+func (p *LoginPage) WriteContent(qq422016 qtio422016.Writer, ctx context.Context) {
+//line templates/login.qtpl:43
+ qw422016 := qt422016.AcquireWriter(qq422016)
+//line templates/login.qtpl:43
+ p.StreamContent(qw422016, ctx)
+//line templates/login.qtpl:43
+ qt422016.ReleaseWriter(qw422016)
+//line templates/login.qtpl:43
+}
+
+//line templates/login.qtpl:43
+func (p *LoginPage) Content(ctx context.Context) string {
+//line templates/login.qtpl:43
+ qb422016 := qt422016.AcquireByteBuffer()
+//line templates/login.qtpl:43
+ p.WriteContent(qb422016, ctx)
+//line templates/login.qtpl:43
+ qs422016 := string(qb422016.B)
+//line templates/login.qtpl:43
+ qt422016.ReleaseByteBuffer(qb422016)
+//line templates/login.qtpl:43
+ return qs422016
+//line templates/login.qtpl:43
+}
+
+//line templates/login.qtpl:45
+func (p *LoginPage) StreamScript(qw422016 *qt422016.Writer, ctx context.Context) {
+//line templates/login.qtpl:45
+ qw422016.N().S(`
+`)
+//line templates/login.qtpl:46
+}
+
+//line templates/login.qtpl:46
+func (p *LoginPage) WriteScript(qq422016 qtio422016.Writer, ctx context.Context) {
+//line templates/login.qtpl:46
+ qw422016 := qt422016.AcquireWriter(qq422016)
+//line templates/login.qtpl:46
+ p.StreamScript(qw422016, ctx)
+//line templates/login.qtpl:46
+ qt422016.ReleaseWriter(qw422016)
+//line templates/login.qtpl:46
+}
+
+//line templates/login.qtpl:46
+func (p *LoginPage) Script(ctx context.Context) string {
+//line templates/login.qtpl:46
+ qb422016 := qt422016.AcquireByteBuffer()
+//line templates/login.qtpl:46
+ p.WriteScript(qb422016, ctx)
+//line templates/login.qtpl:46
+ qs422016 := string(qb422016.B)
+//line templates/login.qtpl:46
+ qt422016.ReleaseByteBuffer(qb422016)
+//line templates/login.qtpl:46
+ return qs422016
+//line templates/login.qtpl:46
+}
diff --git a/templates/navbar.qtpl b/templates/navbar.qtpl
index 68b1fd8..7a07319 100644
--- a/templates/navbar.qtpl
+++ b/templates/navbar.qtpl
@@ -1,3 +1,5 @@
+{% import "context" %}
+
{% code
type Selection int
const (
@@ -5,6 +7,7 @@ const (
List
About
Config
+ Login
)
%}
@@ -21,10 +24,19 @@ const (
{% func insertIfEqual(s, d any) %}{% if s == d %} selected{% endif %}{% endfunc %}
-{% func Navbar (s Selection) %}
+{% func Navbar (ctx context.Context, s Selection) %}
<nav class="container navbar navbar-expand">
<div class="navbar-nav">
<a class="nav-link{%= insertIfEqual(s, Git) %}" href="/">git</a>
+ </div>
+ <div class="navbar-nav ms-auto">
+ {% if !IsAuthenticationDisabled(ctx) %}
+ {% if IsLoggedIn(ctx) %}
+ <a class="nav-link{%= insertIfEqual(s, Login) %}" href="/logout/">logout</a>
+ {% else %}
+ <a class="nav-link{%= insertIfEqual(s, Login) %}" href="/login/">login</a>
+ {% endif %}
+ {% endif %}
{% comment %}
Add this back once needed
<a class="nav-link{%= insertIfEqual(s, List) %}" href="/list/">list</a>
@@ -33,14 +45,13 @@ Add this back once needed
Add this back if needed
<a class="nav-link{%= insertIfEqual(s, About) %}" href="/about/">about</a>
{% endcomment %}
- <a class="nav-link{%= insertIfEqual(s, Config) %}" href="/config">config</a>
</div>
</nav>
{% endfunc %}
{% func GitItemNav (name, ref string, s GitSelection) %}
<div class="row">
- <h3 id="name">{%s name %} {% if ref != "" && (s == Log || s == Tree) %}@ {%s ref %}{% endif %}</h3>
+ <h3 id="name">{%s name %} {% if ref != "" %}@ {%s ref %}{% endif %}</h3>
</div>
<div class="row">
<ul class="nav">
@@ -51,7 +62,7 @@ Add this back if needed
<a class="nav-link{%= insertIfEqual(s, Summary) %}" aria-current="page" href="/{%s name %}/">summary</a>
</li>
<li class="nav-item">
- <a class="nav-link{%= insertIfEqual(s, Refs) %}" aria-current="page" href="/{%s name %}/refs">refs</a>
+ <a class="nav-link{%= insertIfEqual(s, Refs) %}" aria-current="page" href="/{%s name %}/refs/">refs</a>
</li>
<li class="nav-item">
<a class="nav-link{%= insertIfEqual(s, Log) %}" aria-current="page" href="/{%s name %}/log/{%s ref %}/">log</a>
diff --git a/templates/navbar.qtpl.go b/templates/navbar.qtpl.go
index 806df94..0a41d56 100644
--- a/templates/navbar.qtpl.go
+++ b/templates/navbar.qtpl.go
@@ -1,23 +1,26 @@
// Code generated by qtc from "navbar.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
-//line navbar.qtpl:1
+//line templates/navbar.qtpl:1
package templates
-//line navbar.qtpl:1
+//line templates/navbar.qtpl:1
+import "context"
+
+//line templates/navbar.qtpl:3
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
-//line navbar.qtpl:1
+//line templates/navbar.qtpl:3
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
-//line navbar.qtpl:2
+//line templates/navbar.qtpl:4
type Selection int
const (
@@ -25,9 +28,10 @@ const (
List
About
Config
+ Login
)
-//line navbar.qtpl:12
+//line templates/navbar.qtpl:15
type GitSelection int
const (
@@ -38,211 +42,243 @@ const (
Tree
)
-//line navbar.qtpl:22
+//line templates/navbar.qtpl:25
func streaminsertIfEqual(qw422016 *qt422016.Writer, s, d any) {
-//line navbar.qtpl:22
+//line templates/navbar.qtpl:25
if s == d {
-//line navbar.qtpl:22
+//line templates/navbar.qtpl:25
qw422016.N().S(` selected`)
-//line navbar.qtpl:22
+//line templates/navbar.qtpl:25
}
-//line navbar.qtpl:22
+//line templates/navbar.qtpl:25
}
-//line navbar.qtpl:22
+//line templates/navbar.qtpl:25
func writeinsertIfEqual(qq422016 qtio422016.Writer, s, d any) {
-//line navbar.qtpl:22
+//line templates/navbar.qtpl:25
qw422016 := qt422016.AcquireWriter(qq422016)
-//line navbar.qtpl:22
+//line templates/navbar.qtpl:25
streaminsertIfEqual(qw422016, s, d)
-//line navbar.qtpl:22
+//line templates/navbar.qtpl:25
qt422016.ReleaseWriter(qw422016)
-//line navbar.qtpl:22
+//line templates/navbar.qtpl:25
}
-//line navbar.qtpl:22
+//line templates/navbar.qtpl:25
func insertIfEqual(s, d any) string {
-//line navbar.qtpl:22
+//line templates/navbar.qtpl:25
qb422016 := qt422016.AcquireByteBuffer()
-//line navbar.qtpl:22
+//line templates/navbar.qtpl:25
writeinsertIfEqual(qb422016, s, d)
-//line navbar.qtpl:22
+//line templates/navbar.qtpl:25
qs422016 := string(qb422016.B)
-//line navbar.qtpl:22
+//line templates/navbar.qtpl:25
qt422016.ReleaseByteBuffer(qb422016)
-//line navbar.qtpl:22
+//line templates/navbar.qtpl:25
return qs422016
-//line navbar.qtpl:22
+//line templates/navbar.qtpl:25
}
-//line navbar.qtpl:24
-func StreamNavbar(qw422016 *qt422016.Writer, s Selection) {
-//line navbar.qtpl:24
+//line templates/navbar.qtpl:27
+func StreamNavbar(qw422016 *qt422016.Writer, ctx context.Context, s Selection) {
+//line templates/navbar.qtpl:27
qw422016.N().S(`
<nav class="container navbar navbar-expand">
<div class="navbar-nav">
<a class="nav-link`)
-//line navbar.qtpl:27
+//line templates/navbar.qtpl:30
streaminsertIfEqual(qw422016, s, Git)
-//line navbar.qtpl:27
+//line templates/navbar.qtpl:30
qw422016.N().S(`" href="/">git</a>
+ </div>
+ <div class="navbar-nav ms-auto">
+ `)
+//line templates/navbar.qtpl:33
+ if !IsAuthenticationDisabled(ctx) {
+//line templates/navbar.qtpl:33
+ qw422016.N().S(`
+ `)
+//line templates/navbar.qtpl:34
+ if IsLoggedIn(ctx) {
+//line templates/navbar.qtpl:34
+ qw422016.N().S(`
+ <a class="nav-link`)
+//line templates/navbar.qtpl:35
+ streaminsertIfEqual(qw422016, s, Login)
+//line templates/navbar.qtpl:35
+ qw422016.N().S(`" href="/logout/">logout</a>
+ `)
+//line templates/navbar.qtpl:36
+ } else {
+//line templates/navbar.qtpl:36
+ qw422016.N().S(`
+ <a class="nav-link`)
+//line templates/navbar.qtpl:37
+ streaminsertIfEqual(qw422016, s, Login)
+//line templates/navbar.qtpl:37
+ qw422016.N().S(`" href="/login/">login</a>
+ `)
+//line templates/navbar.qtpl:38
+ }
+//line templates/navbar.qtpl:38
+ qw422016.N().S(`
+ `)
+//line templates/navbar.qtpl:39
+ }
+//line templates/navbar.qtpl:39
+ qw422016.N().S(`
`)
-//line navbar.qtpl:31
+//line templates/navbar.qtpl:43
qw422016.N().S(`
`)
-//line navbar.qtpl:35
+//line templates/navbar.qtpl:47
qw422016.N().S(`
- <a class="nav-link`)
-//line navbar.qtpl:36
- streaminsertIfEqual(qw422016, s, Config)
-//line navbar.qtpl:36
- qw422016.N().S(`" href="/config">config</a>
</div>
</nav>
`)
-//line navbar.qtpl:39
+//line templates/navbar.qtpl:50
}
-//line navbar.qtpl:39
-func WriteNavbar(qq422016 qtio422016.Writer, s Selection) {
-//line navbar.qtpl:39
+//line templates/navbar.qtpl:50
+func WriteNavbar(qq422016 qtio422016.Writer, ctx context.Context, s Selection) {
+//line templates/navbar.qtpl:50
qw422016 := qt422016.AcquireWriter(qq422016)
-//line navbar.qtpl:39
- StreamNavbar(qw422016, s)
-//line navbar.qtpl:39
+//line templates/navbar.qtpl:50
+ StreamNavbar(qw422016, ctx, s)
+//line templates/navbar.qtpl:50
qt422016.ReleaseWriter(qw422016)
-//line navbar.qtpl:39
+//line templates/navbar.qtpl:50
}
-//line navbar.qtpl:39
-func Navbar(s Selection) string {
-//line navbar.qtpl:39
+//line templates/navbar.qtpl:50
+func Navbar(ctx context.Context, s Selection) string {
+//line templates/navbar.qtpl:50
qb422016 := qt422016.AcquireByteBuffer()
-//line navbar.qtpl:39
- WriteNavbar(qb422016, s)
-//line navbar.qtpl:39
+//line templates/navbar.qtpl:50
+ WriteNavbar(qb422016, ctx, s)
+//line templates/navbar.qtpl:50
qs422016 := string(qb422016.B)
-//line navbar.qtpl:39
+//line templates/navbar.qtpl:50
qt422016.ReleaseByteBuffer(qb422016)
-//line navbar.qtpl:39
+//line templates/navbar.qtpl:50
return qs422016
-//line navbar.qtpl:39
+//line templates/navbar.qtpl:50
}
-//line navbar.qtpl:41
+//line templates/navbar.qtpl:52
func StreamGitItemNav(qw422016 *qt422016.Writer, name, ref string, s GitSelection) {
-//line navbar.qtpl:41
+//line templates/navbar.qtpl:52
qw422016.N().S(`
<div class="row">
<h3 id="name">`)
-//line navbar.qtpl:43
+//line templates/navbar.qtpl:54
qw422016.E().S(name)
-//line navbar.qtpl:43
+//line templates/navbar.qtpl:54
qw422016.N().S(` `)
-//line navbar.qtpl:43
- if ref != "" && (s == Log || s == Tree) {
-//line navbar.qtpl:43
+//line templates/navbar.qtpl:54
+ if ref != "" {
+//line templates/navbar.qtpl:54
qw422016.N().S(`@ `)
-//line navbar.qtpl:43
+//line templates/navbar.qtpl:54
qw422016.E().S(ref)
-//line navbar.qtpl:43
+//line templates/navbar.qtpl:54
}
-//line navbar.qtpl:43
+//line templates/navbar.qtpl:54
qw422016.N().S(`</h3>
</div>
<div class="row">
<ul class="nav">
<li class="nav-item">
<a class="nav-link`)
-//line navbar.qtpl:48
+//line templates/navbar.qtpl:59
streaminsertIfEqual(qw422016, s, Readme)
-//line navbar.qtpl:48
+//line templates/navbar.qtpl:59
qw422016.N().S(`" aria-current="page" href="/`)
-//line navbar.qtpl:48
+//line templates/navbar.qtpl:59
qw422016.E().S(name)
-//line navbar.qtpl:48
+//line templates/navbar.qtpl:59
qw422016.N().S(`/about/">about</a>
</li>
<li class="nav-item">
<a class="nav-link`)
-//line navbar.qtpl:51
+//line templates/navbar.qtpl:62
streaminsertIfEqual(qw422016, s, Summary)
-//line navbar.qtpl:51
+//line templates/navbar.qtpl:62
qw422016.N().S(`" aria-current="page" href="/`)
-//line navbar.qtpl:51
+//line templates/navbar.qtpl:62
qw422016.E().S(name)
-//line navbar.qtpl:51
+//line templates/navbar.qtpl:62
qw422016.N().S(`/">summary</a>
</li>
<li class="nav-item">
<a class="nav-link`)
-//line navbar.qtpl:54
+//line templates/navbar.qtpl:65
streaminsertIfEqual(qw422016, s, Refs)
-//line navbar.qtpl:54
+//line templates/navbar.qtpl:65
qw422016.N().S(`" aria-current="page" href="/`)
-//line navbar.qtpl:54
+//line templates/navbar.qtpl:65
qw422016.E().S(name)
-//line navbar.qtpl:54
- qw422016.N().S(`/refs">refs</a>
+//line templates/navbar.qtpl:65
+ qw422016.N().S(`/refs/">refs</a>
</li>
<li class="nav-item">
<a class="nav-link`)
-//line navbar.qtpl:57
+//line templates/navbar.qtpl:68
streaminsertIfEqual(qw422016, s, Log)
-//line navbar.qtpl:57
+//line templates/navbar.qtpl:68
qw422016.N().S(`" aria-current="page" href="/`)
-//line navbar.qtpl:57
+//line templates/navbar.qtpl:68
qw422016.E().S(name)
-//line navbar.qtpl:57
+//line templates/navbar.qtpl:68
qw422016.N().S(`/log/`)
-//line navbar.qtpl:57
+//line templates/navbar.qtpl:68
qw422016.E().S(ref)
-//line navbar.qtpl:57
+//line templates/navbar.qtpl:68
qw422016.N().S(`/">log</a>
</li>
<li class="nav-item">
<a class="nav-link`)
-//line navbar.qtpl:60
+//line templates/navbar.qtpl:71
streaminsertIfEqual(qw422016, s, Tree)
-//line navbar.qtpl:60
+//line templates/navbar.qtpl:71
qw422016.N().S(`" aria-current="page" href="/`)
-//line navbar.qtpl:60
+//line templates/navbar.qtpl:71
qw422016.E().S(name)
-//line navbar.qtpl:60
+//line templates/navbar.qtpl:71
qw422016.N().S(`/tree/`)
-//line navbar.qtpl:60
+//line templates/navbar.qtpl:71
qw422016.E().S(ref)
-//line navbar.qtpl:60
+//line templates/navbar.qtpl:71
qw422016.N().S(`/">tree</a>
</li>
</ul>
</div>
`)
-//line navbar.qtpl:64
+//line templates/navbar.qtpl:75
}
-//line navbar.qtpl:64
+//line templates/navbar.qtpl:75
func WriteGitItemNav(qq422016 qtio422016.Writer, name, ref string, s GitSelection) {
-//line navbar.qtpl:64
+//line templates/navbar.qtpl:75
qw422016 := qt422016.AcquireWriter(qq422016)
-//line navbar.qtpl:64
+//line templates/navbar.qtpl:75
StreamGitItemNav(qw422016, name, ref, s)
-//line navbar.qtpl:64
+//line templates/navbar.qtpl:75
qt422016.ReleaseWriter(qw422016)
-//line navbar.qtpl:64
+//line templates/navbar.qtpl:75
}
-//line navbar.qtpl:64
+//line templates/navbar.qtpl:75
func GitItemNav(name, ref string, s GitSelection) string {
-//line navbar.qtpl:64
+//line templates/navbar.qtpl:75
qb422016 := qt422016.AcquireByteBuffer()
-//line navbar.qtpl:64
+//line templates/navbar.qtpl:75
WriteGitItemNav(qb422016, name, ref, s)
-//line navbar.qtpl:64
+//line templates/navbar.qtpl:75
qs422016 := string(qb422016.B)
-//line navbar.qtpl:64
+//line templates/navbar.qtpl:75
qt422016.ReleaseByteBuffer(qb422016)
-//line navbar.qtpl:64
+//line templates/navbar.qtpl:75
return qs422016
-//line navbar.qtpl:64
+//line templates/navbar.qtpl:75
}
diff --git a/templates/tags.qtpl b/templates/tags.qtpl
index 5cd617f..5b7c39b 100644
--- a/templates/tags.qtpl
+++ b/templates/tags.qtpl
@@ -7,7 +7,7 @@
<div class="event me-md-2">
<div class="row ">
<div class="col-4">
- <a title="{%s t.HashString() %}" href="/{%s name %}/commit/{%s t.HashString() %}">{%s t.ShortName() %}</a>
+ <a title="{%s t.HashString() %}" href="/{%s name %}/ref/{%s t.ShortName() %}">{%s t.ShortName() %}</a>
</div>
<div class="col-8">
<div class="float-end">
diff --git a/templates/tags.qtpl.go b/templates/tags.qtpl.go
index 7d8eca8..5aedd78 100644
--- a/templates/tags.qtpl.go
+++ b/templates/tags.qtpl.go
@@ -1,154 +1,154 @@
// Code generated by qtc from "tags.qtpl". DO NOT EDIT.
// See https://github.com/valyala/quicktemplate for details.
-//line tags.qtpl:1
+//line templates/tags.qtpl:1
package templates
-//line tags.qtpl:1
+//line templates/tags.qtpl:1
import "git.gabrielgio.me/cerrado/pkg/git"
-//line tags.qtpl:3
+//line templates/tags.qtpl:3
import (
qtio422016 "io"
qt422016 "github.com/valyala/quicktemplate"
)
-//line tags.qtpl:3
+//line templates/tags.qtpl:3
var (
_ = qtio422016.Copy
_ = qt422016.AcquireByteBuffer
)
-//line tags.qtpl:3
+//line templates/tags.qtpl:3
func StreamListTags(qw422016 *qt422016.Writer, name string, tags []*git.TagReference) {
-//line tags.qtpl:3
+//line templates/tags.qtpl:3
qw422016.N().S(`
`)
-//line tags.qtpl:4
+//line templates/tags.qtpl:4
if len(tags) > 0 {
-//line tags.qtpl:4
+//line templates/tags.qtpl:4
qw422016.N().S(`
<div class="event-list">
`)
-//line tags.qtpl:6
+//line templates/tags.qtpl:6
for _, t := range tags {
-//line tags.qtpl:6
+//line templates/tags.qtpl:6
qw422016.N().S(`
<div class="event me-md-2">
<div class="row ">
<div class="col-4">
<a title="`)
-//line tags.qtpl:10
+//line templates/tags.qtpl:10
qw422016.E().S(t.HashString())
-//line tags.qtpl:10
+//line templates/tags.qtpl:10
qw422016.N().S(`" href="/`)
-//line tags.qtpl:10
+//line templates/tags.qtpl:10
qw422016.E().S(name)
-//line tags.qtpl:10
- qw422016.N().S(`/commit/`)
-//line tags.qtpl:10
- qw422016.E().S(t.HashString())
-//line tags.qtpl:10
+//line templates/tags.qtpl:10
+ qw422016.N().S(`/ref/`)
+//line templates/tags.qtpl:10
+ qw422016.E().S(t.ShortName())
+//line templates/tags.qtpl:10
qw422016.N().S(`">`)
-//line tags.qtpl:10
+//line templates/tags.qtpl:10
qw422016.E().S(t.ShortName())
-//line tags.qtpl:10
+//line templates/tags.qtpl:10
qw422016.N().S(`</a>
</div>
<div class="col-8">
<div class="float-end">
<a href="/`)
-//line tags.qtpl:14
+//line templates/tags.qtpl:14
qw422016.E().S(name)
-//line tags.qtpl:14
+//line templates/tags.qtpl:14
qw422016.N().S(`/archive/`)
-//line tags.qtpl:14
+//line templates/tags.qtpl:14
qw422016.E().S(t.ShortName())
-//line tags.qtpl:14
+//line templates/tags.qtpl:14
qw422016.N().S(`.tar.gz">tar.gz</a>
<a href="/`)
-//line tags.qtpl:15
+//line templates/tags.qtpl:15
qw422016.E().S(name)
-//line tags.qtpl:15
+//line templates/tags.qtpl:15
qw422016.N().S(`/tree/`)
-//line tags.qtpl:15
+//line templates/tags.qtpl:15
qw422016.E().S(t.ShortName())
-//line tags.qtpl:15
+//line templates/tags.qtpl:15
qw422016.N().S(`/">tree</a>
<a href="/`)
-//line tags.qtpl:16
+//line templates/tags.qtpl:16
qw422016.E().S(name)
-//line tags.qtpl:16
+//line templates/tags.qtpl:16
qw422016.N().S(`/log/`)
-//line tags.qtpl:16
+//line templates/tags.qtpl:16
qw422016.E().S(t.ShortName())
-//line tags.qtpl:16
+//line templates/tags.qtpl:16
qw422016.N().S(`/">log</a>
</div>
</div>
</div>
`)
-//line tags.qtpl:20
+//line templates/tags.qtpl:20
if t.Message() != "" {
-//line tags.qtpl:20
+//line templates/tags.qtpl:20
qw422016.N().S(`
<div class="code-view">
<pre>`)
-//line tags.qtpl:22
+//line templates/tags.qtpl:22
qw422016.E().S(t.Message())
-//line tags.qtpl:22
+//line templates/tags.qtpl:22
qw422016.N().S(`</pre>
</div>
`)
-//line tags.qtpl:24
+//line templates/tags.qtpl:24
}
-//line tags.qtpl:24
+//line templates/tags.qtpl:24
qw422016.N().S(`
</div>
`)
-//line tags.qtpl:26
+//line templates/tags.qtpl:26
}
-//line tags.qtpl:26
+//line templates/tags.qtpl:26
qw422016.N().S(`
</div>
`)
-//line tags.qtpl:28
+//line templates/tags.qtpl:28
} else {
-//line tags.qtpl:28
+//line templates/tags.qtpl:28
qw422016.N().S(`
<p> No tags </p>
`)
-//line tags.qtpl:30
+//line templates/tags.qtpl:30
}
-//line tags.qtpl:30
+//line templates/tags.qtpl:30
qw422016.N().S(`
`)
-//line tags.qtpl:31
+//line templates/tags.qtpl:31
}
-//line tags.qtpl:31
+//line templates/tags.qtpl:31
func WriteListTags(qq422016 qtio422016.Writer, name string, tags []*git.TagReference) {
-//line tags.qtpl:31
+//line templates/tags.qtpl:31
qw422016 := qt422016.AcquireWriter(qq422016)
-//line tags.qtpl:31
+//line templates/tags.qtpl:31
StreamListTags(qw422016, name, tags)
-//line tags.qtpl:31
+//line templates/tags.qtpl:31
qt422016.ReleaseWriter(qw422016)
-//line tags.qtpl:31
+//line templates/tags.qtpl:31
}
-//line tags.qtpl:31
+//line templates/tags.qtpl:31
func ListTags(name string, tags []*git.TagReference) string {
-//line tags.qtpl:31
+//line templates/tags.qtpl:31
qb422016 := qt422016.AcquireByteBuffer()
-//line tags.qtpl:31
+//line templates/tags.qtpl:31
WriteListTags(qb422016, name, tags)
-//line tags.qtpl:31
+//line templates/tags.qtpl:31
qs422016 := string(qb422016.B)
-//line tags.qtpl:31
+//line templates/tags.qtpl:31
qt422016.ReleaseByteBuffer(qb422016)
-//line tags.qtpl:31
+//line templates/tags.qtpl:31
return qs422016
-//line tags.qtpl:31
+//line templates/tags.qtpl:31
}