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>
96 lines
2.2 KiB
Go
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
|
|
}
|