diff options
64 files changed, 3871 insertions, 1784 deletions
@@ -1,2 +1,5 @@ -bin/ +# css output static/*.css + +# bin output +cerrado @@ -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 @@ -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 @@ -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 ) @@ -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= @@ -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 } |