Skip to content

Commit bbe493a

Browse files
committed
cmd/cue/cmd: more position information for field errors
Closes #479 Change-Id: I20ad3aa775c84350ea0d2e26c5b5c6a798b0ddbc Reviewed-on: https://cue-review.googlesource.com/c/cue/+/7823 Reviewed-by: Marcel van Lohuizen <[email protected]> Reviewed-by: CUE cueckoo <[email protected]>
1 parent 555fb73 commit bbe493a

File tree

3 files changed

+93
-14
lines changed

3 files changed

+93
-14
lines changed

cmd/cue/cmd/testdata/script/cmd_err.txt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,13 @@
33
cmp stderr cmd_badfields.out
44

55
-- cmd_badfields.out --
6-
command.ref.task.display.contents: invalid bytes argument for field "contents": non-concrete value (string|bytes):
6+
command.ref.task.display.contents: invalid bytes argument: non-concrete value (string|bytes):
77
./task_tool.cue:6:8
8-
command.ref.task.display.filename: non-concrete value string:
9-
tool/file:15:16
8+
tool/file:17:3
9+
command.ref.task.display.filename: invalid string argument: non-concrete value string:
10+
./task_tool.cue:6:8
11+
./task_tool.cue:7:9
12+
tool/file:15:3
1013
-- task_tool.cue --
1114
package home
1215

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
! cue cmd prompter
2+
cmp stderr expect-stderr
3+
4+
# Issue #479
5+
6+
-- expect-stdout --
7+
-- expect-stderr --
8+
command.prompter.contents: invalid bytes argument: non-concrete value string:
9+
./task_tool.cue:9:10
10+
./task_tool.cue:17:3
11+
tool/file:11:3
12+
command.prompter.filename: invalid string argument: non-concrete value string:
13+
./task_tool.cue:9:10
14+
tool/file:9:3
15+
-- task_tool.cue --
16+
package foo
17+
18+
import (
19+
"tool/cli"
20+
"tool/file"
21+
)
22+
23+
24+
command: prompter: {
25+
ask: cli.Ask & {
26+
prompt: "What is your name?"
27+
response: string
28+
}
29+
30+
// inadvertently defined at top level, masking other tasks.
31+
file.Append & {
32+
contents: ask.response
33+
}
34+
}

internal/task/task.go

Lines changed: 53 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ import (
2222

2323
"cuelang.org/go/cue"
2424
"cuelang.org/go/cue/errors"
25+
"cuelang.org/go/cue/token"
26+
"cuelang.org/go/internal"
27+
"cuelang.org/go/internal/core/adt"
2528
)
2629

2730
// A Context provides context for running a task.
@@ -37,8 +40,7 @@ type Context struct {
3740
func (c *Context) Lookup(field string) cue.Value {
3841
f := c.Obj.Lookup(field)
3942
if !f.Exists() {
40-
c.Err = errors.Append(c.Err, errors.Newf(c.Obj.Pos(),
41-
"could not find field %q", field))
43+
c.addErr(f, nil, "could not find field %q", field)
4244
return cue.Value{}
4345
}
4446
if err := f.Err(); err != nil {
@@ -53,8 +55,7 @@ func (c *Context) Int64(field string) int64 {
5355
if err != nil {
5456
// TODO: use v for position for now, as f has not yet a
5557
// position associated with it.
56-
c.Err = errors.Append(c.Err, errors.Wrapf(err, c.Obj.Pos(),
57-
"invalid integer argument for field %q", field))
58+
c.addErr(f, err, "invalid integer argument")
5859
return 0
5960
}
6061
return value
@@ -66,9 +67,7 @@ func (c *Context) String(field string) string {
6667
if err != nil {
6768
// TODO: use v for position for now, as f has not yet a
6869
// position associated with it.
69-
c.Err = errors.Append(c.Err, errors.Wrapf(err, c.Obj.Pos(),
70-
"invalid string argument for field %q", field))
71-
c.Err = errors.Promote(err, "ddd")
70+
c.addErr(f, err, "invalid string argument")
7271
return ""
7372
}
7473
return value
@@ -78,15 +77,58 @@ func (c *Context) Bytes(field string) []byte {
7877
f := c.Obj.Lookup(field)
7978
value, err := f.Bytes()
8079
if err != nil {
81-
// TODO: use v for position for now, as f has not yet a
82-
// position associated with it.
83-
c.Err = errors.Append(c.Err, errors.Wrapf(err, c.Obj.Pos(),
84-
"invalid bytes argument for field %q", field))
80+
c.addErr(f, err, "invalid bytes argument")
8581
return nil
8682
}
8783
return value
8884
}
8985

86+
func (c *Context) addErr(v cue.Value, wrap error, format string, args ...interface{}) {
87+
88+
err := &taskError{
89+
task: c.Obj,
90+
v: v,
91+
Message: errors.NewMessage(format, args),
92+
err: wrap,
93+
}
94+
c.Err = errors.Append(c.Err, err)
95+
}
96+
97+
// taskError wraps some error values to retain position information about the
98+
// error.
99+
type taskError struct {
100+
task cue.Value
101+
v cue.Value
102+
errors.Message
103+
err error
104+
}
105+
106+
var _ errors.Error = &taskError{}
107+
108+
func (t *taskError) Path() (a []string) {
109+
for _, x := range t.v.Path().Selectors() {
110+
a = append(a, x.String())
111+
}
112+
return a
113+
}
114+
115+
func (t *taskError) Position() token.Pos {
116+
return t.task.Pos()
117+
}
118+
119+
func (t *taskError) InputPositions() (a []token.Pos) {
120+
_, nx := internal.CoreValue(t.v)
121+
122+
for _, x := range nx.(*adt.Vertex).Conjuncts {
123+
if src := x.Source(); src != nil {
124+
a = append(a, src.Pos())
125+
}
126+
}
127+
return a
128+
}
129+
130+
func (t *taskError) Unwrap() error { return t.err }
131+
90132
// A RunnerFunc creates a Runner.
91133
type RunnerFunc func(v cue.Value) (Runner, error)
92134

0 commit comments

Comments
 (0)