this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

cue/interpreter/embed: add support for embedding

This is a first-stab and partial implementation of the
embedding proposal. See the TODO list included in
embed.go to see what is outstanding.

Issue #2031

This issue is not closed, as it also referes to the
complementary export attribute.

Signed-off-by: Marcel van Lohuizen <mpvl@gmail.com>
Change-Id: Ic296a28aa009509f9a17913c7e5a0794de5a7a35
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1196718
Unity-Result: CUE porcuepine <cue.porcuepine@gmail.com>
Reviewed-by: Aram Hăvărneanu <aram@cue.works>
Reviewed-by: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: CUEcueckoo <cueckoo@cuelang.org>
Reviewed-by: Roger Peppe <rogpeppe@gmail.com>

+791 -7
+4
cmd/cue/cmd/root.go
··· 30 30 "cuelang.org/go/cue" 31 31 "cuelang.org/go/cue/cuecontext" 32 32 "cuelang.org/go/cue/errors" 33 + "cuelang.org/go/cue/interpreter/embed" 33 34 "cuelang.org/go/cue/stats" 34 35 "cuelang.org/go/internal" 35 36 "cuelang.org/go/internal/core/adt" ··· 219 220 // for `cue cmd mycmd`, so any sub-command suggestions might be confusing. 220 221 DisableSuggestions: true, 221 222 } 223 + 224 + embedding := cuecontext.Interpreter(embed.New()) 225 + rootContextOptions = append(rootContextOptions, embedding) 222 226 223 227 c := &Command{ 224 228 Command: cmd,
+293
cmd/cue/cmd/testdata/script/embed.txtar
··· 1 + exec cue eval 2 + cmp stdout out/noembed 3 + 4 + env CUE_EXPERIMENT=embed 5 + 6 + exec cue eval 7 + cmp stdout out/eval 8 + 9 + exec cue export --out cue 10 + cmp stdout out/export 11 + 12 + exec cue vet 13 + cmp stdout out/vet 14 + 15 + -- test.cue -- 16 + @extern(embed) 17 + 18 + package foo 19 + 20 + a: _ @embed(file="test.json") 21 + 22 + b: _ @embed(file="input.yaml") 23 + 24 + c: _ @embed(file="test.json", type=text) 25 + 26 + d: _ @embed(glob="y/*.*", type=yaml) 27 + 28 + d: _ @embed(glob="x/*.yaml") // merge into the same map 29 + 30 + f: _ @embed(file="openapi.json", type=openapi) 31 + 32 + g: _ @embed(file="openapi.json") // test no auto mode! 33 + 34 + 35 + special: { 36 + // These are all valid. 37 + underscoreFile: _ @embed(file="y/_test.json") 38 + dotFile: _ @embed(file="y/.test.json") 39 + underscoreDir: _ @embed(file="_y/test.json") 40 + dotDir: _ @embed(file=".y/test.json") 41 + 42 + // TODO: fix nested modules are currently not supported, but we may opt to 43 + // support them in the future. This is currently not handled. It should 44 + // probably be up to the loader to provide a fs.FS that handles this 45 + // according to spec. 46 + nestedModJSON: _ @embed(file="a/b/foo.json") 47 + nestedModFile: _ @embed(file="a/b/cue.mod/modules.cue") 48 + } 49 + 50 + -- test.json -- 51 + { "x": 34 } 52 + -- input.yaml -- 53 + a1: 2 54 + 55 + -- y/test.json -- 56 + { "x": 34 } 57 + -- y/_test.json -- 58 + { "z": 45 } 59 + -- y/.test.json -- 60 + { "z": 46 } 61 + -- _y/test.json -- 62 + { "z": 47 } 63 + -- .y/test.json -- 64 + { "z": 48 } 65 + -- _z/test.json -- 66 + -- x/input.yaml -- 67 + a1: 2 68 + -- a/b/cue.mod/modules.cue -- 69 + module: "acme.com" 70 + language: version: "v0.9.0" 71 + -- a/b/foo.json -- 72 + {"a": 1, "b": 2} 73 + -- openapi.json -- 74 + { 75 + "openapi": "3.0.0", 76 + "info": { 77 + "title": "My OpenAPI", 78 + "version": "v1alpha1" 79 + }, 80 + "paths": {}, 81 + "components": { 82 + "schemas": { 83 + "Bar": { 84 + "type": "object", 85 + "required": [ 86 + "foo" 87 + ], 88 + "properties": { 89 + "foo": { 90 + "$ref": "#/components/schemas/Foo" 91 + } 92 + } 93 + }, 94 + "Foo": { 95 + "type": "object", 96 + "required": [ 97 + "a", 98 + "b" 99 + ], 100 + "properties": { 101 + "a": { 102 + "type": "integer" 103 + }, 104 + "b": { 105 + "type": "integer", 106 + "minimum": 0, 107 + "exclusiveMaximum": 10 108 + } 109 + } 110 + } 111 + } 112 + } 113 + } 114 + -- out/noembed -- 115 + a: _ 116 + b: _ 117 + c: _ 118 + d: _ 119 + f: _ 120 + g: _ 121 + special: { 122 + underscoreFile: _ 123 + dotFile: _ 124 + underscoreDir: _ 125 + dotDir: _ 126 + nestedModJSON: _ 127 + nestedModFile: _ 128 + } 129 + -- out/eval -- 130 + a: { 131 + x: 34 132 + } 133 + b: { 134 + a1: 2 135 + } 136 + c: """ 137 + { "x": 34 } 138 + 139 + """ 140 + d: { 141 + "y/.test.json": { 142 + z: 46 143 + } 144 + "y/_test.json": { 145 + z: 45 146 + } 147 + "x/input.yaml": { 148 + a1: 2 149 + } 150 + "y/test.json": { 151 + x: 34 152 + } 153 + } 154 + f: { 155 + info: { 156 + title: "My OpenAPI" 157 + version: "v1alpha1" 158 + } 159 + #Bar: { 160 + foo: { 161 + a: int 162 + b: uint & <10 163 + } 164 + } 165 + #Foo: { 166 + a: int 167 + b: uint & <10 168 + } 169 + } 170 + g: { 171 + openapi: "3.0.0" 172 + info: { 173 + title: "My OpenAPI" 174 + version: "v1alpha1" 175 + } 176 + paths: {} 177 + components: { 178 + schemas: { 179 + Bar: { 180 + type: "object" 181 + required: ["foo"] 182 + properties: { 183 + foo: { 184 + $ref: "#/components/schemas/Foo" 185 + } 186 + } 187 + } 188 + Foo: { 189 + type: "object" 190 + required: ["a", "b"] 191 + properties: { 192 + a: { 193 + type: "integer" 194 + } 195 + b: { 196 + type: "integer" 197 + minimum: 0 198 + exclusiveMaximum: 10 199 + } 200 + } 201 + } 202 + } 203 + } 204 + } 205 + special: { 206 + underscoreFile: { 207 + z: 45 208 + } 209 + dotFile: { 210 + z: 46 211 + } 212 + underscoreDir: { 213 + z: 47 214 + } 215 + dotDir: { 216 + z: 48 217 + } 218 + nestedModJSON: { 219 + a: 1 220 + b: 2 221 + } 222 + nestedModFile: { 223 + module: "acme.com" 224 + language: { 225 + version: "v0.9.0" 226 + } 227 + } 228 + } 229 + -- out/export -- 230 + a: x: 34 231 + b: a1: 2 232 + c: """ 233 + { "x": 34 } 234 + 235 + """ 236 + d: { 237 + "y/.test.json": z: 46 238 + "y/_test.json": z: 45 239 + "x/input.yaml": a1: 2 240 + "y/test.json": x: 34 241 + } 242 + f: info: { 243 + title: "My OpenAPI" 244 + version: "v1alpha1" 245 + } 246 + g: { 247 + openapi: "3.0.0" 248 + info: { 249 + title: "My OpenAPI" 250 + version: "v1alpha1" 251 + } 252 + paths: {} 253 + components: schemas: { 254 + Bar: { 255 + type: "object" 256 + required: ["foo"] 257 + properties: foo: $ref: "#/components/schemas/Foo" 258 + } 259 + Foo: { 260 + type: "object" 261 + required: ["a", "b"] 262 + properties: { 263 + a: type: "integer" 264 + b: { 265 + type: "integer" 266 + minimum: 0 267 + exclusiveMaximum: 10 268 + } 269 + } 270 + } 271 + } 272 + } 273 + special: { 274 + // These are all valid. 275 + underscoreFile: z: 45 276 + dotFile: z: 46 277 + underscoreDir: z: 47 278 + dotDir: z: 48 279 + 280 + // TODO: fix nested modules are currently not supported, but we may opt to 281 + // support them in the future. This is currently not handled. It should 282 + // probably be up to the loader to provide a fs.FS that handles this 283 + // according to spec. 284 + nestedModJSON: { 285 + a: 1 286 + b: 2 287 + } 288 + nestedModFile: { 289 + module: "acme.com" 290 + language: version: "v0.9.0" 291 + } 292 + } 293 + -- out/vet --
+109
cmd/cue/cmd/testdata/script/embed_err.txtar
··· 1 + env CUE_EXPERIMENT=embed 2 + 3 + ! exec cue eval 4 + cmp stdout out/std 5 + cmp stderr out/err 6 + 7 + -- test.cue -- 8 + @extern(embed) 9 + 10 + package foo 11 + 12 + none: _@embed(type=foo) 13 + 14 + both: _ @embed(file=test.json, glob="x/*.*", type=yaml) 15 + 16 + dotdot: _ @embed(file="../test.json") 17 + 18 + abs: _ @embed(file=/input.yaml) 19 + 20 + nonexist: _ @embed(file=y/test.json, type=text) 21 + 22 + dir: _ @embed(glob="x", type=yaml) 23 + 24 + dirslash: _ @embed(glob="x/", type=yaml) 25 + 26 + dotdotglob: _ @embed(glob="../test.json", type=yaml) 27 + 28 + absglob: _ @embed(glob="/x/*.*", type=yaml) 29 + 30 + doublestar: _ @embed(glob="**/*.json") 31 + 32 + stream: _ @embed(file=test.ldjson) 33 + 34 + singlestream: _ @embed(file=single.ldjson) 35 + 36 + yamlstream: _ @embed(file=stream.yaml) 37 + 38 + textproto: _ @embed(file=test.textproto) 39 + 40 + norm1: _ @embed(file=./test.json) 41 + 42 + norm2: _ @embed(file="x/../test.json") 43 + 44 + norm3: _ @embed(file="x/../x/test.json") 45 + 46 + norm4: _ @embed(file="x//test.json") 47 + 48 + noTranslateBS: _ @embed(file="x\\test.json") 49 + 50 + -- test.json -- 51 + { "x": 34 } 52 + -- test.ldjson -- 53 + { "x": 35 } 54 + { "x": 36 } 55 + -- single.ldjson -- 56 + { "x": 37 } 57 + -- stream.yaml -- 58 + 1 59 + --- 60 + 2 61 + -- input.yaml -- 62 + a1: 2 63 + 64 + -- x/test.json -- 65 + { "x": 34 } 66 + -- x/input.yaml -- 67 + a1: 2 68 + -- test.textproto -- 69 + a: 1 70 + -- out/std -- 71 + -- out/err -- 72 + @embed: attribute must have file or glob field: 73 + ./test.cue:5:8 74 + @embed: attribute cannot have both file and glob field: 75 + ./test.cue:7:9 76 + @embed: cannot refer to parent directory: 77 + ./test.cue:9:11 78 + @embed: only relative files are allowed: 79 + ./test.cue:11:8 80 + @embed: open y/test.json: no such file or directory: 81 + ./test.cue:13:13 82 + @embed: cannot embed directories: 83 + ./test.cue:15:8 84 + @embed: path not normalized, use "x" instead: 85 + ./test.cue:17:13 86 + @embed: cannot refer to parent directory: 87 + ./test.cue:19:15 88 + @embed: only relative files are allowed: 89 + ./test.cue:21:12 90 + @embed: double star not supported in glob: 91 + ./test.cue:23:15 92 + @embed: streaming not implemented: found more than one value in file: 93 + ./test.cue:25:11 94 + @embed: encoding "jsonl" not (yet) supported: requires support for streaming: 95 + ./test.cue:27:17 96 + @embed: streaming not implemented: found more than one value in file: 97 + ./test.cue:29:15 98 + @embed: encoding "textproto" not (yet) supported: requires support for schema-guided decoding: 99 + ./test.cue:31:14 100 + @embed: path not normalized, use "test.json" instead: 101 + ./test.cue:33:10 102 + @embed: path not normalized, use "test.json" instead: 103 + ./test.cue:35:10 104 + @embed: path not normalized, use "x/test.json" instead: 105 + ./test.cue:37:10 106 + @embed: path not normalized, use "x/test.json" instead: 107 + ./test.cue:39:10 108 + @embed: open x\test.json: no such file or directory: 109 + ./test.cue:41:18
+53
cmd/cue/cmd/testdata/script/embed_mod.txtar
··· 1 + env CUE_EXPERIMENT=embed 2 + 3 + exec cue mod tidy 4 + exec cue eval ./acme/foo 5 + cmp stdout out/eval 6 + 7 + -- cue.mod/module.cue -- 8 + module: "main.org@v0" 9 + language: version: "v0.8.0" 10 + 11 + -- acme/foo/embed.cue -- 12 + @extern(embed) 13 + 14 + package foo 15 + 16 + import "example.com/e" 17 + 18 + a: _ @embed(file="test.json") 19 + 20 + b: _ @embed(file="x/test.json") 21 + 22 + c: e.a 23 + 24 + -- acme/foo/test.json -- 25 + { "x": 34 } 26 + 27 + -- acme/foo/x/test.json -- 28 + { "x": 35 } 29 + 30 + 31 + -- _registry/example.com_e_v0.0.1/cue.mod/module.cue -- 32 + module: "example.com/e@v0" 33 + language: version: "v0.8.0" 34 + 35 + -- _registry/example.com_e_v0.0.1/main.cue -- 36 + @extern(embed) 37 + 38 + package e 39 + 40 + a: _ @embed(file=foo.txt) 41 + -- _registry/example.com_e_v0.0.1/foo.txt -- 42 + hello 43 + -- out/eval -- 44 + a: { 45 + x: 34 46 + } 47 + b: { 48 + x: 35 49 + } 50 + c: """ 51 + hello 52 + 53 + """
+1
cue/attribute.go
··· 49 49 x := internal.ParseAttrBody(a.Pos().Add(len(key)+1), body) 50 50 x.Name = key 51 51 x.Kind = k 52 + x.Pos = a.Pos() 52 53 return Attribute{x} 53 54 } 54 55
+319
cue/interpreter/embed/embed.go
··· 1 + // Copyright 2024 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 embed provides capabilities to CUE to embed any file that resides 16 + // within a CUE module into CUE either verbatim or decoded. 17 + // 18 + // This package is EXPERIMENTAL and subject to change. 19 + // 20 + // # Overview 21 + // 22 + // To enable file embedding, a file must include the file-level @extern(embed) 23 + // attribute. This allows a quick glance to see if a file embeds any files at 24 + // all. This allows the @embed attribute to be used to load a file within a CUE 25 + // module into a field. 26 + // 27 + // References to files are always relative to directory in which the referring 28 + // file resides. Only files that exist within the CUE module are accessible. 29 + // 30 + // # The @embed attribute 31 + // 32 + // There are two main ways to embed files which are distinguished by the file 33 + // and glob arguments. The @embed attribute supports the following arguments: 34 + // 35 + // file=$filename 36 + // 37 + // The use of the file argument tells embed to load a single file into the 38 + // field. This argument many not be used in conjunction with the glob argument. 39 + // 40 + // glob=$pattern 41 + // 42 + // The use of the glob argument tells embed to load multiple files into the 43 + // field as a map of file paths to the decoded values. The paths are normalized 44 + // to use forward slashes. This argument may not be used in conjunction with the 45 + // file argument. 46 + // 47 + // type=$type 48 + // 49 + // By default, the file type is interpreted based on the file extension. This 50 + // behavior can be overridden by the type argument. See cue help filetypes for 51 + // the list of supported types. This field is required if a file extension is 52 + // unknown, or if a wildcard is used for the file extension in the glob pattern. 53 + // 54 + // # Limitations 55 + // 56 + // The embed interpreter currently does not support: 57 + // - stream values, such as .ldjson or YAML streams. 58 + // - schema-based decoding, such as needed for textproto 59 + // 60 + // # Example 61 + // 62 + // @extern(embed) 63 + // 64 + // package foo 65 + // 66 + // // interpreted as JSON 67 + // a: _ @embed(file="file1.json") // the quotes are optional here 68 + // 69 + // // interpreted the same file as JSON schema 70 + // #A: _ @embed(file=file1.json, type=jsonschema) 71 + // 72 + // // interpret a proprietary extension as OpenAPI represented as YAML 73 + // b: _ @embed(file="file2.crd", type=openapi+yaml) 74 + // 75 + // // include all YAML files in the x directory interpreted as YAML 76 + // // The result is a map of file paths to the decoded YAML values. 77 + // files: _ @embed(glob=x/*.yaml) 78 + // 79 + // // include all files in the y directory as a map of file paths to binary 80 + // // data. The entries are unified into the same map as above. 81 + // files: _ @embed(glob=y/*.*, type=binary) 82 + package embed 83 + 84 + import ( 85 + "io/fs" 86 + "os" 87 + "path" 88 + "path/filepath" 89 + "strings" 90 + 91 + "cuelang.org/go/cue" 92 + "cuelang.org/go/cue/build" 93 + "cuelang.org/go/cue/cuecontext" 94 + "cuelang.org/go/cue/errors" 95 + "cuelang.org/go/cue/token" 96 + "cuelang.org/go/internal" 97 + "cuelang.org/go/internal/core/adt" 98 + "cuelang.org/go/internal/core/runtime" 99 + "cuelang.org/go/internal/cueexperiment" 100 + "cuelang.org/go/internal/encoding" 101 + "cuelang.org/go/internal/filetypes" 102 + "cuelang.org/go/internal/value" 103 + ) 104 + 105 + // TODO: obtain a fs.FS from load or something similar 106 + // TODO: disallow files from submodules 107 + // TODO: record files in build.Instance 108 + // TODO: support stream values 109 + // TODO: support schema-based decoding 110 + 111 + // interpreter is a [cuecontext.ExternInterpreter] for embedded files. 112 + type interpreter struct{} 113 + 114 + // New returns a new interpreter for embedded files as a 115 + // [cuecontext.ExternInterpreter] suitable for passing to [cuecontext.New]. 116 + func New() cuecontext.ExternInterpreter { 117 + return &interpreter{} 118 + } 119 + 120 + func (i *interpreter) Kind() string { 121 + return "embed" 122 + } 123 + 124 + // NewCompiler returns a compiler that can decode and embed files that exist 125 + // within a CUE module. 126 + func (i *interpreter) NewCompiler(b *build.Instance, r *runtime.Runtime) (runtime.Compiler, errors.Error) { 127 + return &compiler{ 128 + b: b, 129 + runtime: (*cue.Context)(r), 130 + }, nil 131 + } 132 + 133 + // A compiler is a [runtime.Compiler] that allows embedding files into CUE 134 + // values. 135 + type compiler struct { 136 + b *build.Instance 137 + runtime *cue.Context 138 + opCtx *adt.OpContext 139 + 140 + // file system cache 141 + dir string 142 + fs fs.FS 143 + pos token.Pos 144 + } 145 + 146 + // Compile interprets an embed attribute to either load a file 147 + // (@embed(file=...)) or a glob of files (@embed(glob=...)). 148 + // and decodes the given files. 149 + func (c *compiler) Compile(funcName string, scope adt.Value, a *internal.Attr) (adt.Expr, errors.Error) { 150 + // This is a really weird spot to disable embedding, but I could not get 151 + // the wasm tests to pass without doing it like this. 152 + if !cueexperiment.Flags.Embed { 153 + return &adt.Top{}, nil 154 + } 155 + 156 + file, _, err := a.Lookup(0, "file") 157 + if err != nil { 158 + return nil, errors.Promote(err, "invalid attribute") 159 + } 160 + 161 + glob, _, err := a.Lookup(0, "glob") 162 + if err != nil { 163 + return nil, errors.Promote(err, "invalid attribute") 164 + } 165 + 166 + typ, _, err := a.Lookup(0, "type") 167 + if err != nil { 168 + return nil, errors.Promote(err, "invalid type argument") 169 + } 170 + 171 + c.opCtx = adt.NewContext((*runtime.Runtime)(c.runtime), nil) 172 + 173 + pos := a.Pos 174 + c.pos = pos 175 + 176 + // Jump through some hoops to get file operations to behave the same for 177 + // Windows and Unix. 178 + // TODO: obtain a fs.FS from load or something similar. 179 + dir := filepath.Dir(pos.File().Name()) 180 + if c.dir != dir { 181 + c.fs = os.DirFS(dir) 182 + c.dir = dir 183 + } 184 + 185 + switch { 186 + case file == "" && glob == "": 187 + return nil, errors.Newf(a.Pos, "attribute must have file or glob field") 188 + 189 + case file != "" && glob != "": 190 + return nil, errors.Newf(a.Pos, "attribute cannot have both file and glob field") 191 + 192 + case file != "": 193 + return c.processFile(file, typ, scope) 194 + 195 + default: // glob != "": 196 + return c.processGlob(glob, typ, scope) 197 + } 198 + } 199 + 200 + func (c *compiler) processFile(file, scope string, schema adt.Value) (adt.Expr, errors.Error) { 201 + file, err := c.clean(file) 202 + if err != nil { 203 + return nil, err 204 + } 205 + 206 + return c.decodeFile(file, scope, schema) 207 + } 208 + 209 + func (c *compiler) processGlob(glob, scope string, schema adt.Value) (adt.Expr, errors.Error) { 210 + glob, ce := c.clean(glob) 211 + if ce != nil { 212 + return nil, ce 213 + } 214 + 215 + if strings.Contains(glob, "**") { 216 + return nil, errors.Newf(c.pos, "double star not supported in glob") 217 + } 218 + 219 + m := &adt.StructLit{} 220 + 221 + matches, err := fs.Glob(c.fs, glob) 222 + if err != nil { 223 + return nil, errors.Promote(err, "failed to match glob") 224 + } 225 + 226 + for _, f := range matches { 227 + expr, err := c.decodeFile(f, scope, schema) 228 + if err != nil { 229 + return nil, err 230 + } 231 + 232 + m.Decls = append(m.Decls, &adt.Field{ 233 + Label: c.opCtx.StringLabel(f), 234 + Value: expr, 235 + }) 236 + } 237 + 238 + return m, nil 239 + } 240 + 241 + func (c *compiler) clean(s string) (string, errors.Error) { 242 + file := path.Clean(s) 243 + if file != s { 244 + return file, errors.Newf(c.pos, "path not normalized, use %q instead", file) 245 + } 246 + if path.IsAbs(file) { 247 + return "", errors.Newf(c.pos, "only relative files are allowed") 248 + } 249 + if strings.HasPrefix(file, "..") { 250 + return "", errors.Newf(c.pos, "cannot refer to parent directory") 251 + } 252 + return file, nil 253 + } 254 + 255 + func (c *compiler) decodeFile(file, scope string, schema adt.Value) (adt.Expr, errors.Error) { 256 + // Do not use the most obvious filetypes.Input in order to disable "auto" 257 + // mode. 258 + f, err := filetypes.ParseFileAndType(file, scope, filetypes.Def) 259 + if err != nil { 260 + return nil, errors.Promote(err, "invalid file type") 261 + } 262 + 263 + // Open and pre-load the file system using fs.FS, instead of relying 264 + r, err := c.fs.Open(file) 265 + if err != nil { 266 + return nil, errors.Newf(c.pos, "open %v: no such file or directory", file) 267 + } 268 + defer r.Close() 269 + 270 + info, err := r.Stat() 271 + if err != nil { 272 + return nil, errors.Promote(err, "failed to decode file") 273 + } 274 + if info.IsDir() { 275 + return nil, errors.Newf(c.pos, "cannot embed directories") 276 + } 277 + f.Source = r 278 + 279 + // TODO: this really should be done at the start of the build process. 280 + // c.b.ExternFiles = append(c.b.ExternFiles, f) 281 + 282 + config := &encoding.Config{ 283 + // TODO: schema is currently the wrong schema, which is a bug in 284 + // internal/core/runtime. There is also an outstanding design choice: 285 + // do we imply the schema from the schema of the current field, or do 286 + // we explicitly enable schema-based encoding with a "schema" argument. 287 + // In the case of YAML it seems to be better to be explicit. In the case 288 + // of textproto it seems to be more convenient to do it implicitly. 289 + // Schema: value.Make(c.opCtx, schema), 290 + } 291 + 292 + d := encoding.NewDecoder(c.runtime, f, config) 293 + if err := d.Err(); err != nil { 294 + return nil, errors.Promote(err, "failed to decode file") 295 + } 296 + 297 + defer d.Close() 298 + 299 + n := d.File() 300 + 301 + if d.Next(); !d.Done() { 302 + return nil, errors.Newf(c.pos, "streaming not implemented: found more than one value in file") 303 + } 304 + 305 + switch f.Encoding { 306 + case build.JSONL: 307 + return nil, errors.Newf(c.pos, "encoding %q not (yet) supported: requires support for streaming", f.Encoding) 308 + case build.BinaryProto, build.TextProto: 309 + return nil, errors.Newf(c.pos, "encoding %q not (yet) supported: requires support for schema-guided decoding", f.Encoding) 310 + } 311 + 312 + val := c.runtime.BuildFile(n) 313 + if err := val.Err(); err != nil { 314 + return nil, errors.Promote(err, "failed to build file") 315 + } 316 + 317 + _, v := value.ToInternal(val) 318 + return v, nil 319 + }
+3 -3
cue/interpreter/wasm/testdata/cue/error.txtar
··· 14 14 not: _ @extern("basic.wasm", abi=c, sig="func(*): bool") 15 15 -- basic.wasm -- 16 16 -- out/wasm -- 17 - can't load from external module: invalid function signature: expected ':', found newline: 17 + @wasm: invalid function signature: expected ':', found newline: 18 18 ./a.cue:4:8 19 - can't load from external module: invalid function signature: expected identifier, found *ast.ListLit: 19 + @wasm: invalid function signature: expected identifier, found *ast.ListLit: 20 20 ./a.cue:5:8 21 - can't load from external module: invalid function signature: expected operand, found ')': 21 + @wasm: invalid function signature: expected operand, found ')': 22 22 ./a.cue:6:8
+2 -2
cue/interpreter/wasm/testdata/cue/missing.txtar
··· 14 14 15 15 x: add(1, 2) 16 16 -- out/wasm -- 17 - can't load from external module: load "foo.wasm": file not found: 17 + @wasm: load "foo.wasm": file not found: 18 18 ./a.cue:4:8 19 - can't load from external module: load "foo.wasm1": invalid file name: 19 + @wasm: load "foo.wasm1": invalid file name: 20 20 ./a.cue:5:8
+2
internal/attrs.go
··· 52 52 Kind AttrKind 53 53 Fields []KeyValue 54 54 Err errors.Error 55 + Pos token.Pos 55 56 } 56 57 57 58 // NewNonExisting creates a non-existing attribute. ··· 153 154 tmpFile.AddLine(len(s) - 1) 154 155 } 155 156 a.Body = s 157 + a.Pos = pos 156 158 var scan scanner.Scanner 157 159 scan.Init(tmpFile, []byte(s), nil, scanner.DontInsertCommas) 158 160 for {
+1 -1
internal/core/runtime/extern.go
··· 332 332 333 333 b, err := c.Compile(name, scope, &attr) 334 334 if err != nil { 335 - err = errors.Newf(info.attr.Pos(), "can't load from external module: %v", err) 335 + err = errors.Newf(info.attr.Pos(), "@%s: %v", info.extern, err) 336 336 d.errs = errors.Append(d.errs, err) 337 337 return true 338 338 }
+1 -1
internal/core/runtime/testdata/compile.txtar
··· 5 5 6 6 foo: _ @test("file.xx", fail) 7 7 -- out/extern -- 8 - can't load from external module: TEST: fail compilation: 8 + @test: TEST: fail compilation: 9 9 ./compile.cue:5:8
+3
internal/cueexperiment/exp.go
··· 20 20 // EvalV3 enables the new evaluator. The new evaluator addresses various 21 21 // performance concerns. 22 22 EvalV3 bool 23 + 24 + // Embed enabled file embedding. 25 + Embed bool 23 26 } 24 27 25 28 // Init initializes Flags. Note: this isn't named "init" because we