Closed jakan0 closed 10 months ago
Thank you very much for reporting this with clear steps on how to reproduce the problem - much appreciated!
This is definitely a bug in chezmoi. I've added a test case to reproduce the problem in #2133.
OK, so on further investigation this has revealed a rather subtle flaw in chezmoi that might take a while to fix. Roughly what seems to be happening is:
remove_
directory containing a file that may or may not exist (the files contents are a template that might be empty).remove_
directories is currently a horrible hack. Specifically, chezmoi adds them to a list when it encounters them and then runs rmdir
on each remove_
directory as a post-apply phase. This removes the directory if it contains no entries, or keeps if it contains at least one entry (whether or not that entry is managed by chezmoi).remove_
directories should be removed if they contain no entries. However, whether the contained file should exist or not can only be determined by evaluating all entries of that directory, which chezmoi does not do correctly..foobar has changed since chezmoi last wrote it
error comes from chezmoi confusing itself because chezmoi records that it last wrote a directory, chezmoi doesn't record that chezmoi later removed that directory with rmdir
, and so chezmoi thinks that someone else removed (changed) the directory.Fixing this will require some effort. The short term fix is to remove the remove_
attribute from the .foobar
directory (chezmoi chattr noremove ~/.foobar
) and add a run_after_
script that removes the directory if it is empty (echo "#\!/bin/sh\nrmdir $HOME/.foobar" > $(chezmoi source-path)/run_after_remove-foobar-if-empty.sh
).
Thanks again for your keen insight and reporting the issue - much appricated!
I'm also running into this problem. The run_after
workaround is only partially working for me though (perhaps I have a slightly different scenario?).
If I repeatedly run chezmoi apply
on a machine where the directories are empty, they are removed as expected, but the next run of chezmoi apply
complains, saying <removeDir> has changed since chezmoi last wrote it
. I think this is because chezmoi has a recording of this directory existing in its state, but then the run_after script removes the directory, causing chezmoi to rightfully complain that things are out of sync.
I'm curious if part of the solution is to only record the <removeDir>
in the entryState
if it contains at least one file or directory that is present and managed by chezmoi?
Thanks @twpayne for investigating this so quickly. I understand that the fix might not be an easy one. I'm currently refactoring my dotfiles repository to take advantage of the new features of chezmoi, so I think I'm just going to leave the remove_
attributes and just deal with the errors one by one when I apply the changes, because I don't want to have for example empty VS Code directories on headless servers.
I don't want to have for example empty VS Code directories on headless servers.
For this you can use .chezmoiignore
to not create the VS Code directory at all on headless servers.
Yeah sorry, I know about .chezmoiignore
, and I've been using it to manage for example my personal and work dotfiles in the same repo. VS Code was actually a really bad example because that won't end up on a headless server in the first place. A better example would be .bashrc
and other Bash related files. Because those are created by default almost always, and I use Zsh as a shell whenever I can, I would like to get rid of Bash config files.
I also tried using a combination of .chezmoiignore
and .chezmoiremove
to get rid of those unwanted config files, but either I get e.g. chezmoi: .bashrc: inconsistent state (.chezmoiremove, private_dot_bashrc.tmpl)
error even when the template outputs an empty file, or the unwanted files are completely ignored.
Describe the bug
I'm not sure if this is just a misunderstanding on my part on how the
remove_
attribute is supposed to work or if it's a bug. What I'm trying to do is to not create empty directory paths when a template file in the path has no output.Initially everything seems to be working fine, but when
apply
command is run for the second time, chezmoi complains that path has changed since chezmoi last wrote it. To me it seems like the internal database is not updated after empty directories withremove_
attribute are removed.To reproduce
Create the following repository structure:
Add the following content to the
.chezmoi.toml.tmpl
file.Add the following content to the
dot_nobackup.tmpl
file.Expected behavior
Based on the documentation I expected to see no empty directories being created, which kind of are not being created, and then the subsequent
apply
command to not complain about the path being changed.Output of command with the
--verbose
flagOutput of
chezmoi doctor
Additional context
The output shown above is from a simplified example running in a Podman container for demonstration purposes but the same thing happens when executing this on the host. The host machine's output of
chezmoi doctor
is shown below.