Stow doesn’t use the “ignore” option given in the rc file

.rcstow

Summary

--ignore=<regex> lines that I put in my .stowrc does not work. When running Stow, it says "Loading defaults from .stowrc", yet it has no effect. But passing the --ignore=<regex> lines to the command directly works.

Problem

Assume this directory:

user@user-machine:~/test-stow/stow$ tree -a
.
├── a
│   └── car
└── .stowrc

1 directory, 2 files

Contents of ./.stowrc:

--ignore='car'

So my expectation is that running the command stow --verbose=3 a/ while in that directory is equivalent to running stow --ignore='car' --verbose=3 a/ if the ./.stowrc file wasn't there.

Now I run:

user@user-machine:~/test-stow/stow$ stow --verbose=3 a
Loading defaults from .stowrc
stow dir is /home/user/test-stow/stow
stow dir path relative to target /home/user/test-stow is stow
cwd now /home/user/test-stow
cwd restored to /home/user/test-stow/stow
cwd now /home/user/test-stow
Planning stow of package a...
Stowing contents of stow/a (cwd=~/test-stow)
Stowing stow/a/car
LINK: car => stow/a/car
Planning stow of package a... done
cwd restored to /home/user/test-stow/stow
Processing tasks...
cwd now /home/user/test-stow
cwd restored to /home/user/test-stow/stow
Processing tasks... done

Note that this does create the symlink to ./car, despite the ignore line in ./.stowrc.

Now I undo the operation by running stow -D --verbose=3 a/:

user@user-machine:~/test-stow/stow$ stow -D --verbose=3 a/
stow dir is /home/user/test-stow/stow
stow dir path relative to target /home/user/test-stow is stow
cwd now /home/user/test-stow
Planning unstow of package a...
Unstowing from . (cwd=~/test-stow, stow dir=stow)
Unstowing stow/a/car
car did not exist to be unstowed
Planning unstow of package a... done
cwd restored to /home/user/test-stow/stow
cwd now /home/user/test-stow
cwd restored to /home/user/test-stow/stow
Processing tasks...

If I delete everything in ./.stowrc and run stow --verbose=3 --ignore='car' a/, I get a different result:

user@user-machine:~/test-stow/stow$ stow --verbose=3 --ignore='car' a/
stow dir is /home/user/test-stow/stow
stow dir path relative to target /home/user/test-stow is stow
cwd now /home/user/test-stow
cwd restored to /home/user/test-stow/stow
cwd now /home/user/test-stow
Planning stow of package a...
Stowing contents of stow/a (cwd=~/test-stow)
Planning stow of package a... done
cwd restored to /home/user/test-stow/stow
Processing tasks...

Now a symlink to ./car was not created, as expected and desired.

What about $HOME/.stowrc?

Placing the .stowrc file in the home directory instead of $HOME/test-stow/stow has the same effect; a symlink to the file car still gets made.

Ignore lists

Having a file $HOME/test-stow/stow/.stow-local-ignore with the content "car" instead of the .stowrc file doesn't work, either. The symlink to the file named car still gets created.


GNU Stow version: 2.2.0
Perl version: perl 5, version 18

Update

Here is my reply to Adam Spiers' answer.

Best Answer

Thanks for the excellent bug report! I can answer your questions, and as the Stow maintainer I can also fix the issues, but I'd appreciate your feedback from a UX perspective so we can figure out the best fix.

Firstly, it's worth noting that --verbose=5 will give you much more detail about the internals of the ignore mechanism, although in this case it would not be sufficient to explain why things are not behaving the way you expect.

There are two reasons why neither of your .stowrc files worked:

  1. The .stowrc parser splits (option, value) pairs based on the space character, not on =. So a line for an ignore option in that file should start --ignore not --ignore=.
  2. The .stowrc parser doesn't automatically strip quotes. When the --ignore option (or any other option, for that matter) is passed via the CLI, the shell will strip the quotes before Stow sees them. That's why it works there.

So the combination of these two means that your .stowrc should contain:

--ignore car

I've tested that, and indeed it works.

Now, there are probably valid arguments saying that either or even both of these points are actually UX bugs. I certainly agree that they do not provide an intuitive UI. The question is whether the behaviour should be changed, or whether it's better to simply make this clearer in the docs.

My current thinking is that based on Postel's Law, the parser should accept splitting on both space and =, but it should not strip quotes because what if the user really did want to ignore 'car' rather than just car? Also there is an existing and related bug report that options with spaces break in stowrc, so this should be taken into account when implementing any fix. (I'll update that bug after posting this answer.)

I'd welcome your opinions on these.

Finally, I believe your .stow-local-ignore did not work because you placed it in the stow directory rather than in the a/ package directory. The documentation about this seems clear to me, so I think it's fair to write this one off as pilot error. However if you have any suggestions for how to make the docs clearer than I'm all ears.

Thanks again! BTW in future you may want to consider sending bug reports to the bug-stow mailing list (or to the horrible but ethically correct Savannah bug tracker or to the less ethical but more usable github issue tracker) and help requests to the help-stow mailing list. Yes, I know that these are too many options for such a small and quiet project; that's a TODO for another day ...

Related Question