Compare commits
9
Commits
main
...
52c060b315
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
52c060b315 | ||
|
|
71ebdd8208 | ||
|
|
6162670570 | ||
|
|
ef0ef6e215 | ||
|
|
56844a3c24 | ||
|
|
f52507aa8f | ||
|
|
191c32b743 | ||
|
|
0f8c2f7666 | ||
|
|
ec7a29598d |
No files matched your search
@@ -10,6 +10,7 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strings"
|
"strings"
|
||||||
|
"text/tabwriter"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getVersion() string {
|
func getVersion() string {
|
||||||
@@ -140,15 +141,19 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("\n\nSUMMARY\n\n")
|
fmt.Printf("\n\nSUMMARY\n\n")
|
||||||
fmt.Printf("%-60s %-10s %-10s %-10s %-10s %-10s %-10s\n\n", "SUITE", "COUNT", "PASSED", "FAILURES", "ERRORS", "DISABLED", "SKIPPED")
|
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
|
||||||
|
|
||||||
|
fmt.Fprintf(w, "%s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\t%-10s\n",
|
||||||
|
"SUITE", "COUNT", "PASSED", "FAILURES", "ERRORS", "DISABLED", "SKIPPED")
|
||||||
|
|
||||||
for _, suite := range testsuites.Suites {
|
for _, suite := range testsuites.Suites {
|
||||||
fmt.Printf("%-60s %-10d %-10d %-10d %-10d %-10d %-10d\n",
|
fmt.Fprintf(w, "%s\t%-10d\t%-10d\t%-10d\t%-10d\t%-10d\t%-10d\n",
|
||||||
suite.Name,
|
suite.Name,
|
||||||
suite.TestCount,
|
suite.TestCount,
|
||||||
suite.TestCount-suite.Failures-suite.Errors-suite.Skipped-suite.Disabled,
|
suite.TestCount-suite.Failures-suite.Errors-suite.Skipped-suite.Disabled,
|
||||||
suite.Failures, suite.Errors, suite.Disabled, suite.Skipped)
|
suite.Failures, suite.Errors, suite.Disabled, suite.Skipped)
|
||||||
}
|
}
|
||||||
fmt.Printf("\n%-60s %-10d %-10d %-10d %-10d %-10d %-10d\n",
|
fmt.Fprintf(w, "\n%s\t%10d\t%10d\t%10d\t%10d\t%10d\t%10d\n",
|
||||||
"TOTAL",
|
"TOTAL",
|
||||||
testsuites.Tests,
|
testsuites.Tests,
|
||||||
testsuites.Tests-testsuites.Failures-testsuites.Errors-testsuites.Skipped-testsuites.Disabled,
|
testsuites.Tests-testsuites.Failures-testsuites.Errors-testsuites.Skipped-testsuites.Disabled,
|
||||||
|
|||||||
@@ -1,54 +1,13 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
yaml "github.com/goccy/go-yaml"
|
"github.com/goccy/go-yaml"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
)
|
)
|
||||||
|
|
||||||
var VERBOSITY = 2
|
|
||||||
|
|
||||||
func read(file string) []byte {
|
|
||||||
data, err := os.ReadFile(file)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return data
|
|
||||||
}
|
|
||||||
|
|
||||||
func parse(data []byte) yaml.MapSlice {
|
|
||||||
var result yaml.MapSlice
|
|
||||||
decoder := yaml.NewDecoder(bytes.NewReader(data),
|
|
||||||
yaml.UseOrderedMap())
|
|
||||||
err := decoder.Decode(&result)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
type TypeId int
|
|
||||||
|
|
||||||
const (
|
|
||||||
Map TypeId = iota
|
|
||||||
Slice
|
|
||||||
Scalar
|
|
||||||
)
|
|
||||||
|
|
||||||
func Type(elem any) TypeId {
|
|
||||||
switch elem.(type) {
|
|
||||||
case yaml.MapSlice:
|
|
||||||
return Map
|
|
||||||
case []any:
|
|
||||||
return Slice
|
|
||||||
default:
|
|
||||||
return Scalar
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// hack to be able to compare slices and dictionires that cannot be put into a map.
|
// hack to be able to compare slices and dictionires that cannot be put into a map.
|
||||||
func strval(v any) string {
|
func strval(v any) string {
|
||||||
return fmt.Sprintf("%v", v)
|
return fmt.Sprintf("%v", v)
|
||||||
@@ -86,7 +45,8 @@ func subtract(yaml2 yaml.MapSlice, yaml1 yaml.MapSlice) yaml.MapSlice {
|
|||||||
v1set[strval(v)] = true
|
v1set[strval(v)] = true
|
||||||
}
|
}
|
||||||
s := make([]any, 0)
|
s := make([]any, 0)
|
||||||
for k2, _ := range v2set {
|
for _, v2value := range v2.([]any) {
|
||||||
|
k2 := strval(v2value)
|
||||||
if v1set[k2] {
|
if v1set[k2] {
|
||||||
if VERBOSITY == 2 {
|
if VERBOSITY == 2 {
|
||||||
s = append(s, "<UNMODIFIED>")
|
s = append(s, "<UNMODIFIED>")
|
||||||
@@ -108,44 +68,47 @@ func subtract(yaml2 yaml.MapSlice, yaml1 yaml.MapSlice) yaml.MapSlice {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
func execute(cmd *cobra.Command, args []string) error {
|
func diff(cmd *cobra.Command, args []string) error {
|
||||||
if len(args) != 2 {
|
if len(args) != 2 {
|
||||||
return fmt.Errorf("Parameters expected")
|
return fmt.Errorf("Expected 2 files")
|
||||||
}
|
}
|
||||||
if VERBOSITY < 1 || VERBOSITY > 3 {
|
if VERBOSITY < 0 || VERBOSITY > 3 {
|
||||||
return fmt.Errorf("Array verbosity out of range")
|
return fmt.Errorf("Array verbosity out of range")
|
||||||
}
|
}
|
||||||
file1 := os.Args[1]
|
file1 := args[0]
|
||||||
file2 := os.Args[2]
|
file2 := args[1]
|
||||||
|
|
||||||
yaml1 := parse(read(file1))
|
yaml1, err := parse(read(file1))
|
||||||
yaml2 := parse(read(file2))
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("%s: %w", file1, err))
|
||||||
yaml2 = subtract(yaml2, yaml1)
|
}
|
||||||
|
yaml2, err := parse(read(file2))
|
||||||
enc := yaml.NewEncoder(os.Stdout,
|
if err != nil {
|
||||||
yaml.UseLiteralStyleIfMultiline(true),
|
panic(fmt.Errorf("%s: %w", file2, err))
|
||||||
yaml.Indent(2), // Set indentation
|
|
||||||
//yaml.UseOrderedMap(), // Preserve map order
|
|
||||||
)
|
|
||||||
err := enc.Encode(yaml2)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
|
|
||||||
cmd := &cobra.Command{
|
|
||||||
Use: "yamldiff <file1> <file2>",
|
|
||||||
Short: "Shows one-way difference between yaml files",
|
|
||||||
Long: `
|
|
||||||
Shows the changes in <file2> compared to <file1>`,
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
return execute(cmd, args)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd.PersistentFlags().IntVarP(&VERBOSITY, "array-output-level",
|
diff1 := subtract(yaml2, yaml1)
|
||||||
"v", 1, "Array output level: , 1: only show changed/added values, 2 show identical as <UNMODIFIED>, 3: show all values")
|
diff2 := make(yaml.MapSlice, 0)
|
||||||
|
if SYMMETRIC_DIFF {
|
||||||
|
diff2 = subtract(yaml1, yaml2)
|
||||||
|
}
|
||||||
|
|
||||||
cmd.Execute()
|
diff := diff1
|
||||||
|
if SYMMETRIC_DIFF {
|
||||||
|
diff = make(yaml.MapSlice, 0)
|
||||||
|
diff = append(diff,
|
||||||
|
yaml.MapItem{Key: "forward", Value: diff1},
|
||||||
|
yaml.MapItem{Key: "backward", Value: diff2},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if VERBOSITY > 0 {
|
||||||
|
if err := encode(os.Stdout, diff); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(diff1) > 0 || len(diff2) > 0 {
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/goccy/go-yaml"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func encode(writer io.Writer, data any) error {
|
||||||
|
enc := yaml.NewEncoder(os.Stdout,
|
||||||
|
yaml.UseLiteralStyleIfMultiline(true),
|
||||||
|
yaml.Indent(2), // Set indentation
|
||||||
|
//yaml.UseOrderedMap(), // Preserve map order
|
||||||
|
)
|
||||||
|
return enc.Encode(data)
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/goccy/go-yaml"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"os"
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
|
type MyMap yaml.MapSlice
|
||||||
|
|
||||||
|
func (m *MyMap) Set(key any, value any) {
|
||||||
|
for i := range len(*m) {
|
||||||
|
if (*m)[i].Key == key {
|
||||||
|
(*m)[i].Value = value
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*m = append(*m, yaml.MapItem{Key: key, Value: value})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m MyMap) Get(key any) any {
|
||||||
|
for _, item := range m {
|
||||||
|
if item.Key == key {
|
||||||
|
return item.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mergeMap(yaml1 yaml.MapSlice, yaml2 yaml.MapSlice) yaml.MapSlice {
|
||||||
|
res := MyMap(yaml1)
|
||||||
|
|
||||||
|
for _, item := range yaml2 {
|
||||||
|
initialValue := res.Get(item.Key)
|
||||||
|
value := item.Value
|
||||||
|
switch {
|
||||||
|
case initialValue != nil:
|
||||||
|
if reflect.TypeOf(initialValue) == reflect.TypeOf(yaml.MapSlice{}) &&
|
||||||
|
reflect.TypeOf(value) == reflect.TypeOf(yaml.MapSlice{}) {
|
||||||
|
mergedMap := mergeMap(initialValue.(yaml.MapSlice), value.(yaml.MapSlice))
|
||||||
|
res.Set(item.Key, mergedMap)
|
||||||
|
} else {
|
||||||
|
res.Set(item.Key, item.Value)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
res.Set(item.Key, item.Value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return yaml.MapSlice(res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func merge(cmd *cobra.Command, args []string) error {
|
||||||
|
res := make(yaml.MapSlice, 0)
|
||||||
|
for _, arg := range args {
|
||||||
|
config, err := parse(read(arg))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("%s: %w", arg, err)
|
||||||
|
}
|
||||||
|
res = mergeMap(res, config)
|
||||||
|
}
|
||||||
|
encode(os.Stdout, res)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/goccy/go-yaml"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func read(file string) []byte {
|
||||||
|
data, err := os.ReadFile(file)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
func parse(data []byte) (yaml.MapSlice, error) {
|
||||||
|
var result yaml.MapSlice
|
||||||
|
decoder := yaml.NewDecoder(bytes.NewReader(data),
|
||||||
|
yaml.UseOrderedMap())
|
||||||
|
err := decoder.Decode(&result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseFiles(cmd *cobra.Command, args []string) error {
|
||||||
|
for _, arg := range args {
|
||||||
|
_, err := parse(read(arg))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("%s: %v\n", arg, err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
yaml "github.com/goccy/go-yaml"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var VERBOSITY = 3
|
||||||
|
var SYMMETRIC_DIFF = false
|
||||||
|
|
||||||
|
type TypeId int
|
||||||
|
|
||||||
|
const (
|
||||||
|
Map TypeId = iota
|
||||||
|
Slice
|
||||||
|
Scalar
|
||||||
|
)
|
||||||
|
|
||||||
|
func Type(elem any) TypeId {
|
||||||
|
switch elem.(type) {
|
||||||
|
case yaml.MapSlice:
|
||||||
|
return Map
|
||||||
|
case []any:
|
||||||
|
return Slice
|
||||||
|
default:
|
||||||
|
return Scalar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
cmd := &cobra.Command{
|
||||||
|
Use: "yamltool",
|
||||||
|
Short: "Shows one-way difference between yaml files",
|
||||||
|
Long: `
|
||||||
|
Shows the changes in <file2> compared to <file1>`,
|
||||||
|
}
|
||||||
|
|
||||||
|
diff := &cobra.Command{
|
||||||
|
Use: "diff [file1] [file2]",
|
||||||
|
Short: "Shows one-way difference between yaml files",
|
||||||
|
Long: `
|
||||||
|
Shows the additions and modifications in <file2> compared to <file1>`,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
return diff(cmd, args)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cmd.AddCommand(diff)
|
||||||
|
|
||||||
|
merge := &cobra.Command{
|
||||||
|
Use: "merge [file1] ... [fileN]",
|
||||||
|
Short: "Merge yaml files.",
|
||||||
|
Long: `Changes will be merged into the first file, so later files override earlier ones`,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
return merge(cmd, args)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cmd.AddCommand(merge)
|
||||||
|
|
||||||
|
parse := &cobra.Command{
|
||||||
|
Use: "parse [file1] ... [fileN]",
|
||||||
|
Short: "Parse yaml files.",
|
||||||
|
Long: `Parse yaml files, usually gives better error messages than yamllint or yq`,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
return parseFiles(cmd, args)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
cmd.AddCommand(parse)
|
||||||
|
|
||||||
|
diff.PersistentFlags().IntVarP(&VERBOSITY, "array-output-level",
|
||||||
|
"v", 3, `Array output level: ,
|
||||||
|
0: no output, only exit status,
|
||||||
|
1: only show changed/added values,
|
||||||
|
2: show identical as <UNMODIFIED>,
|
||||||
|
3: show all values`)
|
||||||
|
diff.Flags().BoolVarP(&SYMMETRIC_DIFF, "symmetric-diff",
|
||||||
|
"s", false, `Symmetric difference, compare in both directions`)
|
||||||
|
|
||||||
|
cmd.Execute()
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
module git.wamblee.org/public/gotools
|
module git.wamblee.org/public/gotools
|
||||||
|
|
||||||
go 1.23.3
|
go 1.24.7
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/goccy/go-yaml v1.15.13
|
github.com/goccy/go-yaml v1.15.13
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
|
github.com/goccy/go-yaml v1.15.13 h1:Xd87Yddmr2rC1SLLTm2MNDcTjeO/GYo0JGiww6gSTDg=
|
||||||
|
github.com/goccy/go-yaml v1.15.13/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||||
|
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||||
|
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||||
|
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
Reference in new issue
Block a user