Files

209 lines
4.6 KiB
Go

package projects
import (
"errors"
"fmt"
"io"
"os"
"path/filepath"
"runtime"
"strings"
"aego/app/assembly"
"aego/app/assembly/builtin"
"aego/app/bootstrap"
"aego/asset/pipeline"
"aego/core/errs"
"aego/core/log"
"aego/engine"
"aego/engine/problems"
"aego/format/aetext"
"aego/project"
"aego/script/bind"
"aego/script/bind/manifest"
"aego/script/diag"
"aego/script/workspace"
)
func EngineRoot(flagValue string) (string, error) {
candidates := []string{flagValue, os.Getenv("AEGO_ROOT")}
if _, file, _, ok := runtime.Caller(0); ok {
candidates = append(candidates, filepath.Join(filepath.Dir(file), "..", ".."))
}
for _, c := range candidates {
if c == "" {
continue
}
abs, err := filepath.Abs(c)
if err != nil {
continue
}
if isEngineRoot(abs) {
return abs, nil
}
}
return "", errors.New("cannot locate the aego source tree; pass --engine <dir> or set AEGO_ROOT")
}
func isEngineRoot(dir string) bool {
data, err := os.ReadFile(filepath.Join(dir, "go.mod"))
if err != nil {
return false
}
for _, line := range strings.Split(string(data), "\n") {
if strings.TrimSpace(line) == "module aego" {
return true
}
}
return false
}
func LoadManifest(p *project.Project, path string) (*manifest.Manifest, error) {
if path == "" {
if !bootstrap.NeedsNative(p) {
return builtin.Manifest()
}
built, err := bootstrap.BuildManifest(p, fmt.Sprintf("%s+v%d", engine.Version, manifest.Version), log.New(log.NewTextSink(os.Stderr)))
if err != nil {
return nil, err
}
path = built
}
data, err := os.ReadFile(path)
if err != nil {
return nil, err
}
return manifest.Decode(data)
}
func OpenWorkspace(p *project.Project, manifestPath string, tests bool) (*workspace.Workspace, error) {
man, err := LoadManifest(p, manifestPath)
if err != nil {
return nil, err
}
tab, err := man.Table()
if err != nil {
return nil, err
}
return workspace.Open(workspace.Config{
Root: p.Root,
Module: p.Module,
Scripts: p.ScriptsDir(),
Bindings: tab,
Docs: man,
Tests: tests,
})
}
func CheckDocuments(p *project.Project, w io.Writer) int {
problems := 0
err := filepath.WalkDir(p.Root, func(path string, d os.DirEntry, err error) error {
if err != nil {
return nil
}
if d.IsDir() {
if path != p.Root && skipCopy[d.Name()] {
return filepath.SkipDir
}
return nil
}
switch filepath.Ext(path) {
case ".aescene", ".aeprefab", ".aego", ".meta":
default:
return nil
}
data, err := os.ReadFile(path)
if err != nil {
return nil
}
if _, err := aetext.Parse(data, path); err != nil {
fmt.Fprintln(w, err)
problems++
}
if len(data) > 0 && data[len(data)-1] != '\n' {
fmt.Fprintf(w, "%s: missing final newline\n", path)
problems++
}
return nil
})
if err != nil {
fmt.Fprintln(w, "aego:", err)
problems++
}
return problems
}
func CheckSections(p *project.Project, w io.Writer) int {
types, err := assembly.NewTypes()
if err != nil {
fmt.Fprintln(w, "aego:", err)
return 1
}
man, err := builtin.Default().Load(types, bind.New(), assembly.Options{})
if err != nil {
fmt.Fprintln(w, "aego:", err)
return 1
}
if _, err := man.LoadSections(p.Block, project.CoreBlocks...); err != nil {
fmt.Fprintf(w, "%s: %v\n", p.FilePath(), err)
return 1
}
return 0
}
func Verify(p *project.Project, w io.Writer) error {
n := CheckDocuments(p, w) + CheckSections(p, w)
ws, err := OpenWorkspace(p, "", false)
if err != nil {
return err
}
snap := ws.Snapshot()
diag.Print(w, snap.Sources, snap.Diagnostics)
n += snap.Errors()
if n > 0 {
return errs.New(errs.BuildFailed, fmt.Sprintf("the new project has %d problem(s)", n), log.F("root", p.Root))
}
return nil
}
func CheckAssets(p *project.Project, imps *pipeline.ImporterRegistry, w io.Writer) int {
types, err := assembly.NewTypes()
if err != nil {
fmt.Fprintln(w, "aego:", err)
return 1
}
man, err := builtin.Default().Load(types, bind.New(), assembly.Options{})
if err != nil {
fmt.Fprintln(w, "aego:", err)
return 1
}
if err := types.Schema().Freeze(); err != nil {
fmt.Fprintln(w, "aego:", err)
return 1
}
pl, err := pipeline.Open(p, imps, log.Nop())
if err != nil {
fmt.Fprintln(w, "aego:", err)
return 1
}
defer pl.Close()
if _, _, err := pl.Scan(); err != nil {
fmt.Fprintln(w, "aego:", err)
return 1
}
if _, err := pl.ImportAll(); err != nil {
fmt.Fprintln(w, "aego:", err)
return 1
}
n := 0
for _, d := range man.ValidateAssets(types.Schema(), pl, bootstrap.NeedsNative(p), nil) {
sev := "warning"
if d.Severity == problems.Error {
sev = "error"
n++
}
fmt.Fprintf(w, "%s: %s %s: %s\n", d.Subject.File, sev, d.Code, d.Message)
}
return n
}