summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--default.nix29
-rw-r--r--go.mod7
-rw-r--r--go.sum24
-rwxr-xr-xjustfile8
-rw-r--r--main.go123
-rw-r--r--page.templ146
-rw-r--r--shell.nix2
-rwxr-xr-xvanity-imports.toml20
-rwxr-xr-xvanity.toml20
10 files changed, 341 insertions, 40 deletions
diff --git a/.gitignore b/.gitignore
index 178135c..2eaf905 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
 /dist/
+*_templ.*
+/result
diff --git a/default.nix b/default.nix
index 52b4962..b6b8243 100644
--- a/default.nix
+++ b/default.nix
@@ -1,28 +1,23 @@
-{ lib
-, buildGoModule
-, fetchFromGitHub
-}:
+{ pkgs ? import <nixpkgs> { } }:
+let
+  inherit (pkgs) buildGoModule lib;
+in
 
-buildGoModule rec {
-  pname = "vanity-imports";
-  version = "0.0.13-unstable";
+buildGoModule {
+  pname = "gopkgs";
+  version = "unstable";
 
-  src = fetchFromGitHub {
-    owner = "alanpearce";
-    repo = "vanity-imports";
-    rev = "95d03037139c6e847d14a35f12496a6fbf2d4370";
-    hash = "sha256-YxCPxJqu/e9BK7iTrn4f6ymbwAlU+RHCneO743DeH/w=";
-  };
+  src = lib.sourceFilesBySuffices ./. [ ".go" ".templ" ".mod" ".sum" ];
 
-  vendorHash = "sha256-w0LaXevbGm1xpHvKxxyubHCOVRN712UzLyOd+hVikKg=";
+  vendorHash = "sha256-ahjgTjV4xXt21DAcVqplVEeZJDszY8amYYb2WENHWq4=";
 
   ldflags = [ "-s" "-w" ];
 
   meta = with lib; {
-    description = "Use a custom domain in your Go import path";
-    homepage = "https://github.com/mlcdf/vanity-imports";
+    description = "Site generator for go vanity imports";
+    homepage = "https://git.alanpearce.eu/gopkgs";
     license = licenses.mit;
     maintainers = with maintainers; [ alanpearce ];
-    mainProgram = "vanity-imports";
+    mainProgram = "gopkgs";
   };
 }
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..2fd9745
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,7 @@
+module go.alanpearce.eu/gopkgs
+
+go 1.22.3
+
+require github.com/a-h/templ v0.2.731
+
+require github.com/pelletier/go-toml/v2 v2.2.2
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..268079f
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,24 @@
+github.com/a-h/templ v0.2.731 h1:yiv4C7whSUsa36y65O06DPr/U/j3+WGB0RmvLOoVFXc=
+github.com/a-h/templ v0.2.731/go.mod h1:IejA/ecDD0ul0dCvgCwp9t7bUZXVpGClEAdsqZQigi8=
+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/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
+github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
+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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
+github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
+github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
+github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/justfile b/justfile
index 4ec188a..9de046c 100755
--- a/justfile
+++ b/justfile
@@ -1,6 +1,10 @@
 #! /usr/bin/env cached-nix-shell
 #! nix-shell -i "just --justfile"
 
-cd:
-	vanity-imports --config vanity-imports.toml
+ci:
+	templ generate
+	nix-build
+	./result/bin/gopkgs
+
+cd: ci
 	rsync --recursive --delete --chmod=go+r dist/ /srv/http/go
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..ed23069
--- /dev/null
+++ b/main.go
@@ -0,0 +1,123 @@
+package main
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"net/url"
+	"os"
+	"path/filepath"
+
+	"github.com/a-h/templ"
+	"github.com/pelletier/go-toml/v2"
+)
+
+type Config struct {
+	Title    string
+	Domain   string
+	Forge    string
+	Menu     []*Link
+	Packages []*Package
+}
+
+type Link struct {
+	Name string
+	URL  string
+}
+
+type Package struct {
+	Name string
+	URL  string
+}
+
+func must[T any](t T, err error) T {
+	if err != nil {
+		panic(err)
+	}
+	return t
+}
+
+func fatal(err error) {
+	if err != nil {
+		log.Fatal(err)
+	}
+}
+
+func importString(config *Config, pkg Package) string {
+	return fmt.Sprintf("%s git %s",
+		must(url.JoinPath(config.Domain, pkg.Name)),
+		must(url.JoinPath(config.Forge, pkg.Name)),
+	)
+}
+
+func sourceString(config *Config, pkg Package) string {
+	return fmt.Sprintf("%s _ %s %s",
+		must(url.JoinPath(config.Domain, pkg.Name)),
+		must(url.JoinPath(config.Forge, pkg.Name, "tree/main{/dir}")),
+		must(url.JoinPath(config.Forge, pkg.Name, "tree/main{/dir}/{file}#n{line}")),
+	)
+}
+
+func godocURL(config *Config, pkg *Package) string {
+	return must(url.JoinPath("https://pkg.go.dev", packageImportPath(config, pkg)))
+}
+
+func packageImportPath(config *Config, pkg *Package) string {
+	return must(url.JoinPath(config.Domain, pkg.Name))
+}
+
+func packageForgeURL(config *Config, pkg *Package) string {
+	return must(url.JoinPath(config.Forge, pkg.Name))
+}
+
+func getConfig(filename string) (cfg *Config, err error) {
+	cfg = new(Config)
+	file, err := os.Open(filename)
+	if err != nil {
+		return nil, err
+	}
+	defer file.Close()
+	dec := toml.NewDecoder(file)
+	err = dec.Decode(cfg)
+	if err != nil {
+		return nil, err
+	}
+
+	return cfg, nil
+}
+
+const destDir = "dist"
+
+func renderToFile(c templ.Component, filename string) error {
+	pathname := filepath.Join(destDir, filename)
+	err := os.MkdirAll(filepath.Dir(pathname), 0755)
+	if err != nil {
+		return err
+	}
+	file, err := os.Create(pathname)
+	if err != nil {
+		return err
+	}
+	defer file.Close()
+
+	return c.Render(context.Background(), file)
+}
+
+func main() {
+	cfg, err := getConfig("vanity.toml")
+	fatal(err)
+
+	err = renderToFile(
+		ListPage(cfg),
+		"index.html",
+	)
+	fatal(err)
+
+	for _, pkg := range cfg.Packages {
+		err = renderToFile(
+			PackagePage(cfg, pkg),
+			filepath.Join(pkg.Name, "index.html"),
+		)
+		fatal(err)
+	}
+}
diff --git a/page.templ b/page.templ
new file mode 100644
index 0000000..d6c15ef
--- /dev/null
+++ b/page.templ
@@ -0,0 +1,146 @@
+package main
+
+templ Page(config *Config, pkg *Package) {
+	<!DOCTYPE html>
+	<html lang="en">
+		<head>
+			<meta charset="utf-8"/>
+			<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
+			if pkg != nil {
+				<meta name="go-import" content={ importString(config, *pkg) }/>
+				<meta name="go-source" content={ sourceString(config, *pkg) }/>
+			}
+			<style>
+      :root {
+        --width: 800px;
+        --font-main: Verdana, sans-serif;
+        --font-secondary: Verdana, sans-serif;
+        --font-scale: 1em;
+        --background-color: #fff;
+        --heading-color: #222;
+        --text-color: #444;
+        --link-color: #3273dc;
+        --visited-color: #8b6fcb;
+        --code-background-color: #f2f2f2;
+        --code-color: #222;
+        --blockquote-color: #222;
+        --icon-external-link: url("/external-link.svg");
+      }
+
+      @media (prefers-color-scheme: dark) {
+        :root {
+          --background-color: #01242e;
+          --heading-color: #eee;
+          --text-color: #ddd;
+          --link-color: #8cc2dd;
+          --visited-color: #8b6fcb;
+          --code-background-color: #000;
+          --code-color: #ddd;
+          --blockquote-color: #ccc;
+        }
+      }
+
+      body {
+        font-family: var(--font-secondary);
+        font-size: var(--font-scale);
+        margin: auto;
+        padding: 20px;
+        max-width: var(--width);
+        text-align: left;
+        background-color: var(--background-color);
+        word-wrap: break-word;
+        overflow-wrap: break-word;
+        line-height: 1.5;
+        color: var(--text-color);
+      }
+
+      h1,
+      h2,
+      h3,
+      h4,
+      h5,
+      h6 {
+        font-family: var(--font-main);
+        color: var(--heading-color);
+        & > a {
+          color: var(--heading-color);
+        }
+      }
+
+      a {
+        color: var(--link-color);
+        cursor: pointer;
+      }
+
+      nav a {
+        margin-right: 8px;
+      }
+
+      strong,
+      b {
+        color: var(--heading-color);
+      }
+
+      main {
+        margin-top: 2ex;
+        line-height: 1.6;
+      }
+
+      table {
+        width: 100%;
+      }
+      </style>
+			<title>{ config.Title }</title>
+		</head>
+		<body>
+			<header>
+				<h1>{ config.Title }</h1>
+				<nav>
+					for _, link := range config.Menu {
+						<a href={ templ.SafeURL(link.URL) }>{ link.Name }</a>
+					}
+				</nav>
+			</header>
+			<main>
+				{ children... }
+			</main>
+		</body>
+	</html>
+}
+
+templ ListPage(config *Config) {
+	@Page(config, nil) {
+		<table>
+			<thead>
+				<tr>
+					<th>Name</th>
+					<th>Source</th>
+					<th>Documentation</th>
+				</tr>
+			</thead>
+			<tbody>
+				for _, pkg := range config.Packages {
+					<tr>
+						<td>{ packageImportPath(config, pkg) }</td>
+						<td><a href={ templ.SafeURL(packageForgeURL(config, pkg)) }>Source </a></td>
+						<td>
+							@GodocBadge(config, pkg)
+						</td>
+					</tr>
+				}
+			</tbody>
+		</table>
+	}
+}
+
+templ PackagePage(config *Config, pkg *Package) {
+	@Page(config, pkg) {
+		<p>You're probably looking for the <a href={ templ.SafeURL(godocURL(config, pkg)) }>documentation</a>.</p>
+	}
+}
+
+templ GodocBadge(config *Config, pkg *Package) {
+	<a href={ templ.SafeURL(godocURL(config, pkg)) }>
+		Go Reference
+	</a>
+}
diff --git a/shell.nix b/shell.nix
index f3c9676..868e8f5 100644
--- a/shell.nix
+++ b/shell.nix
@@ -3,6 +3,6 @@
 pkgs.mkShell {
   buildInputs = with pkgs; [
     rsync
-    (callPackage ./. { })
+    templ
   ];
 }
diff --git a/vanity-imports.toml b/vanity-imports.toml
deleted file mode 100755
index b0ecd5d..0000000
--- a/vanity-imports.toml
+++ /dev/null
@@ -1,20 +0,0 @@
-domain = "go.alanpearce.eu"
-
-[index]
-description = ""
-extra_head = ""
-title = "Alan's go packages"
-
-[repos]
-
-[repos."/website"]
-repo = "https://git.alanpearce.eu/website"
-vcs = "git"
-
-[repos."/searchix"]
-repo = "https://git.alanpearce.eu/searchix"
-vcs = "git"
-
-[repos."/x"]
-repo = "https://git.alanpearce.eu/x"
-vcs = "git"
diff --git a/vanity.toml b/vanity.toml
new file mode 100755
index 0000000..bfe1250
--- /dev/null
+++ b/vanity.toml
@@ -0,0 +1,20 @@
+title = "Alan's go packages"
+domain = "go.alanpearce.eu"
+forge = "https://git.alanpearce.eu"
+
+[[menu]]
+name = "Home"
+URL = "https://alanpearce.eu"
+
+[[menu]]
+name = "Repositories"
+URL = "https://git.alanpearce.eu"
+
+[[packages]]
+name = "website"
+
+[[packages]]
+name = "searchix"
+
+[[packages]]
+name = "x"