Skip to content

Commit

Permalink
add yamldocs as output format, automagically read multi-document YAML…
Browse files Browse the repository at this point in the history
… files as vectors
  • Loading branch information
xrstf committed Jan 4, 2024
1 parent 9f297c8 commit ea75efe
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 42 deletions.
35 changes: 3 additions & 32 deletions cmd/rudi/cmd/script/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,15 @@ package script

import (
"context"
"encoding/json"
"errors"
"fmt"
"os"
"strings"

"go.xrstf.de/rudi"
"go.xrstf.de/rudi/cmd/rudi/encoding"
"go.xrstf.de/rudi/cmd/rudi/options"
"go.xrstf.de/rudi/cmd/rudi/types"
"go.xrstf.de/rudi/cmd/rudi/util"

"github.com/BurntSushi/toml"
"gopkg.in/yaml.v3"
)

func Run(handler *util.SignalHandler, opts *options.Options, args []string) error {
Expand Down Expand Up @@ -86,34 +82,9 @@ func Run(handler *util.SignalHandler, opts *options.Options, args []string) erro
}

// print the output
var encoder interface {
Encode(v any) error
}

switch opts.OutputFormat {
case types.JsonEncoding:
encoder = json.NewEncoder(os.Stdout)
encoder.(*json.Encoder).SetIndent("", " ")
case types.YamlEncoding:
encoder = yaml.NewEncoder(os.Stdout)
encoder.(*yaml.Encoder).SetIndent(2)
case types.TomlEncoding:
encoder = toml.NewEncoder(os.Stdout)
encoder.(*toml.Encoder).Indent = " "
default:
encoder = &rawEncoder{}
}

if err := encoder.Encode(evaluated); err != nil {
return fmt.Errorf("failed to encode %v: %w", evaluated, err)
if err := encoding.Encode(evaluated, opts.OutputFormat, os.Stdout); err != nil {
return fmt.Errorf("failed to encode data: %w", err)
}

return nil
}

type rawEncoder struct{}

func (e *rawEncoder) Encode(v any) error {
fmt.Println(v)
return nil
}
22 changes: 20 additions & 2 deletions cmd/rudi/encoding/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package encoding

import (
"encoding/json"
"errors"
"fmt"
"io"

Expand Down Expand Up @@ -41,8 +42,25 @@ func Decode(input io.Reader, enc types.Encoding) (any, error) {

case types.YamlEncoding:
decoder := yaml.NewDecoder(input)
if err := decoder.Decode(&data); err != nil {
return nil, fmt.Errorf("failed to parse file as YAML: %w", err)

documents := []any{}
for {
var doc any
if err := decoder.Decode(&doc); err != nil {
if errors.Is(err, io.EOF) {
break
}

return nil, fmt.Errorf("failed to parse file as YAML: %w", err)
}

documents = append(documents, doc)
}

if len(documents) == 1 {
data = documents[0]
} else {
data = documents
}

case types.TomlEncoding:
Expand Down
84 changes: 84 additions & 0 deletions cmd/rudi/encoding/encode.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// SPDX-FileCopyrightText: 2024 Christoph Mewes
// SPDX-License-Identifier: MIT

package encoding

import (
"encoding/json"
"fmt"
"io"
"reflect"

"go.xrstf.de/rudi/cmd/rudi/types"

"github.com/BurntSushi/toml"
"gopkg.in/yaml.v3"
)

func newYamlEncoder(out io.Writer) *yaml.Encoder {
encoder := yaml.NewEncoder(out)
encoder.SetIndent(2)

return encoder
}

func Encode(data any, enc types.Encoding, out io.Writer) error {
var encoder interface {
Encode(v any) error
}

switch enc {
case types.JsonEncoding:
encoder = json.NewEncoder(out)
encoder.(*json.Encoder).SetIndent("", " ")
case types.YamlEncoding:
encoder = newYamlEncoder(out)
case types.YamlDocumentsEncoding:
encoder = &yamldocsEncoder{out: out}
case types.TomlEncoding:
encoder = toml.NewEncoder(out)
encoder.(*toml.Encoder).Indent = " "
default:
encoder = &rawEncoder{out: out}
}

return encoder.Encode(data)
}

type rawEncoder struct {
out io.Writer
}

func (e *rawEncoder) Encode(v any) error {
_, err := fmt.Fprintln(e.out, v)
return err
}

type yamldocsEncoder struct {
out io.Writer
}

func (e *yamldocsEncoder) Encode(data any) error {
rValue := reflect.ValueOf(data)
rType := reflect.TypeOf(data)
if rType.Kind() == reflect.Pointer {
rValue = rValue.Elem()
rType = rValue.Type()
}

encoder := newYamlEncoder(e.out)

switch rType.Kind() {
case reflect.Slice, reflect.Array:
for i := 0; i < rValue.Len(); i++ {
value := rValue.Index(i).Interface()
if err := encoder.Encode(value); err != nil {
return err
}
}

return nil
}

return encoder.Encode(data)
}
13 changes: 11 additions & 2 deletions cmd/rudi/options/pflag.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (

type enumValue interface {
fmt.Stringer
IsValid() bool
}

type enumFlag struct {
Expand Down Expand Up @@ -40,7 +39,17 @@ var _ pflag.Value = &enumFlag{}

func (f *enumFlag) Set(s string) error {
newValue := f.stringToEnumValue(s)
if !newValue.IsValid() {

// do not rely on a possible IsValid() on the enum type, as the flag might just be
// accepting a subset of all valid values
valid := false
for _, accepted := range f.values {
if newValue == accepted {
valid = true
break
}
}
if !valid {
return fmt.Errorf("invalid value %q, must be one of %v", s, f.values)
}

Expand Down
25 changes: 19 additions & 6 deletions cmd/rudi/types/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,40 @@ func (e Encoding) IsValid() bool {
}

const (
RawEncoding Encoding = "raw"
JsonEncoding Encoding = "json"
Json5Encoding Encoding = "json5"
YamlEncoding Encoding = "yaml"
TomlEncoding Encoding = "toml"
RawEncoding Encoding = "raw"
JsonEncoding Encoding = "json"
Json5Encoding Encoding = "json5"
YamlEncoding Encoding = "yaml"
YamlDocumentsEncoding Encoding = "yamldocs"
TomlEncoding Encoding = "toml"
)

var (
AllEncodings = []Encoding{
RawEncoding,
JsonEncoding,
Json5Encoding,
YamlEncoding,
YamlDocumentsEncoding,
TomlEncoding,
}

// InputEncodings contains all valid encodings for reading data.
// Note that YAML is always read in multi-document mode, hence
// YamlDocumentsEncoding is not part of this list.
InputEncodings = []Encoding{
RawEncoding,
JsonEncoding,
Json5Encoding,
YamlEncoding,
TomlEncoding,
}

InputEncodings = AllEncodings
OutputEncodings = []Encoding{
RawEncoding,
JsonEncoding,
YamlEncoding,
YamlDocumentsEncoding,
TomlEncoding,
}
)
Expand Down

0 comments on commit ea75efe

Please sign in to comment.