github.com/solo-io/cue@v0.4.7/internal/core/runtime/build.go (about) 1 // Copyright 2020 CUE Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package runtime 16 17 import ( 18 "strings" 19 20 "github.com/solo-io/cue/cue/ast" 21 "github.com/solo-io/cue/cue/ast/astutil" 22 "github.com/solo-io/cue/cue/build" 23 "github.com/solo-io/cue/cue/errors" 24 "github.com/solo-io/cue/cue/token" 25 "github.com/solo-io/cue/internal" 26 "github.com/solo-io/cue/internal/core/adt" 27 "github.com/solo-io/cue/internal/core/compile" 28 ) 29 30 type Config struct { 31 Runtime *Runtime 32 Filename string 33 ImportPath string 34 35 compile.Config 36 } 37 38 // Build builds b and all its transitive dependencies, insofar they have not 39 // been build yet. 40 func (x *Runtime) Build(cfg *Config, b *build.Instance) (v *adt.Vertex, errs errors.Error) { 41 if err := b.Complete(); err != nil { 42 return nil, b.Err 43 } 44 if v := x.getNodeFromInstance(b); v != nil { 45 return v, b.Err 46 } 47 // TODO: clear cache of old implementation. 48 // if s := b.ImportPath; s != "" { 49 // // Use cached result, if available. 50 // if v, err := x.LoadImport(s); v != nil || err != nil { 51 // return v, err 52 // } 53 // } 54 55 errs = b.Err 56 57 // Build transitive dependencies. 58 for _, file := range b.Files { 59 file.VisitImports(func(d *ast.ImportDecl) { 60 for _, s := range d.Specs { 61 errs = errors.Append(errs, x.buildSpec(cfg, b, s)) 62 } 63 }) 64 } 65 66 err := x.ResolveFiles(b) 67 errs = errors.Append(errs, err) 68 69 var cc *compile.Config 70 if cfg != nil { 71 cc = &cfg.Config 72 } 73 if cfg != nil && cfg.ImportPath != "" { 74 b.ImportPath = cfg.ImportPath 75 b.PkgName = astutil.ImportPathName(b.ImportPath) 76 } 77 v, err = compile.Files(cc, x, b.ID(), b.Files...) 78 errs = errors.Append(errs, err) 79 80 if errs != nil { 81 v = adt.ToVertex(&adt.Bottom{Err: errs}) 82 b.Err = errs 83 } 84 85 x.AddInst(b.ImportPath, v, b) 86 87 return v, errs 88 } 89 90 func dummyLoad(token.Pos, string) *build.Instance { return nil } 91 92 func (r *Runtime) Compile(cfg *Config, source interface{}) (*adt.Vertex, *build.Instance) { 93 ctx := build.NewContext() 94 var filename string 95 if cfg != nil && cfg.Filename != "" { 96 filename = cfg.Filename 97 } 98 p := ctx.NewInstance(filename, dummyLoad) 99 if err := p.AddFile(filename, source); err != nil { 100 return nil, p 101 } 102 v, _ := r.Build(cfg, p) 103 return v, p 104 } 105 106 func (r *Runtime) CompileFile(cfg *Config, file *ast.File) (*adt.Vertex, *build.Instance) { 107 ctx := build.NewContext() 108 filename := file.Filename 109 if cfg != nil && cfg.Filename != "" { 110 filename = cfg.Filename 111 } 112 p := ctx.NewInstance(filename, dummyLoad) 113 err := p.AddSyntax(file) 114 if err != nil { 115 return nil, p 116 } 117 _, p.PkgName, _ = internal.PackageInfo(file) 118 v, _ := r.Build(cfg, p) 119 return v, p 120 } 121 122 func (x *Runtime) buildSpec(cfg *Config, b *build.Instance, spec *ast.ImportSpec) (errs errors.Error) { 123 info, err := astutil.ParseImportSpec(spec) 124 if err != nil { 125 return errors.Promote(err, "invalid import path") 126 } 127 128 pkg := b.LookupImport(info.ID) 129 if pkg == nil { 130 if strings.Contains(info.ID, ".") { 131 return errors.Newf(spec.Pos(), 132 "package %q imported but not defined in %s", 133 info.ID, b.ImportPath) 134 } 135 return nil // TODO: check the builtin package exists here. 136 } 137 138 if v := x.index.importsByBuild[pkg]; v != nil { 139 return pkg.Err 140 } 141 142 if _, err := x.Build(cfg, pkg); err != nil { 143 return err 144 } 145 146 return nil 147 }