diff --git a/go.mod b/go.mod index f33bf0ebec9f..fe46d34708e3 100644 --- a/go.mod +++ b/go.mod @@ -55,6 +55,7 @@ require ( google.golang.org/appengine v1.6.5 // indirect gopkg.in/ini.v1 v1.56.0 // indirect gopkg.in/yaml.v2 v2.3.0 + gopkg.in/yaml.v3 v3.0.0-20200506231410-2ff61e1afc86 ) replace github.com/go-git/go-git/v5 => github.com/twpayne/go-git/v5 v5.0.1-0.20200517130039-70111361e674 diff --git a/go.sum b/go.sum index 00dd8317d6e0..87ff33e57c5e 100644 --- a/go.sum +++ b/go.sum @@ -556,6 +556,8 @@ gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.0-20200506231410-2ff61e1afc86 h1:OfFoIUYv/me30yv7XlMy4F9RJw8DEm8WQ6QG1Ph4bH0= +gopkg.in/yaml.v3 v3.0.0-20200506231410-2ff61e1afc86/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/next/internal/chezmoi/recursivemerge.go b/next/internal/chezmoi/recursivemerge.go index 6c25ceb69e62..5be5e7011a70 100644 --- a/next/internal/chezmoi/recursivemerge.go +++ b/next/internal/chezmoi/recursivemerge.go @@ -1,21 +1,46 @@ package chezmoi +import ( + "fmt" + "os" +) + +// recursiveCopy returns a recursive copy of v. +func recursiveCopy(v interface{}) interface{} { + m, ok := v.(map[string]interface{}) + if !ok { + return v + } + c := make(map[string]interface{}) + for key, value := range m { + if mapValue, ok := value.(map[string]interface{}); ok { + c[key] = recursiveCopy(mapValue) + } else { + c[key] = value + } + } + return c +} + // recursiveMerge recursively merges maps in source into dest. func recursiveMerge(dest, source map[string]interface{}) { for key, sourceValue := range source { + if key == "global" { + fmt.Fprintf(os.Stderr, "global: dest=%v source=%v\n", dest[key], sourceValue) + } destValue, ok := dest[key] if !ok { - dest[key] = sourceValue + dest[key] = recursiveCopy(sourceValue) continue } destMap, ok := destValue.(map[string]interface{}) if !ok || destMap == nil { - dest[key] = sourceValue + dest[key] = recursiveCopy(sourceValue) continue } sourceMap, ok := sourceValue.(map[string]interface{}) if !ok { - dest[key] = sourceValue + dest[key] = recursiveCopy(sourceValue) continue } recursiveMerge(destMap, sourceMap) diff --git a/next/internal/chezmoi/recursivemerge_test.go b/next/internal/chezmoi/recursivemerge_test.go index f2683d9e34d4..4c07fc48e9f7 100644 --- a/next/internal/chezmoi/recursivemerge_test.go +++ b/next/internal/chezmoi/recursivemerge_test.go @@ -53,3 +53,16 @@ func TestRecursiveMerge(t *testing.T) { assert.Equal(t, tc.expectedDest, tc.dest) } } + +func TestRecursiveMergeCopies(t *testing.T) { + original := map[string]interface{}{ + "key": "initialValue", + } + dest := make(map[string]interface{}) + recursiveMerge(dest, original) + recursiveMerge(dest, map[string]interface{}{ + "key": "mergedValue", + }) + assert.Equal(t, "mergedValue", dest["key"]) + assert.Equal(t, "initialValue", original["key"]) +} diff --git a/next/internal/chezmoi/sourcestate.go b/next/internal/chezmoi/sourcestate.go index 9ce8b0ee7bd4..88922488ad5a 100644 --- a/next/internal/chezmoi/sourcestate.go +++ b/next/internal/chezmoi/sourcestate.go @@ -468,7 +468,9 @@ func (s *SourceState) addTemplateData(sourcePath string) error { if err := format.Decode(data, &templateData); err != nil { return fmt.Errorf("%s: %w", sourcePath, err) } + fmt.Fprintf(os.Stderr, "TEMPLATE DATA ") recursiveMerge(s.templateData, templateData) + fmt.Fprintf(os.Stderr, "PRIORITY ") recursiveMerge(s.templateData, s.priorityTemplateData) return nil } diff --git a/next/internal/chezmoi/yamlformat.go b/next/internal/chezmoi/yamlformat.go index 6775f069badf..51b4f63b1921 100644 --- a/next/internal/chezmoi/yamlformat.go +++ b/next/internal/chezmoi/yamlformat.go @@ -3,7 +3,7 @@ package chezmoi import ( "bytes" - "gopkg.in/yaml.v2" + "gopkg.in/yaml.v3" ) type yamlFormat struct{} diff --git a/next/testdata/scripts/dump.txt b/next/testdata/scripts/dump.txt index 3a966638775e..bc9db5431cd1 100644 --- a/next/testdata/scripts/dump.txt +++ b/next/testdata/scripts/dump.txt @@ -99,46 +99,46 @@ stderr 'not in source state' } -- golden/dump.yaml -- .bashrc: - type: file - name: .bashrc - contents: | - # contents of .bashrc - perm: 420 + type: file + name: .bashrc + contents: | + # contents of .bashrc + perm: 420 .binary: - type: file - name: .binary - contents: | - #!/bin/sh - perm: 493 + type: file + name: .binary + contents: | + #!/bin/sh + perm: 493 .gitconfig: - type: file - name: .gitconfig - contents: | - [user] - email = user@home.org - perm: 420 + type: file + name: .gitconfig + contents: | + [user] + email = user@home.org + perm: 420 .hushlogin: - type: file - name: .hushlogin - contents: "" - perm: 420 + type: file + name: .hushlogin + contents: "" + perm: 420 .ssh: - type: dir - name: .ssh - perm: 448 + type: dir + name: .ssh + perm: 448 .ssh/config: - type: file - name: .ssh/config - contents: | - # contents of .ssh/config - perm: 420 + type: file + name: .ssh/config + contents: | + # contents of .ssh/config + perm: 420 .symlink: - type: symlink - name: .symlink - linkname: .bashrc + type: symlink + name: .symlink + linkname: .bashrc script: - type: script - name: script - contents: | - #!/bin/sh - echo script + type: script + name: script + contents: | + #!/bin/sh + echo script diff --git a/next/testdata/scripts/editconfig.txt b/next/testdata/scripts/editconfig.txt index c28bc2d15066..495c85d0daa1 100644 --- a/next/testdata/scripts/editconfig.txt +++ b/next/testdata/scripts/editconfig.txt @@ -22,6 +22,6 @@ grep -count=1 '# edited' $CHEZMOICONFIGDIR/chezmoi.json -- home2/user/.config/chezmoi/chezmoi.yaml -- data: - email: "user@home.org" + email: "user@home.org" -- home3/user/.config/chezmoi/chezmoi.json -- {"data":{"email":"user@home.org"}} diff --git a/next/testdata/scripts/executetemplate.txt b/next/testdata/scripts/executetemplate.txt index fbfa17f89585..f19d3a4967a7 100644 --- a/next/testdata/scripts/executetemplate.txt +++ b/next/testdata/scripts/executetemplate.txt @@ -13,24 +13,29 @@ stdout stdin-template chezmoi execute-template '{{ template "partial" }}' stdout partial-template +# FIXME merge the following tests into a single test + +chezmoi execute-template '{{ .last.config }}' +stdout 'chezmoi\.toml' + # test that template data are read from .chezmoidata.json -chezmoi execute-template '{{ .json.key }}' -stdout json +chezmoi execute-template '{{ .last.json }}' +stdout '\.chezmoidata\.json' # test that template data are read from .chezmoidata.toml -chezmoi execute-template '{{ .toml.key }}' -stdout toml +chezmoi execute-template '{{ .last.toml }}' +stdout '\.chezmoidata\.toml' # test that template data are read from .chezmoidata.yaml -chezmoi execute-template '{{ .yaml.key }}' -stdout yaml +chezmoi execute-template '{{ .last.yaml }}' +stdout '\.chezmoidata\.yaml' # test that the last .chezmoidata. file read wins -chezmoi execute-template '{{ .chezmoidata.last }}' -stdout yaml +chezmoi execute-template '{{ .last.format }}' +stdout '\.chezmoidata\.yaml' # test that the config file wins over .chezmoidata. -chezmoi execute-template '{{ .global.last }}' +chezmoi execute-template '{{ .last.global }}' stdout chezmoi.toml # test --init --promptString @@ -40,33 +45,26 @@ stdout 'user@home\.org' -- golden/stdin.tmpl -- {{ "stdin-template" }} -- home/user/.config/chezmoi/chezmoi.toml -- -[data.global] - last = "chezmoi.toml" +[data.last] + config = "chezmoi.toml" + global = "chezmoi.toml" -- home/user/.local/share/chezmoi/.chezmoidata.json -- { - "chezmoidata": { - "last": "json" - }, - "global": { - "last": ".chezmoidata.json" - }, - "json": { - "key": "json" + "last": { + "format": ".chezmoidata.json", + "global": ".chezmoidata.json", + "json": ".chezmoidata.json" } } -- home/user/.local/share/chezmoi/.chezmoidata.toml -- -[chezmoidata] - last = "toml" -[global] - last = ".chezmoidata.toml" -[toml] - key = "toml" +[last] + format = ".chezmoidata.toml" + global = ".chezmoidata.toml" + toml = ".chezmoidata.toml" -- home/user/.local/share/chezmoi/.chezmoidata.yaml -- -chezmoidata: - last: yaml -global: - last: .chezmoidata.yaml -yaml: - key: yaml +last: + format: ".chezmoidata.yaml" + global: ".chezmoidata.yaml" + yaml: ".chezmoidata.yaml" -- home/user/.local/share/chezmoi/.chezmoitemplates/partial -- partial-template