Skip to content

Commit

Permalink
cmd/cue/cmd: simplify usage of --path flag
Browse files Browse the repository at this point in the history
Closes cue-lang#176
Issue cue-lang#193

Change-Id: I95609cec93b0429470f1d7342ab12d45fd9207c7
Reviewed-on: https://cue-review.googlesource.com/c/cue/+/4905
Reviewed-by: Marcel van Lohuizen <mpvl@golang.org>
  • Loading branch information
mpvl committed Feb 7, 2020
1 parent d10e59f commit f8afaed
Show file tree
Hide file tree
Showing 5 changed files with 26 additions and 70 deletions.
86 changes: 21 additions & 65 deletions cmd/cue/cmd/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,9 @@ import (
"github.com/spf13/cobra"
"golang.org/x/sync/errgroup"

"cuelang.org/go/cue"
"cuelang.org/go/cue/ast"
"cuelang.org/go/cue/ast/astutil"
"cuelang.org/go/cue/encoding"
"cuelang.org/go/cue/errors"
"cuelang.org/go/cue/format"
"cuelang.org/go/cue/literal"
"cuelang.org/go/cue/load"
Expand Down Expand Up @@ -125,13 +123,13 @@ Examples:
}
# include the parsed file at the root of the CUE file:
$ cue import -f -l "" foo.yaml
$ cue import -f foo.yaml
$ cat foo.cue
kind: Service
name: booster
# include the import config at the mystuff path
$ cue import -f -l mystuff foo.yaml
$ cue import -f -l '"mystuff"' foo.yaml
$ cat foo.cue
myStuff: {
kind: Service
Expand All @@ -145,16 +143,16 @@ Examples:
name: booster
replicas: 1
# base the path values on th input
$ cue import -f -l '"\(strings.ToLower(kind))" "\(x.name)"' foo.yaml
# base the path values on the input
$ cue import -f -l 'strings.ToLower(kind)' -l name foo.yaml
$ cat foo.cue
service: booster: {
kind: "Service"
name: "booster"
}
# base the path values on the input and file name
$ cue import -f --with-context -l '"\(path.Base(filename))" "\(data.kind)"' foo.yaml
$ cue import -f --with-context -l 'path.Base(filename)' -l data.kind foo.yaml
$ cat foo.cue
"foo.yaml": Service: {
kind: "Service"
Expand All @@ -167,7 +165,7 @@ Examples:
replicas: 1
}
# base the path values on th input
# include all files as list elements
$ cue import -f -list -foo.yaml
$ cat foo.cue
[{
Expand All @@ -179,8 +177,8 @@ Examples:
replicas: 1
}]
# base the path values on th input
$ cue import -f -list -l '"\(strings.ToLower(kind))"' foo.yaml
# collate files with the same path into a list
$ cue import -f -list -l 'strings.ToLower(kind)' foo.yaml
$ cat foo.cue
service: [{
kind: "Service"
Expand Down Expand Up @@ -230,7 +228,7 @@ Example:
cmd.Flags().BoolP(string(flagForce), "f", false, "force overwriting existing files")
cmd.Flags().Bool(string(flagDryrun), false, "only run simulation")

cmd.Flags().StringP(string(flagPath), "l", "", "path to include root")
cmd.Flags().StringArrayP(string(flagPath), "l", nil, "CUE expression for single path component")
cmd.Flags().Bool(string(flagList), false, "concatenate multiple objects into a list")
cmd.Flags().Bool(string(flagFiles), false, "split multiple entries into different files")
cmd.Flags().BoolP(string(flagRecursive), "R", false, "recursively parse string values")
Expand Down Expand Up @@ -397,7 +395,7 @@ func processStream(cmd *Command, pkg, filename string, objs []ast.Expr) error {
}
return nil
} else if len(objs) > 1 {
if !flagList.Bool(cmd) && flagPath.String(cmd) == "" && !flagFiles.Bool(cmd) {
if !flagList.Bool(cmd) && len(flagPath.StringArray(cmd)) == 0 && !flagFiles.Bool(cmd) {
return fmt.Errorf("list, flag, or files flag needed to handle multiple objects in file %q", filename)
}
}
Expand Down Expand Up @@ -456,7 +454,7 @@ func combineExpressions(cmd *Command, pkg, filename string, idx int, objs ...ast
var pathElems []ast.Label

switch {
case flagPath.String(cmd) != "":
case len(flagPath.StringArray(cmd)) > 0:
expr := expr
if flagWithContext.Bool(cmd) {
expr = ast.NewStruct(
Expand All @@ -471,25 +469,17 @@ func combineExpressions(cmd *Command, pkg, filename string, idx int, objs ...ast
return err
}

labels, err := parsePath(flagPath.String(cmd))
if err != nil {
return err
}
for _, l := range labels {
switch x := l.(type) {
case *ast.Interpolation:
v := inst.Eval(x)
if v.Kind() == cue.BottomKind {
return v.Err()
}
pathElems = append(pathElems, v.Syntax().(ast.Label))

case *ast.Ident, *ast.BasicLit:
pathElems = append(pathElems, x)

case *ast.TemplateLabel:
return fmt.Errorf("template labels not supported in path flag")
for _, str := range flagPath.StringArray(cmd) {
l, err := parser.ParseExpr("<path flag>", str)
if err != nil {
return fmt.Errorf(`labels are of form "cue import -l foo -l 'strings.ToLower(bar)'": %v`, err)
}

str, err := inst.Eval(l).String()
if err != nil {
return fmt.Errorf("unsupported label path type: %v", err)
}
pathElems = append(pathElems, ast.NewString(str))
}
}

Expand Down Expand Up @@ -587,40 +577,6 @@ func (x *listIndex) label(label ast.Label) *listIndex {
return idx
}

func parsePath(exprs string) (p []ast.Label, err error) {
f, err := parser.ParseFile("<path flag>", exprs+": _")
if err != nil {
return nil, fmt.Errorf("parser error in path %q: %v", exprs, err)
}

if len(f.Decls) != 1 {
return nil, errors.New("path flag must be a space-separated sequence of labels")
}

for d := f.Decls[0]; ; {
field, ok := d.(*ast.Field)
if !ok {
// This should never happen
return nil, errors.New("%q not a sequence of labels")
}

p = append(p, field.Label)

v, ok := field.Value.(*ast.StructLit)
if !ok {
break
}

if len(v.Elts) != 1 {
// This should never happen
return nil, errors.New("path value may not contain a struct")
}

d = v.Elts[0]
}
return p, nil
}

func newName(filename string, i int) string {
ext := filepath.Ext(filename)
filename = filename[:len(filename)-len(ext)]
Expand Down
2 changes: 1 addition & 1 deletion cmd/cue/cmd/testdata/script/import_context.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cue import -o - -f --with-context -l '"\(path.Ext(filename)):\(index+1)/\(recordCount)" "\(data["@name"])"' ./import
cue import -o - -f --with-context -l '"\(path.Ext(filename)):\(index+1)/\(recordCount)"' -l 'data["@name"]' ./import
cmp stdout expect-stdout
-- expect-stdout --
".jsonl:1/3": elem1: {
Expand Down
2 changes: 1 addition & 1 deletion cmd/cue/cmd/testdata/script/import_hoiststr.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cue import -o - -f --list -l '"\(strings.ToLower(kind))" "\(name)"' --recursive ./import
cue import -o - -f --list -l 'strings.ToLower(kind)' -l name --recursive ./import
cmp stdout expect-stdout
-- expect-stdout --
import json656e63 "encoding/json"
Expand Down
2 changes: 1 addition & 1 deletion cmd/cue/cmd/testdata/script/import_path.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cue import -o - -f -l '"\(strings.ToLower(kind))" "\(name)"' ./import
cue import -o - -f -l 'strings.ToLower(kind)' -l name ./import
cmp stdout expect-stdout
-- expect-stdout --
service: booster: {
Expand Down
4 changes: 2 additions & 2 deletions doc/tutorial/kubernetes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ To accomplish this, we tell `cue` to put each object in the configuration
tree at the path with the "kind" as first element and "name" as second.

```
$ cue import ./... -p kube -l '"\(strings.ToCamel(kind))": "\(metadata.name)"' -f
$ cue import ./... -p kube -l 'strings.ToCamel(kind)' -l metadata.name -f
```

The added `-l` flag defines the labels for each object, based on values from
Expand Down Expand Up @@ -165,7 +165,7 @@ in the configuration files and then converts these recursively.
<-- TODO: update import label format -->

```
$ cue import ./... -p kube -l '"\(strings.ToCamel(kind))": "\(metadata.name)"' -f -R
$ cue import ./... -p kube -l 'strings.ToCamel(kind)' -l metadata.name -f -R
```

Now the file looks like:
Expand Down

0 comments on commit f8afaed

Please sign in to comment.