[engine] Improve error messages when run in invalid directory
1. --var flags are not validated until after shac determines that the
working directory is valid (i.e. contains a shac.star file).
2. If a shac.star file cannot be discovered via git, print the expected
location of the shac.star file.
3. If a --var flag is specified but no shac.textproto file exists, use a
slightly different error message to make it more clear that
shac.textproto doesn't exist yet.
Change-Id: I6bed59f60b73e9ecff0caec97c152f2f7ea94fb7
Reviewed-on: https://fuchsia-review.googlesource.com/c/shac-project/shac/+/926852
Reviewed-by: Anthony Fandrianto <atyfto@google.com>
Fuchsia-Auto-Submit: Oliver Newman <olivernewman@google.com>
Commit-Queue: Auto-Submit <auto-submit@fuchsia-infra.iam.gserviceaccount.com>
diff --git a/internal/engine/run.go b/internal/engine/run.go
index 827c489..4901e3e 100644
--- a/internal/engine/run.go
+++ b/internal/engine/run.go
@@ -224,7 +224,9 @@
}
var b []byte
doc := Document{}
+ configExists := false
if b, err = os.ReadFile(absConfig); err == nil {
+ configExists = true
// First parse the config file ignoring unknown fields and check only
// min_shac_version, so users get an "unsupported version" error if they
// set fields that are only available in a later version of shac (as
@@ -277,17 +279,6 @@
scm = &cachingSCM{scm: scm}
}
- vars := make(map[string]string)
- for _, v := range doc.Vars {
- vars[v.Name] = v.Default
- }
- for name, value := range o.Vars {
- if _, ok := vars[name]; !ok {
- return fmt.Errorf("var not declared in %s: %s", config, name)
- }
- vars[name] = value
- }
-
pkgMgr := NewPackageManager(tmpdir)
packages, err := pkgMgr.RetrievePackages(ctx, root, &doc)
if err != nil {
@@ -304,7 +295,28 @@
packages: packages,
}
- newState := func(scm scmCheckout, subdir string, idx int) *shacState {
+ var vars map[string]string
+
+ newState := func(scm scmCheckout, subdir string, idx int) (*shacState, error) {
+ // Lazy-load vars only once a shac.star file is detected, so that errors
+ // about missing shac.star files are prioritized over var validation
+ // errors.
+ if vars == nil {
+ vars = make(map[string]string)
+ for _, v := range doc.Vars {
+ vars[v.Name] = v.Default
+ }
+ for name, value := range o.Vars {
+ if _, ok := vars[name]; !ok {
+ if configExists {
+ return nil, fmt.Errorf("var not declared in %s: %s", config, name)
+ }
+ return nil, fmt.Errorf("var must be declared in a %s file: %s", config, name)
+ }
+ vars[name] = value
+ }
+ }
+
if subdir != "" {
normalized := subdir + "/"
if subdir == "." {
@@ -327,7 +339,7 @@
writableRoot: doc.WritableRoot,
vars: vars,
passthroughEnv: doc.PassthroughEnv,
- }
+ }, nil
}
var shacStates []*shacState
if o.Recurse {
@@ -363,13 +375,27 @@
}
}
if len(subdirs) == 0 {
- return fmt.Errorf("no %s files found", entryPoint)
+ return fmt.Errorf("no %s files found in %s", entryPoint, root)
}
for i, s := range subdirs {
- shacStates = append(shacStates, newState(scm, s, i))
+ state, err := newState(scm, s, i)
+ if err != nil {
+ return err
+ }
+ shacStates = append(shacStates, state)
}
} else {
- shacStates = []*shacState{newState(scm, "", 0)}
+ if _, err := os.Stat(filepath.Join(root, entryPoint)); err != nil {
+ if errors.Is(err, fs.ErrNotExist) {
+ return fmt.Errorf("no %s file in repository root: %s", entryPoint, root)
+ }
+ return err
+ }
+ state, err := newState(scm, "", 0)
+ if err != nil {
+ return err
+ }
+ shacStates = []*shacState{state}
}
// Parse the starlark files. Run everything from our errgroup.
diff --git a/internal/engine/run_test.go b/internal/engine/run_test.go
index 4f20284..da01076 100644
--- a/internal/engine/run_test.go
+++ b/internal/engine/run_test.go
@@ -113,19 +113,32 @@
{
"no shac.star file",
Options{
- Dir: t.TempDir(),
+ Dir: scratchDir,
+ EntryPoint: "entrypoint.star",
},
- // TODO(olivernewman): This error should be more specific, like "no
- // shac.star file found".
- "shac.star not found",
+ fmt.Sprintf("no entrypoint.star file in repository root: %s", scratchDir),
+ },
+ {
+ "no shac.star file and invalid vars",
+ Options{
+ Dir: scratchDir,
+ EntryPoint: "entrypoint.star",
+ Vars: map[string]string{
+ "this_is_an_invalid_var": "foo",
+ },
+ },
+ // Missing entrypoint file errors should be prioritized over invalid
+ // var errors.
+ fmt.Sprintf("no entrypoint.star file in repository root: %s", scratchDir),
},
{
"no shac.star files (recursive)",
Options{
- Dir: t.TempDir(),
- Recurse: true,
+ Dir: scratchDir,
+ Recurse: true,
+ EntryPoint: "entrypoint.star",
},
- "no shac.star files found",
+ fmt.Sprintf("no entrypoint.star files found in %s", scratchDir),
},
{
"nonexistent directory",
@@ -153,6 +166,20 @@
},
"var not declared in shac.textproto: unknown_var",
},
+ {
+ "invalid var with no config file",
+ func() Options {
+ root := t.TempDir()
+ writeFile(t, root, "shac.star", ``)
+ return Options{
+ Dir: root,
+ Vars: map[string]string{
+ "unknown_var": "",
+ },
+ }
+ }(),
+ "var must be declared in a shac.textproto file: unknown_var",
+ },
}
for i := range data {
i := i
diff --git a/internal/engine/version.go b/internal/engine/version.go
index ef48033..9a5ab01 100644
--- a/internal/engine/version.go
+++ b/internal/engine/version.go
@@ -26,7 +26,7 @@
// Version is the current tool version.
//
// TODO(maruel): Add proper version, preferably from git tag.
- Version = shacVersion{0, 1, 10}
+ Version = shacVersion{0, 1, 11}
)
func (v shacVersion) String() string {