cmd/cue/cmd: move injection mechanism to cue/load
Less cmd/cue-specific code and prepares for build tag
support.
Change-Id: Ie9e6397b5c046de601d48cf876dac1ae662bdc69
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/7063
Reviewed-by: CUE cueckoo <cueckoo@gmail.com>
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
diff --git a/cmd/cue/cmd/common.go b/cmd/cue/cmd/common.go
index a7a75ab..0b03a1c 100644
--- a/cmd/cue/cmd/common.go
+++ b/cmd/cue/cmd/common.go
@@ -376,11 +376,12 @@
return nil, err
}
+ cfg.loadCfg.Tags = flagInject.StringArray(cmd)
+
builds := loadFromArgs(cmd, args, cfg.loadCfg)
if builds == nil {
return nil, errors.Newf(token.NoPos, "invalid args")
}
- decorateInstances(cmd, flagInject.StringArray(cmd), builds)
for _, b := range builds {
if b.Err != nil {
@@ -571,7 +572,12 @@
}
func buildTools(cmd *Command, tags, args []string) (*cue.Instance, error) {
- binst := loadFromArgs(cmd, args, &load.Config{Tools: true})
+
+ cfg := &load.Config{
+ Tags: tags,
+ Tools: true,
+ }
+ binst := loadFromArgs(cmd, args, cfg)
if len(binst) == 0 {
return nil, nil
}
@@ -593,7 +599,6 @@
}
inst.Files = inst.Files[:k]
}
- decorateInstances(cmd, tags, append(binst, ti))
insts, err := buildToolInstances(cmd, binst)
if err != nil {
diff --git a/cue/load/config.go b/cue/load/config.go
index 6a84732..d32f080 100644
--- a/cue/load/config.go
+++ b/cue/load/config.go
@@ -150,11 +150,62 @@
// If Dir is empty, the tool is run in the current directory.
Dir string
- // The build and release tags specify build constraints that should be
- // considered satisfied when processing +build lines. Clients creating a new
- // context may customize BuildTags, which defaults to empty, but it is
- // usually an error to customize ReleaseTags, which defaults to the list of
- // CUE releases the current release is compatible with.
+ // Tags defines boolean tags or key-value pairs to select files to build
+ // or be injected as values in fields.
+ //
+ // Each string is of the form
+ //
+ // key [ "=" value ]
+ //
+ // where key is a valid CUE identifier and value valid CUE scalar.
+ //
+ // The Tags values are used to both select which files get included in a
+ // build and to inject values into the AST.
+ //
+ //
+ // Value injection
+ //
+ // The Tags values are also used to inject values into fields with a
+ // @tag attribute.
+ //
+ // For any field of the form
+ //
+ // field: x @tag(key)
+ //
+ // and Tags value for which the name matches key, the field will be
+ // modified to
+ //
+ // field: x & "value"
+ //
+ // By default, the injected value is treated as a string. Alternatively, a
+ // "type" option of the @tag attribute allows a value to be interpreted as
+ // an int, number, or bool. For instance, for a field
+ //
+ // field: x @tag(key,type=int)
+ //
+ // an entry "key=2" modifies the field to
+ //
+ // field: x & 2
+ //
+ // Valid values for type are "int", "number", "bool", and "string".
+ //
+ // A @tag attribute can also define shorthand values, which can be injected
+ // into the fields without having to specify the key. For instance, for
+ //
+ // environment: string @tag(env,short=prod|staging)
+ //
+ // the Tags entry "prod" sets the environment field to the value "prod".
+ // This is equivalent to a Tags entry of "env=prod".
+ //
+ // The use of @tag does not preclude using any of the usual CUE constraints
+ // to limit the possible values of a field. For instance
+ //
+ // environment: "prod" | "staging" @tag(env,short=prod|staging)
+ //
+ // ensures the user may only specify "prod" or "staging".
+ Tags []string
+
+ // Deprecated: use Tags
BuildTags []string
releaseTags []string
diff --git a/cue/load/loader.go b/cue/load/loader.go
index c589296..da5a590 100644
--- a/cue/load/loader.go
+++ b/cue/load/loader.go
@@ -84,6 +84,14 @@
a = append(a, l.cueFilesPackage(files))
}
+ // TODO(api): have API call that returns an error which is the aggregate
+ // of all build errors. Certain errors, like these, hold across builds.
+ if err := injectTags(c.Tags, l.tags); err != nil {
+ for _, p := range a {
+ p.ReportError(err)
+ }
+ }
+
return a
}
@@ -102,8 +110,9 @@
)
type loader struct {
- cfg *Config
- stk importStack
+ cfg *Config
+ stk importStack
+ tags []tag // tags found in files
}
func (l *loader) abs(filename string) string {
@@ -195,6 +204,11 @@
}
d.Close()
}
+ tags, err := findTags(p)
+ if err != nil {
+ p.ReportError(err)
+ }
+ l.tags = append(l.tags, tags...)
}
func cleanImport(path string) string {
diff --git a/cmd/cue/cmd/tags.go b/cue/load/tags.go
similarity index 92%
rename from cmd/cue/cmd/tags.go
rename to cue/load/tags.go
index 00912ef..fad4d48 100644
--- a/cmd/cue/cmd/tags.go
+++ b/cue/load/tags.go
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-package cmd
+package load
import (
"strings"
@@ -26,13 +26,6 @@
"cuelang.org/go/internal/cli"
)
-func decorateInstances(cmd *Command, tags []string, a []*build.Instance) {
- if len(tags) == 0 {
- return
- }
- exitOnErr(cmd, injectTags(tags, a), true)
-}
-
// A tag binds an identifier to a field to allow passing command-line values.
//
// A tag is of the form
@@ -145,16 +138,7 @@
return tags, errs
}
-func injectTags(tags []string, b []*build.Instance) errors.Error {
- var a []tag
- for _, p := range b {
- x, err := findTags(p)
- if err != nil {
- return err
- }
- a = append(a, x...)
- }
-
+func injectTags(tags []string, a []tag) errors.Error {
// Parses command line args
for _, s := range tags {
p := strings.Index(s, "=")