erros/cue: allow OS-independent error messages
Mostly for testing purposes.
- Strip cwd (more principled than before)
- Convert paths ToSlash in test mode
Change-Id: I24dfdd5b3157df0fe14c1934f559bdfbcd9c353a
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/2260
Reviewed-by: Marcel van Lohuizen <mpvl@google.com>
diff --git a/cmd/cue/cmd/cmd_test.go b/cmd/cue/cmd/cmd_test.go
index e892730..0ad23ff 100644
--- a/cmd/cue/cmd/cmd_test.go
+++ b/cmd/cue/cmd/cmd_test.go
@@ -23,6 +23,8 @@
)
func TestCmd(t *testing.T) {
+ cfg := printConfig(t)
+
testCases := []string{
"echo",
"run",
@@ -48,7 +50,7 @@
}
err = executeTasks("command", name, tools)
if err != nil {
- errors.Print(stdout, err, nil)
+ errors.Print(stdout, err, cfg)
}
return nil
}
diff --git a/cmd/cue/cmd/common.go b/cmd/cue/cmd/common.go
index 3ed7383..b2315cc 100644
--- a/cmd/cue/cmd/common.go
+++ b/cmd/cue/cmd/common.go
@@ -32,6 +32,8 @@
var runtime = &cue.Runtime{}
+var inTest = false
+
func exitIfErr(cmd *cobra.Command, inst *cue.Instance, err error, fatal bool) {
exitOnErr(cmd, err, fatal)
}
@@ -40,10 +42,6 @@
if err == nil {
return
}
- cwd := "////"
- if p, _ := os.Getwd(); p != "" {
- cwd = p
- }
// Link x/text as our localizer.
lang, _ := jibber_jabber.DetectIETF()
@@ -52,12 +50,16 @@
p.Fprintf(w, format, args...)
}
- w := &bytes.Buffer{}
- errors.Print(w, err, &errors.Config{Format: format})
+ cwd, _ := os.Getwd()
- // TODO: do something more principled than this.
+ w := &bytes.Buffer{}
+ errors.Print(w, err, &errors.Config{
+ Format: format,
+ Cwd: cwd,
+ ToSlash: inTest,
+ })
+
b := w.Bytes()
- b = bytes.ReplaceAll(b, []byte(cwd), []byte("."))
cmd.OutOrStderr().Write(b)
if fatal {
exit()
diff --git a/cmd/cue/cmd/common_test.go b/cmd/cue/cmd/common_test.go
index 6a44a37..49b6f87 100644
--- a/cmd/cue/cmd/common_test.go
+++ b/cmd/cue/cmd/common_test.go
@@ -15,14 +15,12 @@
package cmd
import (
- "bytes"
"flag"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
- "regexp"
"testing"
"cuelang.org/go/cue/errors"
@@ -34,16 +32,30 @@
var update = flag.Bool("update", false, "update the test files")
+func printConfig(t *testing.T) *errors.Config {
+ t.Helper()
+
+ inTest = true
+
+ cwd, err := os.Getwd()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ return &errors.Config{
+ Cwd: cwd,
+ ToSlash: true,
+ }
+}
+
func runCommand(t *testing.T, cmd *cobra.Command, name string, args ...string) {
t.Helper()
log.SetFlags(0)
- cwd, err := os.Getwd()
- if err != nil {
- log.Fatal(err)
- }
const dir = "./testdata"
+ cfg := printConfig(t)
+
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
t.Run(path, func(t *testing.T) {
if err != nil {
@@ -72,9 +84,9 @@
switch err := recover().(type) {
case nil:
case panicError:
- errors.Print(wOut, err.Err, nil)
+ errors.Print(wOut, err.Err, cfg)
case error:
- errors.Print(wOut, err, nil)
+ errors.Print(wOut, err, cfg)
default:
fmt.Fprintln(wOut, err)
}
@@ -89,9 +101,6 @@
if err := g.Wait(); err != nil {
t.Error(err)
}
- bOut = bytes.Replace(bOut, []byte(cwd), []byte("$CWD"), -1)
- re := regexp.MustCompile("/.*/cue/")
- bOut = re.ReplaceAll(bOut, []byte(`$$HOME/cue/`))
if *update {
ioutil.WriteFile(testfile, bOut, 0644)
return
diff --git a/cmd/cue/cmd/testdata/tasks/cmd_baddisplay.out b/cmd/cue/cmd/testdata/tasks/cmd_baddisplay.out
index 753329f..39304d4 100644
--- a/cmd/cue/cmd/testdata/tasks/cmd_baddisplay.out
+++ b/cmd/cue/cmd/testdata/tasks/cmd_baddisplay.out
@@ -1,3 +1,3 @@
unsupported op &(int, string):
- $CWD/testdata/tasks/task_tool.cue:29:9
+ ./testdata/tasks/task_tool.cue:29:9
tool/cli:4:9
diff --git a/cue/errors/errors.go b/cue/errors/errors.go
index e5e1a72..9111e65 100644
--- a/cue/errors/errors.go
+++ b/cue/errors/errors.go
@@ -23,6 +23,7 @@
"errors"
"fmt"
"io"
+ "path/filepath"
"sort"
"strings"
@@ -335,6 +336,13 @@
// Format formats the given string and arguments and writes it to w.
// It is used for all printing.
Format func(w io.Writer, format string, args ...interface{})
+
+ // Cwd is the current working directory. Filename positions are taken
+ // relative to this path.
+ Cwd string
+
+ // ToSlash sets whether to use Unix paths. Mostly used for testing.
+ ToSlash bool
}
// Print is a utility function that prints a list of errors to w,
@@ -369,7 +377,32 @@
positions := []string{}
for _, p := range Positions(err) {
- positions = append(positions, p.String())
+ pos := p.Position()
+ s := pos.Filename
+ if cfg.Cwd != "" {
+ if p, err := filepath.Rel(cfg.Cwd, s); err == nil {
+ s = p
+ // Some IDEs (e.g. VSCode) only recognize a path if it start
+ // with a dot. This also helps to distinguish between local
+ // files and builtin packages.
+ if !strings.HasPrefix(s, ".") {
+ s = fmt.Sprintf(".%s%s", string(filepath.Separator), s)
+ }
+ }
+ }
+ if cfg.ToSlash {
+ s = filepath.ToSlash(s)
+ }
+ if pos.IsValid() {
+ if s != "" {
+ s += ":"
+ }
+ s += fmt.Sprintf("%d:%d", pos.Line, pos.Column)
+ }
+ if s == "" {
+ s = "-"
+ }
+ positions = append(positions, s)
}
if path := Path(err); path != nil {