Skip to content

Commit

Permalink
improve egctl to support sending multi configs at once (fix #29) (#230)
Browse files Browse the repository at this point in the history
* improve egctl to support sending multi configs at once (fix #29)

* add a visitor to do the YAML parsing

* rollback function readFromFileOrStdin

* Update comments.

Co-authored-by: Bomin Zhang <[email protected]>

* some improvements
- change the signature of VisitorFunc
- remove useless function readFromFileOrStdin

Co-authored-by: Bomin Zhang <[email protected]>
  • Loading branch information
nevill and localvar committed Sep 7, 2021
1 parent 767eb6d commit 4749392
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 18 deletions.
14 changes: 2 additions & 12 deletions cmd/client/command/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ func printBody(body []byte) {
fmt.Printf("%s", output)
}

func readFromFileOrStdin(specFile string, cmd *cobra.Command) ([]byte, string) {
func buildVisitorFromFileOrStdin(specFile string, cmd *cobra.Command) Visitor {
var buff []byte
var err error
if specFile != "" {
Expand All @@ -177,15 +177,5 @@ func readFromFileOrStdin(specFile string, cmd *cobra.Command) ([]byte, string) {
ExitWithErrorf("%s failed: %v", cmd.Short, err)
}
}

var spec struct {
Kind string `yaml:"kind"`
Name string `yaml:"name"`
}
err = yaml.Unmarshal(buff, &spec)
if err != nil {
ExitWithErrorf("%s failed, invalid spec: %v", cmd.Short, err)
}

return buff, spec.Name
return NewStreamVisitor(string(buff))
}
12 changes: 8 additions & 4 deletions cmd/client/command/object.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@ func createObjectCmd() *cobra.Command {
Use: "create",
Short: "Create an object from a yaml file or stdin",
Run: func(cmd *cobra.Command, args []string) {
buff, _ := readFromFileOrStdin(specFile, cmd)
handleRequest(http.MethodPost, makeURL(objectsURL), buff, cmd)
visitor := buildVisitorFromFileOrStdin(specFile, cmd)
visitor.Visit(func(s *spec) {
handleRequest(http.MethodPost, makeURL(objectsURL), []byte(s.doc), cmd)
})
},
}

Expand All @@ -77,8 +79,10 @@ func updateObjectCmd() *cobra.Command {
Use: "update",
Short: "Update an object from a yaml file or stdin",
Run: func(cmd *cobra.Command, args []string) {
buff, name := readFromFileOrStdin(specFile, cmd)
handleRequest(http.MethodPut, makeURL(objectURL, name), buff, cmd)
visitor := buildVisitorFromFileOrStdin(specFile, cmd)
visitor.Visit(func(s *spec) {
handleRequest(http.MethodPost, makeURL(objectsURL), []byte(s.doc), cmd)
})
},
}

Expand Down
80 changes: 80 additions & 0 deletions cmd/client/command/visitor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package command

import (
"bufio"
"io"
"strings"

"k8s.io/apimachinery/pkg/util/yaml"
)

// VisitorFunc executes visition logic
type VisitorFunc func(*spec)

// Visitor walk through the document via VisitorFunc
type Visitor interface {
Visit(VisitorFunc)
}

type spec struct {
Kind string
Name string
doc string
}

type streamVisitor struct {
io.Reader
}

// NewStreamVisitor returns a streamVisitor.
func NewStreamVisitor(src string) *streamVisitor {
return &streamVisitor{
Reader: strings.NewReader(src),
}
}

type yamlDecoder struct {
reader *yaml.YAMLReader
doc string
}

func newYAMLDecoder(r io.Reader) *yamlDecoder {
return &yamlDecoder{
reader: yaml.NewYAMLReader(bufio.NewReader(r)),
}
}

// Decode reads a YAML document into bytes and tries to yaml.Unmarshal it.
func (d *yamlDecoder) Decode(into interface{}) error {
bytes, err := d.reader.Read()
if err != nil && err != io.EOF {
return err
}
d.doc = string(bytes)
if len(bytes) != 0 {
err = yaml.Unmarshal(bytes, into)
}
return err
}

// Visit implements Visitor over a stream.
func (v *streamVisitor) Visit(fn VisitorFunc) {
d := newYAMLDecoder(v.Reader)
var validSpecs []spec
for {
var s spec
if err := d.Decode(&s); err != nil {
if err == io.EOF {
break
} else {
ExitWithErrorf("error parsing %s: %v", d.doc, err)
}
}
s.doc = d.doc
//TODO can validate spec's Kind here
validSpecs = append(validSpecs, s)
}
for _, s := range validSpecs {
fn(&s)
}
}
6 changes: 4 additions & 2 deletions cmd/client/command/wasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,10 @@ func wasmApplyDataCmd() *cobra.Command {
},

Run: func(cmd *cobra.Command, args []string) {
buf, _ := readFromFileOrStdin(specFile, cmd)
handleRequest(http.MethodPut, makeURL(wasmDataURL, args[0], args[1]), buf, cmd)
visitor := buildVisitorFromFileOrStdin(specFile, cmd)
visitor.Visit(func(s *spec) {
handleRequest(http.MethodPost, makeURL(objectsURL), []byte(s.doc), cmd)
})
},
}
cmd.Flags().StringVarP(&specFile, "file", "f", "", "A yaml file specifying the object.")
Expand Down

0 comments on commit 4749392

Please sign in to comment.