about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFranck Cuny <franck@fcuny.net>2021-08-12 13:10:25 -0700
committerFranck Cuny <franck@fcuny.net>2021-08-12 15:09:48 -0700
commit02734a5b4ffc555a47c5029422ae4015b59c138f (patch)
tree0e1a358114bfd9b0e4a0d36a0d0e363d6485e924
parentbuild: convert to go module (diff)
downloadworld-02734a5b4ffc555a47c5029422ae4015b59c138f.tar.gz
vanity: rewrite with templates and external config
Rewrite the program to use external templates and load the configuration
from an external source.

We don't want to blindly send all the requests to some SCM since we want
to support only some modules / program that way.

There's two templates, one for requests coming from a browser, which
list all the supported modules, and one for the `go get` command.

For requests coming from `go get`, we generate a template that indicates
where the repository is.

The external configuration is in YAML, and list all the supported
repositories, and the URL of the repository. It assumes a default VCS
for all the modules (git in our case).
-rw-r--r--tools/govanity/go.mod2
-rw-r--r--tools/govanity/go.sum3
-rw-r--r--tools/govanity/main.go130
-rw-r--r--tools/govanity/templates/index.html.tpl14
-rw-r--r--tools/govanity/templates/module.html.tpl12
-rw-r--r--tools/govanity/vanity.yaml5
6 files changed, 144 insertions, 22 deletions
diff --git a/tools/govanity/go.mod b/tools/govanity/go.mod
index 9d1ea60..d37f146 100644
--- a/tools/govanity/go.mod
+++ b/tools/govanity/go.mod
@@ -1,3 +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
index 4afe8d1..dd6d653 100644
--- a/tools/govanity/main.go
+++ b/tools/govanity/main.go
@@ -1,35 +1,121 @@
-package repo
+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
+	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))
 }
 
-var vanityTemplate = template.Must(template.New("code").Parse(`
-<!DOCTYPE html>
-<html>
-    <head>
-        <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
-        <meta name="go-import" content="src.fcuny.me{{.Name}} git https://github.com/fcuny/{{.Name}}">
-        <meta http-equiv="refresh" content="0; url=http://fcuny.me">
-    </head>
-    <body>
-    </body>
-</html>
-`))
-
-func init() {
-	http.HandleFunc("/", handleTransactions)
+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 handleTransactions(w http.ResponseWriter, r *http.Request) {
-	repoName := r.URL.Path
-	p := &repository{Name: repoName}
-	if err := vanityTemplate.Execute(w, p); err != nil {
-		http.Error(w, err.Error(), http.StatusInternalServerError)
+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/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..a757729
--- /dev/null
+++ b/tools/govanity/vanity.yaml
@@ -0,0 +1,5 @@
+baseUrl: golang.fcuny.net
+vcs: git
+repositories:
+  - name: homelab
+    repo: https://git.fcuny.net/fcuny/homelab