10

Consider this script.

#! /usr/bin/env bash

mkdir -p target
mkdir -p mydir/package/
touch mydir/package/file

ln --symbolic mydir mylink
file mylink

stow --verbose --dir=./mylink --target=./target package

file target/file

The output is

mylink: symbolic link to mydir
LINK: file => ../mydir/package/file
target/file: symbolic link to ../mydir/package/file

Before running stow, it looks like this:

.
├── mydir
│   └── package
│       └── file
├── mylink -> mydir
└── target

After running stow, on mylink, I expected it to look like this:

.
├── mydir
│   └── package
│       └── file
├── mylink -> mydir
└── target
    └── file -> ../mylink/package/file

However, instead it looks like this:

.
├── mydir
│   └── package
│       └── file
├── mylink -> mydir
└── target
    └── file -> ../mydir/package/file

It seems that the stow command resolves the realpath of the package directory, so instead of pointing to ../mylink/package/file it points to ../mydir/package/file.

This makes sense for avoiding too much indirection, but it happens silently and may not always be desirable. Is there a way to work around this behavior?

Edit: As per request, I will describe an example use case where resolving the realpath is inconvenient.

Symbolic links are sometimes used for compatibility. Debian even talks about this in official policy. Often the target is a single file, but sometimes it is a directory . I happen to have a few hundred on my system in /usr/share/doc/ alone:

$ find /usr/share/doc -xtype d -type l | wc -l
325

The default behavior of stow is fine as long as the symlink target doesn't get moved. But sometimes the desired targeted directory does get moved. For example, on Debian, the vim-runtime package installs files under /usr/share/vim/ in a directory that depends on the version, such as /usr/share/vim/vim64 for version 6.4. However, the package would also update a symlink at /usr/share/vim/vimcurrent that pointed to the current version. This means that a symlink pointing to, say

/usr/share/vim/vim64/doc/cmdline.txt

would break when the next release of Debian upgraded it to

/usr/share/vim/vim70/doc/cmdline.txt

but a symlink to

/usr/share/vim/vimcurrent/doc/cmdline.txt

would work in both versions.

Since stow uses the absolute canonical path of the stow directory, an invocation like

stow --dir=/usr/share/vim/vimcurrent --target=./my-vim-docs doc

would result in symbolic links like, e.g. this:

$ file cmdline.txt
cmdline.txt: symbolic link to ../../../../../usr/share/vim/vim64/doc/cmdline.txt

not like this:

$ file cmdline.txt
cmdline.txt: symbolic link to ../../../../../usr/share/vim/vimcurrent/doc/cmdline.txt

(The motivation for using stow on vimcurrent/docs is to be able to mingle my own vim notes alongside symlinks to the current documentation.) Note that the vimcurrent compatibility symlink is no longer present in current Debian distributions, though it may be in others like Arch Linux; I'm not sure. In any case, here's a script that gives the general idea for vim documentation:

#! /usr/bin/env bash
mkdir -p target
ln --symbolic /usr/share/vim/vim80 vimcurrent
stow --verbose --dir=./vimcurrent --target=./target pack
file target/dist

Output is:

LINK: dist => ../../../../../usr/share/vim/vim80/pack/dist
target/dist: symbolic link to ../../../../../usr/share/vim/vim80/pack/dist

Hypothetically, stow could have a flag called, say, --no-realpath, so the output would look something like this instead:

LINK: dist => ./vimcurrent/pack/dist
target/dist: symbolic link to ./vimcurrent/pack/dist

For other examples of compatibility symlinks that change with each version, here are two more I know of on my laptop:

$ file /usr/share/go
/usr/share/go: symbolic link to go-1.10
$ file /usr/share/mscore
/usr/share/mscore: symbolic link to mscore-2.1

To address the symlink-points-to-symlink case:

#! /usr/bin/env bash
mkdir -p target
mkdir -p mydir/package/
touch mydir/package/file
ln --symbolic mydir mylink
ln --symbolic mylink mylink2
namei mylink2

produces:

f: mylink2
 l mylink2 -> mylink
   l mylink -> mydir
     d mydir

and then:

$ stow --verbose --dir=./mylink2 --target=./target package
$ file target/file

produces:

LINK: file => ../mydir/package/file
target/file: symbolic link to ../mydir/package/file

whereas

$ stow --no-realpath --verbose --dir=./mylink2 --target=./target package
$ file target/file

would produce this:

LINK: file => ../mylink2/package/file
target/file: symbolic link to ../mylink2/package/file

So in the hypothetical --no-realpath behavior it would treat the stow directory as a regular directory.

This feature would be applicable in a scenario where

1) the stow directory has to be a symlink, and

2) it is desirable to preserve that link in the generated symlinks.

While I don't consider the lack of this feature a great deficiency of stow, I hope that this example clarifies the potential usefulness of not always resolving canonical paths.

  • Please could you give an example use case where avoiding this indirection would be helpful? What if mylink instead symlinked to mylink2 which in turn symlinked to mydir? How should Stow decide whether it should create symlinks pointing to ../mylink/package/file or ../mylink2/package/file or ../mydir/package/file? – Adam Spiers Jun 28 '19 at 13:09
  • @AdamSpiers I hope that helps somewhat. I could put this on the Github issue tracker, too, if you'd prefer. – Nathaniel M. Beaver Jun 28 '19 at 22:43
  • Thanks @Nathaniel. Yes please that would be helpful! – Adam Spiers Jun 30 '19 at 5:29
  • 1
7

For now, there's no way.

Internally, stow find absolute canonical path of given path by using chdir to move into the path, then use getcwd() function from POSIX module, which is the Perl interface for POSIX getcwd(), to get the absolute path name.

As POSIX specified, the path name shall contain no components that are . or .., or are symbolic links.

  • 1
    Suggestions on how to fix the implementation to handle this correctly are very welcome. Pull requests are even more welcome! :-) For reference, the issue has been reported here: github.com/aspiers/stow/issues/11 – Adam Spiers Feb 27 '16 at 16:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.