cmd/cue/cmd: improve $after semantics and errors
- report error if not a reference
- reference must be exact (may not point inside task)
- reference may refer to task group
Issue #245
Change-Id: Ib210ab38e0cb6bb750d4c020f9e7138442169ac3
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/4906
Reviewed-by: Grant Zvolský <grant@zvolsky.org>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cmd/cue/cmd/custom.go b/cmd/cue/cmd/custom.go
index 6f592c9..ab4cc24 100644
--- a/cmd/cue/cmd/custom.go
+++ b/cmd/cue/cmd/custom.go
@@ -19,7 +19,6 @@
import (
"context"
"encoding/json"
- "errors"
"fmt"
"io"
"io/ioutil"
@@ -33,6 +32,7 @@
"golang.org/x/sync/errgroup"
"cuelang.org/go/cue"
+ "cuelang.org/go/cue/errors"
"cuelang.org/go/internal"
itask "cuelang.org/go/internal/task"
"cuelang.org/go/internal/walk"
@@ -129,7 +129,7 @@
}
func keyForReference(ref ...string) (k taskKey) {
- return taskKey(strings.Join(ref, "\000"))
+ return taskKey(strings.Join(ref, "\000") + "\000")
}
func (r *customRunner) taskPath(t *task) []string {
@@ -146,14 +146,38 @@
return err
}
-func (r *customRunner) referredTask(ref cue.Value) (t *task, ok bool) {
+func (r *customRunner) tagReference(t *task, ref cue.Value) error {
inst, path := ref.Reference()
- if path != nil && inst == r.root {
- if task := r.findTask(path); task != nil {
- return task, true
+ if len(path) == 0 {
+ return errors.Newf(ref.Pos(),
+ "$after must be a reference or list of references, found %s", ref)
+ }
+ if inst != r.root {
+ return errors.Newf(ref.Pos(),
+ "reference in $after must refer to value in same package")
+ }
+ // TODO: allow referring to group of tasks.
+ if !r.tagDependencies(t, path) {
+ return errors.Newf(ref.Pos(),
+ "reference %s does not refer to task or task group",
+ strings.Join(path, "."), // TODO: more correct representation.
+ )
+
+ }
+ return nil
+}
+
+// tagDependencies marks dependencies in t correpsoning to ref
+func (r *customRunner) tagDependencies(t *task, ref []string) bool {
+ found := false
+ prefix := keyForReference(ref...)
+ for key, task := range r.index {
+ if strings.HasPrefix(string(key), string(prefix)) {
+ found = true
+ t.dep[task] = true
}
}
- return nil, false
+ return found
}
func (r *customRunner) findTask(ref []string) *task {
@@ -221,14 +245,15 @@
// Inject dependency in `$after` field
after := task.Lookup("$after")
if after.Err() == nil {
- if dep, ok := cr.referredTask(after); ok {
- t.dep[dep] = true
- }
- for iter, _ := after.List(); iter.Next(); {
- if dep, ok := cr.referredTask(iter.Value()); ok {
- t.dep[dep] = true
+ if after.Kind() != cue.ListKind {
+ err = cr.tagReference(t, after)
+ } else {
+ for iter, _ := after.List(); iter.Next(); {
+ err = cr.tagReference(t, iter.Value())
+ exitIfErr(cmd, inst, err, true)
}
}
+ exitIfErr(cmd, inst, err, true)
}
task.Walk(func(v cue.Value) bool {
diff --git a/cmd/cue/cmd/testdata/script/cmd_after.txt b/cmd/cue/cmd/testdata/script/cmd_after.txt
index a2704c3..44ac1a8 100644
--- a/cmd/cue/cmd/testdata/script/cmd_after.txt
+++ b/cmd/cue/cmd/testdata/script/cmd_after.txt
@@ -4,6 +4,7 @@
-- expect-stdout --
true
+SUCCESS
-- after_tool.cue --
package home
@@ -14,21 +15,25 @@
)
command: after: {
- t1: exec.Run & {
- cmd: ["sh", "-c", "sleep 2; date +%s"]
- stdout: string
- }
- t2: exec.Run & {
- cmd: ["sh", "-c", "date +%s"]
- stdout: string
- $after: t1
+ group: {
+ t1: exec.Run & {
+ cmd: ["sh", "-c", "sleep 2; date +%s"]
+ stdout: string
+ }
+ t2: exec.Run & {
+ cmd: ["sh", "-c", "date +%s"]
+ stdout: string
+ $after: t1
+ }
}
t3: exec.Run & {
- cmd: ["sh", "-c", "a=\(strings.TrimSpace(t1.stdout));b=\(strings.TrimSpace(t2.stdout));if [ $a -le $b ]; then echo 'true'; fi"]
+ cmd: ["sh", "-c", "a=\(strings.TrimSpace(group.t1.stdout));b=\(strings.TrimSpace(group.t2.stdout));if [ $a -le $b ]; then echo 'true'; fi"]
stdout: string
}
- t4: cli.Print & {
- text: t3.stdout
+ t4: cli.Print & { text: t3.stdout }
+ t5: cli.Print & {
+ text: "SUCCESS"
+ $after: [ group, t4 ]
}
}