Skip to content

Commit

Permalink
yaml-parse,yamlutils: Support multiple documents in a single yaml input
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidGamba committed Feb 1, 2022
1 parent 2eca04d commit f2fdae6
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 33 deletions.
2 changes: 1 addition & 1 deletion yaml-parse/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module github.com/DavidGamba/dgtools/yaml-parse

require (
github.com/DavidGamba/dgtools/yamlutils v0.0.0
github.com/DavidGamba/go-getoptions v0.23.0
github.com/DavidGamba/go-getoptions v0.25.3
)

replace github.com/DavidGamba/dgtools => ../
Expand Down
6 changes: 2 additions & 4 deletions yaml-parse/go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
github.com/DavidGamba/go-getoptions v0.21.0 h1:nVyFTaDSacJ1Sb3kRB4RgxNkGhf+b8khQ0M/ldihwS0=
github.com/DavidGamba/go-getoptions v0.21.0/go.mod h1:wYjd1McJbGzBFD61+lahGR+5A8QGA1aBnRZmfkBLy5A=
github.com/DavidGamba/go-getoptions v0.23.0 h1:j8q36PvconcXzKphnnOmmUcKGpcpHfbaAZ/FD0qwdd0=
github.com/DavidGamba/go-getoptions v0.23.0/go.mod h1:qLaLSYeQ8sUVOfKuu5JT5qKKS3OCwyhkYSJnoG+ggmo=
github.com/DavidGamba/go-getoptions v0.25.3 h1:lSPcMkwWvVZU05C+Uz4DKnKN5wz4bcD1QvJ/QHCRexo=
github.com/DavidGamba/go-getoptions v0.25.3/go.mod h1:qLaLSYeQ8sUVOfKuu5JT5qKKS3OCwyhkYSJnoG+ggmo=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
Expand Down
25 changes: 21 additions & 4 deletions yaml-parse/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func program(args []string) int {
opt := getoptions.New()
opt.Self("", `Parses YAML input passed from file or piped to STDIN and filters it by key or index.
Source: https://github.com/DavidGamba/dgtools`)
Source: https://github.com/DavidGamba/dgtools`)
opt.Bool("help", false, opt.Alias("?"))
opt.Bool("debug", false)
opt.Bool("version", false, opt.Alias("V"))
Expand All @@ -46,6 +46,7 @@ func program(args []string) int {
opt.Description(`Key or index to descend to.
Multiple keys allow to descend further.
Indexes are positive integers.`))
opt.IntOptional("document", 1, opt.Description("Document number"), opt.Alias("d"), opt.ArgName("number"))
_, err := opt.Parse(os.Args[1:])
if opt.Called("help") {
fmt.Println(opt.Help())
Expand Down Expand Up @@ -90,11 +91,11 @@ func realMain(opt *getoptions.GetOpt) error {
stdinIsDevice := (statStdin.Mode() & os.ModeDevice) != 0

var err error
var yml *yamlutils.YML
var ymlList []*yamlutils.YML
if !stdinIsDevice && !opt.Called("file") {
Logger.Printf("Reading from stdin\n")
reader := os.Stdin
yml, err = yamlutils.NewFromReader(reader)
ymlList, err = yamlutils.NewFromReader(reader)
if err != nil {
return fmt.Errorf("reading yaml from STDIN: %w", err)
}
Expand All @@ -103,13 +104,29 @@ func realMain(opt *getoptions.GetOpt) error {
if !opt.Called("file") {
return fmt.Errorf("missing argument '--file <file>'")
}
yml, err = yamlutils.NewFromFile(file)
ymlList, err = yamlutils.NewFromFile(file)
if err != nil {
fmt.Fprintf(os.Stderr, "ERROR: reading yaml file: %s\n", err)
os.Exit(1)
}
}

if !opt.Called("document") && len(ymlList) > 1 {
fmt.Fprintf(os.Stderr,
`WARNING: provided input contains %d YAML documents
specify '--document <number>' to remove this warning
`, len(ymlList))
}

n := 0
if opt.Called("document") {
n = opt.Value("document").(int) - 1
}
if len(ymlList) < n+1 {
return fmt.Errorf("wrong document number: %d", n+1)
}
yml := ymlList[n]

if opt.Called("add") {
str, err := yml.AddString(xpath, add)
if err != nil {
Expand Down
62 changes: 38 additions & 24 deletions yamlutils/yamlutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ Package yamlutils - Utilities to read yml files like if using xpath
package yamlutils

import (
"bytes"
"errors"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"strconv"
"strings"

Expand All @@ -39,33 +39,47 @@ type YML struct {
Tree interface{}
}

// NewFromFile returns a pointer to a YML object from a file.
func NewFromFile(filename string) (*YML, error) {
data, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
var tree interface{}
err = yaml.Unmarshal(data, &tree)
if err != nil {
return nil, err
// NewFromFile returns a list of pointers to a YML object from a file.
//
// Returns a list since YAML files can contain multiple documents:
// https://yaml.org/spec/1.2-old/spec.html#id2800401
func NewFromFile(filename string) ([]*YML, error) {
list := []*YML{}
fh, err := os.Open(filename)
decoder := yaml.NewDecoder(fh)
for {
var tree interface{}
err = decoder.Decode(&tree)
if err != nil {
if !errors.Is(err, io.EOF) {
return nil, err
}
break
}
list = append(list, &YML{Tree: tree})
}
return &YML{Tree: tree}, nil
return list, nil
}

// NewFromReader returns a pointer to a YML object from an io.Reader.
func NewFromReader(reader io.Reader) (*YML, error) {
var tree interface{}
buf := new(bytes.Buffer)
_, err := buf.ReadFrom(reader)
if err != nil {
return nil, err
}
err = yaml.Unmarshal(buf.Bytes(), &tree)
if err != nil {
return nil, err
// NewFromReader returns a list of pointers to a YML object from an io.Reader.
//
// Returns a list since YAML files can contain multiple documents:
// https://yaml.org/spec/1.2-old/spec.html#id2800401
func NewFromReader(reader io.Reader) ([]*YML, error) {
list := []*YML{}
decoder := yaml.NewDecoder(reader)
for {
var tree interface{}
err := decoder.Decode(&tree)
if err != nil {
if !errors.Is(err, io.EOF) {
return nil, err
}
break
}
list = append(list, &YML{Tree: tree})
}
return &YML{Tree: tree}, nil
return list, nil
}

// NewFromString - returns a pointer to a YML object from a string.
Expand Down

0 comments on commit f2fdae6

Please sign in to comment.