chezmoi Init 模板函数完全指南:用交互式提示定制配置文件生成
2026/9/20 19:49:37 网站建设 项目流程
  • 开发工具
  • CLI
  • 配置管理

【免费下载链接】chezmoi

Manage your dotfiles across multiple diverse machines, securely.

项目地址:https://gitcode.com/gh_mirrors/ch/chezmoi
点击查看免费下载

导读

chezmoi是一套跨多台异构机器安全管理 dotfiles 的工具,而init 模板函数(Init template functions)是它在「首次初始化、生成配置文件」这一关键环节提供的专属能力:借助promptStringpromptBoolpromptChoice等函数,用户可以在chezmoi init运行过程中被逐个提问,根据每台机器的实际情况动态决定配置内容;promptXxxOnce系列则更进一步,优先复用已存在的数据、避免重复提问。读完本文,你将掌握全部 12 个 init 函数(外加exit)的签名、参数规则、返回值语义与完整示例,并理解它们在 internal/cmd/config.go 与 internal/cmd/executetemplatecmd.go 中的底层注册与调用机制,从而能独立编写出「一次提问、处处复用」的初始化模板。

什么是 init 模板函数

按 init-functions 索引文档 的定义:这些模板函数只有在使用chezmoi init生成配置文件时才可用。它们被注入到「配置文件模板」的执行环境中——也就是当 chezmoi 根据chezmoi.toml.tmpl之类的模板生成实际配置时,模板里可以调用这些函数来向用户提问、读取数据或提前终止执行。

对于日常的 dotfile 渲染(chezmoi apply时的普通模板),这些函数并不存在。但如果你希望在chezmoi execute-template下调试它们,需要显式传入--init标志来启用,例如 helps.gen.go 中展示的用法:

chezmoi execute-template --init --promptString email=me@home.org < ~/.config/chezmoi/chezmoi.toml.tmpl

从源码结构看,这个机制有两处独立实现,但注册的函数集合完全一致(共 12 个函数加exit):

  • chezmoi init生成配置文件时,createConfigFileContents 会先把当前templateFuncs克隆备份,再RecursiveMerge注入 init 函数,执行完毕后恢复原状——注释明确指出「这确保了 init 模板函数在“正常”模板解析前被移除」;
  • chezmoi execute-template --init时,executetemplatecmd.go 同样构造并合并这组函数。

init 函数总览

以下 12 个函数被统一注册在 init 模板环境中(见 executetemplatecmd.go 与 config.go):

函数签名作用
exitexitcode停止模板执行并使 chezmoi 以code退出
promptStringpromptStringprompt[default]提示输入字符串
promptStringOncepromptStringOncemappathprompt[default]数据已存在则复用,否则提问字符串
promptBoolpromptBoolprompt[default]提示输入布尔值
promptBoolOncepromptBoolOncemappathprompt[default]数据已存在则复用,否则提问布尔值
promptIntpromptIntprompt[default]提示输入整数
promptIntOncepromptIntOncemappathprompt[default]数据已存在则复用,否则提问整数
promptChoicepromptChoicepromptchoices[default]从候选项中单选
promptChoiceOncepromptChoiceOncemappathpromptchoices[default]数据已存在则复用,否则单选
promptMultichoicepromptMultichoicepromptchoices[default]从候选项中多选
promptMultichoiceOncepromptMultichoiceOncemappathpromptchoices[default]数据已存在则复用,否则多选
writeToStdoutwriteToStdoutstring...将各字符串原样写入 stdout

下面按函数逐个深入讲解。完整的函数参考见 init-functions 目录。

字符串与数值提问:promptString/promptInt/promptBool

promptString—— 采集字符串输入

promptStringprompt[default]:向用户展示prompt并返回其输入,返回前会去除首尾空白;如果传入了default且用户直接回车(响应为空),则返回default

官方示例:

{{ $email := promptString "email" -}} [data] email = {{ $email | quote }}

promptInt—— 采集整数输入

promptIntprompt[default]:向用户展示prompt,返回值被解释为整数;若传入default且响应为空则返回default。参考 promptInt 文档。注意promptInt不像promptString那样去除空白,用户输入会被直接解析为整数。

promptBool—— 采集布尔输入

promptBoolprompt[default]:向用户展示prompt,返回值被解释为布尔值;若传入default且响应为空则返回default。用户的响应按如下规则(不区分大小写)解释,见 promptBool 文档:

响应结果
1,on,t,true,y,yestrue
0,off,f,false,n,nofalse

单选与多选:promptChoice/promptMultichoice

promptChoice—— 从候选项中单选

promptChoicepromptchoices[default]:向用户展示promptchoices必须是字符串列表)并返回用户的选择;若传入default且响应为空则返回default。参考 promptChoice 文档:

{{- $choices := list "desktop" "server" -}} {{- $hosttype := promptChoice "What type of host are you on" $choices -}} [data] hosttype = {{- $hosttype | quote -}}

这里用list构造候选列表,用quote将选择结果安全地写为 TOML 字符串。

promptMultichoice—— 从候选项中多选

promptMultichoicepromptchoices[default]:向用户展示promptchoices并返回其响应,choices必须是字符串列表;若传入默认列表且响应为空则返回default。参考 promptMultichoice 文档:

{{- $choices := list "chocolate" "strawberry" "vanilla" "pistachio" -}} {{- $icecream := promptMultichoice "What type of ice cream do you like" $choices (list "pistachio" "chocolate") -}} [data] icecream = {{- $icecream | toToml -}}

与单选不同,多选的结果是一个列表,因此示例用toToml管道将其序列化为 TOML 数组再写入配置。

Once 系列:避免重复提问的「缓存」机制

promptXxxOnce系列共 5 个函数(promptStringOncepromptBoolOncepromptIntOncepromptChoiceOncepromptMultichoiceOnce),它们的语义高度一致:先从mappath处取值,若存在且类型匹配则直接返回该值;否则才退回到对应的promptXxx交互式提问。这非常适合在首次初始化时把答案沉淀到数据里,之后再次初始化(或重跑模板)时直接复用,无需重复打扰用户。

从源码实现看,executetemplatecmd.go 中的 Once 函数都遵循同一模式:

promptStringOnceInitTemplateFunc := func(m map[string]any, path any, prompt string, args ...string) string { nestedMap, lastKey := mustValues(nestedMapAtPath(m, path)) if value, ok := nestedMap[lastKey]; ok { if stringValue, ok := value.(string); ok { return stringValue } } return promptStringInitTemplateFunc(prompt, args...) }

即先通过nestedMapAtPath沿path定位嵌套 map,命中且类型正确就直接返回,否则回落到提问函数(promptBoolOnce检查布尔、promptIntOnce检查int64,见 executetemplatecmd.go)。这也解释了Once函数第一参数总是.(根数据 map)的原因。

promptStringOnce

promptStringOncemappathprompt[default]:若mappath处存在字符串值则返回它,否则用promptString提问(可带default)。参考 promptStringOnce 文档:

{{ $email := promptStringOnce . "email" "What is your email address" }}

promptBoolOnce

promptBoolOncemappathprompt[default]:若mappath处存在布尔值则返回它,否则用promptBool提问。参考 promptBoolOnce 文档:

{{ $hasGUI := promptBoolOnce . "hasGUI" "Does this machine have a GUI" }}

promptIntOnce

promptIntOncemappathprompt[default]:若mappath处存在整数值则返回它,否则用promptInt提问。参考 promptIntOnce 文档:

{{ $monitors := promptIntOnce . "monitors" "How many monitors does this machine have" }}

promptChoiceOnce

promptChoiceOncemappathpromptchoices[default]:若mappath处存在字符串值则返回它,否则用promptChoicechoices中单选提问(可带default)。参考 promptChoiceOnce 文档:

{{- $choices := list "desktop" "laptop" "server" "termux" -}} {{- $hosttype := promptChoiceOnce . "hosttype" "What type of host are you on" $choices -}} [data] hosttype = {{- $hosttype | quote -}}

promptMultichoiceOnce

promptMultichoiceOncemappathpromptchoices[default]:若mappath处存在字符串值则返回它,否则用promptMultichoice多选提问(可带列表default)。参考 promptMultichoiceOnce 文档:

{{- $choices := list "chocolate" "strawberry" "vanilla" "pistachio" -}} {{- $icecream := promptMultichoiceOnce . "icecream" "What type of ice cream do you like" $choices (list "pistachio" "chocolate") -}} [data] icecream = {{- $icecream | toToml -}}

控制流:exitwriteToStdout

exit—— 提前终止模板执行

exitcode停止模板执行并使 chezmoi 以code退出,见 exit 文档。典型的应用场景是:检测到当前机器类型不受支持或缺少必要前置条件时,立即以非零退出码中止初始化流程,而不是让模板在残缺状态下继续渲染。例如:

{{- if eq (promptString "Do you accept the terms?") "no" -}} {{- exit 1 -}} {{- end -}}

writeToStdout—— 向标准输出写入内容

writeToStdoutstring...:将传入的每个字符串依次写入 stdout,见 writeToStdout 文档:

{{- writeToStdout "Hello, world\n" -}}

注意示例开头使用了{{-修剪前导空白,确保只有目标字符串被输出,避免模板自身的换行与缩进污染 stdout。它常用于向用户打印提示信息或调试诊断输出,且不会改变模板的结果内容。

实战:组装一份可复用的初始化配置模板

综合以上函数,一个典型的chezmoi init配置模板可以这样组织——用 Once 系列保证「已答不重问」,用writeToStdout输出引导信息,用exit守卫异常分支:

{{- writeToStdout "Setting up chezmoi for this machine...\n" -}} {{- $hosttype := promptChoiceOnce . "hosttype" "What type of host are you on" (list "desktop" "laptop" "server") -}} {{- $email := promptStringOnce . "email" "What is your email address" -}} {{- $hasGUI := promptBoolOnce . "hasGUI" "Does this machine have a GUI" -}} {{- $monitors := promptIntOnce . "monitors" "How many monitors does this machine have" -}} [data] hosttype = {{ $hosttype | quote }} email = {{ $email | quote }} hasGUI = {{ $hasGUI }} monitors = {{ $monitors }}
  • 首次运行时,每个promptXxxOnce都会向用户提问,答案写入[data]段并被持久化;
  • 之后再次chezmoi init(或传入已有数据),Once 函数直接命中path处的值,不再提问;
  • 若某台机器不需要 GUI,回答n/no/false/off/0之一即可(见上文布尔解释表)。

调试时可用chezmoi execute-template --init配合--promptString key=value之类的标志预设答案(见 helps.gen.go 的用法示例),或用管道把模板内容喂给 stdin(见 executetemplatecmd.go 中对 stdin 的处理),从而在真正执行init之前验证模板行为。

边界与注意事项

  • 作用域限定:init 函数只在chezmoi init生成配置文件的模板环境中注册,chezmoi apply等常规 dotfile 渲染不会加载它们(config.go 中「先备份、执行后恢复」的实现保证了这一点)。调试时务必加--init标志。
  • Once的类型严格性promptBoolOnce只接受已存在的布尔值、promptIntOnce只接受整数(源码中分别断言为boolint64,见 executetemplatecmd.go),promptStringOnce/promptChoiceOnce/promptMultichoiceOnce接受字符串;类型不符时会回落到交互式提问,而不是报错中断。
  • 数据合并chezmoi init --data会要求把已有模板数据合并进当前数据(initcmd.go 定义了该标志,config.go 中通过RecursiveMerge实现),这正是 Once 系列「读取旧值」的数据来源之一。
  • 默认值语义:所有可带default的函数,默认值都只在「用户响应为空」时生效;promptMultichoice/promptMultichoiceOnce的默认值是列表。
  • 开发工具
  • CLI
  • 配置管理

【免费下载链接】chezmoi

Manage your dotfiles across multiple diverse machines, securely.

项目地址:https://gitcode.com/gh_mirrors/ch/chezmoi
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询