mirror of https://github.com/coder/coder.git
151 lines
3.5 KiB
Go
151 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"fmt"
|
|
"go/parser"
|
|
"go/token"
|
|
"io/fs"
|
|
"os"
|
|
"path"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/gohugoio/hugo/parser/pageparser"
|
|
"golang.org/x/xerrors"
|
|
|
|
"github.com/coder/coder/v2/codersdk"
|
|
)
|
|
|
|
const (
|
|
examplesDir = "examples"
|
|
examplesSrc = "examples.go"
|
|
)
|
|
|
|
func main() {
|
|
if err := run(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func run() error {
|
|
fset := token.NewFileSet()
|
|
src, err := parser.ParseFile(fset, filepath.Join(examplesDir, examplesSrc), nil, parser.ParseComments)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
var paths []string
|
|
for _, comment := range src.Comments {
|
|
for _, line := range comment.List {
|
|
if s, ok := parseEmbedTag(line.Text); ok && !strings.HasSuffix(s, ".json") {
|
|
paths = append(paths, s)
|
|
}
|
|
}
|
|
}
|
|
|
|
var examples []codersdk.TemplateExample
|
|
files := os.DirFS(examplesDir)
|
|
for _, name := range paths {
|
|
dir, err := fs.Stat(files, name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if !dir.IsDir() {
|
|
continue
|
|
}
|
|
exampleID := dir.Name()
|
|
// Each one of these is a example!
|
|
readme, err := fs.ReadFile(files, path.Join(name, "README.md"))
|
|
if err != nil {
|
|
return xerrors.Errorf("example %q does not contain README.md", exampleID)
|
|
}
|
|
|
|
frontMatter, err := pageparser.ParseFrontMatterAndContent(bytes.NewReader(readme))
|
|
if err != nil {
|
|
return xerrors.Errorf("parse example %q front matter: %w", exampleID, err)
|
|
}
|
|
|
|
nameRaw, exists := frontMatter.FrontMatter["display_name"]
|
|
if !exists {
|
|
return xerrors.Errorf("example %q front matter does not contain name", exampleID)
|
|
}
|
|
|
|
name, valid := nameRaw.(string)
|
|
if !valid {
|
|
return xerrors.Errorf("example %q name isn't a string", exampleID)
|
|
}
|
|
|
|
descriptionRaw, exists := frontMatter.FrontMatter["description"]
|
|
if !exists {
|
|
return xerrors.Errorf("example %q front matter does not contain name", exampleID)
|
|
}
|
|
|
|
description, valid := descriptionRaw.(string)
|
|
if !valid {
|
|
return xerrors.Errorf("example %q description isn't a string", exampleID)
|
|
}
|
|
|
|
tags := []string{}
|
|
tagsRaw, exists := frontMatter.FrontMatter["tags"]
|
|
if exists {
|
|
tagsI, valid := tagsRaw.([]interface{})
|
|
if !valid {
|
|
return xerrors.Errorf("example %q tags isn't a slice: type %T", exampleID, tagsRaw)
|
|
}
|
|
for _, tagI := range tagsI {
|
|
tag, valid := tagI.(string)
|
|
if !valid {
|
|
return xerrors.Errorf("example %q tag isn't a string: type %T", exampleID, tagI)
|
|
}
|
|
tags = append(tags, tag)
|
|
}
|
|
}
|
|
|
|
var icon string
|
|
iconRaw, exists := frontMatter.FrontMatter["icon"]
|
|
if exists {
|
|
icon, valid = iconRaw.(string)
|
|
if !valid {
|
|
return xerrors.Errorf("example %q icon isn't a string", exampleID)
|
|
}
|
|
icon, err = filepath.Rel("../site/static/", filepath.Join(examplesDir, name, icon))
|
|
if err != nil {
|
|
return xerrors.Errorf("example %q icon is not in site/static: %w", exampleID, err)
|
|
}
|
|
// The FE needs a static path!
|
|
icon = "/" + icon
|
|
}
|
|
|
|
examples = append(examples, codersdk.TemplateExample{
|
|
ID: exampleID,
|
|
Name: name,
|
|
Description: description,
|
|
Icon: icon,
|
|
Tags: tags,
|
|
Markdown: string(frontMatter.Content),
|
|
|
|
// URL is set by examples/examples.go.
|
|
})
|
|
}
|
|
|
|
w := os.Stdout
|
|
|
|
_, err = fmt.Fprint(w, "// Code generated by examplegen. DO NOT EDIT.\n")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
enc := json.NewEncoder(os.Stdout)
|
|
enc.SetIndent("", " ")
|
|
return enc.Encode(examples)
|
|
}
|
|
|
|
func parseEmbedTag(s string) (string, bool) {
|
|
if !strings.HasPrefix(s, "//go:embed") {
|
|
return "", false
|
|
}
|
|
return strings.TrimSpace(strings.TrimPrefix(s, "//go:embed")), true
|
|
}
|