Compare commits
	
		
			3 Commits
		
	
	
		
			0f8c2f7666
			...
			56844a3c24
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					56844a3c24 | ||
| 
						 | 
					f52507aa8f | ||
| 
						 | 
					191c32b743 | 
@ -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)
 | 
				
			||||||
@ -108,44 +67,41 @@ 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 := parse(read(file1))
 | 
				
			||||||
	yaml2 := parse(read(file2))
 | 
						yaml2 := parse(read(file2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	yaml2 = subtract(yaml2, yaml1)
 | 
						diff1 := subtract(yaml2, yaml1)
 | 
				
			||||||
 | 
						diff2 := make(yaml.MapSlice, 0)
 | 
				
			||||||
	enc := yaml.NewEncoder(os.Stdout,
 | 
						if SYMMETRIC_DIFF {
 | 
				
			||||||
		yaml.UseLiteralStyleIfMultiline(true),
 | 
							diff2 = subtract(yaml1, yaml2)
 | 
				
			||||||
		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",
 | 
						diff := diff1
 | 
				
			||||||
		"v", 1, "Array output level: , 1: only show changed/added values, 2 show identical as <UNMODIFIED>, 3: show all values")
 | 
						if SYMMETRIC_DIFF {
 | 
				
			||||||
 | 
							diff = make(yaml.MapSlice, 0)
 | 
				
			||||||
 | 
							diff = append(diff,
 | 
				
			||||||
 | 
								yaml.MapItem{Key: "forward", Value: diff1},
 | 
				
			||||||
 | 
								yaml.MapItem{Key: "backward", Value: diff2},
 | 
				
			||||||
 | 
							)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cmd.Execute()
 | 
						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
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										16
									
								
								cmd/yamltool/encode.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								cmd/yamltool/encode.go
									
									
									
									
									
										Normal file
									
								
							@ -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)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										61
									
								
								cmd/yamltool/merge.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								cmd/yamltool/merge.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,61 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"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 := parse(read(arg))
 | 
				
			||||||
 | 
							res = mergeMap(res, config)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						encode(os.Stdout, res)
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										26
									
								
								cmd/yamltool/parse.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								cmd/yamltool/parse.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import (
 | 
				
			||||||
 | 
						"bytes"
 | 
				
			||||||
 | 
						"github.com/goccy/go-yaml"
 | 
				
			||||||
 | 
						"os"
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										70
									
								
								cmd/yamltool/yamltool.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								cmd/yamltool/yamltool.go
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,70 @@
 | 
				
			|||||||
 | 
					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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user