stow icon indicating copy to clipboard operation
stow copied to clipboard

The '--dotfiles' option does not work as expected in conjunction with tree folding

Open MalbrottsAsnan opened this issue 11 months ago • 4 comments

Hello,

The behaviour of the '--dotfiles' option seems unexpected when stow folds subtrees containing 'dot-' prefixed files. It appears that tree folding takes precedence over '--dotfiles', which is unintuitive as we are explicitly requesting translation to a dotfile.

Steps to reproduce: $ tree -a ~ /home/user/ ... └── stow  └── stow-dir   └── pkg-dir    └── dot-file

$ cd ~/stow && stow --dotfiles stow-dir

Expected behaviour: $ tree -a ~ /home/user/ ... ├── pkg-dir │ └── .file -> ../stow/stow-dir/pkg-dir/dot-file └── stow  └── stow-dir   └── pkg-dir    └── dot-file

Actual behaviour: $ tree -a ~ /home/user/ ... ├── pkg-dir -> stow/stow-dir/pkg-dir └── stow  └── stow-dir   └── pkg-dir    └── dot-file

Would it be possible to modify the implementation of '--dotfiles' or introduce an option to control this behaviour? While a workaround is to use '--no-folding', it is not ideal since you lose a lot of functionality. Another workaround is to manually create the 'pkg-dir' prior to stowing, which would then also result in the expected behaviour shown above.

Additionally, if this new behaviour is to be implemented, I'm assuming it would be impossible/out of scope to have 'pkg-dir' removed when unstowing with 'stow -D stow-dir'. This means that stow will leave empty directories after itself even when it "owns" everything, which I understand may not align with design guidelines. Should it be implemented however, a note in the '--dotfiles' documentation warning about this would likely also be needed.

MalbrottsAsnan avatar Jan 05 '25 21:01 MalbrottsAsnan

Hi, thanks for the report. Please can you confirm which version you see this on?

aspiers avatar Jan 05 '25 23:01 aspiers

Of course, I also forgot to mention that I'm using WSL2. I'm not sure if/how this affects stow, so if there's a user error on my part, feel free to let me know! I have tested on Debian and Ubuntu and the behavior is identical even though '--verbose' output is different between the stow versions.

On Debian in WSL2:

$ stow -V stow (GNU Stow) version 2.4.1

$ perl -v This is perl 5, version 36, subversion 0 (v5.36.0) built for x86_64-linux-gnu-thread-multi ...

$ hostnamectl ... Virtualization: wsl Operating System: Debian GNU/Linux 12 (bookworm) Kernel: Linux 5.15.167.4-microsoft-standard-WSL2 Architecture: x86-64

On Ubuntu in WSL2:

$ stow -V stow (GNU Stow) version 2.3.1

$ perl -v This is perl 5, version 38, subversion 2 (v5.38.2) built for x86_64-linux-gnu-thread-multi ...

$ hostnamectl ... Virtualization: wsl Operating System: Ubuntu 24.04.1 LTS Kernel: Linux 5.15.167.4-microsoft-standard-WSL2 Architecture: x86-64

Verbose outputs

--verbose=5 on Debian in WSL2:

$ stow --dotfiles --simulate --verbose=5 stow-dir stow dir is /home/user/stow stow dir path relative to target /home/user is stow Planning stow of: stow-dir ... cwd now /home/user      | Joining: stow stow-dir      | Final join: stow/stow-dir Planning stow of package stow-dir...      | Joining: . .stow      | Final join: .stow      | Joining: . .nonstow      | Final join: .nonstow  . not protected; shouldn't skip Stowing contents of stow / stow-dir / . (cwd=/home/user)  target subdir is .      | Joining: stow stow-dir .      | Final join: stow/stow-dir     | Checking whether . is a current/planned node     | link_task_action(.): no task     | dir_task_action(.): no task      | Joining: .      | Final join: .     | parent_link_scheduled_for_removal(.): prefix .     | parent_link_scheduled_for_removal(.): returning false    | is_a_node(.): really exists      | Joining: . pkg-dir      | Final join: pkg-dir      | Joining: . pkg-dir      | Final join: pkg-dir      | Joining: stow stow-dir      | Final join: stow/stow-dir      | Joining: stow/stow-dir .stow-local-ignore      | Final join: stow/stow-dir/.stow-local-ignore      | Joining: /home/user .stow-global-ignore      | Final join: /home/user/.stow-global-ignore  stow/stow-dir/.stow-local-ignore didn't exist  /home/user/.stow-global-ignore didn't exist  Using built-in ignore list   Ignore list regexp for paths: /(?^:(^|/)(^/.stow-local-ignore$|^/LICENSE.|^/COPYING|^/README.)(/|$))/   Ignore list regexp for segments: /(?^:^(CVS|.cvsignore|.svn|.+,v|.#.+|_darcs|#.*#|.gitmodules|.git|.+~|.gitignore|RCS|.hg)$)/  Not ignoring pkg-dir Stowing entry stow / stow-dir / pkg-dir      | Joining: stow stow-dir pkg-dir      | Final join: stow/stow-dir/pkg-dir  level of pkg-dir is 0      | Joining: stow/stow-dir/pkg-dir      | Final join: stow/stow-dir/pkg-dir  link destination stow/stow-dir/pkg-dir   is_a_link(pkg-dir)     | link_task_action(pkg-dir): no task   is_a_link(pkg-dir): returning 0     | Checking whether pkg-dir is a current/planned node     | link_task_action(pkg-dir): no task     | dir_task_action(pkg-dir): no task      | Joining: pkg-dir      | Final join: pkg-dir     | parent_link_scheduled_for_removal(pkg-dir): prefix pkg-dir     | parent_link_scheduled_for_removal(pkg-dir): returning false    | is_a_node(pkg-dir): returning false LINK: pkg-dir => stow/stow-dir/pkg-dir Planning stow of package stow-dir... done cwd restored to /home/user/stow WARNING: in simulation mode so not modifying filesystem.

--verbose=5 on Ubuntu in WSL2:

$ stow --dotfiles --simulate --verbose=5 stow-dir stow dir is /home/user/stow stow dir path relative to target /home/user is stow cwd now /home/user cwd restored to /home/user/stow cwd now /home/user Planning stow of package stow-dir... . not protected Stowing contents of stow/stow-dir (cwd=/home/user) => stow/stow-dir is_a_node(.) link_task_action(.): no task dir_task_action(.): no task parent_link_scheduled_for_removal(.): prefix parent_link_scheduled_for_removal(.): returning false is_a_node(.): really exists stow/stow-dir/.stow-local-ignore didn't exist /home/user/.stow-global-ignore didn't exist Using built-in ignore list Ignore list regexp for paths: /(?^:(^|/)(^/COPYING|^/README.|^/.stow-local-ignore$|^/LICENSE.)(/|$))/ Ignore list regexp for segments: /(?^:^(.+,v|.hg|.gitignore|CVS|.#.+|.git|.cvsignore|RCS|_darcs|.+~|.svn|#.*#)$)/ Not ignoring pkg-dir Adjusting: pkg-dir => pkg-dir Stowing stow / stow-dir / pkg-dir => stow/stow-dir/pkg-dir is_a_link(pkg-dir) link_task_action(pkg-dir): no task is_a_link(pkg-dir): returning 0 is_a_node(pkg-dir) link_task_action(pkg-dir): no task dir_task_action(pkg-dir): no task parent_link_scheduled_for_removal(pkg-dir): prefix pkg-dir parent_link_scheduled_for_removal(pkg-dir): returning false is_a_node(pkg-dir): returning false LINK: pkg-dir => stow/stow-dir/pkg-dir Planning stow of package stow-dir... done cwd restored to /home/user/stow WARNING: in simulation mode so not modifying filesystem.

MalbrottsAsnan avatar Jan 06 '25 00:01 MalbrottsAsnan

Much appreciated, especially with all the very helpful and well-structured detail. While anything prior to 2.4.0 can be flakey with respect to --dotfiles, it sounds like you have discovered a genuine bug here still present in 2.4.1. Hopefully it won't be too hard to figure out and fix given the work I did in 2.4.0 to clean up that code, but I won't know until I take a closer look.

aspiers avatar Jan 06 '25 00:01 aspiers

Thank you for your quick response and for looking into it!

MalbrottsAsnan avatar Jan 06 '25 00:01 MalbrottsAsnan