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) } }