cuelang.org/go@v0.10.1/cue/load/loader.go (about) 1 // Copyright 2018 The 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 load 16 17 // Files in this package are to a large extent based on Go files from the following 18 // Go packages: 19 // - cmd/go/internal/load 20 // - go/build 21 22 import ( 23 "path/filepath" 24 25 "cuelang.org/go/cue/build" 26 "cuelang.org/go/cue/errors" 27 "cuelang.org/go/cue/token" 28 "cuelang.org/go/internal/mod/modpkgload" 29 30 // Trigger the unconditional loading of all core builtin packages if load 31 // is used. This was deemed the simplest way to avoid having to import 32 // this line explicitly, and thus breaking existing code, for the majority 33 // of cases, while not introducing an import cycle. 34 _ "cuelang.org/go/pkg" 35 ) 36 37 type loader struct { 38 cfg *Config 39 tagger *tagger 40 stk importStack 41 pkgs *modpkgload.Packages 42 43 // dirCachedBuildFiles caches the work involved when reading a 44 // directory. It is keyed by directory name. When we descend into 45 // subdirectories to load patterns such as ./... we often end up 46 // loading parent directories many times over; this cache 47 // amortizes that work. 48 dirCachedBuildFiles map[string]cachedDirFiles 49 } 50 51 type cachedDirFiles struct { 52 err errors.Error 53 filenames []string 54 } 55 56 func newLoader(c *Config, tg *tagger, pkgs *modpkgload.Packages) *loader { 57 return &loader{ 58 cfg: c, 59 tagger: tg, 60 pkgs: pkgs, 61 dirCachedBuildFiles: make(map[string]cachedDirFiles), 62 } 63 } 64 65 func (l *loader) abs(filename string) string { 66 if !isLocalImport(filename) { 67 return filename 68 } 69 return filepath.Join(l.cfg.Dir, filename) 70 } 71 72 func (l *loader) errPkgf(importPos []token.Pos, format string, args ...interface{}) *PackageError { 73 err := &PackageError{ 74 ImportStack: l.stk.Copy(), 75 Message: errors.NewMessagef(format, args...), 76 } 77 err.fillPos(l.cfg.Dir, importPos) 78 return err 79 } 80 81 // cueFilesPackage creates a package for building a collection of CUE files 82 // (typically named on the command line). 83 func (l *loader) cueFilesPackage(files []*build.File) *build.Instance { 84 // ModInit() // TODO: support modules 85 pkg := l.cfg.Context.NewInstance(l.cfg.Dir, l.loadFunc()) 86 87 for _, bf := range files { 88 f := bf.Filename 89 if f == "-" { 90 continue 91 } 92 if !filepath.IsAbs(f) { 93 f = filepath.Join(l.cfg.Dir, f) 94 } 95 fi, err := l.cfg.fileSystem.stat(f) 96 if err != nil { 97 return l.cfg.newErrInstance(errors.Wrapf(err, token.NoPos, "could not find file %v", f)) 98 } 99 if fi.IsDir() { 100 return l.cfg.newErrInstance(errors.Newf(token.NoPos, "file is a directory %v", f)) 101 } 102 } 103 104 fp := newFileProcessor(l.cfg, pkg, l.tagger) 105 if l.cfg.Package == "*" { 106 fp.allPackages = true 107 pkg.PkgName = "_" 108 } 109 for _, bf := range files { 110 fp.add(l.cfg.Dir, bf, allowAnonymous|allowExcludedFiles) 111 } 112 113 // TODO: ModImportFromFiles(files) 114 pkg.Dir = l.cfg.Dir 115 rewriteFiles(pkg, pkg.Dir, true) 116 for _, err := range errors.Errors(fp.finalize(pkg)) { // ImportDir(&ctxt, dir, 0) 117 var x *NoFilesError 118 if len(pkg.OrphanedFiles) == 0 || !errors.As(err, &x) { 119 pkg.ReportError(err) 120 } 121 } 122 // TODO: Support module importing. 123 // if ModDirImportPath != nil { 124 // // Use the effective import path of the directory 125 // // for deciding visibility during pkg.load. 126 // bp.ImportPath = ModDirImportPath(dir) 127 // } 128 129 pkg.User = true 130 l.addFiles(pkg) 131 132 _ = pkg.Complete() 133 pkg.DisplayPath = "command-line-arguments" 134 135 return pkg 136 } 137 138 // addFiles populates p.Files by reading CUE syntax from p.BuildFiles. 139 func (l *loader) addFiles(p *build.Instance) { 140 for _, bf := range p.BuildFiles { 141 f, err := l.cfg.fileSystem.getCUESyntax(bf) 142 if err != nil { 143 p.ReportError(errors.Promote(err, "load")) 144 } 145 _ = p.AddSyntax(f) 146 } 147 }