package main import ( "encoding/json" "flag" "fmt" "os" "strings" "gopkg.in/yaml.v3" ) var ( input = stringsArray{} output = "" replaceArrays = false outType = "yaml" ) func main() { flag.Var(&input, "i", "input files") flag.StringVar(&output, "o", "out.yaml", "output file") flag.BoolVar(&replaceArrays, "replace_arrays", false, "replace arrays with same keys. Merge otherwise.") flag.StringVar(&outType, "out_type", "yaml", "output type, 'yaml' (default) or 'json'") flag.Parse() result := map[string]any{} for _, inputFile := range input { b, err := os.ReadFile(inputFile) if err != nil { panic(err) } m := map[string]any{} if err := yaml.Unmarshal(b, m); err != nil { panic(err) } merge(result, m, replaceArrays) } fp, err := os.Create(output) if err != nil { panic(err) } defer fp.Close() var enc Encoder switch outType { case "yaml": enc = yaml.NewEncoder(fp) case "json": enc = json.NewEncoder(fp) default: panic(fmt.Errorf("unknown output type: %s", outType)) } if err := enc.Encode(result); err != nil { panic(err) } } func merge(target map[string]any, in map[string]any, replaceArrays bool) { for k, v := range in { old, exist := target[k] if !exist { target[k] = v continue } switch old := old.(type) { case map[string]any: v, ok := v.(map[string]any) if ok { merge(old, v, replaceArrays) target[k] = old continue } case []any: v, ok := v.([]any) if ok && !replaceArrays { old = append(old, v...) target[k] = old continue } } target[k] = v } } type stringsArray []string func (i *stringsArray) Set(value string) error { *i = append(*i, value) return nil } func (i *stringsArray) String() string { return strings.Join(*i, ",") } type Encoder interface { Encode(any) error }