package build import ( "fmt" "go/parser" "go/token" "os" "path/filepath" "strconv" "strings" ) var modelsSiblingLeaves = []string{ "classes", "controllers", "console", "jobs", "middleware", "updates", } func checkModelsLeaf(appDir string, m Manifest) error { for _, p := range m.Plugins { pluginDir := localModuleDir(appDir, p.Module) if pluginDir == "" { pluginDir = filepath.Join(appDir, "plugins", pluginName(p.ID)) } if !underRoot(appDir, pluginDir) { continue } modelsDir := filepath.Join(pluginDir, "models") st, err := os.Stat(modelsDir) if err != nil || !st.IsDir() { continue } module, err := readModulePath(filepath.Join(pluginDir, "go.mod")) if err != nil { return err } if err := inspectModelsImports(p.ID, pluginDir, module, modelsDir); err != nil { return err } } return nil } func inspectModelsImports(pluginID, pluginDir, module, modelsDir string) error { entries, err := os.ReadDir(modelsDir) if err != nil { return fmt.Errorf("build: read %s: %w", modelsDir, err) } fset := token.NewFileSet() for _, entry := range entries { name := entry.Name() if entry.IsDir() || !strings.HasSuffix(name, ".go") { continue } path := filepath.Join(modelsDir, name) file, err := parser.ParseFile(fset, path, nil, parser.ImportsOnly) if err != nil { return fmt.Errorf("build: parse %s: %w", path, err) } rel, err := filepath.Rel(pluginDir, path) if err != nil { rel = filepath.Join("models", name) } for _, spec := range file.Imports { imp, err := strconv.Unquote(spec.Path.Value) if err != nil { continue } for _, sib := range modelsSiblingLeaves { prefix := module + "/" + sib if imp == prefix || strings.HasPrefix(imp, prefix+"/") { return fmt.Errorf("build: plugin %s: %s imports %s", pluginID, filepath.ToSlash(rel), imp) } } } } return nil }