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 }