Skip to content

Commit fdf75f5

Browse files
committed
mod/modfile: better error message when disallowed field is used
The current error message looks like this: ``` source: conflicting values 1 and {kind!:("self"|"git")} (mismatched types int and struct): cuelang.org/go/mod/modfile/schema.cue:24:21 cuelang.org/go/mod/modfile/schema.cue:65:12 cuelang.org/go/mod/modfile/schema.cue:122:11 source: conflicting values 2 and 1: cuelang.org/go/mod/modfile/schema.cue:24:21 cuelang.org/go/mod/modfile/schema.cue:24:25 cuelang.org/go/mod/modfile/schema.cue:55:18 ``` The new error message is somewhat improved: ``` instance: invalid module.cue file: source field is not allowed at this language version; need at least v0.9.0-alpha.0 ``` Signed-off-by: Roger Peppe <[email protected]> Change-Id: I81481a90fcd5a4478fed8c8b6711b878b37ee461 Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1193895 Reviewed-by: Daniel Martí <[email protected]> TryBot-Result: CUEcueckoo <[email protected]> Unity-Result: CUE porcuepine <[email protected]>
1 parent 70cc402 commit fdf75f5

File tree

3 files changed

+68
-11
lines changed

3 files changed

+68
-11
lines changed

mod/modfile/modfile.go

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ import (
4040
)
4141

4242
//go:embed schema.cue
43-
var moduleSchemaData []byte
43+
var moduleSchemaData string
44+
45+
const schemaFile = "cuelang.org/go/mod/modfile/schema.cue"
4446

4547
// File represents the contents of a cue.mod/module.cue file.
4648
type File struct {
@@ -152,10 +154,14 @@ type schemaInfo struct {
152154
EarliestClosedSchemaVersion string `json:"earliestClosedSchemaVersion"`
153155
}
154156

157+
// moduleSchemaDo runs f with information about all the schema versions
158+
// present in schema.cue. It does this within a mutex because it is
159+
// not currently allowed to use cue.Value concurrently.
160+
// TODO remove the mutex when https://cuelang.org/issue/2733 is fixed.
155161
func moduleSchemaDo[T any](f func(*cue.Context, *schemaInfo) (T, error)) (T, error) {
156162
moduleSchemaOnce.Do(func() {
157163
_cueContext = cuecontext.New()
158-
schemav := _cueContext.CompileBytes(moduleSchemaData, cue.Filename("cuelang.org/go/mod/modfile/schema.cue"))
164+
schemav := _cueContext.CompileString(moduleSchemaData, cue.Filename(schemaFile))
159165
if err := schemav.Decode(&_schemas); err != nil {
160166
panic(fmt.Errorf("internal error: invalid CUE module.cue schema: %v", errors.Details(err, nil)))
161167
}
@@ -372,10 +378,55 @@ func parse(modfile []byte, filename string, strict bool) (*File, error) {
372378
}
373379

374380
func newCUEError(err error, filename string) error {
375-
// TODO we have some potential to improve error messages here.
381+
ps := errors.Positions(err)
382+
for _, p := range ps {
383+
if errStr := findErrorComment(p); errStr != "" {
384+
return fmt.Errorf("invalid module.cue file: %s", errStr)
385+
}
386+
}
387+
// TODO we have more potential to improve error messages here.
376388
return err
377389
}
378390

391+
// findErrorComment finds an error comment in the form
392+
//
393+
// //error: ...
394+
//
395+
// before the given position.
396+
// This works as a kind of poor-man's error primitive
397+
// so we can customize the error strings when verification
398+
// fails.
399+
func findErrorComment(p token.Pos) string {
400+
if p.Filename() != schemaFile {
401+
return ""
402+
}
403+
off := p.Offset()
404+
source := moduleSchemaData
405+
if off > len(source) {
406+
return ""
407+
}
408+
source, _, ok := cutLast(source[:off], "\n")
409+
if !ok {
410+
return ""
411+
}
412+
_, errorLine, ok := cutLast(source, "\n")
413+
if !ok {
414+
return ""
415+
}
416+
errStr, ok := strings.CutPrefix(errorLine, "//error: ")
417+
if !ok {
418+
return ""
419+
}
420+
return errStr
421+
}
422+
423+
func cutLast(s, sep string) (before, after string, found bool) {
424+
if i := strings.LastIndex(s, sep); i >= 0 {
425+
return s[:i], s[i+len(sep):], true
426+
}
427+
return "", s, false
428+
}
429+
379430
// DepVersions returns the versions of all the modules depended on by the
380431
// file. The caller should not modify the returned slice.
381432
//

mod/modfile/modfile_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ module: "foo.com/bar@v0"
139139
language: version: "v0.8.6"
140140
source: kind: "git"
141141
`,
142-
wantError: `source: conflicting values 1 and (.|\n)+`,
142+
wantError: `invalid module.cue file: source field is not allowed at this language version; need at least v0.9.0-alpha.0`,
143143
}, {
144144
testName: "AmbiguousDefaults",
145145
parse: Parse,

mod/modfile/schema.cue

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@
1818
// used instead, which will be rewritten to the canonical form by the cue command tooling.
1919
// To check against that form,
2020

21-
// Note: we're using 1&2 rather than _|_ because
22-
// use of _|_ causes the source location of the errors
23-
// to be lost. See https://github.com/cue-lang/cue/issues/2319.
24-
let unimplemented = 1 & 2
25-
2621
// versions holds an element for each supported version
2722
// of the schema. The version key specifies that
2823
// the schema covers all versions from then until the
@@ -51,8 +46,8 @@ versions: "v0.8.0": {
5146
versions["v0.9.0-alpha.0"]
5247

5348
// The source field was added in v0.9.0, so "remove"
54-
// it here by marking it as unimplemented.
55-
#File: source?: unimplemented
49+
// it here by marking it as an error when used.
50+
#File: source?: _errorSourceFieldRequiredVersion
5651
}
5752

5853
versions: "v0.9.0-alpha.0": {
@@ -131,3 +126,14 @@ versions: "v0.9.0-alpha.0": {
131126
// kind!: "self" | "git" | "bzr" | "hg" | "svn"
132127
}
133128
}
129+
130+
// The //error comments are specially recognized by the parsing
131+
// code so we can avoid opaque conflict errors.
132+
// TODO use error function when that's available.
133+
//
134+
// Note: we're using 1&2 rather than _|_ because
135+
// use of _|_ causes the source location of the errors
136+
// to be lost. See https://github.com/cue-lang/cue/issues/2319.
137+
138+
//error: source field is not allowed at this language version; need at least v0.9.0-alpha.0
139+
let _errorSourceFieldRequiredVersion = 1&2

0 commit comments

Comments
 (0)