- icons/gen writes to the current directory so `go generate ./internal/master/web/icons` works (output verified byte-identical) - share the registry-host check as imageref.IsRegistryHost (with test) - agents fragment refreshes the "N machines" header count out of band - ignore the saved machine filter at <=760px where the machine list is hidden - aria-current on the active machine filter link, aria-pressed on theme toggle - CLAUDE.md: icons package, SSE ping event, swarm_cluster_id Claude-Session: https://claude.ai/code/session_01GAZsp3P7Qto6JnhipxWUJQ
129 lines
3.2 KiB
Go
129 lines
3.2 KiB
Go
// Command gen builds simple-icons.json.gz, the icon data the icons package
|
|
// embeds. It downloads the pinned simple-icons npm tarball, checks its
|
|
// sha256 and writes a gzipped JSON object {slug: svg path data}. The output
|
|
// is deterministic. It writes into the current directory; run it with
|
|
//
|
|
// go generate ./internal/master/web/icons
|
|
package main
|
|
|
|
import (
|
|
"archive/tar"
|
|
"bytes"
|
|
"compress/gzip"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"os"
|
|
"path"
|
|
"regexp"
|
|
"strings"
|
|
)
|
|
|
|
const (
|
|
tarballURL = "https://registry.npmjs.org/simple-icons/-/simple-icons-16.35.0.tgz"
|
|
tarballSHA256 = "20ebead4f6bc93464812a5e260d19fc4d84772e5eeff69a6fbea263ca2441c5f"
|
|
)
|
|
|
|
var pathData = regexp.MustCompile(`<path d="([^"]+)"`)
|
|
|
|
func main() {
|
|
if err := run(); err != nil {
|
|
fmt.Fprintln(os.Stderr, "gen:", err)
|
|
os.Exit(1)
|
|
}
|
|
}
|
|
|
|
func run() error {
|
|
tgz, err := download(tarballURL)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if sum := sha256.Sum256(tgz); hex.EncodeToString(sum[:]) != tarballSHA256 {
|
|
return fmt.Errorf("sha256 mismatch for %s: got %x, want %s", tarballURL, sum, tarballSHA256)
|
|
}
|
|
icons, license, err := extract(tgz)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var js bytes.Buffer
|
|
enc := json.NewEncoder(&js)
|
|
enc.SetEscapeHTML(false)
|
|
if err := enc.Encode(icons); err != nil { // map keys are written sorted
|
|
return err
|
|
}
|
|
var gz bytes.Buffer
|
|
zw, err := gzip.NewWriterLevel(&gz, gzip.BestCompression)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if _, err := zw.Write(js.Bytes()); err != nil { // the header has no name and a zero mtime
|
|
return err
|
|
}
|
|
if err := zw.Close(); err != nil {
|
|
return err
|
|
}
|
|
if err := os.WriteFile("simple-icons.json.gz", gz.Bytes(), 0o644); err != nil {
|
|
return err
|
|
}
|
|
if err := os.WriteFile("LICENSE-simple-icons.md", license, 0o644); err != nil {
|
|
return err
|
|
}
|
|
fmt.Printf("wrote %d icons\n", len(icons))
|
|
return nil
|
|
}
|
|
|
|
func download(url string) ([]byte, error) {
|
|
resp, err := http.Get(url)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, fmt.Errorf("GET %s: %s", url, resp.Status)
|
|
}
|
|
return io.ReadAll(resp.Body)
|
|
}
|
|
|
|
// extract returns the path data of every package/icons/*.svg by slug, and
|
|
// package/LICENSE.md.
|
|
func extract(tgz []byte) (icons map[string]string, license []byte, err error) {
|
|
zr, err := gzip.NewReader(bytes.NewReader(tgz))
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
tr := tar.NewReader(zr)
|
|
icons = map[string]string{}
|
|
for {
|
|
h, err := tr.Next()
|
|
if err == io.EOF {
|
|
break
|
|
}
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
switch {
|
|
case h.Name == "package/LICENSE.md":
|
|
if license, err = io.ReadAll(tr); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
case path.Dir(h.Name) == "package/icons" && strings.HasSuffix(h.Name, ".svg"):
|
|
svg, err := io.ReadAll(tr)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
m := pathData.FindAllSubmatch(svg, -1)
|
|
if len(m) != 1 {
|
|
return nil, nil, fmt.Errorf("%s: want exactly one <path>, found %d", h.Name, len(m))
|
|
}
|
|
icons[strings.TrimSuffix(path.Base(h.Name), ".svg")] = string(m[0][1])
|
|
}
|
|
}
|
|
if license == nil || len(icons) == 0 {
|
|
return nil, nil, fmt.Errorf("tarball has no LICENSE.md or no icons")
|
|
}
|
|
return icons, license, nil
|
|
}
|