Files
summercms/internal/build/registry.go
Jakub Zych 1edf9d7e4c feat(04-01): scaffold Winter-shaped plugins with generated registry
Render plugin.go, routes.go, leaf packages and go.mod from embedded
templates, emit empty registry accessors, and define job, admin, lang
and mail capability contracts so a new plugin compiles before artifacts.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-18 13:34:32 +02:00

96 lines
2.2 KiB
Go

package build
import (
"bytes"
"fmt"
"os"
"path/filepath"
"sort"
)
const registryFileName = "registry.gen.go"
type registryRef struct {
Package string
Ident string
}
type registryData struct {
Package string
Module string
Imports []string
Models []registryRef
Migrations []registryRef
Commands []registryRef
Jobs []registryRef
AdminControllers []registryRef
}
func emptyRegistry(pkg, module string) registryData {
data := registryData{Package: pkg, Module: module}
data.prepare()
return data
}
func (d *registryData) prepare() {
d.Imports = uniqueLeafImports(d.Module, d.Models, d.Migrations, d.Commands, d.Jobs, d.AdminControllers)
}
func uniqueLeafImports(module string, groups ...[]registryRef) []string {
if module == "" {
return nil
}
seen := make(map[string]struct{})
var imports []string
for _, group := range groups {
for _, ref := range group {
if ref.Package == "" {
continue
}
path := module + "/" + ref.Package
if _, ok := seen[path]; ok {
continue
}
seen[path] = struct{}{}
imports = append(imports, path)
}
}
sort.Strings(imports)
return imports
}
func writeRegistry(pluginDir string, data registryData) error {
data.prepare()
src, err := renderStub("registry.go", data)
if err != nil {
return err
}
path := filepath.Join(pluginDir, registryFileName)
existing, err := os.ReadFile(path)
if err == nil && bytes.Equal(existing, src) {
return nil
}
if err != nil && !os.IsNotExist(err) {
return fmt.Errorf("build: read %s: %w", path, err)
}
tmp, err := os.CreateTemp(pluginDir, registryFileName+".*")
if err != nil {
return fmt.Errorf("build: create %s temp: %w", registryFileName, err)
}
tmpName := tmp.Name()
if _, err := tmp.Write(src); err != nil {
tmp.Close()
os.Remove(tmpName)
return fmt.Errorf("build: write %s temp: %w", registryFileName, err)
}
if err := tmp.Close(); err != nil {
os.Remove(tmpName)
return fmt.Errorf("build: close %s temp: %w", registryFileName, err)
}
if err := os.Rename(tmpName, path); err != nil {
os.Remove(tmpName)
return fmt.Errorf("build: rename %s: %w", registryFileName, err)
}
return nil
}