ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

chezmoi 模板函数 promptChoice 完全指南:让 `chezmoi init` 交互式采集机器配置

chezmoi 模板函数 promptChoice 完全指南:让 `chezmoi init` 交互式采集机器配置 chezmoi 模板函数 promptChoice 完全指南让chezmoi init交互式采集机器配置【免费下载链接】chezmoiManage your dotfiles across multiple diverse machines, securely.项目地址: https://gitcode.com/gh_mirrors/ch/chezmoipromptChoice是 chezmoi 在chezmoi init阶段可用的交互式模板函数init function它向用户展示一个提示语和一组候选选项并返回用户的选择从而让同一份 dotfiles 仓库在初始化时就能按目标机器的类型桌面、服务器、笔记本等生成差异化配置。读完本文你将掌握promptChoice的完整签名与参数规则、交互式与非交互--no-tty两种运行方式、如何用--promptChoice和--promptDefaults标志实现无人值守初始化以及它与promptChoiceOnce、promptMultichoice等兄弟函数的分工和底层实现原理。函数签名与适用场景promptChoice属于 chezmoi 的init functions一族。根据 init-functions 索引文档这类模板函数只有在执行chezmoi init生成配置文件时才可用若要用chezmoi execute-template做测试必须加上--init标志才能启用它们。promptChoice *prompt* *choices* [*default*]参数类型必填说明prompt字符串是展示给用户的提示语例如What type of host are you onchoices字符串列表是可选的候选项例如(list desktop server)必须是字符串列表default字符串否当用户直接回车响应为空时返回的默认值promptChoice向用户展示prompt与choices并返回用户的选择如果传入了default且用户响应为空则返回default。它在实践中最常见的用途是在chezmoi init引导阶段采集「这台机器是什么类型」这类离散型信息随后把结果写进模板变量data供仓库内其他模板按机器类型渲染不同的配置内容。基础用法把机器类型写入模板数据官方文档示例展示了最典型的使用方式——在.chezmoi.toml.tmpl或.chezmoi.yaml.tmpl等配置模板中调用该函数将选择结果存入[data]{{- $choices : list desktop server -}} {{- $hosttype : promptChoice What type of host are you on $choices -}} [data] hosttype {{- $hosttype | quote -}}逐行拆解这段模板list desktop server用 Go 模板内置的list函数构造一个包含两个元素的字符串列表赋值给$choicespromptChoice在终端上显示提示What type of host are you on用户从desktop/server中二选一返回值存入$hosttype模板其余部分把$hosttype通过quote过滤器转成带引号的字符串写入[data]段的hosttype键前面两行模板末尾的-}}与行首的{{-是 Go 模板的空白控制语法用于吞掉换行与缩进确保最终生成的 TOML 文件格式正确hosttype desktop与[data]保持合理间距。chezmoi init执行完成后~/.config/chezmoi/chezmoi.toml中就会出现类似下面的内容而仓库中任何模板都可以通过{{ .data.hosttype }}引用这个值[data] hosttype desktop参数规则choices 与 default 的约束从源码实现看promptChoice对参数有严格的校验逻辑理解这些约束可以避免写出运行时报错的模板。在 internal/cmd/prompt.go 中promptChoice的实现首先校验参数个数——最多接受 2 个或 3 个参数即prompt、choices外加可选的default否则返回want 2 or 3 arguments错误func (c *Config) promptChoice(prompt string, choices []string, args ...string) (string, error) { var defaultValue *string switch len(args) { case 0: // Do nothing. case 1: if !slices.Contains(choices, args[0]) { return , fmt.Errorf(%s: invalid default value, args[0]) } defaultValue args[0] default: return , fmt.Errorf(want 2 or 3 arguments, got %d, len(args)2) } ... }关键点有两个default必须是choices中的一员。如果传入的默认值不在选项列表里chezmoi 会直接报xxx: invalid default value错误而不是静默接受。这意味着模板作者无法用默认值引入选项之外的隐藏值保证了数据的一致性参数数量有上限。promptChoice只接受 2 或 3 个参数模板中多传一个参数就会触发want 2 or 3 arguments的 panic 级错误经由mustValue包装。此外choices会被强制转换为字符串列表。在 internal/cmd/interactivetemplatefuncs.go 中模板函数层的promptChoiceInteractiveTemplateFunc调用anyToStringSlice(choices)完成转换因此即使传入的是其他可转换类型也会统一归一为字符串切片再交给底层实现。只在 init 阶段可用与chezmoi init和execute-template --init的关系promptChoice依赖用户的实时键盘输入因此它不能出现在后续的chezmoi apply、chezmoi cat等需要无交互渲染模板的阶段只能用于chezmoi init生成配置文件的过程。在模板函数注册上这类交互函数与普通模板函数是分开的只有 init 流程才会注入。如果你想在编写模板时快速验证promptChoice的写法是否正确可以使用chezmoi execute-template --init显式启用 init functions例如chezmoi execute-template --init {{ promptChoice host type (list desktop server) }}此时会真的在终端弹出交互式选择框。若在非 TTY 环境如 CI 脚本中执行则会退化为纯文本提示模式详见下一节。交互式体验TTY 下的选择框与缩写补全当chezmoi init运行在真实终端TTY上时promptChoice借助 charmbracelet 的 bubbletea 框架渲染一个交互式输入框实现在 internal/chezmoibubbles/choiceinputmodel.go。其体验细节包括候选列表即占位符输入框的 Placeholder 显示为用/连接的全部选项如desktop/server若有默认值还会追加, default desktop缩写补全每个选项的任意前缀都视为有效输入。输入d即可匹配desktop输入s匹配server。底层通过chezmoi.UniqueAbbreviations(choices)计算唯一缩写映射见 internal/cmd/prompt.go 与 internal/chezmoibubbles/choiceinputmodel.go并在输入值与某个选项完全一致时自动结束输入非法输入即时校验输入框中内置Validate函数输入既不是空串有默认值时允许也不是任何选项前缀时会提示unknown or ambiguous choice直接回车若提供了default直接回车会以默认值结束Esc或Ctrl-C可取消输入返回退出码 0。从 internal/cmd/prompt.go 的readChoice可以看到TTY 分支会先向标准输出打印prompt ?\n随后运行 bubbletea 的ChoiceInputModel最终通过finalModel.Value()取得用户选择。非交互环境--no-tty下的文本提示与缩写输入在管道、脚本或 CI 等没有 TTY 的场景下readChoice走c.noTTY分支行为完全不同但同样可用首先打印完整提示格式为prompt (choice1/choice2/...)?若存在默认值则追加, default xxx用户输入的内容同样通过chezmoi.UniqueAbbreviations匹配缩写输入d也能选中desktop直接回车且存在默认值时返回默认值输入不合法时不会报错退出而是循环重问直到拿到合法输入。这套逻辑在chezmoi init --no-tty下可以配合标准输入流完成自动化配置例如用 echo 管道预先喂入选择echo server | chezmoi init --no-tty无人值守初始化--promptChoice与--promptDefaults标志promptChoice家族还支持通过命令行标志跳过交互这在批量部署多台机器时非常实用。--promptChoice keyvalue以prompt文本为键、以返回值为值预填结果。在 internal/cmd/interactivetemplatefuncs.go 中该标志定义为StringToStringVar可重复传入多个键值对。实现层在 promptChoiceInteractiveTemplateFunc 中先查表若c.interactiveTemplateFuncs.promptChoice[prompt]命中直接返回预填值完全不会弹出交互。例如chezmoi init --promptChoice What type of host are you onserver注意键必须与模板中的prompt文本完全一致才能命中。--promptDefaults让所有 prompt 函数直接返回各自的默认值见 internal/cmd/prompt.go 中promptDefaults的判断。只要模板为每个promptChoice都提供了default参数加了这个标志就能一键静默生成配置。这两个标志与promptChoiceOnce配合还能实现已有配置则复用、无配置才询问的幂等初始化见下节。幂等变体promptChoiceOnce与多选兄弟函数为了让chezmoi init可以安全地重复执行例如初始化后修改配置模板再重新 initchezmoi 提供了一组*Once变体。promptChoiceOnce 文档 给出的签名是promptChoiceOnce *map* *path* *prompt* *choices* [*default*]它在调用promptChoice之前先检查map通常传.即整个数据上下文中path位置是否已有字符串值若有则直接返回该值否则才发起交互。典型用法{{- $choices : list desktop laptop server termux -}} {{- $hosttype : promptChoiceOnce . hosttype What type of host are you on $choices -}} [data] hosttype {{- $hosttype | quote -}}实现位于 internal/cmd/interactivetemplatefuncs.gopromptChoiceOnceInteractiveTemplateFunc通过nestedMapAtPath(m, path)定位嵌套键命中且类型为string时直接返回此外--prompt标志forcePromptOnce可以强制忽略已有值、重新询问。这使模板作者可以实现首次初始化询问、之后复用既有配置的行为。仓库的测试脚本 internal/cmd/testdata/scripts/inittemplatefuncs.txtar 用--promptChoice choiceone验证了该路径exec chezmoi execute-template --init --promptChoice choiceone {{ promptChoiceOnce . choice choice (list one two three) }} stdout one同一个测试文件还验证了已有数据时不再提示的行为第二次chezmoi init在存在chezmoi.toml的情况下直接复用了[data]中已有的值。若需要多选可以使用promptMultichoice返回字符串列表支持default列表参数见 promptMultichoice 文档及其幂等变体promptMultichoiceOnce其模板函数层的预填标志为--promptMultichoice多值用/分隔如one/two参见 interactivetemplatefuncs.go。实战组合一套 dotfiles 适配四种机器类型把以上知识组合起来可以在.chezmoi.toml.tmpl中写出既支持交互、又支持预填和幂等重入的初始化模板{{- $choices : list desktop laptop server termux -}} {{- $hosttype : promptChoiceOnce . hosttype What type of host are you on $choices laptop -}} [data] hosttype {{- $hosttype | quote -}}对应的三种初始化方式# 1) 交互式初始化弹框或文本提示中选择 chezmoi init # 2) 无人值守用标志直接指定跳过所有询问 chezmoi init --promptChoice What type of host are you onserver # 3) 二次初始化已有配置直接复用无需再次回答 chezmoi init随后在仓库任意模板如.chezmoitermuxrc.tmpl、dot_zshrc.tmpl中用{{ if eq .data.hosttype termux }}这类条件分支即可实现真正的一份仓库、多机差异化管理——这正是 chezmoi 跨多台异构机器安全管理 dotfiles 的核心工作流。小结promptChoice看似只是一个选择题输入模板函数但围绕它展开的完整机制——参数校验default必须属于choices、TTY 下的 bubbletea 选择框与缩写补全、--no-tty下的文本循环询问、--promptChoice/--promptDefaults的无人值守能力以及promptChoiceOnce带来的幂等重入——共同构成了 chezmoi 初始化阶段采集机器级变量的完整方案。结合 init-functions 索引 中的其他函数promptBool、promptInt、promptString、promptMultichoice及各自的*Once变体你可以在chezmoi init引导流程中精确采集任意类型的配置数据让 dotfiles 仓库在第一时间就知道自己部署在哪类机器上。【免费下载链接】chezmoiManage your dotfiles across multiple diverse machines, securely.项目地址: https://gitcode.com/gh_mirrors/ch/chezmoi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表