Skip to content

Commit

Permalink
fix: keep initFuncs when using 'includeTemplate' in config
Browse files Browse the repository at this point in the history
When trying to exec 'chezmoi init' or 'chezmoi apply --init'  with
.chezmoi.toml.tmpl including another file through 'includeTemplate',
the initTemplateFuncs are only available in the first file,
but not in the included template.

This is because the initial execution operates on a copy of c.templateFuncs,
which wouldn't get passed on to includeTemplateTemplateFunc.

With this change, initFunctions will be added directly to c.templateFuncs
and then removed after the config has been generated.

Note: Due to a separate implementation, 'chezmoi execute-template --init'
is not affected by this bug.
  • Loading branch information
kdomanski authored and twpayne committed Jul 12, 2024
1 parent 4ebcb0b commit 2615c52
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 2 deletions.
11 changes: 9 additions & 2 deletions internal/cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -811,8 +811,15 @@ func (c *Config) createAndReloadConfigFile(cmd *cobra.Command) error {
// createConfigFile creates a config file using a template and returns its
// contents.
func (c *Config) createConfigFile(filename chezmoi.RelPath, data []byte, cmd *cobra.Command) ([]byte, error) {
// Clone funcMap and restore it after creating the config.
// This ensures that the init template functions
// are removed before "normal" template parsing.
funcMap := make(template.FuncMap)
chezmoi.RecursiveMerge(funcMap, c.templateFuncs)
defer func() {
c.templateFuncs = funcMap
}()

initTemplateFuncs := map[string]any{
"exit": c.exitInitTemplateFunc,
"promptBool": c.promptBoolInteractiveTemplateFunc,
Expand All @@ -826,9 +833,9 @@ func (c *Config) createConfigFile(filename chezmoi.RelPath, data []byte, cmd *co
"stdinIsATTY": c.stdinIsATTYInitTemplateFunc,
"writeToStdout": c.writeToStdout,
}
chezmoi.RecursiveMerge(funcMap, initTemplateFuncs)
chezmoi.RecursiveMerge(c.templateFuncs, initTemplateFuncs)

tmpl, err := chezmoi.ParseTemplate(filename.String(), data, funcMap, chezmoi.TemplateOptions{
tmpl, err := chezmoi.ParseTemplate(filename.String(), data, c.templateFuncs, chezmoi.TemplateOptions{
Options: slices.Clone(c.Template.Options),
})
if err != nil {
Expand Down
24 changes: 24 additions & 0 deletions internal/cmd/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,30 @@ func TestParseConfig(t *testing.T) {
}
}

func TestInitConfigWithIncludedTemplate(t *testing.T) {
mainFilename := ".chezmoi.yaml.tmpl"
secondaryFilename := "personal.config.yaml.tmpl"
mainContents := chezmoitest.JoinLines(
`color: true`,
fmt.Sprintf(`{{ includeTemplate %q . }}`, secondaryFilename),
)
secondaryContents := chezmoitest.JoinLines(
`verbose: true`,
`safe: {{ stdinIsATTY }}`,
)

chezmoitest.WithTestFS(t, map[string]any{
"/home/user/.local/share/chezmoi/" + mainFilename: mainContents,
"/home/user/.local/share/chezmoi/" + secondaryFilename: secondaryContents,
}, func(fileSystem vfs.FS) {
c := newTestConfig(t, fileSystem)
assert.NoError(t, c.execute([]string{"init"}))
assert.Equal(t, true, c.Color.Value(c.colorAutoFunc))
assert.Equal(t, true, c.Verbose)
assert.Equal(t, false, c.Safe)
})
}

func TestUpperSnakeCaseToCamelCase(t *testing.T) {
for s, expected := range map[string]string{
"BUG_REPORT_URL": "bugReportURL",
Expand Down

0 comments on commit 2615c52

Please sign in to comment.