twpayne / chezmoi

Manage your dotfiles across multiple diverse machines, securely.
https://www.chezmoi.io/
MIT License
12.9k stars 478 forks source link

`—prompt*` not working with `promptOnce*` #2945

Closed chris468 closed 1 year ago

chris468 commented 1 year ago

Describe the bug

chezmoi init --promptString email="me@home.org" prompts instead of using the email value from the command line. chezmoi execute-template --init --promptString email="me@home.org" renders the prompt instead of the value from the command line.

To reproduce

Follow the example from Create a config file on a new machine automatically on the User Guide Setup page, on a clean ubuntu 22.04 vm, script available here:

#!/usr/bin/env bash

mkdir -p ~/.local/share/chezmoi

cat > .local/share/chezmoi/.chezmoi.toml.tmpl <<EOF
{{- \$email := promptStringOnce . "email" "Email address" -}}

[data]
    email = {{ \$email | quote }}
EOF

echo ".local/share/chezmoi/.chezmoi.toml.tmpl contents:"
cat .local/share/chezmoi/.chezmoi.toml.tmpl
echo

curl -fsLS get.chezmoi.io | sh
export PATH="$HOME/bin:$PATH"

chezmoi --verbose execute-template --init --promptString email="me@home.org" < ~/.local/share/chezmoi/.chezmoi.toml.tmpl

chezmoi --verbose init --promptString email="me@home.org"

Output:


$ curl -fsSL https://raw.githubusercontent.com/chris468/chezmoi/prompt-parameter-bug/prompt-param-bug.sh | bash -x
+ mkdir -p /home/chris/.local/share/chezmoi
+ cat                                                                               
+ echo '.local/share/chezmoi/.chezmoi.toml.tmpl contents:'
.local/share/chezmoi/.chezmoi.toml.tmpl contents:
+ cat .local/share/chezmoi/.chezmoi.toml.tmpl                                       
{{- $email := promptStringOnce . "email" "Email address" -}}

[data]
    email = {{ $email | quote }}
+ echo

+ curl -fsLS get.chezmoi.io
+ sh
info found version 2.33.3 for latest/linux/amd64
info installed ./bin/chezmoi
+ export PATH=/home/chris/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
+ PATH=/home/chris/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
+ chezmoi --verbose execute-template --init --promptString email=me@home.org
[data]
    email = "Email address"
+ chezmoi --verbose init --promptString email=me@home.org
Email address? string

Expected behavior

The execute-template command should have output

[data]
    email = "me@home.org"

The init command should have used “me@home.org” for email without prompting.

Output of command with the --verbose flag

From above:

+ chezmoi --verbose execute-template --init --promptString email=me@home.org
[data]
    email = "Email address"
+ chezmoi --verbose init --promptString email=me@home.org
Email address? string

Output of chezmoi doctor

```console $ chezmoi doctor RESULT CHECK MESSAGE ok version v2.33.3, commit fe6010e8b2518ddabfcd5f58236763b4f2e90ff8, built at 2023-04-21T20:41:23Z, built by goreleaser ok latest-version v2.33.3 ok os-arch linux/amd64 (Ubuntu 22.04.2 LTS (Jammy Jellyfish)) ok uname Linux ubuntu-22-04 5.15.0-67-generic #74-Ubuntu SMP Wed Feb 22 14:14:39 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux ok go-version go1.20.3 (gc) ok executable ~/bin/chezmoi ok upgrade-method replace-executable ok config-file no config file found warning source-dir ~/.local/share/chezmoi is a git working tree (dirty) ok suspicious-entries no suspicious entries warning working-tree ~/.local/share/chezmoi is a git working tree (dirty) ok dest-dir ~ is a directory ok umask 002 ok cd-command found /bin/bash ok cd-args /bin/bash info diff-command not set ok edit-command found /usr/bin/vi ok edit-args /usr/bin/vi ok git-command found /usr/bin/git, version 2.34.1 ok merge-command found /usr/bin/vimdiff ok shell-command found /bin/bash ok shell-args /bin/bash info age-command age not found in $PATH ok gpg-command found /usr/bin/gpg, version 2.2.27 info pinentry-command not set info 1password-command op not found in $PATH info bitwarden-command bw not found in $PATH info dashlane-command dcli not found in $PATH info gopass-command gopass not found in $PATH info keepassxc-command keepassxc-cli not found in $PATH info keepassxc-db not set info keeper-command keeper not found in $PATH info lastpass-command lpass not found in $PATH info pass-command pass not found in $PATH info passhole-command ph not found in $PATH info rbw-command rbw not found in $PATH info vault-command vault not found in $PATH info secret-command not set ```

Additional context

Discovered using promptBoolOnce, but used the example straight from the user guide for a reproducing case. I believe it is an issue w/ all of the *Once. promptBool, etc. work.

Here is an attempt to reproduce in the tests. This makes the test hang, I suspect because it has prompted, but I don't know that testing framework.

I saw #2575, don’t think this is the same thing. I don’t understand what the {{- “” -}} at the end of the variables is for but it doesn’t seem to make a difference. I straight out of the setup guide, so if I’m missing something the doc may need to be updated.

twpayne commented 1 year ago

Thank you very much for reporting this, and for the amazing bug report including a full set of scripts to reproduce the issue :)

Simplifying slightly, the fundamental problem was that the --promptBool flag takes a map[string]string value as an argument, but promptBoolOnce was expecting a map[string]bool value. So, promptBoolOnce was silently ignoring the --promptBool value. #2950 fixes this.

For the other aspects:

Your attempt to reproduce the problem with the test framework was really close. The things that stopped it from working are:

The {{- "" -}} is a hack to persuade text/template to remove whitespace around template directives, while evaluating to nothing itself.

Thanks again!

twpayne commented 1 year ago

I believe it is an issue w/ all of the *Once. promptBool, etc. work.

It turns out that it was limited to promptBoolOnce because of the map[string]bool / map[string]string mismatch. promptIntOnce uses a map[string]int consistently, and promptStringOnce uses a map[string]string consistently. The tests seem to verify this.