yamldiff re-implementation in go
This commit is contained in:
parent
03a1a4e132
commit
3a6a913ef2
99
cmd/yamldiff/yamldiff.go
Normal file
99
cmd/yamldiff/yamldiff.go
Normal file
@ -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 <file1> <file2>")
|
||||||
|
Shows changes and additions made in <file2> w.r.t. <file1>
|
||||||
|
`)
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user