twpayne / chezmoi

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

Comments containing {{ and }} break .chezmoiignore on Windows #3633

Closed PebcakCity closed 8 months ago

PebcakCity commented 8 months ago

Describe the bug

In my .chezmoiignore, I have comments I included that outline a series of steps I needed to take to have certain files be located in different directories on different systems. These comment lines all begin with '#' like ordinary comments. When one or more of the comment lines looks like this:

#   {{- template "bashrc.tmpl" . -}}

... this apparently causes Chezmoi to actually include .chezmoitemplates/bashrc.tmpl at that location and process it as if it's part of .chezmoiignore. When trying to run chezmoi apply or chezmoi diff, I get errors like:

chezmoi: C:/Users/tannmatter/.local/share/chezmoi/.chezmoiignore:64: prepend_to_path () {: invalid pattern

(My .chezmoiignore isn't even 64 lines long, it's actually 52 including all the comments. But I have a function defined in my .chezmoitemplates/bashrc.tmpl file called prepend_to_path that lets me easily prepend directories to my path. Chezmoi apparently includes bashrc.tmpl and tries to process its lines as if they're ignore patterns ala .gitignore/.chezmoiignore.)

To reproduce

  1. Create a file in .chezmoitemplates called bashrc.tmpl that is a template for a .bashrc file
  2. In your .chezmoiignore file, place a comment like # {{- template "bashrc.tmpl" . -}}
  3. Clone the repo on Windows and run chezmoi diff

Expected behavior

Comments, including those with {{- template ... -}} should be ignored

Output of command with the --verbose flag

$ chezmoi --verbose diff
chezmoi: C:/Users/tannmatter/.local/share/chezmoi/.chezmoiignore:64: prepend_to_path () {: invalid pattern

Output of chezmoi doctor

```console $ chezmoi doctor RESULT CHECK MESSAGE ok version v2.47.1, commit 1ce6b2eeb0caf75bd91883e5a968e713a26e7be2, built at 2024-03-03T01:06:52Z, built by goreleaser ok latest-version v2.47.1 ok os-arch windows/amd64 ok systeminfo Microsoft Windows 11 Enterprise (10.0.22621 N/A Build 22621) ok go-version go1.22.0 (gc) ok executable ~/Programs/Networking/chezmoi/chezmoi.exe ok upgrade-method replace-executable ok config-file ~/.config/chezmoi/chezmoi.toml, last modified 2024-03-05T16:13:27-06:00 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 cd-command found C:/WINDOWS/system32/cmd.exe ok cd-args 'C:\\WINDOWS\\system32\\cmd.exe' info diff-command not set ok edit-command found C:/WINDOWS/system32/notepad.exe ok edit-args 'C:\\WINDOWS\\system32\\notepad.exe' ok git-command found C:/Program Files/Git/cmd/git.exe, version 2.44.0 warning merge-command vimdiff not found in $PATH ok shell-command found C:/WINDOWS/system32/cmd.exe ok shell-args 'C:\\WINDOWS\\system32\\cmd.exe' info age-command age not found in $PATH info gpg-command gpg not found in $PATH info pinentry-command not set info 1password-command op not found in $PATH info bitwarden-command bw not found in $PATH info bitwarden-secrets-command bws not found in $PATH info dashlane-command dcli not found in $PATH info doppler-command doppler 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 vlt-command vlt not found in $PATH info secret-command not set ```

Additional context

This only seems to happen on Windows? When I remove these "template" comments, it runs correctly. It took a while for me to figure out what was causing these errors. When I inserted a similar comment into my .chezmoiignore file on a Mac, it did not seem to affect it. I'm using this roundabout method for keeping bashrc in different locations because on my Linux and Mac systems, I keep bashrc in .config/bash. But I'm running Cygwin on Windows and it's ... different. Doesn't handle symlinks too well so I gave up on trying to tame it into being XDG compliant.

Below is the section of my .chezmoiignore that temporarily broke my Chezmoi's brain:

{{ if eq .chezmoi.os "windows" }}
# Ignore Zsh configs, we'll stick with Bash on Cygwin for now
.config/zsh/
.config/zsh/**

# Symlinks cause a world of hurt on Windows/Cygwin and trying to keep these in
# $XDG_CONFIG_HOME will just cause way more trouble than it's worth.
# Keep Cygwin's configs in ~/.bashrc and ~/.bash_profile.  See how below.
.config/bash/
.config/bash/**

# We handle different locations of config files on Windows and non-Windows
# systems like so:
# https://www.chezmoi.io/user-guide/manage-machine-to-machine-differences/#handle-different-file-locations-on-different-systems-with-the-same-contents
#
# 1. Create ~/.local/share/chezmoi/.chezmoitemplates/
# 2. Place inside here the templates for bashrc and bash_profile
# 3. In the bash_profile template, change path of rcfile to source for windows
#    systems to ~/.bashrc.  For non-Windows it's .config/bash/bashrc.
# 4. Under private_dot_config/bash/ create bashrc.tmpl that sources the
#    bashrc.tmpl file in .chezmoitemplates:
#    {{- template "bashrc.tmpl" . -}}
#    and bash_profile.tmpl that sources bash_profile.tmpl from .chezmoitemplates
#    {{- template "bash_profile.tmpl" . -}}
# 5. At the root of the repo, create dot_bashrc.tmpl and dot_bash_profile.tmpl
#    that do the same as above.
# 6. In .chezmoiignore (this file), for non-windows systems ignore ~/.bashrc and
#    ~/bash_profile.  For windows systems, ignore .config/bash/bashrc and
#    .config/bash/bash_profile.
# 7. Create a script called run_once_after_symlink_bashrc_and_zshenv.sh.tmpl -
#    this script should only run on non-Windows systems.  It will check if
#    there is already a file called ~/.bashrc, and if not it will create a
#    symlink there pointing to .config/bash/bashrc.  It does the same for
#    ~/.zshenv and .config/zsh/.zshenv.

{{ end }}

Thank you for Chezmoi, it's awesome! Keep up the good work.

halostatue commented 8 months ago

The presence of # … does not mean anything to go templates. If you want to put comments like that, you will need to either use (a) a delimiter directive, (b) template them out ({{ "{{" }}- template "basic.tmpl" . -}}), (c) escape them ({\{- template "basic.tmpl" -}}), or (d) fake them out ([[- template "basic.tmpl" -]]).

This is probably only visible on Windows because of the {{ if eq .chezmoi.os "windows" }} at the beginning. While Go templates more or less parse everything, they do so "opportunistically", so that if an if condition prevents template replacements from being seen, it will not be executed.

PebcakCity commented 8 months ago

Understood, thanks for the info.