Unstowing with `--dotfiles` didn't work with `--compat`, because when
traversing the target tree rather than the package tree, there was no
mechanism for mapping a `.foo` file or directory back to its original
`dot-foo` and determine whether it should be unstowed.
So add a reverse `unadjust_dotfile()` mapping mechanism to support
this.
If the target directory as a file named X and a package has a
directory named X, or vice-versa, then it is impossible for Stow
to stow that entry X from the package, even if --adopt is supplied.
However we were previously only handling the former case, and not the
latter, and the test for the former was actually broken. So fix
stow_contents() to handle both cases correctly, fix the broken test,
and add a new test for the latter case.
Stow walks the package and target tree hierarchies by using mutually
recursive pairs of functions:
- `stow_contents()` and `stow_node()`
- `unstow_contents()` and `unstow_node()`
As Stow runs its planning from the target directory (`plan_*()` both
call `within_target_do()`), previously the parameters for these
included:
- `$target_subpath` (or `$target_subdir` in the `*_node()` functions):
the relative path from the target top-level directory to the target
subdirectory (initially `.` at the beginning of recursion). For
example, this could be `dir1/subdir1/file1`.
- `$source`: the relative path from the target _subdirectory_ (N.B. _not_
top-level directory) to the package subdirectory. For example, if
the relative path to the Stow directory is `../stow`, this could be
`../../../stow/pkg1/dir1/subdir1/file1`. This is used when stowing
to construct a new link, or when unstowing to detect whether the
link can be unstowed.
Each time it descends into a further subdirectory of the target and
package, it appends the new path segment onto both of these, and also
prefixes `$source` with another `..`. When the `--dotfiles` parameter
is enabled, it adjusts `$target_subdir`, performing the `dot-foo` =>
`.foo` adjustment on all segments of the path in one go. In this
case, `$target_subpath` could be something like `.dir1/subdir1/file1`,
and the corresponding `$source` could be something like
`../../../stow/pkg1/dot-dir1/subdir1/file1`.
However this doesn't leave an easy way to obtain the relative path
from the target _top-level_ directory to the package subdirectory
(i.e. `../stow/pkg1/dot-dir1/subdir1/file1`), which is needed for
checking its existence and if necessary iterating over its contents.
The current implementation solves this by including an extra `$level`
parameter which tracks the recursion depth, and uses that to strip the
right number of leading path segments off the front of `$source`.
(In the above example, it would remove `../..`.)
This implementation isn't the most elegant because:
- It involves adding things to `$source` and then removing them again.
- It performs the `dot-` => `.` adjustment on every path segment
at each level, which is overkill, since when recursing down a level,
only adjustment on the final subdirectory is required since the higher
segments have already had any required adjustment.
This in turn requires `adjust_dotfile` to be more complex than it
needs to be.
It also prevents a potential future where we might want Stow to
optionally start iterating from within a subdirectory of the whole
package install image / target tree, avoiding adjustment at higher
levels and only doing it at the levels below the starting point.
- It requires passing an extra `$level` parameter which can be
automatically calculated simply by counting the number of slashes
in `$target_subpath`.
So change the `$source` recursion parameter to instead track the
relative path from the top-level package directory to the package
subdirectory or file being considered for (un)stowing, and rename it
to avoid the ambiguity caused by the word "source".
Also automatically calculate the depth simply by counting the number
of slashes, and reconstruct `$source` when needed by combining the
relative path to the Stow directory with the package name and
`$target_subpath`.
Closes#33.
There was a ton of duplication which is not maintainable, so refactor
everything into a single test which still covers the differences.
This in turn revealed some issues in the unstowing logic:
- We shouldn't conflict if we find a file which isn't a link or a
directory; we can just skip over it.
- Unstowing with `--dotfiles` was using the wrong variable to obtain
the package path, and as a result having to perform an unnecessary
call to `adjust_dotfile()`.
So fix those at the same time.
is_a_node(), is_a_dir(), is_a_link() all operate on paths within
the target directory, so make this explicit by avoiding the vague
variable name "$path".
The use of the word "source" to describe a link's destination is
confusing in the context of Stow for reasons explained in the manual.
So rename the $source variable to avoid this.
The use of the word "source" to describe a link's destination is
confusing in the context of Stow for reasons explained in the manual.
So rename the $existing_source variable to $link_dest avoid this.
The use of the word "source" to describe a link's destination is
confusing in the context of Stow for reasons explained in the manual.
So rename the $second_source variable to avoid this.
$path is horribly vague, so rename to $link to be more informative.
Also the use of "$target" to describe a link's destination is very
confusing in the context of Stow for reasons explained in the manual.
So rename to $link_dest.
The $target variable was ambiguous, as it could have referred to the
path to the target directory, or the path to a sub-directory in the
target, as well as its intended meaning of a subpath relative to the
target directory. So rename it to try to find the balance between
clarity and verbosity.
This is very similar to a previous commit which did the same rename in
stow_node().
The $target variable was ambiguous, as it could have referred to the
path to the target directory, or the path to a sub-directory in the
target, as well as its intended meaning of a subpath relative to the
target directory. So rename it to try to find the balance between
clarity and verbosity.
Refactor the compat mode code to reuse the existing unstow_contents()
and unstow_node(). This allows us to remove the parallel versions in
unstow_contents_orig() and unstow_node(), which contained a lot of
duplicated code and were a significant maintenance burden.
The $target variable was ambiguous, as it could have referred to the
path to the target directory, or the path to a sub-directory in the
target, as well as its intended meaning of a subpath relative to the
target directory. So rename it to try to find the balance between
clarity and verbosity.
As previously noted, the old comment style was difficult to edit.
It's also not idiomatic Perl style, so reformat as pod. This exposes
more of the inner workings of Stow as documentation, but that
shouldn't be a problem.
As part of this change, remove outdated and sometimes misleading
information about if/when each function throws an exception.