From 3a6a913ef2a648f6897202e6e44905a7778c9ed5 Mon Sep 17 00:00:00 2001 From: Erik Brakkee Date: Tue, 24 Dec 2024 22:39:09 +0100 Subject: [PATCH] yamldiff re-implementation in go --- cmd/yamldiff/yamldiff.go | 99 ++++++++++++++++++++++++++++++++++++++++ go.mod | 2 + 2 files changed, 101 insertions(+) create mode 100644 cmd/yamldiff/yamldiff.go diff --git a/cmd/yamldiff/yamldiff.go b/cmd/yamldiff/yamldiff.go new file mode 100644 index 0000000..0a2255c --- /dev/null +++ b/cmd/yamldiff/yamldiff.go @@ -0,0 +1,99 @@ +package main + +import ( + "bytes" + "fmt" + yaml "github.com/goccy/go-yaml" + "os" + "reflect" +) + +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 + } +} + +func subtract(yaml1 yaml.MapSlice, yaml2 yaml.MapSlice) yaml.MapSlice { + res := make(yaml.MapSlice, 0) + for _, item := range yaml2 { + k := item.Key + v1 := item.Value + v2 := yaml1.ToMap()[k] + switch { + case reflect.DeepEqual(v1, v2): + // delete is implicit by not copying to the output + case Type(v1) == Map && Type(v2) == Map: + diff := subtract(v2.(yaml.MapSlice), v1.(yaml.MapSlice)) + if len(diff) > 0 { + res = append(res, item) + } + case Type(v1) == Slice && Type(v2) == Slice: + if !reflect.DeepEqual(v1, v2) { + res = append(res, item) + } + default: + res = append(res, item) + } + } + return res +} + +func main() { + if len(os.Args) != 3 { + fmt.Fprintf(os.Stderr, ` +Usage: yamldiff ") + Shows changes and additions made in w.r.t. +`) + } + file1 := os.Args[1] + file2 := os.Args[2] + + yaml1 := parse(read(file1)) + yaml2 := parse(read(file2)) + + subtract(yaml2, yaml1) + + enc := yaml.NewEncoder(os.Stdout, + yaml.UseLiteralStyleIfMultiline(true), + yaml.Indent(2), // Set indentation + //yaml.UseOrderedMap(), // Preserve map order + ) + err := enc.Encode(yaml2) + if err != nil { + panic(err) + } + +} diff --git a/go.mod b/go.mod index 67b9e4c..9212ccf 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module git.wamblee.org/public/gotools go 1.23.3 + +require github.com/goccy/go-yaml v1.15.13