diff options
-rw-r--r-- | tools/govanity/.drone.yml | 18 | ||||
-rw-r--r-- | tools/govanity/.envrc | 1 | ||||
-rw-r--r-- | tools/govanity/.gitignore | 1 | ||||
-rw-r--r-- | tools/govanity/Dockerfile | 30 | ||||
-rw-r--r-- | tools/govanity/README.org | 15 | ||||
-rw-r--r-- | tools/govanity/flake.lock | 90 | ||||
-rw-r--r-- | tools/govanity/flake.nix | 37 | ||||
-rw-r--r-- | tools/govanity/fly.toml | 34 | ||||
-rw-r--r-- | tools/govanity/go.mod | 5 | ||||
-rw-r--r-- | tools/govanity/go.sum | 3 | ||||
-rw-r--r-- | tools/govanity/main.go | 121 | ||||
-rwxr-xr-x | tools/govanity/scripts/deploy.sh | 14 | ||||
-rw-r--r-- | tools/govanity/templates/index.html.tpl | 14 | ||||
-rw-r--r-- | tools/govanity/templates/module.html.tpl | 12 | ||||
-rw-r--r-- | tools/govanity/vanity.yaml | 9 |
15 files changed, 404 insertions, 0 deletions
diff --git a/tools/govanity/.drone.yml b/tools/govanity/.drone.yml new file mode 100644 index 0000000..ee50017 --- /dev/null +++ b/tools/govanity/.drone.yml @@ -0,0 +1,18 @@ +--- +kind: pipeline +type: exec +name: default + +trigger: + event: + - push + branch: + - main + +steps: + - name: deploy + environment: + FLY_API_TOKEN: + from_secret: FLY_API_TOKEN + commands: + - nix run .#deploy diff --git a/tools/govanity/.envrc b/tools/govanity/.envrc new file mode 100644 index 0000000..3550a30 --- /dev/null +++ b/tools/govanity/.envrc @@ -0,0 +1 @@ +use flake diff --git a/tools/govanity/.gitignore b/tools/govanity/.gitignore new file mode 100644 index 0000000..c4a847d --- /dev/null +++ b/tools/govanity/.gitignore @@ -0,0 +1 @@ +/result diff --git a/tools/govanity/Dockerfile b/tools/govanity/Dockerfile new file mode 100644 index 0000000..20df29f --- /dev/null +++ b/tools/govanity/Dockerfile @@ -0,0 +1,30 @@ +FROM golang:1.16 AS builder + +ENV USER=app +RUN adduser \ + --disabled-password \ + --gecos "" \ + --home "/src" \ + --shell "/sbin/nologin" \ + --uid "10001" \ + "${USER}" + +WORKDIR /src + +ADD go.mod /src +ADD go.sum /src +RUN go mod download + +ADD . /src + +RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -a -installsuffix cgo -ldflags '-extldflags "-static"' -o app . + +FROM scratch +COPY --from=builder /src/app /vanity +COPY --from=builder /src/vanity.yaml /vanity.yaml +COPY --from=builder /etc/passwd /etc/passwd +COPY --from=builder /etc/group /etc/group + +USER app:app + +ENTRYPOINT ["/vanity"] diff --git a/tools/govanity/README.org b/tools/govanity/README.org new file mode 100644 index 0000000..7955ead --- /dev/null +++ b/tools/govanity/README.org @@ -0,0 +1,15 @@ +A service to manage vanity URLs for go packages. + +It makes it possible to install tools like this: +#+begin_src sh +GOPRIVATE=1 go install -v golang.fcuny.net/tools/cmd/music-organizer@latest +#+end_src + +* Build +Running =nix build= in the repository will create the binary. +* Run +Running =nix run= in the repository will start the server. +* Deployment +To update the application with the most recent code, run =make deploy=. +* Configuration +Add repositories to the [[file+sys:vanity.yaml][configuration file]]. diff --git a/tools/govanity/flake.lock b/tools/govanity/flake.lock new file mode 100644 index 0000000..a334e5c --- /dev/null +++ b/tools/govanity/flake.lock @@ -0,0 +1,90 @@ +{ + "nodes": { + "flake-utils": { + "locked": { + "lastModified": 1644229661, + "narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "3cecb5b042f7f209c56ffd8371b2711a290ec797", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1652298859, + "narHash": "sha256-hcwRboK+NxMWUJh0fQ3VsocDcAHrYJ95FmPEHlddV0Y=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "051448e41537c3463ae776d46115d01afb6c498d", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "release-21.11", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1645655918, + "narHash": "sha256-ZfbEFRW7o237+A1P7eTKhXje435FCAoe0blj2n20Was=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "77a7a4197740213879b9a1d2e1788c6c8ade4274", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, + "pre-commit-hooks": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1649054408, + "narHash": "sha256-wz8AH7orqUE4Xog29WMTqOYBs0DMj2wFM8ulrTRVgz0=", + "path": "/nix/store/2bw70fnmml6w0vjkcj2n7jvzcxpgprrm-source", + "rev": "e5e7b3b542e7f4f96967966a943d7e1c07558042", + "type": "path" + }, + "original": { + "id": "pre-commit-hooks", + "type": "indirect" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "pre-commit-hooks": "pre-commit-hooks", + "utils": "utils" + } + }, + "utils": { + "locked": { + "lastModified": 1649676176, + "narHash": "sha256-OWKJratjt2RW151VUlJPRALb7OU2S5s+f0vLj4o1bHM=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "a4b154ebbdc88c8498a5c7b01589addc9e9cb678", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/tools/govanity/flake.nix b/tools/govanity/flake.nix new file mode 100644 index 0000000..d2c2254 --- /dev/null +++ b/tools/govanity/flake.nix @@ -0,0 +1,37 @@ +{ + description = "govanity"; + + inputs = { + nixpkgs.url = "github:nixos/nixpkgs/release-21.11"; + utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, utils, nixpkgs, pre-commit-hooks }: + utils.lib.eachDefaultSystem (system: + let pkgs = nixpkgs.legacyPackages.${system}; + in { + + defaultPackage = self.packages.${system}.vanity; + + packages.vanity = pkgs.buildGoModule { + pname = "vanity"; + version = "0.0.1"; + src = ./.; + vendorSha256 = "sha256-iu2QE+vvenFWpOOz1NHVQHudiWkvkKqZvD4ZX4Xa1sY="; + nativeBuildInputs = with pkgs; [ go ]; + }; + + apps = { + deploy = pkgs.pkgs.writeShellScriptBin "run-deploy" '' + set -euxo pipefail + export PATH=${ + pkgs.lib.makeBinPath [ pkgs.go pkgs.git pkgs.jq pkgs.flyctl ] + }:$PATH + bash ./scripts/deploy.sh + ''; + }; + + devShell = with pkgs; + mkShell { nativeBuildInputs = [ git go gopls golangci-lint bash ]; }; + }); +} diff --git a/tools/govanity/fly.toml b/tools/govanity/fly.toml new file mode 100644 index 0000000..286cd1e --- /dev/null +++ b/tools/govanity/fly.toml @@ -0,0 +1,34 @@ +app = "golang-fcuny-net" + +kill_signal = "SIGINT" +kill_timeout = 5 + +[env] + +[experimental] + allowed_public_ports = [] + auto_rollback = true + +[[services]] + internal_port = 8080 + protocol = "tcp" + script_checks = [] + + [services.concurrency] + hard_limit = 25 + soft_limit = 20 + type = "connections" + + [[services.ports]] + handlers = ["http"] + port = 80 + + [[services.ports]] + handlers = ["tls", "http"] + port = 443 + + [[services.tcp_checks]] + grace_period = "1s" + interval = "15s" + restart_limit = 6 + timeout = "2s" diff --git a/tools/govanity/go.mod b/tools/govanity/go.mod new file mode 100644 index 0000000..d37f146 --- /dev/null +++ b/tools/govanity/go.mod @@ -0,0 +1,5 @@ +module golang.fcuny.net/vanity + +go 1.16 + +require gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b diff --git a/tools/govanity/go.sum b/tools/govanity/go.sum new file mode 100644 index 0000000..97f8991 --- /dev/null +++ b/tools/govanity/go.sum @@ -0,0 +1,3 @@ +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tools/govanity/main.go b/tools/govanity/main.go new file mode 100644 index 0000000..dd6d653 --- /dev/null +++ b/tools/govanity/main.go @@ -0,0 +1,121 @@ +package main + +import ( + "bytes" + "embed" + "flag" + "html/template" + "io/ioutil" + "log" + "net/http" + "strings" + + "gopkg.in/yaml.v3" +) + +//go:embed templates +var tpls embed.FS + +type repository struct { + Name string `yaml:"name"` + Repo string `yaml:"repo"` +} + +type config struct { + BaseUrl string `yaml:"baseUrl"` + VCS string `yaml:"vcs"` + Repositories []repository `yaml:"repositories"` +} + +type moduleTmpl struct { + Name string + Repo string + VCS string + BaseUrl string +} + +func main() { + flag.Parse() + buf, err := ioutil.ReadFile("vanity.yaml") + if err != nil { + log.Fatalf("failed to read the configuration: %+v", err) + } + + cfg := &config{} + err = yaml.Unmarshal(buf, cfg) + if err != nil { + log.Fatalf("failed to parse the YAML configuration: %+v", err) + } + + http.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(200) + w.Write([]byte("ok")) + }) + + http.HandleFunc("/", goGet(cfg)) + + log.Printf("starting web server on :8080") + log.Fatal(http.ListenAndServe(":8080", nil)) +} + +func goGet(cfg *config) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if r.Method != http.MethodGet { + status := http.StatusMethodNotAllowed + http.Error(w, http.StatusText(status), status) + return + } + + if r.FormValue("go-get") == "1" { + pathParts := strings.Split(r.URL.Path, "/") + for _, m := range cfg.Repositories { + if pathParts[1] == m.Name { + goGetModule(w, r, m, cfg) + return + } + } + status := http.StatusNotFound + http.Error(w, http.StatusText(status), status) + return + } + browserURL(w, r, cfg) + } +} + +func goGetModule(w http.ResponseWriter, r *http.Request, m repository, cfg *config) { + tmpl, err := template.ParseFS(tpls, "templates/module.html.tpl") + if err != nil { + log.Fatal(err) + } + mod := moduleTmpl{ + VCS: cfg.VCS, + BaseUrl: cfg.BaseUrl, + Name: m.Name, + Repo: m.Repo, + } + var buf bytes.Buffer + if err := tmpl.Execute(&buf, mod); err != nil { + log.Printf("error: %+v", err) + status := http.StatusInternalServerError + http.Error(w, http.StatusText(status), status) + } else { + w.Header().Set("Cache-Control", "no-store") + w.Write(buf.Bytes()) + } +} + +func browserURL(w http.ResponseWriter, r *http.Request, cfg *config) { + tmpl, err := template.ParseFS(tpls, "templates/index.html.tpl") + if err != nil { + log.Fatal(err) + } + var buf bytes.Buffer + if err := tmpl.Execute(&buf, cfg); err != nil { + log.Printf("error: %+v", err) + status := http.StatusInternalServerError + http.Error(w, http.StatusText(status), status) + } else { + w.Header().Set("Cache-Control", "no-store") + w.Write(buf.Bytes()) + } +} diff --git a/tools/govanity/scripts/deploy.sh b/tools/govanity/scripts/deploy.sh new file mode 100755 index 0000000..4f46b68 --- /dev/null +++ b/tools/govanity/scripts/deploy.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +git diff --exit-code +git diff --staged --exit-code + +flyctl deploy + +VERSION=$(flyctl info -j |jq -r '.App | "\(.Name)/v\(.Version)"') + +git tag -a --message ${VERSION} ${VERSION} +git push origin --all +git push origin --tags + +flyctl agent stop diff --git a/tools/govanity/templates/index.html.tpl b/tools/govanity/templates/index.html.tpl new file mode 100644 index 0000000..fd8fc56 --- /dev/null +++ b/tools/govanity/templates/index.html.tpl @@ -0,0 +1,14 @@ +<!DOCTYPE html> +<html> + <head> + <title>golang repo</title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> + </head> + <body> + <ul> + {{ range $idx, $m := .Repositories }} + <li>go get <a href="{{ $m.Repo }}">{{ $.BaseUrl }}/{{ $m.Name }}/</a></li> + {{end}} + </ul> + </body> +</html> diff --git a/tools/govanity/templates/module.html.tpl b/tools/govanity/templates/module.html.tpl new file mode 100644 index 0000000..fab3414 --- /dev/null +++ b/tools/govanity/templates/module.html.tpl @@ -0,0 +1,12 @@ +<!DOCTYPE html> +<html> + <head> + <title>{{.Name}}: golang repo</title> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> + <meta name="go-import" content="{{.BaseUrl}}/{{.Name}} {{.VCS}} {{.Repo}}"> + <meta name="go-source" content="{{.BaseUrl}}/{{.Name}} _ {{.Repo}}/src{/dir} {{.Repo}}/src{/dir}/{file}/#L{line}"> + </head> + <body> + go get {{.BaseUrl}}/{{.Name}} + </body> +</html> diff --git a/tools/govanity/vanity.yaml b/tools/govanity/vanity.yaml new file mode 100644 index 0000000..cfe5b03 --- /dev/null +++ b/tools/govanity/vanity.yaml @@ -0,0 +1,9 @@ +baseUrl: golang.fcuny.net +vcs: git +repositories: + - name: vanity + repo: https://git.fcuny.net/fcuny/govanity + - name: tools + repo: https://git.fcuny.net/fcuny/tools + - name: mpd-stats + repo: https://git.fcuny.net/fcuny/mpd-stats |