Precedence of .chezmoiremove vs. exact_ attributes?
rlue opened this issue · comments
Describe the bug
This is not a bug in a strict sense; chezmoi is not behaving the way I expect it to, and I hope to make the case here that my expectations agree with how it should work.
I would like to:
- keep an
exact_
directory in my source dir - conditionally ensure the absence of that directory on certain systems via
.chezmoiremove
chezmoi diff
shows that it would add the directory to my target dir, but I would expect .chezmoiremove
to take precedence over a file attribute, since the former offers more expressive and fine-grained control than the latter.
It appears that adding the file to .chezmoiignore
as well resolves this problem—but leaves us having to duplicate entries between the two files. So perhaps another way of stating this "bug" report is that, IMO, entries in .chezmoiremove
should be implicitly ignored, as well.
To reproduce
$ chezmoi cd
$ mkdir exact_foo
$ touch exact_foo/bar
$ echo "foo" >> .chezmoiremove
$ chezmoi diff
Expected behavior
foo
should not appear in the diff.
Why?
Of course, there are more complex cases where the correct behavior is not so clear. What if we list a file in .chezmoiremove
that is within an exact_
directory?
# .chezmoiremove
foo/bar
but
chezmoi
└── exact_foo
├── bar
└── baz
IMO, the behavior of .chezmoiremove
here should mirror that of .chezmoiignore
—which currently ignores the listed file and generates a non-exact copy of the directory foo
.
Output of command with the --verbose
flag
$ chezmoi --verbose diff
diff --git a/foo b/foo
new file mode 40755
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
--- /dev/null
+++ b/foo
Output of chezmoi doctor
$ chezmoi doctor
RESULT CHECK MESSAGE
ok version v2.49.0, commit 2e0573779db0c42717585ac8abc4ad1ab814dfb2, built at 2024-06-10T20:04:26Z, built by goreleaser
ok latest-version v2.49.0
ok os-arch linux/amd64 (Debian GNU/Linux 12 (bookworm))
ok uname Linux gossamer 6.1.0-18-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.76-1 (2024-02-01) x86_64 GNU/Linux
ok go-version go1.22.4 (gc)
ok executable /usr/bin/chezmoi
ok upgrade-method sudo-upgrade-package
ok config-file ~/.config/chezmoi/chezmoi.toml, last modified 2024-06-18T09:46:03-07: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 umask 022
ok cd-command found /bin/bash
ok cd-args /bin/bash
info diff-command not set
ok edit-command found /usr/bin/nvim
ok edit-args /usr/bin/nvim
ok git-command found /usr/bin/git, version 2.39.2
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.40
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
ok pass-command found /usr/bin/pass, version 1.7.4
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
N/A
Thanks for spotting this. This is an interesting case of non-orthogonality in chezmoi.
The tl;dr is that .chezmoiremove
is a separate system to chezmoi's source state and they don't interact well. Use the remove_
attribute on the directory instead.
Note that this is not specific to exact_
directories, so I'll ignore exact_
.
In a sense, the configuration that you have is inconsistent: it states that foo
and foo/bar
should exist (because they are present in the source state) and also that foo
should be removes. The reason that chezmoi does not detect the inconsistency is because chezmoi's order of operations is roughly:
- Read the source state.
- Make a list of files and directories that match any
.chezmoiremove
lines. - Apply the source state.
- Remove the files and directories found in stage 2.
In your case, foo
does not exist at stage 2, so it is not added to the list, and therefore created in stage 3 and not removed in stage 4.
Instead, use the remove_
attribute on foo
, which will tell chezmoi to remove the directory if it is empty.
Hopefully this is now resolved. Please re-open if needed.