Compare commits

...

520 commits

Author SHA1 Message Date
08d7a9f7af Release 2.4.0
-----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEElCuQdazKBOkDfHP+0xtVY9rB1PoFAmYS3jkACgkQ0xtVY9rB
 1PqSxBAAvPPMSrrxdfGAL9anzCDZArRrtplbS1493fj+OiNIjDWSGsJwm1mZX1ny
 i04te8Hne/ppZs/CrYAe0PZGl6LowswBKFuHkft//f9maeXG/zl+Uh4E7dYWhXik
 N0+9cgh/ngKJ5QgQelfNxZGrHTZZmbbnNfrtuMPqGIDGIDSzNw2qlqdFzp9VxRth
 /dbLLAHoRXY2uRhSgSnEhnk+zJyxR9od5tU3p094xyUEhbBkNRzCE4TwA9oGvyFQ
 N6onEo4wj5w8Mqtu5p6BY5IktYIgechJxF86Sqy27UU/uNQyzeaG2Qs+diwScpop
 9eOsEUDY5mi7oLs4KME0SGqF/V54Spv+QDGks7bftvSQf3WQvFWX+w1fYymbtctD
 US1caKlsleODnQGmyXEBPyNwGmsLmbaF03yIW1BtLfibDxKeDXK0e2zznpBHRRGO
 2klSjH+qd2hqDT3eYNP8SLpRPUdWiuHP2fb1LV+VzjO7vR4iPLdjvTddFEsm7u2M
 IknSXtxCzJuBD4Dz9fZ/fbVEp+2wYmbtKgqmcnKSNtZ5GaFrmA96mekAbyVWYwdB
 IHuscAWlZSCwJJVPp3VMVGVdXfbYhLJRC+Ft6QAzJeJZ2Q44dxnmPDLQHpngNXWJ
 3YhZ62j5C0wInTh0NzUiDbGkxHwY1v4xJC4OXrR6k8+qqPOe1J4=
 =SC3E
 -----END PGP SIGNATURE-----
gpgsig -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEdnljh8gT62W19LaLaFR4GgSIQhwFAmZdM3cACgkQaFR4GgSI
 Qhx/GA/7BbccrVBYNEnu1TJ9riozvN0k1AO6LE96R7QJQH+hpVcM+al4uIc2+GXA
 gcgoVtdADv7nD3DMtQsJlPxQsS+RFjaipZy3kdLSZyU3EixK/Zy2GtK0zjYLMlI/
 rGEEkPx0um3MBm/gtvfZ/pK9i9v2Au61jn49+z4moPnfc4Gk6ZlRXtggDP4ApHPp
 uHeQmr34AZ+dAcc+cs7bCuZvzxxv97WNB7dfFA8RR3+5cQzkbw+Fjjp4GT1J6ifA
 pn4znVZCdb4HhqjFoQzRi68x61MVdhEq4309Mm8xGi7fTqWgxoRPZjKmgpLUF0Wp
 rUNpmd+whNiebMhi0G1yYl1+Pf0x5Thoa7x66M6YWrSMwbr5KJuU3XFNQAr787ls
 pN3nXimX3jw1Mrp8QP4WQby563jHqG4yzBNn+qX22xXxhZOctDJFUDmGZMHHRD5D
 +GICfmgCEp1Ph/YlP4x34jnC4phoIKRs1pUQuIKZM9ECN5Pg6spbT5BmuOn2AhtF
 dLgdSfXAEhnfhxNzf+uvHgelgeeXpTTZEJbX63XoZelK337f1n9CL4Cbumm3JCNS
 YcgJV5L/lw7jRHcaSnyKY37b6iw5+vOdr5yibgJN1LlCGVEbHdpBOPoFZkBA1cTM
 TouP87RHfb47yu+W8WYnBZ+Tr9M6h1S7gfTJ+qjJf244wWaYLO8=
 =Q/B6
 -----END PGP SIGNATURE-----

Pull in upstream Stow 2.4.0
2024-06-03 13:07:34 +10:00
Adam Spiers
1e2513417d
Merge pull request #108 from aspiers/release-v2.4.0 2024-04-07 18:55:18 +01:00
Adam Spiers
a7b1200b63
Merge pull request #97 from ilyagr/patch-1 2024-04-07 18:54:44 +01:00
Adam Spiers
20031c0001 Rebuild META.* 2024-04-07 18:38:12 +01:00
Adam Spiers
9985de7c78 HOWTO-RELEASE: THANKS is no longer being updated 2024-04-07 18:34:35 +01:00
Adam Spiers
413278f178 Update NEWS for v2.4.0 2024-04-07 18:32:51 +01:00
Adam Spiers
fdac519bdf Bump version to 2.4.0 2024-04-07 18:24:49 +01:00
Adam Spiers
49aa3458e5 Add details on how to view coverage locally
Unfortunately for now, Coveralls reports don't include source due
to #84, but this is a good workaround.
2024-04-07 18:22:56 +01:00
Adam Spiers
cbc12d7a3b stow: remove misleading comment about current dir
The current directory is changed by within_target_do() which is called
by `plan_stow()`, `plan_unstow()`, and `process_tasks()`.  It is not
changed when constructing a new `Stow` object, so remove this outdated
and misleading comment.

Fixes #102.
2024-04-07 18:00:03 +01:00
Adam Spiers
143dbf83e2
Merge pull request #107 from aspiers/improve-dotfiles-fix 2024-04-07 17:56:54 +01:00
Adam Spiers
94ed916466 t/unstow.t: move final set of tests into a subtest 2024-04-07 17:44:44 +01:00
Adam Spiers
c0b8890b14 t/unstow.t: remove superfluous spaces 2024-04-07 17:24:13 +01:00
Adam Spiers
93fc195ddb Fix unstowing with --compat --dotfiles
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.
2024-04-07 17:21:44 +01:00
Adam Spiers
723ddcf3a4 t/dotfiles.t: improve language in test names and assertion messages
We use the term "directory" (or "dir" for short) rather than "folder".
Also explicitly say whether a test is stowing or unstowing, and fix
the odd typo.
2024-04-07 17:21:10 +01:00
Adam Spiers
34421ba5cf stow_contents: fix bugs and corner cases with type mismatch conflicts
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.
2024-04-07 17:21:10 +01:00
Adam Spiers
8ed799a3a3 t/unstow.t: create a bunch of unowned files to make tests more robust
This should make it harder for Stow to do the right thing.
2024-04-07 17:21:10 +01:00
Adam Spiers
afa50077c9 dotfiles: switch {un,}stow_{contents,node}() recursion parameters
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.
2024-04-07 17:21:07 +01:00
Adam Spiers
744ba651f5 unstow_link_node(): don't register conflicts when unstowing unowned links 2024-04-07 15:47:38 +01:00
Adam Spiers
06fdfc185f merge unstow_orig.t into unstow.t and fix unstowing logic
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.
2024-04-07 15:47:38 +01:00
Adam Spiers
001b287b1b allow playground/ directory for testing stuff 2024-04-07 15:47:38 +01:00
Adam Spiers
a7c251c316 tidy up MANIFEST.SKIP 2024-04-07 15:47:38 +01:00
Adam Spiers
5e21f47879 read_a_link(): clarify debug message when it's a real link 2024-04-07 15:47:38 +01:00
Adam Spiers
a070116621 Fix Dockerfile by updating from jessie to bookworm 2024-04-07 13:50:09 +01:00
Adam Spiers
fee2225dc9
Merge pull request #106 from aspiers/dev 2024-04-06 15:37:36 +01:00
Adam Spiers
5bb65f60d6 Update manifest files to keep ./Build distcheck happy 2024-04-06 15:09:53 +01:00
Adam Spiers
748a34b211 Revert "testutil: Add sanity check for cwd"
This reverts commit 5d4e68291e.

It turns out that this broke `make distcheck`.
2024-04-06 14:59:52 +01:00
Adam Spiers
7815bc8b44 Revert "Remove unnecessary AM_MAKEINFOFLAGS tweak"
This reverts commit 1a20a3f7ee.

It turns out that `texi2dvi` _does_ require `-I $(srcdir)` for
`@verbatiminclude default-ignore-list` to work after all.  It's needed
not for a normal docs build, but when `make distcheck` is run,
presumably because `distcheck` runs from a different directory.
2024-04-06 14:54:32 +01:00
Adam Spiers
c691b8fa6e Makefile.am: include DEFAULT_IGNORE_LIST in doc_deps 2024-04-06 14:39:16 +01:00
Adam Spiers
2a647d125f iterate over directories in sorted order
This makes behaviour more deterministic, and makes debugging easier.
2024-04-06 13:33:53 +01:00
Adam Spiers
e9ad20576c t/unstow.t: convert to use subtests 2024-04-06 11:59:23 +01:00
Adam Spiers
6d6781dcef t/unstow_orig.t: use like() for regexp matching tests
This is better because it outputs the mismatching value when
the matching check fails.
2024-04-06 11:59:10 +01:00
Adam Spiers
599944bce1 t/unstow_orig.t: use is() for equality tests
This is better because it outputs the mismatching values when
the equality check fails.
2024-04-06 11:51:37 +01:00
Adam Spiers
bca711fac2 tests: use stderr_like() instead of home-grown STDERR capturing
The STDERR capturing in testutil just reinvents Test::Output which
we already use in chkstow.t, so it's pointless to reinvent that wheel.
2024-04-06 11:33:18 +01:00
Adam Spiers
ebfbb6cc13 testutil: rename parameter names to be less confusing
$target was the source of the link, and $source was the
target (destination) of the link.  Obviously this was hopelessly
confusing, so rename to avoid this.
2024-04-05 22:32:12 +01:00
Adam Spiers
238346f134 manual: clarify the pros and cons and history of --compat 2024-04-05 22:28:40 +01:00
Adam Spiers
96ada510fd
Merge pull request #105 from aspiers/github-workflow 2024-04-05 01:57:29 +01:00
Adam Spiers
58c1946ed9 Port Travis CI workflow to a GitHub CI workflow
Travis is no longer free, so move to GitHub.  (In the future ideally
we should reduce dependencies on proprietary platforms.)
2024-04-05 01:52:42 +01:00
Adam Spiers
4cde7eb19f t/stow.t: fix typos, whitespace, and ordering of lines 2024-04-01 23:58:17 +01:00
Adam Spiers
67081cec02 testutil: use croak() instead of die() for more useful errors 2024-04-01 23:58:17 +01:00
Adam Spiers
1282acf6b5 t/stow: use like() instead of ok(... =~ /.../) 2024-04-01 23:58:17 +01:00
Adam Spiers
4cac249ddc rename $path => $target_path in node helpers
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".
2024-04-01 23:58:17 +01:00
Adam Spiers
2c9065995c fold_tree: rename $target parameter to $target_subdir
$target is vague and could refer to the top-level target directory,
so rename to clarify.
2024-04-01 22:39:32 +01:00
Adam Spiers
8f6a320b50 fold_tree: rename $source parameter to $pkg_subpath
$source is vague and confusing as per the manual.
2024-04-01 22:39:32 +01:00
Adam Spiers
bae7890aa5 unstow_node / unstow_existing_node: rename foldable return value
$parent is a bit vague so rename to $parent_in_pkg.
2024-04-01 22:39:32 +01:00
Adam Spiers
b3ed86d616 unstow_valid_link: rename $existing_path
Unqualified references to "path" are horribly vague, so rename to
$existing_pkg_path_from_cwd for clarity.
2024-04-01 22:39:32 +01:00
Adam Spiers
c45a0632a9 stow_node: rename $existing_path
Unqualified references to "path" are horribly vague, so rename to
$existing_pkg_path_from_cwd for clarity.
2024-04-01 22:39:32 +01:00
Adam Spiers
3c904dade2 link_owned_by_package: rename $source => $link_dest
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.
2024-04-01 22:39:32 +01:00
Adam Spiers
381fd71155 remove or rename XXX
Remove old XXX FIXMEs which tell us nothing useful and may not be
relevant any more.

Also rename another XXX to an industry-standard FIXME.
2024-04-01 22:39:32 +01:00
Adam Spiers
221449d640 unstow_node: remove redundant return 2024-04-01 22:39:32 +01:00
Adam Spiers
a337a2fcd0 Change debug indentation in some helpers
These helpers can be called at more deeply nested levels, so they
should be indented more than they were.
2024-04-01 22:39:32 +01:00
Adam Spiers
08e1c902ec unstow_link_node: rename $existing_path
Unqualified references to "path" are horribly vague, so rename to
$existing_pkg_path_from_cwd for clarity.
2024-04-01 22:39:32 +01:00
Adam Spiers
4272e7c4bb unstow_link_node: rename $existing_source => $link_dest
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.
2024-04-01 22:39:32 +01:00
Adam Spiers
4525b9447d unstow_contents: remove reference to "source"
The use of the word "source" is confusing in the context of Stow for
reasons explained in the manual.
2024-04-01 22:39:32 +01:00
Adam Spiers
a8c93487c3 stow_node: remove comments about implementation details from POD
These don't add much value, and the reference to $source was out of
date anyway.
2024-04-01 22:39:32 +01:00
Adam Spiers
b137191d27 stow_node: rename $second_source => $link_dest
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.
2024-04-01 22:39:32 +01:00
Adam Spiers
b5a467fd06 foldable: make more understandable
Improve variable names, POD, and add helpful comments.
2024-04-01 22:39:32 +01:00
Adam Spiers
cc521ec14e foldable: rename $path to $target_node_path
$path is horribly vague, so rename it to be more informative.
2024-04-01 22:39:32 +01:00
Adam Spiers
09a34e7272 foldable: add debug for different cases when not foldable 2024-04-01 22:39:32 +01:00
Adam Spiers
1b597999e2 read_a_link: improve variable names
$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.
2024-04-01 22:39:32 +01:00
Adam Spiers
79f90d39b3 parent_link_scheduled_for_removal: tweak debug 2024-04-01 22:39:32 +01:00
Adam Spiers
2c255af187 t/unstow_orig: split into subtests 2024-04-01 22:39:32 +01:00
Adam Spiers
6cf41850b3 foldable: rename $target => $target_subdir
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.
2024-04-01 22:39:32 +01:00
Adam Spiers
2851b36df4 find_stowed_path: rename $path / $dest to $pkg_path_from_cwd
$path is horribly vague, so rename to be more informative.
2024-04-01 22:39:32 +01:00
Adam Spiers
0daf352200 unstow_node: rename $path to $pkg_path_from_cwd
$path is horribly vague, so rename to be more informative.
2024-04-01 22:39:32 +01:00
Adam Spiers
6b9bbc9cbb link_dest_within_stow_dir: rename $path to $pkg_subpath
$path is horribly vague, so rename to be more informative.
2024-04-01 22:39:32 +01:00
Adam Spiers
170d161692 find_containing_marked_stow_dir: rename $path to $pkg_path_from_cwd
$path is horribly vague, so rename to be more informative.
2024-04-01 22:39:32 +01:00
Adam Spiers
75c892abc6 unstow_* helpers: rename $path to $pkg_path_from_cwd
$path is horribly vague, so rename to be more informative.
2024-04-01 22:39:32 +01:00
Adam Spiers
c0060443ee marked_stow_dir: rename $path to $dir
It's always a directory, so make this explicit.
2024-04-01 22:39:32 +01:00
Adam Spiers
caefb641b8 find_stowed_path: reintroduce missing comment lines
These lines were accidentally removed by 84367681.
2024-04-01 22:39:32 +01:00
Adam Spiers
10c86841de stow_contents / unstow_node: rename $target => $target_sub{dir,path}
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.
2024-04-01 22:39:32 +01:00
Adam Spiers
8a17d8b4f2 manual: use American punctuation of "vs."
GNU and Stow are both originally from the USA, so it makes sense
to stay consistent with American English.
2024-04-01 22:39:32 +01:00
Adam Spiers
0782be7106 Remove unstow_*_orig() functions
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.
2024-04-01 22:39:32 +01:00
Adam Spiers
4054d40a2a emacs: tweak more cperl indentation config to match existing style 2024-04-01 22:39:32 +01:00
Adam Spiers
456424c560 unstow_node_orig: replace a bunch of duplicated code with unstow_link_node() 2024-04-01 22:39:32 +01:00
Adam Spiers
517384407b unstow_node: extract new unstow_existing_node() sub 2024-04-01 22:39:32 +01:00
Adam Spiers
42cc1d2e60 unstow_node: extract new unstow_link_node() sub 2024-04-01 22:39:32 +01:00
Adam Spiers
cc592bdc44 unstow_node: extract new unstow_valid_link() sub 2024-04-01 22:39:32 +01:00
Adam Spiers
1f752a3c94 stow_node: rename $target => $target_subpath
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.
2024-04-01 22:39:32 +01:00
Adam Spiers
86f03d115d t/dotfiles.t: switch to subtests 2024-04-01 22:39:32 +01:00
Adam Spiers
a328c2cd4b t/stow: convert to subtests() 2024-04-01 22:39:32 +01:00
Adam Spiers
0871a483cf rename $existing_source => $existing_link_dest
Source can be ambiguous, as mentioned in the manual.
2024-04-01 00:39:18 +01:00
Adam Spiers
e0212d4f49 stow_node(): fix odd whitespace 2024-04-01 00:35:35 +01:00
Adam Spiers
f60c203c45 should_skip_target(): add docs explaining its purpose 2024-04-01 00:34:39 +01:00
Adam Spiers
c2da8b416d do_link(): improve variable names 2024-04-01 00:34:19 +01:00
Adam Spiers
48c6b5956b Add emacs config to prevent insertion of hard tabs 2024-04-01 00:07:33 +01:00
Adam Spiers
bffc347a19 Remove hard tabs 2024-04-01 00:06:24 +01:00
Adam Spiers
8c09d41054 add unit tests for adjust_dotfiles() 2024-03-31 23:52:00 +01:00
Adam Spiers
2f762e3908 Merge commit 'pullreqs/70' into dev 2024-03-31 23:41:02 +01:00
Adam Spiers
e8c46cf058 manual: disambiguate meaning of "source" 2024-03-31 23:20:22 +01:00
Adam Spiers
373ef62e70 manual: clarify that installation image is pre-installation 2024-03-31 23:20:22 +01:00
Adam Spiers
245dc83849 Stow.pm: reformat old comment style as pod
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.
2024-03-31 23:19:08 +01:00
Adam Spiers
f4f3836c5f Stow.pm: rename $ldest to $link_dest for clarity 2024-03-31 15:38:38 +01:00
Adam Spiers
1be40c0532 Stow.pm: reformat comments
Some methods had comments with a prefix which made the paragraph
inconveniently narrow, and made refilling it really awkward.  So
switch to a more natural comment style.
2024-03-31 15:33:14 +01:00
Adam Spiers
11d4ff01d7 manual: avoid double spaces after "i.e." 2024-03-31 15:25:35 +01:00
Adam Spiers
2791d00d06 manual: Expand the definition of symlinks and disambiguate "target"
Target can have two opposing meanings:

1. the target directory where symlinks are managed by Stow, and
2. the destinations of those symlinks

So try to move away from this by using the word "destination" for
symlinks.
2024-03-31 15:25:26 +01:00
Adam Spiers
d12f107f3c NEWS: more updates in preparation for next release 2024-03-31 14:11:36 +01:00
Adam Spiers
8436768144 Eliminate erroneous warning when unstowing (#65)
When unstowing a package, cleanup_invalid_links() is invoked to remove
any invalid links owned by Stow.  It was invoking link_owned_by_package()
to check whether each existing link is owned by Stow.  This in turn
called find_stowed_path() which since 40a0807185 was not allowing for
the possibility that it could be passed a symlink *not* owned by Stow
with an absolute target and consequently emitting an erroneous warning.

So remove this erroneous warning, and refactor find_stowed_path()
to use two new helper functions for detecting stow directories:
link_dest_within_stow_dir() and find_containing_marked_stow_dir().
Also refactor the logic within each to be simpler and more accurate,
and add more test cases to the corresponding parts of the test suite.

Fixes #65.
Closes #103.

https://github.com/aspiers/stow/issues/65
2024-03-31 14:03:47 +01:00
Adam Spiers
877fc0ce7e cleanup_invalid_links: add test for non-cleanup of an unowned link 2024-03-31 12:24:02 +01:00
Adam Spiers
541faf68eb cleanup_invalid_links: improve docs 2024-03-31 12:16:42 +01:00
Adam Spiers
08b06ccb40 t/cleanup_invalid_links: divide into subtests
This makes the code and test output both more legible.
2024-03-31 12:16:42 +01:00
Adam Spiers
a2beb7b371 Separate treatment of .stow and .nonstow marked dirs
Placing a .stow file in a directory tells Stow that this directory
should be considered a Stow directory.  This is already
well-documented.

There was an undocumented and slightly broken feature where placing a
.nonstow file in a directory was treated in exactly the same way.  The
intention was for .nonstow to cause Stow to skip stowing into and
unstowing from that directory and any of its descendants.  However, it
also caused Stow to consider symlinks into any of those directories as
owned by Stow, even though that was clearly not the intention.  So
separate treatment of .stow and .nonstow markers, so that while both
provide protection against Stow stowing and unstowing, only .stow
affects the symlink ownership logic in find_stowed_path() and
marked_stow_dir().

Probably no one uses the undocumented .nonstow feature, so it may make
sense to remove this in future.
2024-03-31 12:15:53 +01:00
Adam Spiers
287d8016f6 join_paths: improve docs to clarify purpose / differences
join_paths() is used in specific ways and has specific behaviour
required which is nuanced and not obvious at first sight.  So make
this explicit for future reference.
2024-03-31 12:04:09 +01:00
Adam Spiers
4d711fc4ac Make join_paths correctly handle absolute paths
Previously join_paths() was incorrectly handling absolute paths, for
example join_paths('a/b', '/c/d') would return 'a/b/c/d' rather than
'/c/d'.  This was a problem when following a symlink in
find_stowed_path(), because if the symlink was not owned by Stow and
pointed to an absolute path, find_stowed_path() might accidentally
deem the link owned by Stow, if c/d was a valid path relative to the
current directory.
2024-03-31 12:02:58 +01:00
Adam Spiers
ff4d87efaf Disable emacs auto-fill-mode
This completely messes up the current function documentation.
2024-03-31 12:02:58 +01:00
Adam Spiers
d1480195b6 Move setting of cperl-indent-level to .dir-locals.el
This removes duplication.
2024-03-31 12:02:58 +01:00
Adam Spiers
66ca2826d6 Highlight an issue with prove overriding TEST_VERBOSE 2024-03-31 12:02:57 +01:00
Adam Spiers
1657c5b772 t/find_stowed_path.t: Add a couple of missing spaces 2024-03-10 17:40:17 +00:00
Adam Spiers
9db0de3005 Add some helpful comments
Explain a few things in preparation for a bugfix.
2024-03-10 17:40:17 +00:00
Adam Spiers
aa03922520 manual: fix duplicated "of" typo 2024-03-09 17:57:04 +00:00
Adam Spiers
9ce37d9575 Remove $stow_path parameter from unstow_{contents,node}{,_orig}()
Unlike with the stow_{contents,node}{,_orig}() counterpart functions,
when unstowing, it's not necessary to pass the $stow_path parameter
because it can never differ from $self->{stow_path}.

The stow_*() functions need this for the corner case of unfolding a
tree which is stowed from a different stow directory to the one being
used for the current stowing operation (see the "Multiple Stow
Directories" section of the manual).
2024-03-09 17:57:04 +00:00
Adam Spiers
4e2776224f Tweak text of error and debug messages 2024-03-09 17:57:04 +00:00
Adam Spiers
b7bf77da52 Add a missing period to the stow_contents() comments. 2024-03-09 17:57:04 +00:00
Adam Spiers
72084f6fec Add a comment explaining that $node_target can be adjusted for dot- prefix 2024-03-09 17:57:04 +00:00
Adam Spiers
a3700e7171 Add a comment explaining path in stow_contents() 2024-03-09 17:57:04 +00:00
Adam Spiers
20bee7428e Add a comment explaining $stow_path parameter of stow_contents()
At first sight this parameter looks redundant since we have
$self->{stow_path}, but in one case the value can differ from that,
so mention that explicitly.
2024-03-09 17:57:04 +00:00
Adam Spiers
f51fc1248c plan_*: rename $path to $pkg_path for clarity
$path is a vague variable name.
2024-03-09 17:57:04 +00:00
Adam Spiers
457fa98527 dotfiles.t: improve comment descriptions 2024-03-09 17:57:04 +00:00
Adam Spiers
6519ee8426 aclocal.m4: update to 1.16.5 2024-03-09 17:56:57 +00:00
Adam Spiers
5d4e68291e testutil: Add sanity check for cwd 2024-03-09 17:56:57 +00:00
Adam Spiers
2c7d3d4762 manual: update the Reporting Bugs / Known Bugs sections 2024-03-09 17:56:48 +00:00
Adam Spiers
c30792270e manual: use @email{} for email addresses 2024-03-09 17:56:41 +00:00
Adam Spiers
cb4b0c6a9a Remove trailing whitespace 2024-03-09 17:56:41 +00:00
Adam Spiers
a426a5979d testutil: clarify reason for default paths in new_Stow() 2024-03-09 17:56:29 +00:00
Adam Spiers
72140071ad manual: improve explanation of target directory definition
Bring this more up to date by mentioning the dotfiles use case.
2024-03-09 17:56:14 +00:00
Adam Spiers
478c7b921d Add watch target to Makefile for easier hacking 2024-03-09 17:56:14 +00:00
Adam Spiers
28a4e82741 CONTRIBUTING: document how to test using prove(1) 2024-03-09 17:56:02 +00:00
51e303a798
Add explict --enable-relative ./configure flag for using FindBin 2023-10-23 16:13:57 +11:00
70b6c6cd9e
Prerelease v2.3.2-fixbug56727 2023-10-23 14:54:38 +11:00
47634b9cf1
Support relative --with-pmdir by using FindBin 2023-10-23 14:38:27 +11:00
a6391cd291
Save upgraded aclocal.m4 produced by autoreconf -vi 2023-10-23 14:02:03 +11:00
23928d5af8
Merge branch 'bug-56727'
Merge in fixed --dotfiles support. We need it.
2023-10-23 12:49:55 +11:00
Ilya Grigoriev
6f76606390
Add .gitmodules to the default ignore list 2022-08-12 20:43:56 -07:00
Adam Spiers
a829eeb4a0 Upgrade aclocal to 1.16.3 2021-04-15 15:11:30 +01:00
Adam Spiers
ee240c5bf2 cleanup_invalid_links: it's a bug if called with a non-directory 2021-04-15 15:11:30 +01:00
Adam Spiers
6870e96873 CONTRIBUTING: Add a section on how to run the tests 2021-04-15 15:11:30 +01:00
Adam Spiers
64e0dc8793 Beef up README.md and add CONTRIBUTING.md 2021-04-15 15:11:30 +01:00
Adam Spiers
205158a528 manual: request --verbose=5 for bug reports 2021-04-15 15:11:30 +01:00
Adam Spiers
5b0efb3757 AUTHORS: mention THANKS file 2021-04-15 15:11:30 +01:00
Adam Spiers
a3f526edc2 NEWS: update for 2.3.2 2021-04-15 15:11:30 +01:00
Adam Spiers
134e448aec NEWS: set org-blank-before-new-entry 2021-04-15 15:11:30 +01:00
Adam Spiers
e76dda400a Skip unnecessary planning 2021-04-15 15:11:30 +01:00
Adam Spiers
c0c01a6c61 cleanup_invalid_links: improve handling of scheduled actions 2021-04-15 15:11:30 +01:00
Adam Spiers
208f383580 Further improve debug output 2021-04-15 15:11:30 +01:00
Adam Spiers
396357dc67 Rename path_owned_by_package() to link_owned_by_package() 2021-04-15 15:11:30 +01:00
Adam Spiers
832135e269 Make cleanup_invalid_links() more explicit
And add some debug.
2021-04-15 15:11:30 +01:00
Adam Spiers
86f4694d96 Improve debug indent levels 2021-04-15 15:11:30 +01:00
Adam Spiers
c872baba2d Add support for emacs dumb-jump
Allow easy navigation to function definitions in emacs.

The rg (ripgrep) search is needed because as the dumb-jump README says:

   [...] the default searcher (git-grep) won't be able to search
   outside of the project root. This edge case will be fixed in a
   future release.

See: https://github.com/jacktasia/dumb-jump
2021-04-15 15:11:30 +01:00
Adam Spiers
90278f854c Move to explicit debug indentation levels 2021-04-15 15:11:30 +01:00
Adam Spiers
8d7b7a7310 foldable(): fix debug indentation 2021-04-15 15:11:30 +01:00
Adam Spiers
9f4f8185ac should_skip_target_which_is_stow_dir(): fix debug indentation 2021-04-15 15:11:30 +01:00
Adam Spiers
3aae830e56 HOWTO-RELEASE: maintainer-clean is better than distclean 2021-04-15 15:11:30 +01:00
Adam Spiers
0b72724066 Correct comment about overriding the check rule
We actually override check-TESTS.
2021-04-15 15:11:30 +01:00
Adam Spiers
1a20a3f7ee Remove unnecessary AM_MAKEINFOFLAGS tweak
We no longer need to ensure that texi2any (a.k.a. makeinfo) is called
with -I $(srcdir) in order to make the

    @verbatiminclude default-ignore-list

in the manual work, because texi2any includes the current working
directory by default anyway.  Presumably this behaviour was introduced
after this AM_MAKEINFOFLAGS was previously added, because it was
needed at some point in the past.
2021-04-15 15:11:30 +01:00
Adam Spiers
8cd6cadd3d Replace broken gmane links with links to lists.gnu.org
gmane has been dead for quite a while:

    https://lars.ingebrigtsen.no/2020/01/06/whatever-happened-to-news-gmane-org/
2021-04-15 15:11:29 +01:00
Adam Spiers
d18b5e99a0 aclocal.m4: update to 1.16.2
This only updates copyright notices to 2020, and URLs to https.
2021-04-15 15:11:29 +01:00
Adam Spiers
69614059a8 Ditch texinfo.tex from distribution 2021-04-15 15:11:29 +01:00
Adam Spiers
4ef5eca4a9
Merge pull request #86 from gutierri/patch-manpage
add option --simulate on manpage
2021-04-15 12:18:10 +01:00
Gutierri Barboza
57d7b76bd3
add option --simulate on manpage 2021-04-14 22:08:38 -03:00
Adam Spiers
3bdb912612
Merge pull request #85 from gutierri/patch-usage-dotfiles
add --dotfiles sub usage
2021-04-14 11:03:00 +01:00
Gutierri Barboza
ca1e5e500f
add --dotfiles sub usage 2021-04-13 22:09:38 -03:00
Adam Spiers
72dd8723b4
Merge pull request #71 from egli/master
Mention the dotfiles option in the manual
2020-11-01 12:24:52 +00:00
Christian Egli
74e0eab0c5 Mention the dotfiles option in the manual
This should have been part of 182acbbb64
when the option was first added.

This commit basically just copies the help text from stow.in into the
texinfo manual.
2020-05-27 17:51:37 +02:00
ATuinDev
a41118d927
Fix missing variable 2020-05-25 22:26:31 +02:00
ATuinDev
056d648d53
Add more tests for testing directories in dotfiles.t 2020-05-25 22:23:23 +02:00
ATuinDev
a2db7a9c76
Add $level variable in stow_contents and stow_node
This variables is used to keep track of the current level in the source.
2020-05-25 22:21:31 +02:00
ATuinDev
d4e413536e
Fixes Bug #56727
Problem was that when running stow_contents/unstow_contents recursively from
stow_node/unstow_node the information for the source path (without the dot- to
. transformation) was lost.

In the case of stow_contents the solution is just to remove the leading
dots (..) from the $source path (since the $source path is passed as an argument
to the function)

In the case of unstow_contents the solution is the same as for stow_contents but
the arguments was now passed so I added it to the function.
2020-05-24 18:12:49 +02:00
Adam Spiers
9fd3624a75 HOWTO-RELEASE: explicitly push to master
This avoids errors like

    fatal: You are pushing to remote 'savannah', which is not the upstream of
    your current branch 'master', without telling me what to push
    to update which remote branch.
2019-07-28 14:54:36 +01:00
Adam Spiers
d94f325e51 Bump version to 2.3.2 for development of next release 2019-07-28 14:52:53 +01:00
Adam Spiers
c84a3b0f25 HOWTO-RELEASE: fix final step of bumping to next release version 2019-07-28 14:52:16 +01:00
Adam Spiers
59658a6c4e NEWS: disable org-export-with-toc
2.3.0 was a big release with lots of stuff, but most releases will
be smaller, so default to not having a ToC.
2019-07-28 14:29:06 +01:00
Adam Spiers
4f043bbd58 NEWS: don't export with author name
Avoid extra noise when exporting to text for a release announcement.
2019-07-28 14:28:41 +01:00
Adam Spiers
71b9606ba4 HOWTO-RELEASE: explain how to confirm PAUSE acceptance of upload 2019-07-28 13:58:00 +01:00
Adam Spiers
7fae30ecce HOWTO-RELEASE: do ./Build dist earlier
docker builds break ./Build dist, so do it earlier.
2019-07-28 13:28:46 +01:00
Adam Spiers
5602166a57 Make sure release process starts from a clean slate 2019-07-28 13:15:11 +01:00
Adam Spiers
bfe091f28e Prepare NEWS for 2.3.1 release 2019-07-28 13:10:49 +01:00
Adam Spiers
3aa30ae1aa fix cross-references under --no-folding section of manual
Under emacs, this was previously rendered as

    '--no-folding'

         This disables any further *note tree folding:: or *note tree
         refolding::.  If a new subdirectory is encountered whilst stowing a

which looks awkward.  Similarly under info(1):

    '--no-folding'

         This disables any further *note tree folding:: or *note tree
         refolding::.  If a new subdirectory is encountered whilst stowing a

The new way is undesirably repetitive, but at least grammatically
correct.  I don't think there's a better solution with texinfo :-/
2019-07-28 13:04:17 +01:00
Adam Spiers
ed2091e9a5 HOWTO-RELEASE: add suggested commands for updating home page 2019-07-28 13:04:17 +01:00
Adam Spiers
9d546b1843
cli.t: test with the right Perl executable (#62)
cli.t: test with the right Perl executable
2019-07-28 13:03:54 +01:00
Adam Spiers
80d1472253 HOWTO-RELEASE: update news section of online home page 2019-07-16 19:24:19 +01:00
Adam Spiers
cfb3ff7eff HOWTO-RELEASE: update online docs *after* uploading release
It doesn't make sense to have docs online relating to a release which
isn't yet available; it's less confusing to have a small time window
in which the online docs are out of date.
2019-07-16 19:21:04 +01:00
Adam Spiers
b6ee2d10d6 cli.t: test with the right Perl executable
t/cli.t calls scripts which run with the first perl found in the
user's PATH (usually the system perl), not with the perl used for the
build, as reported here:

    https://rt.cpan.org/Ticket/Display.html?id=129944

Thanks to Slaven Rezic for spotting this and reporting it!
2019-07-15 16:12:26 -04:00
Adam Spiers
9f59494d4e
Remove dependencies on Hash::Merge and Clone::Choose (#60)
Remove dependencies on Hash::Merge and Clone::Choose
2019-06-29 13:48:59 +01:00
Adam Spiers
9ce10eb3b1 Remove dependencies on Hash::Merge and Clone::Choose
stow 2.3.0 added external runtime dependencies on Hash::Merge and
Clone::Choose. Historically stow hasn't had runtime dependencies other
than Perl itself, which is a useful property if you're managing the
installation of Perl using stow; the bootstrapping instructions in
stow's manual would need updating to describe how to install these two
modules (and any dependencies they have now or in the future) as well.

However, Hash::Merge is much more general than stow actually needs, so
replace the merge() call with a few lines of equivalent code -- this
avoids the external dependencies, and is clearer than the merge()
call.

Many thanks to Adam Sampson for this patch:

https://lists.gnu.org/archive/html/bug-stow/2019-06/msg00001.html
2019-06-29 13:42:19 +01:00
Adam Spiers
4a9121eec9 Bump version to 2.3.1 for development of next release 2019-06-29 13:40:55 +01:00
Adam Spiers
7eb1a0c57b
Maintainer tweaks (#59)
Maintainer tweaks
2019-06-29 13:03:11 +01:00
Adam Spiers
583f0f01ea Add GPL v3 upgrade to NEWS for 2.3.0 release
Forgot to do this prior to the release :-(  But at least it will
be mentioned in the announcement on the mailing lists.
2019-06-29 01:30:56 +01:00
Adam Spiers
94175829b9 Make NEWS export to text better
Run org-convert-to-odd-levels on NEWS and set local variables so
that sections can easily be exported for release announcements.
2019-06-29 01:30:33 +01:00
Adam Spiers
8d0a46cc88 Set DISTCLEANFILES to clean up more
Docker generates a whole bunch of files as root.
2019-06-29 00:56:11 +01:00
Adam Spiers
872ec96350 HOWTO-RELEASE: Fix cvs commit command for docs 2019-06-29 00:55:51 +01:00
Adam Spiers
cef930852c HOWTO-RELEASE: Fix git tag command 2019-06-29 00:36:00 +01:00
Adam Spiers
8b2123847d Split perlbrew install-multiple into separate RUN cmd
This allows changing which Perls are used etc. without
re-bootstrapping perlbrew.
2019-06-28 23:54:30 +01:00
Adam Spiers
2a4c3d3120
Use Clone backend for Hash::Merge, not Storable (#58)
Use Clone backend for Hash::Merge, not Storable
2019-06-28 21:57:08 +01:00
Adam Spiers
00c92076d9 Use Clone backend for Hash::Merge, not Storable
Need to avoid Storable backend, since it can't deal with regexps:

    https://rt.perl.org/Public/Bug/Display.html?id=50608

This should fix the Docker builds.
2019-06-28 21:20:45 +01:00
Adam Spiers
089151c116 make maintainer-clean remove cover_db/ 2019-06-28 21:20:45 +01:00
Adam Spiers
d991dfbbf8
Make testing within Docker containers easier (#56)
Make testing within Docker containers easier
2019-06-28 20:46:15 +01:00
Adam Spiers
5d667c3e71 Make testing within Docker containers easier 2019-06-28 20:36:38 +01:00
Adam Spiers
8acb10e26c
Merge pull request #57 from aspiers/strict-tests
Allow make to fail if missing modules for test dependencies
2019-06-28 20:33:30 +01:00
Adam Spiers
ba243c0a61 Allow make to fail if missing modules for test dependencies
e.g. make STRICT_TESTS=1

However we don't need this in .travis.yml as explained in the
comments.
2019-06-28 20:28:22 +01:00
Adam Spiers
651f1e6503
Dockerfile: fix Debian jessie sources (#55)
Dockerfile: fix Debian jessie sources
2019-06-28 17:48:04 +01:00
Adam Spiers
71a8d5d42c Dockerfile: fix Debian jessie sources
https://superuser.com/questions/1423486/issue-with-fetching-http-deb-debian-org-debian-dists-jessie-updates-inrelease
2019-06-28 17:14:37 +01:00
Adam Spiers
97b6a35b38
Make docker scripts use get-version (#54)
Make docker scripts use get-version
2019-06-28 17:14:23 +01:00
Adam Spiers
ded84b0d08
rebuild META.* in preparation for 2.3.0 release (#53)
rebuild META.* in preparation for 2.3.0 release
2019-06-28 17:10:42 +01:00
Adam Spiers
ee57b1abc6 Make docker scripts use get-version 2019-06-28 17:08:48 +01:00
Adam Spiers
e98fa1603a rebuild META.* in preparation for 2.3.0 release 2019-06-28 17:04:40 +01:00
Adam Spiers
6d195f95e0
Various improvements to tests (#52)
Various improvements to tests
2019-06-28 16:48:59 +01:00
Adam Spiers
74f0182834 Add separate tests for .stowrc from $HOME and $PWD
.stowrc can be obtained from $HOME and/or the current working
directory; however only the $HOME case was tested before, because
during tests Stow was being run from $HOME.

So switch $TEST_DIR to an absolute path, create a new run_from/
subdirectory, and chdir to that before invoking any Stow code.  This
allows us to test the behaviour of .stowrc in $HOME and run_from/
separately.
2019-06-28 16:39:53 +01:00
Adam Spiers
ac74d75a98 Split up is_deeply() assertions in find_stowed_path.t
This makes the tests and any failures more readable.
2019-06-28 15:24:50 +01:00
Adam Spiers
40a0807185 Check that find_stowed_path $path matches relative/absolute with target
Watch out for a corner case probably only relevant in tests.
2019-06-28 15:24:50 +01:00
Adam Spiers
3270b145e1 Improve comments on function parameters for clarity 2019-06-28 15:24:50 +01:00
Adam Spiers
e4f6a6742b Add examples of how to enable debugging in tests 2019-06-28 15:24:50 +01:00
Adam Spiers
6233298a91 Replace testutil::make_dir with File::Path::make_path
No need for a custom function here.
2019-06-28 01:02:48 +01:00
Adam Spiers
ba48fd3908 Rename $OUT_DIR to $TEST_DIR
This is a more accurate reflection of what it is.
2019-06-28 00:53:12 +01:00
Adam Spiers
5f875009f8
Avoid dereferencing $ENV{HOME} if it is undefined (#32)
Avoid dereferencing $ENV{HOME} if it is undefined
2019-06-28 00:41:55 +01:00
Adam Spiers
fea63ffe65
Improve the history of individual contributions and repositories (#49)
Improve the history of individual contributions and repositories
2019-06-27 20:49:44 +01:00
Adam Spiers
d5d710e3e3
Upgrade to GPL v3 and add headers to files (#50)
Upgrade to GPL v3 and add headers to files
2019-06-27 20:49:18 +01:00
Adam Spiers
311c2d139e Improve the history of individual contributions and repositories
The source code has been through a rather complicated journey, and
it's occasionally useful to understand this history from CVS to a
private Subversion repository to its current location in git.  So
document this more thoroughly, and ensure that everyone involved
is in the THANKS file.
2019-06-27 20:44:48 +01:00
Adam Spiers
157f39385a Change -w to "use warnings;" in tools/get-version
This is more idiomatic and consistent with everywhere else.
2019-06-27 20:39:16 +01:00
Adam Spiers
0979a9c7bd Change #!/usr/local/bin/perl to #!/usr/bin/perl in t/*.t
This doesn't really matter, since these are not executed directly, but
it's more consistent with everything else and modern systems.
2019-06-27 20:37:50 +01:00
Adam Spiers
27796720d5 Upgrade to GPL v3 and add headers to files (#44)
Following advice from maintainers@gnu.org, bring Stow in line with
other GNU projects by upgrading it from GPL v2 to v3

  https://www.gnu.org/prep/maintain/html_node/Licensing-of-GNU-Packages.html#Licensing-of-GNU-Packages

as obtained in plain text and texinfo formats from

  https://www.gnu.org/licenses/

and adding appropriate headers:

  https://www.gnu.org/prep/maintain/html_node/License-Notices-for-Code.html#License-Notices-for-Code

Fixes #44: https://github.com/aspiers/stow/issues/44
2019-06-27 20:37:40 +01:00
Adam Spiers
a4c0ad62d1
Fix Travis failure after merging #42 (#46)
Fix Travis failure after merging #42
2019-06-27 14:14:23 +01:00
Adam Spiers
0f54900cfe
remove trailing whitespace from lines (#45)
remove trailing whitespace from lines
2019-06-27 14:06:19 +01:00
Adam Spiers
fd17b807f5 Fix Travis failure after merging #42
Something weird happened with
https://travis-ci.org/aspiers/stow/jobs/551290921 after merging #42,
as shown below.  Maybe removing texi2html from the list of packages
for Travis to install will help.

---
Installing APT Packages
15.50s$ travis_apt_get_update
0.11s$ sudo -E apt-get -yq --no-install-suggests --no-install-recommends $(travis_apt_get_options) install texinfo texlive texi2html
Reading package lists...
Building dependency tree...
Reading state information...
Package texinfo is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source
However the following packages replace it:
  info install-info
E: Package 'texinfo' has no installation candidate
E: Unable to locate package texi2html
apt-get.diagnostics
apt-get install failed
$ cat ${TRAVIS_HOME}/apt-get-update.log
Get:2 http://dl.hhvm.com/ubuntu trusty InRelease [3,106 B]
Get:3 http://security.ubuntu.com/ubuntu trusty-security InRelease [65.9 kB]
Get:4 http://ppa.launchpad.net/chris-lea/redis-server/ubuntu trusty InRelease [15.4 kB]
Ign:5 http://repo.mongodb.org/apt/ubuntu trusty/mongodb-org/3.4 InRelease
Get:6 http://repo.mongodb.org/apt/ubuntu trusty/mongodb-org/3.4 Release [2,495 B]
Get:7 http://repo.mongodb.org/apt/ubuntu trusty/mongodb-org/3.4 Release.gpg [801 B]
Get:8 http://dl.hhvm.com/ubuntu trusty/main amd64 Packages [1,812 B]
Get:9 http://security.ubuntu.com/ubuntu trusty-security/main Sources [220 kB]
Get:10 http://security.ubuntu.com/ubuntu trusty-security/restricted Sources [5,050 B]
Get:11 http://security.ubuntu.com/ubuntu trusty-security/universe Sources [126 kB]
Get:12 http://security.ubuntu.com/ubuntu trusty-security/multiverse Sources [3,070 B]
Get:13 http://security.ubuntu.com/ubuntu trusty-security/main amd64 Packages [1,032 kB]
Get:14 http://security.ubuntu.com/ubuntu trusty-security/main i386 Packages [934 kB]
Get:15 http://security.ubuntu.com/ubuntu trusty-security/main Translation-en [541 kB]
Get:16 http://security.ubuntu.com/ubuntu trusty-security/restricted amd64 Packages [18.1 kB]
Get:17 http://security.ubuntu.com/ubuntu trusty-security/restricted i386 Packages [17.8 kB]
Get:18 http://security.ubuntu.com/ubuntu trusty-security/restricted Translation-en [3,272 B]
Get:19 http://security.ubuntu.com/ubuntu trusty-security/universe amd64 Packages [377 kB]
Get:20 http://security.ubuntu.com/ubuntu trusty-security/universe i386 Packages [355 kB]
Get:21 http://security.ubuntu.com/ubuntu trusty-security/universe Translation-en [203 kB]
Get:22 http://security.ubuntu.com/ubuntu trusty-security/multiverse amd64 Packages [4,730 B]
Get:23 http://security.ubuntu.com/ubuntu trusty-security/multiverse i386 Packages [4,887 B]
Get:24 http://security.ubuntu.com/ubuntu trusty-security/multiverse Translation-en [2,426 B]
Get:25 https://download.docker.com/linux/ubuntu trusty InRelease [37.1 kB]
Get:26 http://repo.mongodb.org/apt/ubuntu trusty/mongodb-org/3.4/multiverse amd64 Packages [14.1 kB]
Get:27 https://download.docker.com/linux/ubuntu trusty/stable amd64 Packages [5,763 B]
Get:28 https://download.docker.com/linux/ubuntu trusty/edge amd64 Packages [6,911 B]
Ign:29 http://ppa.launchpad.net/couchdb/stable/ubuntu trusty InRelease
Get:30 http://ppa.launchpad.net/git-core/ppa/ubuntu trusty InRelease [20.8 kB]
Get:31 http://ppa.launchpad.net/hvr/ghc/ubuntu trusty InRelease [15.4 kB]
Get:32 http://ppa.launchpad.net/pollinate/ppa/ubuntu trusty InRelease [15.4 kB]
Get:33 http://ppa.launchpad.net/webupd8team/java/ubuntu trusty InRelease [15.5 kB]
Get:34 http://ppa.launchpad.net/chris-lea/redis-server/ubuntu trusty/main amd64 Packages [1,843 B]
Get:35 http://ppa.launchpad.net/chris-lea/redis-server/ubuntu trusty/main i386 Packages [1,842 B]
Get:36 http://ppa.launchpad.net/chris-lea/redis-server/ubuntu trusty/main Translation-en [990 B]
Get:37 http://ppa.launchpad.net/couchdb/stable/ubuntu trusty Release [15.1 kB]
Get:38 http://ppa.launchpad.net/couchdb/stable/ubuntu trusty Release.gpg [316 B]
Ign:39 http://dl.google.com/linux/chrome/deb stable InRelease
Get:40 http://dl.google.com/linux/chrome/deb stable Release [943 B]
Get:41 http://dl.google.com/linux/chrome/deb stable Release.gpg [819 B]
Get:42 http://ppa.launchpad.net/git-core/ppa/ubuntu trusty/main amd64 Packages [3,494 B]
Get:43 http://ppa.launchpad.net/git-core/ppa/ubuntu trusty/main i386 Packages [3,496 B]
Get:44 http://ppa.launchpad.net/git-core/ppa/ubuntu trusty/main Translation-en [2,368 B]
Get:45 http://ppa.launchpad.net/hvr/ghc/ubuntu trusty/main amd64 Packages [18.5 kB]
Get:46 http://ppa.launchpad.net/hvr/ghc/ubuntu trusty/main i386 Packages [15.7 kB]
Get:47 http://ppa.launchpad.net/hvr/ghc/ubuntu trusty/main Translation-en [1,107 B]
Get:48 http://ppa.launchpad.net/pollinate/ppa/ubuntu trusty/main amd64 Packages [430 B]
Get:49 http://ppa.launchpad.net/pollinate/ppa/ubuntu trusty/main i386 Packages [430 B]
Get:50 http://ppa.launchpad.net/pollinate/ppa/ubuntu trusty/main Translation-en [374 B]
Get:51 http://ppa.launchpad.net/webupd8team/java/ubuntu trusty/main amd64 Packages [20 B]
Get:52 http://ppa.launchpad.net/webupd8team/java/ubuntu trusty/main i386 Packages [20 B]
Get:53 http://ppa.launchpad.net/webupd8team/java/ubuntu trusty/main Translation-en [20 B]
Get:54 http://ppa.launchpad.net/couchdb/stable/ubuntu trusty/main amd64 Packages [985 B]
Get:55 http://ppa.launchpad.net/couchdb/stable/ubuntu trusty/main i386 Packages [985 B]
Get:56 http://ppa.launchpad.net/couchdb/stable/ubuntu trusty/main Translation-en [644 B]
Get:57 http://dl.google.com/linux/chrome/deb stable/main amd64 Packages [1,107 B]
Err:58 https://packagecloud.io/computology/apt-backport/ubuntu trusty InRelease
  Failed to connect to packagecloud.io port 443: Connection timed out
Err:59 http://us-east-1.ec2.archive.ubuntu.com/ubuntu trusty InRelease
  Could not connect to apt.cache.travis-ci.com:80 (34.96.81.152), connection timed out
Err:60 http://us-east-1.ec2.archive.ubuntu.com/ubuntu trusty-updates InRelease
  Unable to connect to apt.cache.travis-ci.com:http:
Err:61 http://toolbelt.heroku.com/ubuntu ./ InRelease
  Could not connect to apt.cache.travis-ci.com:80 (34.96.81.152), connection timed out
Err:62 http://us-east-1.ec2.archive.ubuntu.com/ubuntu trusty-backports InRelease
  Unable to connect to apt.cache.travis-ci.com:http:
Err:63 http://apt.postgresql.org/pub/repos/apt trusty-pgdg InRelease
  Could not connect to apt.cache.travis-ci.com:80 (34.96.81.152), connection timed out
Err:1 http://dl.bintray.com/apache/cassandra 39x InRelease
  Could not connect to apt.cache.travis-ci.com:80 (34.96.81.152), connection timed out
Get:64 https://packagecloud.io/github/git-lfs/ubuntu trusty InRelease [23.2 kB]
Ign:64 https://packagecloud.io/github/git-lfs/ubuntu trusty InRelease
Get:65 https://packagecloud.io/rabbitmq/rabbitmq-server/ubuntu trusty InRelease [23.7 kB]
Get:66 https://packagecloud.io/github/git-lfs/ubuntu trusty/main Sources [20 B]
Get:67 https://packagecloud.io/github/git-lfs/ubuntu trusty/main amd64 Packages [8,003 B]
Get:68 https://packagecloud.io/github/git-lfs/ubuntu trusty/main i386 Packages [7,761 B]
Get:69 https://packagecloud.io/rabbitmq/rabbitmq-server/ubuntu trusty/main Sources [20 B]
Get:70 https://packagecloud.io/rabbitmq/rabbitmq-server/ubuntu trusty/main amd64 Packages [7,866 B]
Get:71 https://packagecloud.io/rabbitmq/rabbitmq-server/ubuntu trusty/main i386 Packages [7,866 B]
Fetched 4,218 kB in 15s (279 kB/s)
Reading package lists...
W: http://ppa.launchpad.net/couchdb/stable/ubuntu/dists/trusty/Release.gpg: Signature by key 15866BAFD9BCC4F3C1E0DFC7D69548E1C17EAB57 uses weak digest algorithm (SHA1)
W: GPG error: https://packagecloud.io/github/git-lfs/ubuntu trusty InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 6B05F25D762E3157
W: The repository 'https://packagecloud.io/github/git-lfs/ubuntu trusty InRelease' is not signed.
W: There is no public key available for the following key IDs:
6B05F25D762E3157
W: Failed to fetch http://us-east-1.ec2.archive.ubuntu.com/ubuntu/dists/trusty/InRelease  Could not connect to apt.cache.travis-ci.com:80 (34.96.81.152), connection timed out
W: Failed to fetch http://us-east-1.ec2.archive.ubuntu.com/ubuntu/dists/trusty-updates/InRelease  Unable to connect to apt.cache.travis-ci.com:http:
W: Failed to fetch http://us-east-1.ec2.archive.ubuntu.com/ubuntu/dists/trusty-backports/InRelease  Unable to connect to apt.cache.travis-ci.com:http:
W: Failed to fetch http://www.apache.org/dist/cassandra/debian/dists/39x/InRelease  Could not connect to apt.cache.travis-ci.com:80 (34.96.81.152), connection timed out
W: Failed to fetch https://packagecloud.io/computology/apt-backport/ubuntu/dists/trusty/InRelease  Failed to connect to packagecloud.io port 443: Connection timed out
W: Failed to fetch http://toolbelt.heroku.com/ubuntu/./InRelease  Could not connect to apt.cache.travis-ci.com:80 (34.96.81.152), connection timed out
W: Failed to fetch http://apt.postgresql.org/pub/repos/apt/dists/trusty-pgdg/InRelease  Could not connect to apt.cache.travis-ci.com:80 (34.96.81.152), connection timed out
W: Some index files failed to download. They have been ignored, or old ones used instead.
The command "sudo -E apt-get -yq --no-install-suggests --no-install-recommends $(travis_apt_get_options) install texinfo texlive texi2html" failed and exited with 100 during .
Your build has been stopped.
2019-06-27 13:55:35 +01:00
Adam Spiers
c2a399985a remove trailing whitespace from lines 2019-06-27 13:54:36 +01:00
Adam Spiers
4efb438224
Update maintainership to reflect reality (#41)
Update maintainership to reflect reality
2019-06-27 13:27:12 +01:00
Adam Spiers
a3e8103787
switch from unmaintained texi2html to makeinfo --html --no-split (#42)
switch from unmaintained texi2html to makeinfo --html --no-split
2019-06-26 14:08:48 +01:00
Adam Spiers
833abc4d93 Update maintainership to reflect reality
Troy hasn't been active on the project for many years.

https://lists.gnu.org/archive/html/stow-devel/2011-11/msg00009.html
2019-06-26 13:59:58 +01:00
Adam Spiers
22ca973d59 Switch to makeinfo --html --no-split for single-page HTML manual (#21)
Remove the dependency on the ancient and unmaintained texi2html, which
was difficult to get running on most distros other than openSUSE.

There are two more modern alternative approaches which can replace
this:

  - Use texi2any
  - Use makeinfo --html --no-split

The latter seems to be the standard way these days, so we switch to
that; however we keep Makefile rules for all three, and a phony
meta-rule 'manual-single-html-all' to allow quick comparison between
them.  Make tweaks accordingly to minimise the differences and improve
the output.

The rules for the older two approaches do not get triggered by
default.

Fixes #21: https://github.com/aspiers/stow/issues/21
2019-06-26 13:48:06 +01:00
Adam Spiers
9c402559d2 Include the preamble in online versions of the manual
This is more inline with the suggestion in the texinfo manual:

https://www.gnu.org/software/texinfo/manual/texinfo/html_node/_0040top-Command.html

and also the preamble is useful in all cases.
2019-06-26 13:46:37 +01:00
Adam Spiers
b4cb6e775a Add Guillaume and myself to the list of @authors 2019-06-26 13:46:37 +01:00
Adam Spiers
6764788f71 remove trailing whitespace from lines 2019-06-26 13:25:53 +01:00
Adam Spiers
8b0733a8a0 add tools/get-version to MANIFEST
Forgot to do this, and it broke ./Build.PL distcheck.
2019-06-25 20:33:48 +01:00
Adam Spiers
66d511b07b Merge remote-tracking branch 'bricewge/fix-34' 2019-06-25 20:10:43 +01:00
Adam Spiers
e647c53af1 Add some polish to the release process 2019-06-25 20:05:47 +01:00
Adam Spiers
42ed9ed942
Perform shell expansion on the contents of .stowrc (#40)
Perform shell expansion on the contents of .stowrc
2019-06-25 19:49:46 +01:00
Charles LeDoux
dc42c34107 Add function to expand ~ in .stowrc files (#14)
Add a new expand_tilde() function that performs tilde expansion of
strings, and corresponding unit tests:

    * A ~ at the beginning of a path is expanded to the user's home
      directory.
    * Literal '~' can be provided with '\~'

Combine this with expand_environment() in a new expand_filepath()
function which applies all (both) required expansion functions to a
string, and use that in get_config_file_options() to expand .stowrc
options.

Add more tests to check that tilde expanded in correct places, i.e.:

    * expanded for --target and --dir
    * not expanded for --ignore, --defer, or --override

Update documentation on stowrc files according to this functionality
change.

Fixes #14: https://github.com/aspiers/stow/issues/14
2019-06-25 19:38:43 +01:00
Charles LeDoux
9674738792 Apply environment expansion to options in .stowrc files
Expand environment variables used in stowrc, as requested in

    https://savannah.gnu.org/bugs/?41826

This is achieved by creating a new function expand_environment() that
replaces any substring of the form '$VAR' or '${VAR}' with contents of
environment variable $VAR.  Literal '$' can be given by '\$'.

N.B. The function is only applied to the --target and --dir options,
and only for options specified in .stowrc; cli options are left
untouched.

Undefined variables are expanded to the empty string, as they would be
in normal shell parameter expansion.

Unit tests added accordingly:

  - Test expand_environment():
    * Expand $HOME
    * Expand ${HOME}
    * Expand ${WITH SPACE}
    * Expand '\$HOME'. Expected is '$HOME'
    * Expand ${UNDEFINED}. Expected is ''.

  - Test that it's applied to the correct options.

  - Test that CLI options are not expanded.
2019-06-25 19:38:26 +01:00
Charles LeDoux
4d1167ffd7 Parse cli and stowrc files separately
Why:

* We want to selectively apply expansion to:
    * Only options from stowrc files.
    * Only options that take a path.
* This requires ability to:
    * Differentiate cli options from stowrc options
    * Distinguish between individual stowrc options.

This change addresses the need by:

* Options from ARGV and stowrc files are separately parsed, resulting in
  two options hashes.
    * Creating an option hash from stowrc files allows modification of
      specific arguments without having to rely on something like regex
      parsing of the options.

* get_config_file_options modified to return options hash.
    * Uses the same parse_options function that parses ARGV

* Add Hash:Merge to dependencies in order to merge the two option
  hashes.

* process_options() merges the two option hashes.
    * Get option hash for ARGV
    * Get option hash from get_config_file_options().
    * Merge the two hashes with Hash::Merge.
    * Sanitation and checks are ran on the merged options.

* The options -S, -D, and -R are ignored in stowrc files.
    * Due to the way argument parsing happens, the effect of these
      actions is not carried from stowrc into parsing of cli options.
    * It doesn't seem to make sense to put these options in stowrc
      anyway.
2019-06-25 19:38:25 +01:00
Charles LeDoux
feb885fda6 Factor out parsing of options
Why:

* Want to be able to selectively apply filepath expansion to:
    1. Only options in a stowrc file.
    2. Only options that take a file path.

* Because of need 1, any expansion must be performed on stowrc options
  before merging with cli options.

* Because of need 2, stowrc options need to be parsed before expansion
  in order to know which options need expanding.

This change addresses the need by:

* Create parse_options()
    * Implements option parsing logic previously in process_options()
    * Takes an array as parameter instead of assuming ARGV
* Edit process_options() to still work as expected.
    * Only change was to call parse_options() instead of directly
      parsing ARGV

* By factoring out the option parsing code, we can reuse the existing
  parsing code for stowrc options.
    * Allows expansion of only the option itself, i.e expansion on
      "$HOME/target" rather than "--target=$HOME/target"
    * Allows easy determination of which options need expansion.
2019-06-25 19:38:25 +01:00
Charles LeDoux
ebc895a540 Add test for conflicting stowrc and cli args
Why:

* Want to add feature to stowrc parsing.
* Missing regression test for conflicting cli and stowrc options.

This change addresses the need by:

* Add missing regression tests to rc_options.t
    * Two types of tests for the two types of options possible.

* For scalar options such as --target, cli arguments should overwrite
  stowrc arguments.

* For options that result in a list, such as --ignore, the arguments
  from cli and stowrc files should be merged.
2019-06-25 19:38:25 +01:00
Charles LeDoux
237288fb7e Add test harness for stowrc files
Why:

* Planning on developing a new feature for parsing of stowrc files.
* Need a test harness that performs initialization and clean up
    * Initialization: Create directory structure that allows creation of
      stowrc files without worrying about squashing existing files.
    * Clean up: Remove all files created during testing.

This change addresses the need by:

* Add intialization and cleanup harness in t/rc_options.t
    * Define the location to write stowrc files to in $RC_FILE
    * Ensures that location $RC_FILE does not already exist.
    * Calls the init_test_dirs to bootstrap directory tree.
    * After all tests are run, removes $RC_FILE and the testing
      directory tree.

* Add basic test of stowrc parsing to t/rc_options.t
    * Provides a template of how to create and test a stowrc file.

* Newly created t/rc_options.t file added to MANIFEST
2019-06-25 19:38:25 +01:00
Charles LeDoux
048203b7f9 Change init_test_dirs to point $HOME at $OUT_DIRS
Why:

* Want to add a new feature to parsing of stowrc files.
* Need ability to write .stowrc files for testing without risk of
  squashing existing files.

This change addresses the need by:

* Reusing logic in init_test_dirs
    * init_test_dirs already creates new directory structure and overwrites
      $HOME to point into /tmp.
* This commit changes init_test_dirs to point $HOME at the newly created
  directory structure ($OUT_DIR) instead of /tmp.
    * Grants ability to write .stowrc to $HOME without fear.
    * Pointing $HOME at $OUT_DIR instead of /tmp also makes cleanup easier.
        * Remove $OUT_DIR vs remove specific files in /tmp.
2019-06-25 19:38:25 +01:00
Adam Spiers
bb8b79e031 Don't warn when .stowrc is used
We fully support and expect some users using .stowrc, so there is
no reason to issue a warning when they do.
2019-06-25 19:38:25 +01:00
Adam Spiers
0f3e1b33fc Group news items for 2.3.0
Since 2.3.0 is a long overdue release and has many changes,
document them in NEWS in three groups:

- New features / changes in behaviour
- Documentation fixes and enhancements
- Fixes for bugs and technical debt
2019-06-25 19:36:49 +01:00
Adam Spiers
2eb3be13c5
Update docs according to recent commits (#39)
Update docs according to recent commits
2019-06-25 17:48:07 +01:00
Adam Spiers
f6bf45af9c Update NEWS and THANKS according to recent commits 2019-06-25 17:41:17 +01:00
Adam Spiers
c3cbdeb812 Synchronise --verbose documentation
The man page was updated with regard to higher --verbose levels but
not the info manual, so fix that.
2019-06-25 17:41:17 +01:00
Adam Spiers
b9c13df5f7
Fix old descriptions of Stow (#22) (#38)
Fix old descriptions of Stow (#22)
2019-06-25 17:05:43 +01:00
Adam Spiers
72ef83cebd Fix old descriptions of Stow (#22)
De-emphasise the package management aspects, since these days
almost everyone prefers to use modern package managers such as
rpm / dpkg / Nix for (system-wide) package management.

Also include more popular modern use cases for Stow such as management
of dotfiles and software compiled in the user's $HOME directory.

Fixes #22: https://github.com/aspiers/stow/issues/22
2019-06-25 16:52:33 +01:00
Adam Spiers
a70c60e888
Merge pull request #37 from aspiers/invalid-option-exit-code
Return non-zero exit code when invalid option is specified (#34)
2019-06-25 15:55:15 +01:00
Adam Spiers
e79c5938bc Return non-zero exit code when invalid option is specified (#34)
Also add a unit test for this.

Fixes #34: https://github.com/aspiers/stow/issues/34
2019-06-25 15:43:08 +01:00
Adam Spiers
1e9fa23d2e
Add black box CLI testing and 2 other tweaks (#36)
Add black box CLI testing and 2 other tweaks
2019-06-25 15:41:41 +01:00
Adam Spiers
8394507891 Add cli.t for testing invocation of stow executable
Unlike the other tests, this actually treats stow(1) as a black box
script, running it directly rather than require-ing it as a library.
This allows us to check things like the exit codes returned.
2019-06-25 15:26:25 +01:00
Adam Spiers
bd4241b3e4 Make dotfiles.t executable for consistency with other tests 2019-06-25 14:30:30 +01:00
Adam Spiers
e618ef1526 remove duplicate "the" typo 2019-06-25 13:46:30 +01:00
Brice Waegeneire
77b0cf8f45 retrun exit code 1 when unknown option 2019-06-11 14:13:51 +02:00
Brice Waegeneire
c86d9aa148 make non docker scripts more portable 2019-06-11 10:53:28 +02:00
Brice Waegeneire
d6924bdbc3 fix dockerfile apt-get lock issue
E: Could not open lock file /var/cache/apt/archives/lock - open (2: No such file or directory)
E: Unable to lock the download directory
2019-06-11 10:28:25 +02:00
Will Aoki
b42cb89fdd Avoid dereferencing $ENV{HOME} if it is undefined 2019-04-03 09:49:53 -06:00
Adam Spiers
74defd4812
Merge pull request #30 from aspiers/chkstow-stow-dir
make chkstow honour $STOW_DIR environment variable
2019-02-09 17:08:44 +00:00
Adam Spiers
1a752bf70b make chkstow honour $STOW_DIR environment variable
Thanks to Matan Nassau for reporting this deficiency.
2019-02-09 17:03:45 +00:00
Adam Spiers
88ec3f58aa add Jean Louis to THANKS file
Forgot to do this in e7e6c7f.
2018-02-11 17:58:33 +00:00
Adam Spiers
dd42b09a5b avoid "regex" abbreviation for consistency 2018-02-11 17:55:40 +00:00
Adam Spiers
c84de4eb14 fix erroneous glob examples in --ignore documentation
Many thanks to Daniel Shahaf for noticing this.

http://lists.gnu.org/archive/html/bug-stow/2017-07/msg00000.html
2018-02-11 17:55:31 +00:00
Adam Spiers
e2af22c11a update aclocal.m4 using aclocal 1.15.1 2018-02-11 11:52:56 +00:00
Adam Spiers
e7e6c7fbde update the introductory text to clarify Stow's common usage
Thanks to Jean Louis for some suggestions on this.
2018-02-11 11:47:39 +00:00
Adam Spiers
655e8e4a3d INSTALL.md: document how to build from git (#20)
Fixes https://github.com/aspiers/stow/issues/20
2017-03-19 21:12:46 +00:00
Adam Spiers
ea11f266a5 fix typo in "Deleting Packages" chapter
Thanks to Hongyi Zhao for spotting this error and reporting it.
2017-03-04 14:29:06 +00:00
Adam Spiers
b160a1c807 clarify that ~/.stowrc args don't get processed by a shell
Address confusion reported here:

  http://lists.gnu.org/archive/html/bug-stow/2016-08/msg00000.html
2016-12-18 23:17:19 +00:00
Adam Spiers
5a8d275c47 replace a "you" typo with better text
The contents are prepended to the arguments; they still come after the
stow executable.
2016-12-18 23:14:39 +00:00
Adam Spiers
8d738353f8 fix documentation for --verbose
It actually goes up to 5 these days.  Thanks to Kristoffer Haugsbakk
for spotting that:

  http://lists.gnu.org/archive/html/bug-stow/2016-08/msg00000.html
2016-12-18 23:11:23 +00:00
Adam Spiers
6e5209fb2d Bump version to 2.3.0 2016-11-20 22:57:39 +00:00
Adam Spiers
94b155d99b Prepare NEWS file for 2.3.0 release 2016-11-20 22:57:39 +00:00
Adam Spiers
fd10706ce3 HOWTO-RELEASE: use Docker to test before releasing
Charles LeDoux did some awesome work providing this Docker environment
which can test across multiple Perl versions using perlbrew, so it
would be crazy not to use it.
2016-11-20 22:57:39 +00:00
Adam Spiers
5123a585a2 ignore cover_db generated by Coveralls 2016-11-20 22:57:39 +00:00
Adam Spiers
03480626a2 tag Docker images with the corresponding version number 2016-11-20 22:50:22 +00:00
Adam Spiers
98a8f7e3e7 use PAUSE upload for final validation step of release 2016-11-20 22:50:22 +00:00
Adam Spiers
a9f79c6a5b make sure release tags are also pushed to GitHub 2016-11-20 22:50:22 +00:00
Adam Spiers
17bbfb05c6 further refine the release process
Let's try a new approach where we increment the version number
immediately after publishing a release, not just before.

This will mean that anyone who builds from git gets a version of Stow
which is higher than the release which was just cut, and this could
provide valuable debugging hints in case a bug report does not clearly
state whether the problem arose with the latest release or with a build
from git.
2016-11-20 22:50:22 +00:00
Adam Spiers
08bff6df00 whitespace cleanups 2016-11-20 22:20:46 +00:00
Adam Spiers
68838c8d9d THANKS: add some recent contributors 2016-11-20 22:07:52 +00:00
Adam Spiers
b2fdd27596 THANKS: clarify mention of Bob Glickstein 2016-11-20 22:07:52 +00:00
Adam Spiers
0bc06e58e1 HOWTO-RELEASE: add a reminder to update THANKS
Make sure the maintainer always gives credit to contributors :-)
2016-11-20 22:07:47 +00:00
Adam Spiers
1b320b1dc3 Merge pull request #17 from jvkersch/enh/dot-files
Special processing for dotfiles
2016-10-05 17:47:51 +01:00
Joris Vankerschaver
182acbbb64 Special processing for dotfiles 2016-10-04 17:51:01 +01:00
Adam Spiers
928f893d9e Merge pull request #16 from cledoux/feature/docker
Added docker files for local testing.
2016-09-25 19:32:08 +01:00
Adam Spiers
7ede3c8df0 fix naming of man page
The title of the generated man page was ending up as something like

  IO::FILE=IO(0XA719C0)(1)

Also, with newer perls (e.g. v5.22.1), pod2man requires --name if
used within a pipeline.

Closes #18.

https://github.com/aspiers/stow/issues/18
2016-09-20 18:33:07 +01:00
Adam Spiers
f5e12670d6 remove superfluous space in function call
Be consistent with style elsewhere.
2016-08-23 10:37:12 +01:00
Charles LeDoux
95ffbc5ebd Add docker files for local testing.
* Use docker to locally run tests on multiple perl versions
    * perlbrew used to install multiple perls
    * perl environments bootstrapped when image built
* Based on travis configuration
* Adds docker folder to MANIFEST.SKIP
* Running image runs all tests.
    * If exit with no error, then all tests pass.
* ./build-docker.sh builds stow testing image.
* ./test-docker.sh runs stow testing image.
    * Assumes built with options in build-docker.sh
* *-docker.sh scripts added to MANIFEST.SKIP
2016-05-18 17:31:04 -05:00
Lucas Theisen
c171ca8d83 fixed testutil to support cygwin which reports -z = true on directories 2016-02-28 13:39:03 +00:00
Adam Spiers
cc0767597e another attempt to fix automake config
d527094b was not the right fix - Util.pm was being installed alongside
Stow.pm under $(PMDIR).  This should be the correct fix.
2015-11-17 17:27:39 +00:00
Adam Spiers
1664be4125 add coveralls badge 2015-11-17 01:50:27 +00:00
Adam Spiers
c512ff6357 add coveralls 2015-11-17 01:43:38 +00:00
Adam Spiers
21ffd2dfec add make distcheck and Module::Build to Travis tests 2015-11-17 01:35:47 +00:00
Adam Spiers
b52d7890f8 add .travis.yml to MANIFEST.SKIP 2015-11-17 01:35:47 +00:00
Adam Spiers
d527094bb4 fix make distcheck
Stow/Util.pm was not being installed correctly
2015-11-17 01:35:47 +00:00
Adam Spiers
fcdb1af67a add Travis CI badge to README.md 2015-11-16 22:39:53 +00:00
Adam Spiers
22139efe2b fix breakage caused by converting files to Markdown 2015-11-16 22:35:56 +00:00
Adam Spiers
4feff09211 convert INSTALL to Markdown 2015-11-16 22:22:01 +00:00
Adam Spiers
589da27138 convert README to Markdown 2015-11-16 22:17:20 +00:00
Adam Spiers
7ca44238ea switch to Travis CI containers 2015-11-16 21:56:45 +00:00
Adam Spiers
a38e918d4a Merge pull request #9 from Gnouc/master
Allow directory with trailing and leading spaces
2015-11-13 14:50:19 +00:00
LE Manh Cuong
8544b2f0f5 Allow directory with trailing and leading spaces
- The `sanitize_path_options` functions remove all trailing
 and leading spaces. So any valid directory like ` 123`,
 `123 ` can not be used

 - Also if there are two directories ` 123` and `123`, and if
 user pick the ` 123` as option to `-d` or `-t`, then stow pick
 directory `123` as the argument instead of ` 123` as user want.

    ```
    STOW_DIR=. stow -n -v3 -t \ 123 456
    stow dir is /tmp/test
    stow dir path relative to target 123 is ..
    cwd now 123
    cwd restored to /tmp/test
    cwd now 123
    Planning stow of package 456...
    Stowing contents of ../456 (cwd=/tmp/test/123)
    Planning stow of package 456... done
    cwd restored to /tmp/test
    WARNING: in simulation mode so not modifying filesystem.
    ```
 - This commit remove the check in `sanitize_path_options` function,
 and now stow can work with those directories. There have been a check
 for valid directory, so we are safe.
2015-11-13 20:17:58 +07:00
Adam Spiers
dc1ded469b set up Travis CI 2015-11-13 12:05:42 +00:00
Adam Spiers
f24de47b82 add IO::Scalar to build_requires 2015-11-13 12:05:42 +00:00
Adam Spiers
a111eeb8ae Do more validation on --dir / --target directories (#7)
Previously STOW_DIR=0 would cause the cwd to be used as the STOW_DIR.
Make that instead raise an error.  Do similar validation on the target
directory.

Closes #7 - https://github.com/aspiers/stow/pull/7
2015-11-11 12:30:50 +00:00
Adam Spiers
d0f3e5458f Correctly handle empty STOW_DIR (#5, #6)
In shell, a variable is often considered unset even if it is
set to the empty string.  In other words,

  STOW_DIR= stow [args]

is an idiomatic alternative to writing:

  unset STOW_DIR
  stow [args]

and it also has the advantage of temporarily "unsetting" STOW_DIR
for a single command.

Therefore we should treat STOW_DIR being set to the empty string
as equivalent to it not being set at all.

Thanks to Cuong Manh Le for highlighting this issue!

Fixes #6  - https://github.com/aspiers/stow/issues/6
Closes #5 - https://github.com/aspiers/stow/pull/5
2015-11-11 11:28:47 +00:00
Adam Spiers
b5dbc3b7b4 More fixes to "make distcheck"
As with dc6a141d, the dependency of distributed files on non-distributed
files was causing this error:

    ERROR: files left in build directory after distclean:

The automake FAQ explains why this happens:

    https://www.gnu.org/software/automake/manual/html_node/Errors-with-distclean.html

so change the dependency to Makefile.am which is distributed.
2015-11-09 12:38:39 +00:00
Adam Spiers
c482b0291d NEWS: Explain why 2.2.1 was not released 2015-11-09 12:36:51 +00:00
Adam Spiers
ab9d03535d Bump version to 2.2.2 2015-11-09 12:36:51 +00:00
Adam Spiers
43333b8eca add Stow/Util.pm.in with @VERSION@ substitution
This is now necessary in order to prevent pause.perl.org from
complaining:

    Status: Decreasing version number
    =================================

         module : Stow::Util
         version: undef
         in file: lib/Stow/Util.pm
         status : Not indexed because lib/Stow/Util.pm in
                 A/AS/ASPIERS/Stow-v2.2.0.tar.gz has a higher version number
                 (0)
2015-11-09 12:36:51 +00:00
Adam Spiers
d82b6aa1a8 HOWTO-RELEASE: remove body indent 2015-11-09 11:05:20 +00:00
Adam Spiers
ee118fb616 HOWTO-RELEASE: add link to official GNU maintainers guide 2015-11-09 11:05:14 +00:00
Adam Spiers
2119e75d2b HOWTO-RELEASE: encourage use of SemVer 2015-11-09 10:13:34 +00:00
Adam Spiers
0a54a6bbab HOWTO-RELEASE: encourage GPG-signing of release tags 2015-11-09 10:11:59 +00:00
Adam Spiers
7faa1d86dc HOWTO-RELEASE: use gnulib for gendocs instead of texinfo
These days it seems that gendocs can be done entirely from
the templates in gnulib, rather than requiring the texinfo
repository.
2015-11-09 10:10:36 +00:00
Adam Spiers
dc6a141da4 fix make distcheck
The dependency of the distributed file stow.8 on the non-distributed
file Makefile was causing this error:

    ERROR: files left in build directory after distclean:
    ./doc/stow.8

The automake FAQ explains why this happens:

    https://www.gnu.org/software/automake/manual/html_node/Errors-with-distclean.html

so change stow.8 to depend on Makefile.am which is distributed.
2015-11-09 10:08:31 +00:00
Adam Spiers
f1b67d2432 HOWTO-RELEASE: include automake --add-missing
This is necessary since automake files were removed from the repository
recently.
2015-11-09 09:28:51 +00:00
Adam Spiers
c749cc4f26 Update META.{yml,json}
Rebuilt with newer Module::Build.
2015-11-09 09:27:49 +00:00
Adam Spiers
99e4b7049a Bump version to 2.2.1 2015-11-09 09:17:34 +00:00
Adam Spiers
c77e85c5e9 Prepare NEWS file for 2.2.1 release 2015-11-09 09:16:53 +00:00
Adam Spiers
3d0e3cb48e Remove trailing whitespace from NEWS file 2015-11-09 09:16:51 +00:00
Adam Spiers
29a8b5d4e5 Add more index entries to the manual. 2015-11-09 09:03:49 +00:00
Adam Spiers
e255b27976 Fix a typo in the docs. 2015-11-09 09:03:42 +00:00
Adam Spiers
99b669968d substitute @VERSION@ in stow.8 man page
Thanks to Yue Du for spotting this issue and providing the fix.
2015-02-07 19:30:29 +00:00
Adam Spiers
3a7cf35165 remove automake files
These should be generated at development / install-time, rather than
distributing versions via git which will inevitably age over time.
2015-02-07 19:30:26 +00:00
Adam Spiers
7b43622dd9 fix stowing of relative links when --no-folding is used
With a tree like this:

    .
    |-- stow
    |   `-- pkg
    |       `-- lib
    |           |-- itk-current -> itk4.0.0
    |           `-- itk4.0.0
    |               `-- libitk4.0.0.so
    `-- target
        `-- lib
            |-- itk4.0.0 -> ../../stow/pkg/lib/itk4.0.0
            `-- libfoo-1.2.3.so

stowing pkg with the --no-folding option resulted in itk-current
being "unpacked":

    .
    `-- target
        `-- lib
            |-- itk-current
            |   `-- libitk4.0.0.so -> ../../../stow/pkg/lib/itk-current/libitk4.0.0.so
            |-- itk4.0.0
            |   `-- libitk4.0.0.so -> ../../../stow/pkg/lib/itk4.0.0/libitk4.0.0.so
            `-- libfoo-1.2.3.so

This commit fixes it so that it gets stowed as a symlink:

  .
  `-- target
      `-- lib
          ...
          |-- itk-current -> ../../stow/pkg/lib/itk-current
          ...

Thanks to Gabriele Balducci for reporting this problem:

    http://thread.gmane.org/gmane.comp.gnu.stow.general/6676
2015-01-01 19:02:46 +00:00
Adam Spiers
5be496a795 improve debug 2015-01-01 19:02:26 +00:00
Adam Spiers
07a84541f1 make it more obvious when target (sub)directory is skipped
This should avoid the sort of confusion seen in:

  https://github.com/aspiers/shell-env/issues/1
2014-09-23 01:37:54 +01:00
Adam Spiers
497a067621 trim trailing whitespace 2014-09-23 01:37:54 +01:00
Adam Spiers
dda7c5a359 update aclocal 2014-09-22 00:14:56 +01:00
Adam Spiers
d788ce0c1c avoid precedence warning
With Perl 5.20, installing a package with stow gives a warning like
this:

  Possible precedence issue with control flow operator at
  /gar/packages/stow-2.2.0/lib/perl5/site_perl/5.20.0/Stow.pm line 1736.

http://lists.gnu.org/archive/html/bug-stow/2014-06/msg00000.html

Suggested-by: Adam Sampson <ats@offog.org>
2014-06-16 10:22:55 +01:00
Adam Spiers
20d3759ac1 add TODO for install-hooks 2013-04-24 08:46:52 +01:00
Adam Spiers
c500216f20 correctly handle the stow/target directories as non-canonical paths
Fix the case discovered by Hiroyuki Iwatsuki where stowing fails if
the stow / target directories are non-canonical paths.  For example,
on FreeBSD /home is a symlink pointing to 'usr/home', so running with
the stow directory as /home/user/local/stow and the target directory
as /home/user/local previously resulted in the stow directory path
being calculated as ../../../usr/home/user/local/stow relative to
the target.

http://article.gmane.org/gmane.comp.gnu.stow.bugs/8820
2013-04-12 17:48:08 +01:00
Adam Spiers
fe5b658803 default-ignore-list: ignore top-level README.*, LICENSE.*, and COPYING
These files are by definition specific to a given package,
so if they exist in the top-level directory, they should
not be stowed.
2013-04-12 17:42:14 +01:00
Adam Spiers
8ccef07601 Only include $! in error messages for failed syscalls. 2012-07-09 01:06:13 +01:00
Adam Spiers
67936bd7de Fix RT ticket #75349
https://rt.cpan.org/Ticket/Display.html?id=75349
2012-07-09 01:05:27 +01:00
Adam Spiers
db7819dbf2 Bug #36478 - fix Perl warnings from 'require 5.6.1;'
https://savannah.gnu.org/bugs/?36478
2012-05-16 11:02:40 +01:00
Adam Spiers
b6f9ef2b2f Revamp README. 2012-03-01 11:40:34 +00:00
Adam Spiers
af36a44bcb Remove accidentally duplicated code. 2012-02-19 19:16:00 +00:00
Adam Spiers
1517384e53 Improve docs for path_owned_by_package() 2012-02-19 11:58:45 +00:00
Adam Spiers
db784f0a5f Fix typo in manual. 2012-02-19 01:42:10 +00:00
Adam Spiers
037ce9ee8a Add a few more items to index. 2012-02-19 01:42:04 +00:00
Adam Spiers
50d28a4306 Add boilerplate commit message for web docs update. 2012-02-18 20:43:20 +00:00
Adam Spiers
4cd91ed54c Bump version to 2.2.0 2012-02-18 20:33:34 +00:00
Adam Spiers
ed12c787df Add --no-folding option. 2012-02-18 20:33:34 +00:00
Adam Spiers
17d3586e84 Remove -a option for safety reasons (but keep --adopt). 2012-02-18 20:33:34 +00:00
Adam Spiers
a127d22457 Improve error message when package is not found. 2012-02-18 20:33:34 +00:00
Adam Spiers
91c816e32d Use make_invalid_link() to reliably setup symlink fixtures. 2012-02-18 20:33:34 +00:00
Adam Spiers
af4557c543 Add documentation improvements to NEWS. 2012-02-18 20:33:34 +00:00
Adam Spiers
30a70aa3ef Update TODO 2012-02-18 20:33:34 +00:00
Adam Spiers
1af824908d Last known bug was fixed a long time ago :-) 2012-02-18 20:33:34 +00:00
Adam Spiers
52d7e2f384 Update structure of manual to match recommended texinfo structure.
TOC now appears after title page.
Copying information is no longer duplicated.
2012-02-18 20:33:34 +00:00
Adam Spiers
934ff5e273 Fix various formatting issues in the manual. 2012-02-18 20:20:15 +00:00
Adam Spiers
2ae90481cb Add some more index entries to the manual. 2012-02-18 20:20:13 +00:00
Adam Spiers
c6a45b7c81 Add some @sections to the manual to break larger nodes up. 2012-02-18 20:19:45 +00:00
Adam Spiers
149034de9f Use @command / @samp / @env / @var in the manual where appropriate, rather than @code. 2012-02-18 20:19:44 +00:00
Adam Spiers
2da2f44a20 Fix formatting of regexp values in the manual. 2012-02-18 20:19:44 +00:00
Adam Spiers
2c5950ed00 Add --adopt to usage text. 2012-02-18 17:14:50 +00:00
Adam Spiers
7b36267dd2 Improve ordering of options in usage text. 2012-02-18 17:14:50 +00:00
Adam Spiers
a5c2134f59 Add missing options to pod, and reference to front-end documentation. 2012-02-18 17:14:50 +00:00
Adam Spiers
6c3c617fd2 Ignore tmp-testing-trees anywhere. 2012-02-18 17:14:50 +00:00
Adam Spiers
1847b36e18 Make shared library tests match real-world scenarios.
Typically, libfoo.so.X.Y.Z is the file, and libfoo.so is the symlink
which points to it.
2012-02-18 12:28:00 +00:00
Adam Spiers
9c6faebb95 Include --simulate in usage text. 2012-02-18 11:53:46 +00:00
Adam Spiers
fe18b6c442 Avoid "Use of uninitialized value" warnings from test suite.
Happened on some versions of Perl when TEST_VERBOSE not yet.
Thanks Adam Sampson!
2012-01-13 11:35:53 +00:00
Adam Spiers
25b9ce0f21 Remove reference to old FSF address (thank you rpmlint for catching this!) 2012-01-12 17:54:32 +00:00
Adam Spiers
8357dca645 Remove "There are no outstanding operations to perform" warning.
This is more in keeping with the UNIX convention of no output on success,
and is also the way Stow v1.x behaved.  Thanks to Adam Sampson for the suggestion.
2012-01-11 14:01:40 +00:00
Adam Spiers
d51ff055c2 Fix wrong version number in NEWS. 2012-01-10 12:17:58 +00:00
Adam Spiers
9889d10b2e Bump version to 2.1.3 2012-01-09 22:12:49 +00:00
Adam Spiers
0c6d5639e3 Rename test files to reflect their purpose. 2012-01-09 22:12:49 +00:00
Adam Spiers
c3c866a00b Rename stow.t to be more consistent with its purpose. 2012-01-09 22:12:49 +00:00
Adam Spiers
92eee74bb3 perl Build.PL needs a prefix during testing 2012-01-09 22:10:48 +00:00
Adam Spiers
7e44666640 Add --adopt / -a option. 2012-01-09 21:29:34 +00:00
Adam Spiers
5110ea8338 Add stacktrace to internal error report to aid debugging. 2012-01-09 21:11:58 +00:00
Adam Spiers
4dce3d0ce8 Use get_conflict_count() in tests since get_conflicts() no longer returns a flat structure. 2012-01-09 18:32:06 +00:00
Adam Spiers
1200420687 Link to website to encourage users to report bugs. 2012-01-09 17:52:11 +00:00
Adam Spiers
e466732bbf Improve readability of NEWS file when viewed raw. 2012-01-09 16:42:40 +00:00
Adam Spiers
1efb786140 Improve existing comments. 2012-01-09 16:25:27 +00:00
Adam Spiers
782836bad7 Improve the footnote which defines 'subpath'. 2011-12-21 11:45:59 +00:00
Adam Spiers
7c90000393 Add another ignore example to the manual and test suite. 2011-12-21 11:45:43 +00:00
Adam Spiers
6e5331814d Fix some incorrect CPAN meta-data about the project. 2011-12-15 21:14:07 +00:00
Adam Spiers
215e0dac13 Make configure check for Perl modules required by test suite. 2011-12-13 16:12:29 +00:00
Adam Spiers
d3847e951a Make stow script return true for t/stow.t
According to http://matrix.cpantesters.org/?dist=Stow
this only seems to be an issue with Perl <= 5.8.7.
2011-12-11 13:23:37 +00:00
Adam Spiers
1f35c6c94f Automate check for 'use lib' line in bin/stow. 2011-12-11 13:16:03 +00:00
Adam Spiers
23fe1510d2 Bump version to 2.1.2. 2011-12-07 20:48:50 +00:00
Adam Spiers
195c80e9d7 Significantly improve the handling of --with-pmdir. 2011-12-07 20:48:50 +00:00
Adam Spiers
8817815059 Make capitalisation consistent in usage text. 2011-12-07 20:31:20 +00:00
Adam Spiers
d88434f16e Abort ./configure if we can't find Perl. 2011-12-07 20:31:18 +00:00
Adam Spiers
e7e0646db0 Ensure the ChangeLog is up-to-date when making a new distribution.
Thanks to Stefano Lattarini for this suggestion.
2011-12-07 01:23:41 +00:00
Adam Spiers
5eef9830c1 Use maintainer-clean-local rule, not maintainer-clean. 2011-12-07 01:22:56 +00:00
Adam Spiers
15f44a3275 `make clean' shouldn't remove files which the user may not be able to rebuild. 2011-12-06 20:33:08 +00:00
Adam Spiers
d051936bf5 Bump version to 2.1.1 2011-12-06 17:42:02 +00:00
Adam Spiers
fb2f621b1c Ignore .mrdownload files from my `download' plugin to Joey Hess' mr utility. 2011-12-06 17:34:31 +00:00
Adam Spiers
7b62cbf09a Add a workaround for not being able to ensure that git commit triggers
ChangeLog update.
2011-12-06 17:31:10 +00:00
Adam Spiers
8fea1a8dbb Show when ChangeLog is rebuilt. 2011-12-06 17:24:50 +00:00
Adam Spiers
9dbe5e4c92 Fix release instructions regarding CPAN distribution. 2011-12-06 17:23:09 +00:00
Adam Spiers
d6afb3d062 Refill paragraph in README. 2011-12-06 17:23:09 +00:00
Adam Spiers
7d30557b4d Don't duplicate information from INSTALL. 2011-12-06 17:23:09 +00:00
Adam Spiers
6951315218 Document installation via Module::Build. 2011-12-06 17:23:08 +00:00
Adam Spiers
82debd4e8f Document prerequisites for installation. 2011-12-06 17:11:12 +00:00
Adam Spiers
d6d51a7883 chkstow was missing from Module::Build install. 2011-12-06 17:11:12 +00:00
Adam Spiers
51b1bd3958 File::Slurp is no longer used. 2011-12-06 17:11:12 +00:00
Adam Spiers
bbaace4d5a Fix automake issues (thanks to Stefano Lattarini for spotting these!) 2011-12-06 17:11:12 +00:00
Adam Spiers
d1073789d2 Add $(PDF) and $(HTML) variables. 2011-12-06 17:11:12 +00:00
Adam Spiers
813a016c1a Add *.orig to MANIFEST.SKIP. 2011-12-06 17:11:12 +00:00
Adam Spiers
884a4b8556 Ditch deprecated AM_MAINTAINER_MODE. 2011-12-06 16:26:29 +00:00
Adam Spiers
a9469a0f67 Add licensing changes to TODO. 2011-12-06 16:26:29 +00:00
Adam Spiers
bc661ae77b Add bug-reporting email address and a couple of URLs to usage text
to comply with GNU Coding Standards for --help option.
2011-12-06 16:26:29 +00:00
Adam Spiers
1507d1a055 Calculated the correct default value for pmdir based on the local Perl installation. 2011-12-06 16:26:27 +00:00
Adam Spiers
d879bde678 Fixed bug where --with-pmdir was ineffectual. 2011-12-06 16:26:24 +00:00
Adam Spiers
419e31b4c6 Change @dircategory to `System administration' as suggested by Karl Berry. 2011-12-04 14:57:34 +00:00
Adam Spiers
f032e30cc8 Add git push and update of online documentation to HOWTO-RELEASE. 2011-12-03 18:13:09 +00:00
Adam Spiers
f5d0bd178d Release announcements should go to stow-devel too. 2011-12-03 17:51:48 +00:00
Adam Spiers
f649cd2766 Fix error in gnupload command-line. 2011-12-03 17:51:44 +00:00
Adam Spiers
4b75cb5fa9 Add a missing space. 2011-12-03 17:09:48 +00:00
Adam Spiers
519566f3f4 Add a missing hyperlink to the Stow homepage. 2011-12-03 16:40:20 +00:00
Adam Spiers
a17537af3e Give up on automake's built-in rules for generating PDF and HTML and use our own.
Also include split version of the manual.
2011-12-03 14:42:41 +00:00
Adam Spiers
e046048a1c Update reference to maintainer. 2011-12-03 02:07:19 +00:00
Adam Spiers
6682aa9caf Temporarily remove PDF from dist_doc_DATA due to automake issue.
http://article.gmane.org/gmane.comp.sysutils.automake.general/13192

This means that it is still included in the distribution and
installed, but is only automatically (re)built when making a
new distribution - if stow.texi changes during development, it
has to be rebuilt manually via 'make pdf'.
2011-12-03 01:36:23 +00:00
Adam Spiers
e3eeedc2c1 Module::Build generates archive files with 'v' for version 2011-12-03 01:36:23 +00:00
Adam Spiers
d55c314d28 Add TODOs for .rpm and .deb support. 2011-12-03 01:36:23 +00:00
Adam Spiers
aeedec3a57 Add doc/version.texi to distribution. 2011-12-03 01:36:22 +00:00
Adam Spiers
e1e8175ea5 Switch to renaming to manual via install hook as suggested by Stefano Lattarini
http://article.gmane.org/gmane.comp.sysutils.automake.general/13191
2011-12-03 01:36:22 +00:00
Adam Spiers
4d6c23600b Fix corner case where only -d is specified as a single directory. 2011-12-01 16:23:04 +00:00
Adam Spiers
4e831ae7bd Add result of ./Build dist to .gitignore 2011-11-28 23:47:53 +00:00
Adam Spiers
d2473363b2 Synchronise CPAN MANIFEST files with automake distribution list. 2011-11-28 23:47:53 +00:00
Adam Spiers
e915435f32 Ignore split page version of HTML manual. 2011-11-28 23:47:53 +00:00
Adam Spiers
aad96a0a44 Don't duplicate stow.texi to manual.texi. 2011-11-28 23:47:53 +00:00
Adam Spiers
d672e3e6cf Improve debug levels. 2011-11-26 19:18:33 +00:00
Adam Spiers
4933d9623d Add a TODO concerning .nonstow. 2011-11-26 18:24:35 +00:00
Adam Spiers
08e15e3d43 Add HOWTO-RELEASE 2011-11-26 18:15:26 +00:00
Adam Spiers
b03c6df978 Add NEWS entry for 2.1.0 2011-11-26 16:34:58 +00:00
Adam Spiers
a70302f99d Bump version to 2.1.0 2011-11-26 16:34:58 +00:00
Adam Spiers
d5aa061abe Fix documentation regarding splitting of symlinks across multiple stow directories. 2011-11-26 16:34:57 +00:00
Adam Spiers
1f41616b12 Tidy up chkstow code and documentation. 2011-11-26 16:34:57 +00:00
Adam Spiers
6b815a9a90 Add chkstow to NEWS 2011-11-26 16:34:57 +00:00
Adam Spiers
a8a0e360ae Add comment to manual about test_examples_in_manual() in t/ignore.t. 2011-11-26 16:34:57 +00:00
Adam Spiers
bcac91d68a Remove quote stripping code.
I'm guessing it was added due to a misunderstanding of how shell
quoting works.  When you invoke

   stow --ignore=".#.*" ...

the shell strips out the quotes before the Perl process ever sees them.
I can't imagine any sensible scenario in which you would need to invoke

   stow --ignore='"foo"'

but if the user has a filename containing quotes at the beginning and
end, they can now choose to ignore it (prior to this patch, they couldn't).
2011-11-26 16:34:57 +00:00
Adam Spiers
3d414dc071 Improve conflict reporting 2011-11-26 16:34:57 +00:00
Adam Spiers
81da7be357 Sync up .gitignore and MANIFEST* with recent changes. 2011-11-26 16:34:57 +00:00
Adam Spiers
55d3f05cf2 Ditch obsolete --conflicts option and update misleading documentation. 2011-11-26 16:34:57 +00:00
Adam Spiers
00d4e68445 Auto-generate ChangeLog from git 2011-11-26 16:34:57 +00:00
Adam Spiers
685d449963 Sort .gitignore alphabetically 2011-11-26 16:34:57 +00:00
Adam Spiers
62c513d7bc Add some missing stuff to .gitignore 2011-11-26 16:34:57 +00:00
Adam Spiers
c019af00a0 Distribute .tar.gz and .tar.bz2 but not .shar.gz 2011-11-26 16:34:57 +00:00
Adam Spiers
10ea9c6f4b Numerous fixes so that `make distcheck' succeeds.
Moves temporary test trees into a separate directory.
2011-11-26 16:34:57 +00:00
Adam Spiers
0db112441f Strip superfluous quotes from $hash{'lookups'} 2011-11-26 16:34:54 +00:00
Adam Spiers
6534b21d29 Tidy up the copyright attributions in the manual. 2011-11-26 16:34:50 +00:00
Adam Spiers
b87ca607ba Fix some minor issues in the manual. 2011-11-26 16:34:50 +00:00
Adam Spiers
ad77ca6db7 Add HTML and PDF versions of manual to distribution. 2011-11-26 16:34:50 +00:00
Adam Spiers
ea82ef5b8b Add support for ignore lists. 2011-11-26 16:34:48 +00:00
Adam Spiers
7777e181a8 Rename $old_* to $existing_* 2011-11-26 15:10:29 +00:00
Adam Spiers
b20228721e Rename protected_dir() to marked_stow_dir(). 2011-11-26 15:10:29 +00:00
Adam Spiers
d8a4cda11b Rename should_skip_stow_dir_target() to should_skip_target_which_is_stow_dir() 2011-11-26 15:10:28 +00:00
Adam Spiers
7c0bb53bff Be clearer when we're not actually (un)stowing, just planning. 2011-11-26 15:10:28 +00:00
Adam Spiers
8960a4f1fb Add another test to join_paths.t 2011-11-26 15:10:28 +00:00
Adam Spiers
7bef0fb700 Clean up coding style in tests 2011-11-26 15:10:28 +00:00
Adam Spiers
a7262a98bc Avoid use of map in void context 2011-11-26 15:10:28 +00:00
Adam Spiers
1873e4b4ef Add a comment about a relative weakness of compat mode. 2011-11-26 15:10:28 +00:00
Adam Spiers
2244539b6b Test stow/unstow with stow dir / target dir as absolute paths. 2011-11-26 15:10:28 +00:00
Adam Spiers
4d45d3e0c7 Fix more inconsistencies in coding style. 2011-11-26 15:10:27 +00:00
Adam Spiers
b8942c9f79 Fix typos 2011-11-26 15:10:27 +00:00
Adam Spiers
1f9c5bed1a Fix/remove some outdated TODOs 2011-11-26 15:10:27 +00:00
Adam Spiers
59fa7ae4a6 Add build-time dependencies on Test::More and Test::Output. 2011-11-26 15:10:27 +00:00
Adam Spiers
f93796dce3 Add MYMETA.* to .gitignore 2011-11-26 15:10:27 +00:00
Adam Spiers
0cd971d3a1 Add .dirstamp and stamp-vti to .gitignore 2011-11-26 15:10:27 +00:00
Adam Spiers
a84ba4c16d Convert man page to POD format which is easier to maintain within stow.in. 2011-11-26 15:10:27 +00:00
Adam Spiers
58625800ee Reorganise more files into subdirectories and add CPAN support via Module::Build 2011-11-26 15:10:26 +00:00
Adam Spiers
382ad5c58d Add myself (Adam) to AUTHORS and THANKS ;-) 2011-11-24 18:08:15 +00:00
Adam Spiers
dc61da22d4 Major refactoring of code into separate Stow and Stow::Util Perl modules 2011-11-24 16:56:11 +00:00
Adam Spiers
1365c4c4f1 Fix indentation in Makefile.am 2011-11-24 16:55:55 +00:00
Adam Spiers
fbe547c132 Test unstowing when target contains a real file generates a conflict. 2011-11-24 16:55:55 +00:00
Adam Spiers
6e7ed071c1 Test unstowing stuff which doesn't exist in the target tree. 2011-11-24 16:55:55 +00:00
Adam Spiers
eda2b83355 Add a missing conflict if we tried to unstow a file in compat mode. 2011-11-24 16:55:55 +00:00
Adam Spiers
a1246072dd Remove setting of verbosity from tests 2011-11-24 16:55:55 +00:00
Adam Spiers
3418cadb8e Make 'verbose' option default to 0 in testmode. 2011-11-24 16:55:55 +00:00
Adam Spiers
80826b96e2 Add protection against stowing into stow dirs 2011-11-24 16:55:55 +00:00
Adam Spiers
89b7de8c04 Debug stow dir in stow/unstow contents routines 2011-11-24 16:55:55 +00:00
Adam Spiers
c26e62de43 Trace individual cases separately when skipping stow dirs during unstow. 2011-11-24 16:55:55 +00:00
Adam Spiers
5db0c0bbf7 Allow TEST_VERBOSE to control level of verbosity.
Defaults to 3.  'verbose' option now has precedence if set.
2011-11-24 16:55:55 +00:00
Adam Spiers
fdca9bd57a Debug when skipping over stow directories 2011-11-24 16:55:55 +00:00
Adam Spiers
b5c49db524 Add debug when target to be unstowed doesn't exist 2011-11-24 16:55:55 +00:00
Adam Spiers
0592daf3ef Add comments justifying is_a_node($target) check in unstow_contents(). 2011-11-24 16:55:54 +00:00
Adam Spiers
9012dd8aa8 Test unstowing an already unstowed package 2011-11-24 16:55:54 +00:00
Adam Spiers
bcddf67d73 Fix incorrect comments. 2011-11-24 16:55:54 +00:00
Adam Spiers
28dbad2933 Sync t/unstow_contents{,_orig}.t 2011-11-24 16:55:54 +00:00
Adam Spiers
c26236d93c Debug with maximum verbosity to STDOUT when running tests. 2011-11-24 16:55:54 +00:00
Adam Spiers
497f272c12 Refactored reset_state() into t/util.pm 2011-11-24 16:55:54 +00:00
Adam Spiers
aefaad37a4 Refactored is_a_{link,dir,node}() code. 2011-11-24 16:55:54 +00:00
Adam Spiers
7167eeb903 Improve tree splitting comments. 2011-11-24 16:55:54 +00:00
Adam Spiers
1d3f45580b Don't tolerate '' as value for $target parameter to (un)stow_contents 2011-11-24 16:55:54 +00:00
Adam Spiers
063331c34d Add debug tracing to helper routines 2011-11-24 16:55:54 +00:00
Adam Spiers
422a748724 Fix Parameters comments. 2011-11-24 16:55:54 +00:00
Adam Spiers
c23e314848 Improve debug output 2011-11-24 16:55:54 +00:00
Adam Spiers
da7255528e Clarify meaning of `--defer' in the manual. 2011-11-24 16:55:54 +00:00
Adam Spiers
cb86578b87 Finish "Deferred Operation" section in manual. 2011-11-24 16:55:54 +00:00
Adam Spiers
85f1f8619c Fix inconsistencies in coding style. 2011-11-24 16:55:53 +00:00
Adam Spiers
6ee8747c9b Set cperl-indent-level to 4 2011-11-24 16:55:53 +00:00
Adam Spiers
ba3c052c1f Simplify GetOptions() code 2011-11-24 16:55:53 +00:00
Adam Spiers
ca49579fa1 Refactor verbosity-controlled output to STDERR into debug() subroutine. 2011-11-24 16:55:53 +00:00
Adam Spiers
8da4e15fbf Fix broken 'make install' due to man page being duplicated in install-man8 target 2011-11-24 16:55:53 +00:00
Adam Spiers
090519496c Stow directory now defaults to STOW_DIR environment variable if set. 2011-11-24 16:55:53 +00:00
Adam Spiers
801446a5eb Use File::Spec->abs2rel() instead of home-grown relative_path
which actually gets some inputs wrong (e.g. "/" relative to "/")
2011-11-24 16:55:53 +00:00
Adam Spiers
8b5a0f5aa3 Add a bunch of stuff to the TODO 2011-11-24 16:55:53 +00:00
Adam Spiers
010877255a Add FIXME for Deferred Operation section in manual. 2011-11-24 16:55:53 +00:00
Adam Spiers
5a09c527b3 Fix indentation issues in NEWS 2011-11-24 16:55:53 +00:00
Adam Spiers
ad28894a85 Switch NEWS and TODO to org-mode.
org-mode has been included in emacs by default for a long time and is
much more friendly than outline-mode.  No impact to non-emacs users.
2011-11-24 16:55:53 +00:00
Adam Spiers
8ce4d3be52 Stow now requires Perl 5.6.1 or newer, due to use of 'our'. 2011-11-24 16:55:53 +00:00
Adam Spiers
59b7835fd8 Troy is the maintainer now. 2011-11-24 16:55:52 +00:00
Adam Spiers
d674d13a68 Fix typos 2011-11-24 16:55:52 +00:00
Adam Spiers
8de15394bb Catch warnings in tests when no outstanding operations to perform.
Tests now all pass completely cleanly.
2011-11-24 16:55:52 +00:00
Adam Spiers
d74ae26f89 Fix %Options typo in several tests 2011-11-24 16:55:52 +00:00
Adam Spiers
4296500c94 Fix t/stow.t 2011-11-24 16:55:52 +00:00
Adam Spiers
8da2a43eb1 Fix chkstow.t 2011-11-24 16:55:52 +00:00
Adam Spiers
5fe30e9f1a Add #! header to t/util.pm for benefit of editor mode selection 2011-11-24 16:55:52 +00:00
Adam Spiers
d6dbb932ac Fix chkstow.in for emacs users 2011-11-24 16:55:52 +00:00
Adam Spiers
8e14cb641f Support ./configure --disable-maintainer-mode
to optionally avoid auto-reconfiguring on make.
2011-11-24 16:55:52 +00:00
Adam Spiers
5d7f967ebd Run autoreconf with more recent GNU autotools. 2011-11-24 16:55:51 +00:00
Adam Spiers
f5e6bfddc2 Add test target to Makefile 2011-11-24 16:55:51 +00:00
Adam Spiers
9f8a6c2be3 Remove auto-generated files from git. 2011-11-24 16:55:43 +00:00
Adam Spiers
b5697ce98e Add .gitignore 2011-11-17 12:38:37 +00:00
73 changed files with 12327 additions and 20034 deletions

1
.coveralls.yml Normal file
View file

@ -0,0 +1 @@
repo_token: xl1m2EiKjG4YlJQ0KjTTBNDRcAFD0lCVt

6
.dir-locals.el Normal file
View file

@ -0,0 +1,6 @@
((cperl-mode . ((dumb-jump-force-searcher . rg)
(cperl-indent-level . 4)
(cperl-close-paren-offset . -4)
(cperl-indent-subs-specially . nil)
(indent-tabs-mode . nil)
(eval . (auto-fill-mode -1)))))

2
.dumbjump Normal file
View file

@ -0,0 +1,2 @@
+bin/*.in
+lib/*.pm.in

80
.github/workflows/test.yml vendored Normal file
View file

@ -0,0 +1,80 @@
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
name: Test suite
on:
push:
branches: [master]
pull_request:
branches: [master]
types: [opened, synchronize, reopened, ready_for_review]
jobs:
# call-simple-perl-test:
# uses: perl-actions/github-workflows/.github/workflows/simple-perltester-workflow.yml@main
# with:
# since-perl: 5.14
test:
name: Perl ${{ matrix.perl-version }}
runs-on: ubuntu-latest
strategy:
matrix:
perl-version:
- '5.38'
- '5.36'
- '5.34'
- '5.32'
- '5.30'
container:
# This Docker image should avoid the need to run:
#
# cpanm -n Devel::Cover::Report::Coveralls
image: perldocker/perl-tester:${{ matrix.perl-version }}
steps:
- run: apt-get update && apt-get install -y sudo texinfo texlive
- name: Checkout code
uses: actions/checkout@v2
# - uses: awalsh128/cache-apt-pkgs-action@latest
# with:
# debug: true
# packages: texinfo texlive
# version: 1.0
- run: autoreconf --install
- name: ./configure && make
run: |
eval `perl -V:siteprefix`
# Note: this will complain Test::Output isn't yet installed:
./configure --prefix=$siteprefix && make
# but that's OK because we install it here:
make cpanm
#- name: Run tests
# run: make test
- run: make distcheck
- run: perl Build.PL
- run: ./Build build
- run: cover -test -report coveralls
- run: ./Build distcheck

35
.gitignore vendored Normal file
View file

@ -0,0 +1,35 @@
.dirstamp
/Build
/ChangeLog
/MYMETA.json
/MYMETA.yml
/Makefile
/Makefile.in
/bin/chkstow
/bin/stow
/doc/stow.info
/doc/version.texi
/playground/
tmp-testing-trees*/
_build/
autom4te.cache/
blib/
config.log
config.status
configure
/cover_db/
/doc/ChangeLog.OLD
/doc/manual.pdf
/doc/manual-single.html
/doc/manual-single-old-texi2html.html
/doc/manual-single-texi2html-wrapper.html
/doc/manual-split/
/doc/manual.texi
/doc/stow.pdf
/doc/stow.8
/lib/Stow.pm
/lib/Stow/Util.pm
stamp-vti
stow-[0-9].[0-9].[0-9].tar.*
stow-[0-9].[0-9].[0-9]/
Stow-v[0-9].[0-9].[0-9].tar.*

25
.travis.yml Normal file
View file

@ -0,0 +1,25 @@
language: perl
perl:
- "5.20"
- "5.18"
- "5.16"
- "5.14"
sudo: false
addons:
apt:
packages:
- texinfo
- texlive
before_install:
- cpanm -n Devel::Cover::Report::Coveralls
install:
- autoreconf --install
- eval `perl -V:siteprefix`
# Note: this will complain Test::Output isn't yet installed:
- ./configure --prefix=$siteprefix && make
# but that's OK because we install it here:
- make cpanm
script:
- make distcheck
- perl Build.PL && ./Build build && cover -test -report coveralls
- ./Build distcheck

84
AUTHORS
View file

@ -1,35 +1,79 @@
Stow was written by Bob Glickstein <bobg+stow@zanshin.com>, Zanshin
Software, Inc.
This file documents the high-level history of Stow, and some of its
major contributors. See also the THANKS file for a more complete list
of contributors.
Contributions from Gord Matzigkeit <gord@enci.ucalgary.ca>.
Stow was originally written by Bob Glickstein <bobg+stow@zanshin.com>,
Zanshin Software, Inc.
Gord Matzigkeit <gord@enci.ucalgary.ca> made some early contributions.
John Bazik wrote `fastcwd', the Perl subroutine for computing the
current working directory.
current working directory (later removed in 1.3.3).
Charles Briscoe-Smith <cpbs@debian.org> wrote the fix to prevent
stow -D / stow -R removing initially-empty directories.
Charles Briscoe-Smith <cpbs@debian.org> wrote the fix to prevent
stow -D / stow -R removing initially-empty directories (mentioned
in 1.3.3 section of NEWS).
Adam Lackorzynski <al10@inf.tu-dresden.de> wrote the fix to prevente
Adam Lackorzynski <al10@inf.tu-dresden.de> wrote the fix to prevent
the generation of wrong links if there are links in the stow directory.
Stow was maintained by Guillaume Morin <gmorin@gnu.org> up to November 2007.
Stow was maintained by Guillaume Morin <gmorin@gnu.org> up to November
2007. Guillaume originally imported the source code into the Savannah
CVS repository on 2001/12/24 with the tag "v1_3_2". This history was
later imported into git as described below.
Kahlil (Kal) Hodgson <kahlil@internode.on.net> performed a major rewrite
inorder to implement:
1.3.3 was the last release of the 1.x series. The CVS history
contains a few commits after 1.3.3 preparing for a 1.3.4 release which
was never published (see the "import-cvs" tag in git).
1. defered operations,
Between 2007 and 2009, a small team of people collaborated on a
private in-house project on Stow:
https://lists.gnu.org/archive/html/stow-devel/2011-11/msg00003.html
Kahlil (Kal) Hodgson <kahlil@internode.on.net> performed a major
rewrite in order to implement:
1. deferred operations,
2. option parsing via Getopt::Long,
3. options to support shared files,
3. options to support shared files,
4. support for multiple operations per invocation,
5. default command line arguments via '.stowrc' and '~/.stowrc' files,
5. default command line arguments via '.stowrc' and '~/.stowrc' files,
6. better cooperation between multiple stow directories,
7. a test suite (and support code) to ensure that everything still works.
7. a test suite (and support code) to ensure that everything still works.
As these changes required a dramatic reorganisation of the code, very little
was left untouched, and so stows major version was bumped up to version 2.
As these changes required a dramatic reorganisation of the code, very
little was left untouched, and so Stow's major version number was
bumped up to 2. Austin Wood <austin.wood@rmit.edu.au> and Chris
Hoobin <christopher.hoobin@rmit.edu.au> helped clean up the
documentation for the new 2.x.y series, and created the texi2man
script.
Austin Wood <austin.wood@rmit.edu.au> and Chris Hoobin
<christopher.hoobin@rmit.edu.au> helped clean up the documentation for
version 2 and created the texi2man script.
Kahlil obtained permission to donate these changes back to GNU. The
Subversion history from this period is no longer accessible, so the
breakdown of the individual changes to the source code between 1.3.3
and the unreleased 2.0.2 version have been lost; however some details
are still visible in ChangeLog.OLD, which also acknowledges the
contributions of Geoffrey Giesemann and Emil Mikulc.
Stow is currently maintained by Kahlil (Kal) Hodgson <kahlil@internode.on.net>.
Sometime after this, Troy Will took over maintainership and imported
the unreleased 2.0.2 code base as the original root commit into
Savannah git repository.
On 25th November 2011, Adam Spiers <stow@adamspiers.org> took over
maintainership. He imported the CVS history into the Savannah git
repository, grafting it onto the previous root commit imported by
Troy, and tagged this as v2.0.2:
https://lists.gnu.org/archive/html/stow-devel/2011-11/msg00001.html
https://lists.gnu.org/archive/html/stow-devel/2011-11/msg00002.html
refactored the backend code into new Stow.pm and Stow/Util.pm modules
providing an OO interface, tightened up the test suite, added support
for ignore lists, `make test', and distribution via CPAN, and cleaned
up numerous other minor issues.
These changes were included in 2.1.0, which was the first official
release since 1.3.3 in 2002.
Stow is currently maintained by Adam Spiers.

102
Build.PL Normal file
View file

@ -0,0 +1,102 @@
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
use strict;
use warnings;
use Module::Build;
# These are required by the test suite.
use lib "t";
use lib "bin";
my $build = Module::Build->new(
module_name => 'Stow',
keywords => [ qw/stow symlink software package management install/ ],
license => 'gpl',
# Module::Build forces us to use v1.4 of the CPAN Meta Spec:
# https://rt.cpan.org/Ticket/Display.html?id=71502
# 'meta-spec' => {
# version => '2.0',
# url => 'http://search.cpan.org/perldoc?CPAN::Meta::Spec',
# },
meta_add => {
resources => {
license => 'http://www.gnu.org/licenses/gpl-2.0.html' ,
homepage => 'https://savannah.gnu.org/projects/stow',
# Module::Build forces us to use v1.4 of the CPAN Meta Spec:
# https://rt.cpan.org/Ticket/Display.html?id=71502
# bugtracker => {
# web => 'http://rt.cpan.org/Public/Dist/Display.html?Name=Stow',
# mailto => 'stow-devel@gnu.org',
# },
#bugtracker => 'http://rt.cpan.org/Public/Dist/Display.html?Name=Stow',
# Module::Build forces us to use v1.4 of the CPAN Meta Spec:
# https://rt.cpan.org/Ticket/Display.html?id=71502
# repository => {
# url => 'git://git.savannah.gnu.org/stow.git',
# web => 'https://savannah.gnu.org/git/?group=stow',
# type => 'git',
# },
repository => 'git://git.savannah.gnu.org/stow.git',
},
},
requires => {
'perl' => '5.006',
'Carp' => 0,
'IO::File' => 0,
},
script_files => [ 'bin/stow', 'bin/chkstow' ],
all_from => 'lib/Stow.pm.in',
configure_requires => {
'Module::Build' => 0,
},
build_requires => {
'Test::More' => 0,
'Test::Output' => 0,
'IO::Scalar' => 0,
},
);
if (system('grep', '-q', '^use lib ', 'bin/stow') >> 8 == 0) {
die <<'EOF';
ERROR: bin/stow contains 'use lib' line which could interfere
with CPAN-style installation via Module::Build. To avoid this,
you should run ./configure with parameters which result in
--with-pmdir's value being in Perl's built-in @INC, and then run
'make' (NOT 'make install') to regenerate bin/stow, e.g.
eval `perl -V:siteprefix`
./configure --prefix=$siteprefix && make
or
./configure --with-pmdir=`PERL5LIB= perl -le 'print $INC[0]'` && make
Then re-run this script.
Note that these parameters are chosen purely to regenerate
bin/stow without a 'use lib' line, so don't run 'make install'
while Stow is configured in this way unless you really want an
installation using these parameters.
EOF
}
$build->create_build_script();

123
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,123 @@
Contributing to GNU Stow
========================
Development of Stow, and GNU in general, is a volunteer effort, and
you can contribute. If you'd like to get involved, it's a good idea to join
the [stow-devel](https://lists.gnu.org/mailman/listinfo/stow-devel)
mailing list.
Bug reporting
-------------
Please follow the procedure described in [the "Reporting Bugs"
section](https://www.gnu.org/software/stow/manual/html_node/Reporting-Bugs.html#Reporting-Bugs)
of [the manual](README.md#documentation).
Development
-----------
For [development sources](https://savannah.gnu.org/git/?group=stow)
and other information, please see the [Stow project
page](http://savannah.gnu.org/projects/stow/) at
[savannah.gnu.org](http://savannah.gnu.org).
There is also a
[stow-devel](https://lists.gnu.org/mailman/listinfo/stow-devel)
mailing list (see [Mailing lists](README.md#mailing-lists)).
Please be aware that all program source files (excluding the test
suite) end in `.in`, and are pre-processed by `Makefile` into
corresponding files with that prefix stripped before execution. So if
you want to test any modifications to the source, make sure that you
change the `.in` files and then run `make` to regenerate the
pre-processed versions before doing any testing. To avoid forgetting
(which can potentially waste a lot of time debugging the wrong code),
you can automatically run `make` in an infinite loop every second via:
make watch
(You could even use fancier approaches like
[`inotifywait(1)`](https://www.man7.org/linux/man-pages/man1/inotifywait.1.html)
or [Guard](https://guardgem.org/). But those are probably overkill in
this case where the simple `while` loop is plenty good enough.)
Testing
~~~~~~~
The test suite can be found in the [`t/`](t/) subdirectory. You can
run the test suite via:
make check
Tests can be run individually as follows. First you have to ensure
that the `t/`, `bin/`, and `lib/` directories are on Perl's search path.
Assuming that you run all tests from the root of the repository tree,
this will do the job:
export PERL5LIB=t:bin:lib
(Not all tests require all of these, but it's safer to include all of
them.)
Secondly, be aware that if you want to test modifications to the
source files, you will need to run `make watch`, or `make` before each
test run as explained above.
Now running an individual test is as simple as:
perl t/chkstow.t
or with a given debugging verbosity corresponding to the `-v` / `--verbose`
command-line option:
TEST_VERBOSE=4 perl t/chkstow.t
The [`prove(1)` test runner](https://perldoc.perl.org/prove) is another
good alternative which provides several handy extra features. Invocation
is very similar, e.g.:
prove t/stow.t
or to run the whole suite:
prove
However currently there is an issue where this interferes with
`TEST_VERBOSE`.
If you want to create test files for experimentation, it is
recommended to put them in a subdirectory called `playground/` since
this will be automatically ignored by git and the build process,
avoiding any undesirable complications.
Test coverage
~~~~~~~~~~~~~
To view test coverage reports, first ensure that
[`Devel::Cover`](https://metacpan.org/dist/Devel-Cover) is installed.
Then type `make coverage`. The last lines of the output should
include something like:
HTML output written to /home/user/path/to/stow/cover_db/coverage.html
which you can open in a web browser to view the report.
Translating Stow
----------------
Stow is not currently multi-lingual, but patches would be very
gratefully accepted. Please e-mail
[stow-devel](https://lists.gnu.org/mailman/listinfo/stow-devel) if you
intend to work on this.
Maintainers
-----------
Stow is currently being maintained by Adam Spiers. Please use [the
mailing lists](README.md#mailing-lists).
Helping the GNU project
-----------------------
For more general information, please read [How to help
GNU](https://www.gnu.org/help/).

848
COPYING
View file

@ -1,285 +1,626 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
TERMS AND CONDITIONS
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
0. Definitions.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
"This License" refers to version 3 of the GNU General Public License.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
A "covered work" means either the unmodified Program or a work based
on the Program.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
1. Source Code.
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
The Corresponding Source for a work in source code form is that
same work.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
13. Use with the GNU Affero General Public License.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
14. Revised Versions of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
NO WARRANTY
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
15. Disclaimer of Warranty.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
@ -287,15 +628,15 @@ free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
@ -304,37 +645,30 @@ the "copyright" line and a pointer to where the full notice is found.
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<https://www.gnu.org/licenses/>.
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<https://www.gnu.org/licenses/why-not-lgpl.html>.

108
INSTALL
View file

@ -1,108 +0,0 @@
Basic Installation
==================
Stow is a Perl script. You must have Perl 5.005 or later in order for
it to run.
The steps in building stow are:
1. `cd' to the directory containing the source code (and this file)
and type `./configure' to configure stow for your system. This
step will attempt to locate your copy of perl and set its location
`Makefile.in'.
2. Type `make' to create `stow' and `'stow.info'. If perl could not
be found by `./configure', you'll have to edit line 1 of `stow'
from `#!false' to `#!/path/to/perl' (where /path/to/perl is wherever
perl will be found when stow runs).
3. Type `make install' to install `stow' and `stow.info'.
4. You can remove the generated files from the source code directory
by typing `make clean'. To also remove the files that `configure'
created (so you can compile the package for a different computer),
type `make distclean'. There is also a `make maintainer-clean'
target, but that is intended mainly for stow's developers. If you
use it, you may have to get all sorts of other programs in order
to regenerate files that came with the distribution.
Installation Names
==================
By default, `make install' will install the package's files in
`/usr/local/bin' and `/usr/local/info'. You can specify an
installation prefix other than `/usr/local' by giving `configure' the
option `--prefix=PATH'.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure'
the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
Since `stow' is concerned with separating a package's installation
tree from its run-time tree, you might want to install `stow' into a
directory such as `/usr/local/stow/stow' but have it run out of
`/usr/local'. Do this by giving the run-time prefix (e.g.,
/usr/local) to configure as described above; then run `make'; then run
`make install prefix=/usr/local/stow/stow'. For more information on
this technique, see the Stow manual.
The configuration system
========================
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile' and to create the `stow' script
itself, using Makefile.in and stow.in as templates. Finally, it
creates a shell script `config.status' that you can run in the future
to recreate the current configuration, a file `config.cache' that
saves the results of its tests to speed up reconfiguring, and a file
`config.log' containing other output.
The file `configure.ac' is used to create `configure' by a program
called `autoconf'. You only need `configure.ac' if you want to change
it or regenerate `configure' using a newer version of `autoconf'.
The file `Makefile.am' is used to create `Makefile.in' by a program
called `automake'. You only need `Makefile.am' if you want to change
it or regenerate `Makefile.in' using a newer version of `automake'.
Sharing Defaults
================
If you want to set default values for `configure' scripts to share,
you can create a site shell script called `config.site' that gives
default values for variables like `CC', `cache_file', and `prefix'.
`configure' looks for `PREFIX/share/config.site' if it exists, then
`PREFIX/etc/config.site' if it exists. Or, you can set the
`CONFIG_SITE' environment variable to the location of the site script.
A warning: not all `configure' scripts look for a site script.
Operation Controls
==================
`configure' recognizes the following options to control how it
operates.
`--cache-file=FILE'
Use and save the results of the tests in FILE instead of
`./config.cache'. Set FILE to `/dev/null' to disable caching, for
debugging `configure'.
`--help'
Print a summary of the options to `configure', and exit.
`--quiet'
`--silent'
`-q'
Do not print messages saying which checks are being made.
`--srcdir=DIR'
Look for the package's source code in directory DIR. Usually
`configure' can determine that directory automatically.
`--version'
Print the version of Autoconf used to generate the `configure'
script, and exit.
`configure' also accepts some other, not widely useful, options.

202
INSTALL.md Normal file
View file

@ -0,0 +1,202 @@
How to install GNU Stow
=======================
Prerequisites
-------------
Stow is a collection of Perl scripts and modules. You must have Perl
5.6.1 or later in order for it to run. The test suite also requires
the `Test::More` and `Test::Output` modules which can be obtained from
CPAN. They are also available as packages in some of the GNU/Linux
distributions.
Installation methods
--------------------
Stow can either be installed via the standard GNU Autotools procedure
(`./configure && make install`) or since 2.1.0, via CPAN-style via
Module::Build.
Advantages of the Autotools approach:
- It's arguably more flexible.
- It will install the documentation in Info, HTML, man, and PDF
formats.
Advantages of the `Module::Build` approach:
- It's more in keeping with the standard way to distribute CPAN
modules.
- It performs dependency checking to ensure you have the necessary
Perl modules installed.
Both approaches are described in detail below. However if you are
building from the git repository rather than an official release,
you first need to perform some extra steps:
Preparatory steps required only when building from git
------------------------------------------------------
`configure` and `Makefile` are included in official releases of Stow,
but they are deliberately omitted from the git repository because they
are autogenerated. Therefore if you are installing directly from git,
you first need to generate them as follows.
First `cd` to the directory containing the source code (and this
file), and then run:
autoreconf -iv
If this runs successfully then you are ready to continue with one of
the two installation methods below.
Basic Installation via `Module::Build`
--------------------------------------
The steps in building Stow are:
1. `cd` to the directory containing the source code (and this file).
2. If you are building from an official GNU release tarball, type
`./configure && make` to configure stow for your system. If you
are building from a CPAN tarball, this step can be skipped.
If `make` warns that the Perl module installation directory is
not in `@INC`, then you should run:
eval `perl -V:siteprefix`
./configure --prefix=$siteprefix && make
to avoid a superfluous `use lib` line in your stow executable.
3. Type `perl Build.PL`.
4. Type `./Build install` to install the various files. As noted
above, this installs fewer files than the Autotools installation.
Basic Installation via Autotools
--------------------------------
The steps in building Stow are:
1. `cd` to the directory containing the source code (and this file).
2. Type `./configure` to configure stow for your system. This step
will attempt to locate your copy of perl and set its location in
`Makefile.in`. You can use the normal arguments to change the
default installation paths (see below); additionally you can use
the
--with-pmdir=/path/to/perl/modules
option to manually choose where the Perl modules get installed.
However, if you don't, the `configure` script will go to great
lengths to try to choose a sensible default.
3. Type `make install` to install the various files. If the chosen
installation directory for Perl modules is not included in Perl's
built-in `@INC` search path, the Makefile rules will automatically
insert a
use lib "...";
line into the generated stow script to ensure that it can always
locate the Perl modules without needing to manually set `PERL5LIB`.
4. You can remove the generated files from the source code directory
by typing `make clean`. To also remove the files that `configure`
created (so you can compile the package for a different computer),
type `make distclean`. There is also a `make maintainer-clean`
target, but that is intended mainly for stow's developers. If you
use it, you may have to get all sorts of other programs in order
to regenerate files that came with the distribution.
Installation Names
------------------
By default, `make install` will install the package's files in
`/usr/local/bin` and `/usr/local/info`. You can specify an
installation prefix other than `/usr/local` by giving `configure` the
option `--prefix=PATH`.
If the package supports it, you can cause programs to be installed
with an extra prefix or suffix on their names by giving `configure`
the option `--program-prefix=PREFIX` or `--program-suffix=SUFFIX`.
Since `stow` is concerned with separating a package's installation
tree from its run-time tree, you might want to install `stow` into a
directory such as `/usr/local/stow/stow` but have it run out of
`/usr/local`. Do this by giving the run-time prefix (e.g.,
/usr/local) to configure as described above; then run `make`; then run
`make install prefix=/usr/local/stow/stow`. For more information on
this technique, see the Stow manual.
The configuration system
------------------------
The `configure` shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses
those values to create a `Makefile` and to create the `stow` script
itself, using Makefile.in and stow.in as templates. Finally, it
creates a shell script `config.status` that you can run in the future
to recreate the current configuration, a file `config.cache` that
saves the results of its tests to speed up reconfiguring, and a file
`config.log` containing other output.
The file `configure.ac` is used to create `configure` by a program
called `autoconf`. You only need `configure.ac` if you want to change
it or regenerate `configure` using a newer version of `autoconf`.
The file `Makefile.am` is used to create `Makefile.in` by a program
called `automake`. You only need `Makefile.am` if you want to change
it or regenerate `Makefile.in` using a newer version of `automake`.
Sharing Defaults
----------------
If you want to set default values for `configure` scripts to share,
you can create a site shell script called `config.site` that gives
default values for variables like `CC`, `cache_file`, and `prefix`.
`configure` looks for `PREFIX/share/config.site` if it exists, then
`PREFIX/etc/config.site` if it exists. Or, you can set the
`CONFIG_SITE` environment variable to the location of the site script.
A warning: not all `configure` scripts look for a site script.
Operation Controls
------------------
`configure` recognizes the following options to control how it
operates.
`--cache-file=FILE`
Use and save the results of the tests in FILE instead of
`./config.cache`. Set FILE to `/dev/null` to disable caching, for
debugging `configure`.
`--help`
Print a summary of the options to `configure`, and exit.
`--quiet`
`--silent`
`-q`
Do not print messages saying which checks are being made.
`--srcdir=DIR`
Look for the package's source code in directory DIR. Usually
`configure` can determine that directory automatically.
`--version`
Print the version of Autoconf used to generate the `configure`
script, and exit.
`configure` also accepts some other, not widely useful, options.
License for this file
---------------------
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. This file is offered as-is,
without any warranty.

57
MANIFEST Normal file
View file

@ -0,0 +1,57 @@
AUTHORS
aclocal.m4
automake/install-sh
automake/mdate-sh
automake/missing
automake/texinfo.tex
bin/chkstow
bin/chkstow.in
bin/stow
bin/stow.in
Build.PL
ChangeLog
configure
configure.ac
CONTRIBUTING.md
COPYING
default-ignore-list
doc/ChangeLog.OLD
doc/manual-single.html
doc/manual.pdf
doc/stow.8
doc/stow.info
doc/stow.texi
doc/version.texi
INSTALL.md
lib/Stow.pm
lib/Stow.pm.in
lib/Stow/Util.pm
lib/Stow/Util.pm.in
Makefile.am
Makefile.in
MANIFEST This list of files
MANIFEST.SKIP
NEWS
README.md
t/chkstow.t
t/cleanup_invalid_links.t
t/cli.t
t/cli_options.t
t/defer.t
t/dotfiles.t
t/examples.t
t/find_stowed_path.t
t/foldable.t
t/ignore.t
t/join_paths.t
t/link_dest_within_stow_dir.t
t/parent.t
t/stow.t
t/rc_options.t
t/testutil.pm
t/unstow.t
tools/get-version
THANKS
TODO
META.yml
META.json

96
MANIFEST.SKIP Normal file
View file

@ -0,0 +1,96 @@
#!start included /usr/share/perl5/ExtUtils/MANIFEST.SKIP
# Avoid version control files.
\bRCS\b
\bCVS\b
\bSCCS\b
,v$
\B\.svn\b
\B\.git\b
\B\.gitignore\b
\b_darcs\b
\B\.cvsignore$
^\.mrdownload$
# Avoid VMS specific MakeMaker generated files
\bDescrip.MMS$
\bDESCRIP.MMS$
\bdescrip.mms$
# Avoid Makemaker generated and utility files.
\bMANIFEST\.bak
\bMakefile$
\bblib/
\bMakeMaker-\d
\bpm_to_blib\.ts$
\bpm_to_blib$
\bblibdirs\.ts$ # 6.18 through 6.25 generated this
# Avoid Module::Build generated and utility files.
\bBuild$
\b_build/
\bBuild.bat$
\bBuild.COM$
\bBUILD.COM$
\bbuild.com$
# Avoid temp and backup files.
~$
\.old$
\#$
\b\.#
\.bak$
\.tmp$
\.#
\.rej$
\.orig$
# Avoid OS-specific files/dirs
# Mac OSX metadata
\B\.DS_Store
# Mac OSX SMB mount metadata files
\B\._
# Avoid Devel::Cover files.
\bcover_db\b
#!end included /usr/share/perl5/ExtUtils/MANIFEST.SKIP
# Avoid configuration metadata file
^MYMETA\.
# Avoid Module::Build generated and utility files.
\bBuild$
\bBuild.bat$
\b_build
\bBuild.COM$
\bBUILD.COM$
\bbuild.com$
^MANIFEST\.SKIP
# Avoid archives of this distribution
\b[sS]tow-v?[\d\.\_]+
# Avoid autotools stuff
^aclocal.m4$
^automake/
^autom4te\.cache/.+$
^config\.(log|status)$
^doc/\.dirstamp$
^doc/manual-single-old-texi2html\.html
^doc/manual-single-texi2html-wrapper\.html
^doc/manual-split/
^doc/stamp-vti$
^doc/HOWTO-RELEASE$
# Avoid test files
tmp-testing-trees*
^.coveralls.yml
^.github/workflows/
^.travis.yml
^docker/
^[a-zA-Z]*-docker.sh
^playground/
# Avoid development config
^.dir-locals.el
^.dumbjump

60
META.json Normal file
View file

@ -0,0 +1,60 @@
{
"abstract" : "manage farms of symbolic links",
"author" : [
"unknown"
],
"dynamic_config" : 1,
"generated_by" : "Module::Build version 0.4234",
"license" : [
"gpl_1"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : 2
},
"name" : "Stow",
"prereqs" : {
"build" : {
"requires" : {
"IO::Scalar" : "0",
"Test::More" : "0",
"Test::Output" : "0"
}
},
"configure" : {
"requires" : {
"Module::Build" : "0"
}
},
"runtime" : {
"requires" : {
"Carp" : "0",
"IO::File" : "0",
"perl" : "5.006"
}
}
},
"provides" : {
"Stow" : {
"file" : "lib/Stow.pm",
"version" : "v2.4.0"
},
"Stow::Util" : {
"file" : "lib/Stow/Util.pm",
"version" : "v2.4.0"
}
},
"release_status" : "stable",
"resources" : {
"homepage" : "https://savannah.gnu.org/projects/stow",
"license" : [
"http://www.gnu.org/licenses/gpl-2.0.html"
],
"repository" : {
"type" : "git",
"url" : "git://git.savannah.gnu.org/stow.git"
}
},
"version" : "v2.4.0",
"x_serialization_backend" : "JSON::PP version 4.16"
}

34
META.yml Normal file
View file

@ -0,0 +1,34 @@
---
abstract: 'manage farms of symbolic links'
author:
- unknown
build_requires:
IO::Scalar: '0'
Test::More: '0'
Test::Output: '0'
configure_requires:
Module::Build: '0'
dynamic_config: 1
generated_by: 'Module::Build version 0.4234, CPAN::Meta::Converter version 2.150010'
license: gpl
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
version: '1.4'
name: Stow
provides:
Stow:
file: lib/Stow.pm
version: v2.4.0
Stow::Util:
file: lib/Stow/Util.pm
version: v2.4.0
requires:
Carp: '0'
IO::File: '0'
perl: '5.006'
resources:
homepage: https://savannah.gnu.org/projects/stow
license: http://www.gnu.org/licenses/gpl-2.0.html
repository: git://git.savannah.gnu.org/stow.git
version: v2.4.0
x_serialization_backend: 'CPAN::Meta::YAML version 0.018'

View file

@ -1,54 +1,332 @@
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
## Process this file with Automake to produce Makefile.in
bin_SCRIPTS = stow chkstow
info_TEXINFOS = stow.texi
man8_MANS = stow.8
dist_man_MANS = stow.8
dist_doc_DATA = README
bin_SCRIPTS = bin/stow bin/chkstow
info_TEXINFOS = doc/stow.texi
dist_man_MANS = doc/stow.8
PDF = doc/manual.pdf
HTML = doc/manual-single.html
dist_doc_DATA = \
README.md INSTALL.md \
$(PDF) $(HTML) doc/version.texi \
ChangeLog doc/ChangeLog.OLD
TESTS_ENVIRONMENT=$(PERL) -I $(top_srcdir)
TESTS = \
t/cleanup_invalid_links.t \
t/defer.t \
t/examples.t \
t/find_stowed_path.t \
t/foldable.t \
t/join_paths.t \
t/parent.t \
t/relative_path.t \
t/stow_contents.t \
t/stow.t \
t/unstow_contents_orig.t \
t/unstow_contents.t \
t/chkstow.t
# automake magic to define where *_DATA files get installed:
pmdir = $(PMDIR)
pmstowdir = $(pmdir)/Stow
AUTOMAKE_OPTIONS = dist-shar
EXTRA_DIST = $(TESTS) t/util.pm stow.in
CLEANFILES = $(bin_SCRIPTS)
pm_DATA = lib/Stow.pm
pmstow_DATA = lib/Stow/Util.pm
# clean up files left behind by test suite
export TEXI2DVI_BUILD_MODE = clean
AM_MAKEINFOFLAGS = -I $(srcdir)
# We require this -I parameter to ensure that the include of the
# default ignore list in the manual works correctly, even when the
# manual is being built via make distcheck from a different directory.
# Unfortunately this is the only way to do it:
#
# https://lists.gnu.org/archive/html/bug-automake/2008-09/msg00040.html
#
# even though it annoyingly produces a warning with the -Wall option
# to AM_INIT_AUTOMAKE which has to be silenced via -Wno-override.
TEXI2DVI = texi2dvi $(AM_MAKEINFOFLAGS)
DEFAULT_IGNORE_LIST = $(srcdir)/default-ignore-list
doc_deps = $(info_TEXINFOS) doc/version.texi $(DEFAULT_IGNORE_LIST)
TESTS_DIR = $(srcdir)/t
TESTS_OUT = tmp-testing-trees tmp-testing-trees-compat
TESTS_ENVIRONMENT = $(PERL) -Ibin -Ilib -I$(TESTS_DIR)
# This is a kind of hack; TESTS needs to be set to ensure that the
# `check-am' target makes check-TESTS, but we override check-TESTS
# so it doesn't really matter what it's set to, as long as it already
# exists (otherwise automake will try to build it).
TESTS = t
# GNU autotools standardised on the 'check' target, but CPAN (and the
# rest of the world) standardised on the 'test' target.
test: check
# required in vpath mode to ensure $build/t/ exists
check_DATA = $(TESTS_OUT)
# Test::Harness produces cleaner output than automake's default test
# harness, albeit without the pretty colours provided by the
# `color-tests' AM_INIT_AUTOMAKE option. This also dodges having to
# set TESTS to the full list of tests, which is good because automake
# doesn't support wildcards, and so it would be too easy to forget to
# add a new one to the list.
#
# Note that automake's `check' rule cannot be overridden
# for some weird reason:
#
# https://lists.gnu.org/archive/html/automake/2011-09/msg00029.html
#
# so we override check-TESTS instead which is where the real work is
# done anyway. Unfortunately this produces a warning with the -Wall
# option to AM_INIT_AUTOMAKE which has to be silenced via
# -Wno-override.
check-TESTS:
dir=$(TESTS_DIR); \
$(TESTS_ENVIRONMENT) -MTest::Harness -e 'runtests(@ARGV)' "$${dir#./}"/*.t
coverage:
PERL5OPT=-MDevel::Cover $(MAKE) check-TESTS
cover
$(TESTS_OUT):
mkdir -p $@
CPAN_FILES = MANIFEST MANIFEST.SKIP Build.PL META.yml META.json
EXTRA_DIST = \
bin/stow.in bin/chkstow.in lib/Stow.pm.in lib/Stow/Util.pm.in \
doc/manual-split \
$(TESTS) t/testutil.pm \
$(DEFAULT_IGNORE_LIST) \
$(CPAN_FILES)
CLEANFILES = $(bin_SCRIPTS) $(pm_DATA) $(pmstow_DATA)
DISTCLEANFILES = Makefile.in configure Build MYMETA.*
MAINTAINERCLEANFILES = $(dist_man_MANS) $(HTML) $(PDF) ChangeLog
# clean up auto-generated files
clean-local:
-rm -rf t/target t/stow
-rm -rf $(TESTS_OUT)
maintainer-clean-local:
-rm -rf doc/manual-split cover_db
# this is more explicit and reliable than the config file trick
edit = sed -e 's|[@]PERL[@]|$(PERL)|g' \
-e 's|[@]PACKAGE[@]|$(PACKAGE)|g' \
-e 's|[@]VERSION[@]|$(VERSION)|g'
edit = sed -e 's|[@]PERL[@]|$(PERL)|g' \
-e 's|[@]VERSION[@]|$(VERSION)|g' \
-e "s|[@]USE_LIB_PMDIR[@]|$$use_lib_pmdir|g"
stow: stow.in Makefile
pmdir_in_INC = \
PERL5LIB= $(PERL) -V | \
awk '/@INC/ {p=1; next} p==1 {print $$1}' | \
grep -F -x -q "$(pmdir)"
calc_use_lib_pmdir = \
pmdir="$(pmdir)"; \
if [ $(FINDBIN) = yes ]; then \
use_lib_pmdir="use FindBin; use lib \"\$$FindBin::Bin/../$${pmdir\#$(prefix)/}\";"; \
elif $(pmdir_in_INC); then \
use_lib_pmdir=""; \
else \
use_lib_pmdir="use lib \"$(pmdir)\";"; \
fi
check_pmdir = \
echo; \
echo "\# Perl modules will be installed to $(pmdir)"; \
echo "\# "; \
if $(pmdir_in_INC); then \
echo "\# This is in $(PERL)'s built-in @INC, so everything"; \
echo "\# should work fine with no extra effort."; \
else \
echo "\# This is not in $(PERL)'s built-in @INC, so the"; \
echo "\# front-end scripts will have an appropriate \"use lib\""; \
echo "\# line inserted to compensate."; \
fi; \
echo
bin/stow: bin/stow.in Makefile.am
[ -d bin ] || mkdir bin # required in vpath mode
@$(check_pmdir)
@$(calc_use_lib_pmdir); \
$(edit) < $< > $@
@echo "Generated $@ from $<"
chmod +x $@
chkstow: chkstow.in Makefile
$(edit) < $< > $@
bin/chkstow: bin/chkstow.in Makefile.am
@[ -d bin ] || mkdir bin # required in vpath mode
@$(edit) < $< > $@
@echo "Generated $@ from $<"
chmod +x $@
# The rules for manual.html and manual.texi are only used by
# the developer
manual.html: manual.texi
-rm -f $@
texi2html -expandinfo -menu -monolithic -verbose $<
lib/Stow.pm: lib/Stow.pm.in $(DEFAULT_IGNORE_LIST) Makefile.am
@[ -d lib ] || mkdir lib # required in vpath mode
@( $(edit) < $<; cat $(DEFAULT_IGNORE_LIST) ) > $@
@echo "Generated $@ from $< and $(DEFAULT_IGNORE_LIST)"
manual.texi: stow.texi
lib/Stow/Util.pm: lib/Stow/Util.pm.in Makefile.am
@[ -d lib/Stow ] || mkdir -p lib/Stow # required in vpath mode
@$(edit) < $< > $@
@echo "Generated $@ from $<"
##############################################################################
# The below rules should only be needed by developers.
##############################################################################
cpanm:
cpanm --quiet --installdeps --notest .; \
CPANM_RESULT=$$?; \
if [ $$CPANM_RESULT != 0 ]; then \
echo ---------------------------------------------------; \
cat ~/.cpanm/build.log; \
echo ---------------------------------------------------; \
exit $$CPANM_RESULT; \
fi
doc/stow.8: bin/stow.in Makefile.am
[ -d doc ] || mkdir doc # required in vpath mode
$(edit) < $< | pod2man --name stow --section 8 > $@
# We use automake's built-in rule to generate stow.info. The built-in
# rules would also generate doc/stow.html and doc/stow.pdf, but after
# installation we want $(docdir) (typically /usr/share/doc/stow/) to
# contain manual-single.html, manual.pdf, and manual-split/*.html, to
# make it explicitly obvious that these files contain the user manual
# rather than some other Stow-related documentation.
#
# If it were not for a troublesome dependency on doc/$(am__dirstamp):
#
# https://lists.gnu.org/archive/html/automake/2011-11/msg00107.html
#
# we could have achieved this using the built-in rules combined with
# install-data-hook to rename from stow.pdf to manual.pdf etc. on
# install. Instead, by overriding the built-in rules with modified
# versions, we can kill both birds with one stone.
# Generating the single-page HTML version used to be done with the old
# texi2html, which is no longer maintained. This rule is not used,
# but is kept to allow comparing of results during the transition, and
# potentially longer for posterity.
doc/manual-single-old-texi2html.html: $(doc_deps)
texi2html --P=$(srcdir) --output=$@ -expandinfo -menu -monolithic -verbose $<
# One alternative to the old texi2html approach is to use the texi2html
# wrapper around texi2any which is provided as a partial drop-in replacement:
#
# https://www.gnu.org/software/texinfo/manual/texinfo/html_node/texi2html.html#texi2html
#
# Differences to the old texi2html:
#
# - Doesn't wrap @file{foo} paths with quotes, which looks better.
# - Missing certain sections
doc/manual-single-texi2html-wrapper.html: $(doc_deps)
texi2any -P $(srcdir) --output=$@ --verbose \
-c TEXI2HTML=1 -c SHOW_MENU=1 -c MONOLITHIC=1 $<
.PHONY: manual-single-html-all
manual-single-html-all: \
$(HTML) \
doc/manual-single-texi2html-wrapper.html \
doc/manual-single-old-texi2html.html
# Modern approach using $(MAKEINFOHTML) --no-split
# Differences to the older two approaches:
#
# - Nicer navigation links between sections
$(HTML): $(doc_deps)
[ -d doc ] || mkdir doc # required in vpath mode
-rm -f $@
cp $< $@
$(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I doc -I $(srcdir)/doc \
-c USE_TITLEPAGE_FOR_TITLE=1 --no-split -o $@ \
`test -f 'doc/stow.texi' || echo '$(srcdir)/'`doc/stow.texi
$(PDF): $(doc_deps)
TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I doc -I $(srcdir)/doc' \
$(TEXI2PDF) -o $@ `test -f 'doc/stow.texi' || echo '$(srcdir)/'`doc/stow.texi
doc/manual-split: $(doc_deps)
rm -rf $@.new
if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I doc -I $(srcdir)/doc \
-o $@.new `test -f 'doc/stow.texi' || echo '$(srcdir)/'`doc/stow.texi; \
then \
rm -rf $@; \
mv $@.new $@; \
else \
rm -Rf $@.new $@; \
exit 1; \
fi
# The split version of the manual is copied to $(docdir)/manual-split
# by install-data-hook. The whole subdirectory is included via
# EXTRA_DIST in order to avoid having to list each file explicitly in
# dist_doc_DATA, since automake doesn't support wildcards, and
# dist_doc_DATA cannot refer to directories while EXTRA_DIST can (go
# figure ...)
install-data-hook: doc/manual-split
cp -r $(srcdir)/doc/manual-split $(DESTDIR)$(docdir)
uninstall-hook:
chmod u+w -R $(DESTDIR)$(docdir)/manual-split
rm -rf $(DESTDIR)$(docdir)/manual-split
# Using install-data-hook has the slightly annoying disadvantage that
# by default the split version of the manual isn't automatically
# rebuilt during development by a simple `make'. A workaround hack
# for this is to piggy-back the dependency onto manual-single.html,
# which *is* automatically rebuilt by `make':
$(HTML): doc/manual-split
# With the above hack, this probably isn't necessary but is safer to
# keep in anyway:
dist-hook: doc/manual-split
dist-hook: $(dist_man_MANS)
## If we are creating a distribution from a git checkout, ensure
## the ChangeLog file is in sync the git repository.
if test -d $(top_srcdir)/.git; then \
rm -f ChangeLog \
&& $(MAKE) $(AM_MAKEFLAGS) ChangeLog \
&& cp -f ChangeLog $(distdir)/ChangeLog; \
fi
ChangeLog: doc/ChangeLog.OLD
@if [ -d .git ]; then \
( \
git log \
--format="format:%ad %aN <%aE>%n%n * %w(70,0,4)%s%+b%n" \
--name-status \
v2.0.2..HEAD \
| sed 's/^\([A-Z]\)\t/ \1 /'; \
cat $< \
) > $@; \
echo "Rebuilt $@ from git commit history."; \
else \
echo "Not in a git repository; can't update ChangeLog."; \
fi
# Watch for changes, and if any rebuilds are required, also do a
# make install.
#
# If we solved https://github.com/aspiers/stow/issues/84, we could
# probably ditch this:
watch:
@echo "Watching for changes to program source files ..."
@while true; do \
if $(MAKE) 2>&1 | \
grep -vE 'make\[[1-9]\]: (Entering|Leaving) directory ' | \
grep -v 'Nothing to be done'; \
then \
echo; \
echo "-----------------------------------------------------"; \
echo "make found things to rebuild; doing $(MAKE) install ..."; \
echo; \
$(MAKE) install; \
echo; \
echo ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"; \
echo; \
fi; \
sleep 1; \
done 2>&1 | \
grep -vE 'make\[[1-9]\]: (Entering|Leaving) directory '

View file

@ -1,887 +0,0 @@
# Makefile.in generated by automake 1.10 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
subdir = .
DIST_COMMON = README $(am__configure_deps) $(dist_doc_DATA) \
$(dist_man_MANS) $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
$(srcdir)/stamp-vti $(srcdir)/version.texi \
$(top_srcdir)/configure AUTHORS COPYING ChangeLog INSTALL NEWS \
THANKS TODO install-sh mdate-sh missing texinfo.tex
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
configure.lineno config.status.lineno
mkinstalldirs = $(install_sh) -d
CONFIG_CLEAN_FILES =
am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(infodir)" \
"$(DESTDIR)$(man8dir)" "$(DESTDIR)$(docdir)"
binSCRIPT_INSTALL = $(INSTALL_SCRIPT)
SCRIPTS = $(bin_SCRIPTS)
SOURCES =
DIST_SOURCES =
INFO_DEPS = $(srcdir)/stow.info
am__TEXINFO_TEX_DIR = $(srcdir)
DVIS = stow.dvi
PDFS = stow.pdf
PSS = stow.ps
HTMLS = stow.html
TEXINFOS = stow.texi
TEXI2DVI = texi2dvi
TEXI2PDF = $(TEXI2DVI) --pdf --batch
MAKEINFOHTML = $(MAKEINFO) --html
AM_MAKEINFOHTMLFLAGS = $(AM_MAKEINFOFLAGS)
DVIPS = dvips
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
am__vpath_adj = case $$p in \
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
*) f=$$p;; \
esac;
am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
man8dir = $(mandir)/man8
NROFF = nroff
MANS = $(dist_man_MANS) $(man8_MANS)
dist_docDATA_INSTALL = $(INSTALL_DATA)
DATA = $(dist_doc_DATA)
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
distdir = $(PACKAGE)-$(VERSION)
top_distdir = $(distdir)
am__remove_distdir = \
{ test ! -d $(distdir) \
|| { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \
&& rm -fr $(distdir); }; }
DIST_ARCHIVES = $(distdir).tar.gz $(distdir).shar.gz
GZIP_ENV = --best
distuninstallcheck_listfiles = find . -type f -print
distcleancheck_listfiles = find . -type f -print
ACLOCAL = @ACLOCAL@
AMTAR = @AMTAR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
CYGPATH_W = @CYGPATH_W@
DEFS = @DEFS@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LTLIBOBJS = @LTLIBOBJS@
MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PERL = @PERL@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
STRIP = @STRIP@
VERSION = @VERSION@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
am__leading_dot = @am__leading_dot@
am__tar = @am__tar@
am__untar = @am__untar@
bindir = @bindir@
build_alias = @build_alias@
builddir = @builddir@
datadir = @datadir@
datarootdir = @datarootdir@
docdir = @docdir@
dvidir = @dvidir@
exec_prefix = @exec_prefix@
host_alias = @host_alias@
htmldir = @htmldir@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localedir = @localedir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
prefix = @prefix@
program_transform_name = @program_transform_name@
psdir = @psdir@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
srcdir = @srcdir@
sysconfdir = @sysconfdir@
target_alias = @target_alias@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
bin_SCRIPTS = stow chkstow
info_TEXINFOS = stow.texi
man8_MANS = stow.8
dist_man_MANS = stow.8
dist_doc_DATA = README
TESTS_ENVIRONMENT = $(PERL) -I $(top_srcdir)
TESTS = \
t/cleanup_invalid_links.t \
t/defer.t \
t/examples.t \
t/find_stowed_path.t \
t/foldable.t \
t/join_paths.t \
t/parent.t \
t/relative_path.t \
t/stow_contents.t \
t/stow.t \
t/unstow_contents_orig.t \
t/unstow_contents.t \
t/chkstow.t
AUTOMAKE_OPTIONS = dist-shar
EXTRA_DIST = $(TESTS) t/util.pm stow.in
CLEANFILES = $(bin_SCRIPTS)
# this is more explicit and reliable than the config file trick
edit = sed -e 's|[@]PERL[@]|$(PERL)|g' \
-e 's|[@]PACKAGE[@]|$(PACKAGE)|g' \
-e 's|[@]VERSION[@]|$(VERSION)|g'
all: all-am
.SUFFIXES:
.SUFFIXES: .dvi .html .info .pdf .ps .texi
am--refresh:
@:
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \
cd $(srcdir) && $(AUTOMAKE) --gnu \
&& exit 0; \
exit 1;; \
esac; \
done; \
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \
cd $(top_srcdir) && \
$(AUTOMAKE) --gnu Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
@case '$?' in \
*config.status*) \
echo ' $(SHELL) ./config.status'; \
$(SHELL) ./config.status;; \
*) \
echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
esac;
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
$(SHELL) ./config.status --recheck
$(top_srcdir)/configure: $(am__configure_deps)
cd $(srcdir) && $(AUTOCONF)
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
install-binSCRIPTS: $(bin_SCRIPTS)
@$(NORMAL_INSTALL)
test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
@list='$(bin_SCRIPTS)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
if test -f $$d$$p; then \
f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
echo " $(binSCRIPT_INSTALL) '$$d$$p' '$(DESTDIR)$(bindir)/$$f'"; \
$(binSCRIPT_INSTALL) "$$d$$p" "$(DESTDIR)$(bindir)/$$f"; \
else :; fi; \
done
uninstall-binSCRIPTS:
@$(NORMAL_UNINSTALL)
@list='$(bin_SCRIPTS)'; for p in $$list; do \
f=`echo "$$p" | sed 's|^.*/||;$(transform)'`; \
echo " rm -f '$(DESTDIR)$(bindir)/$$f'"; \
rm -f "$(DESTDIR)$(bindir)/$$f"; \
done
.texi.info:
restore=: && backupdir="$(am__leading_dot)am$$$$" && \
am__cwd=`pwd` && cd $(srcdir) && \
rm -rf $$backupdir && mkdir $$backupdir && \
if ($(MAKEINFO) --version) >/dev/null 2>&1; then \
for f in $@ $@-[0-9] $@-[0-9][0-9] $(@:.info=).i[0-9] $(@:.info=).i[0-9][0-9]; do \
if test -f $$f; then mv $$f $$backupdir; restore=mv; else :; fi; \
done; \
else :; fi && \
cd "$$am__cwd"; \
if $(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
-o $@ $<; \
then \
rc=0; \
cd $(srcdir); \
else \
rc=$$?; \
cd $(srcdir) && \
$$restore $$backupdir/* `echo "./$@" | sed 's|[^/]*$$||'`; \
fi; \
rm -rf $$backupdir; exit $$rc
.texi.dvi:
TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
$(TEXI2DVI) $<
.texi.pdf:
TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
MAKEINFO='$(MAKEINFO) $(AM_MAKEINFOFLAGS) $(MAKEINFOFLAGS) -I $(srcdir)' \
$(TEXI2PDF) $<
.texi.html:
rm -rf $(@:.html=.htp)
if $(MAKEINFOHTML) $(AM_MAKEINFOHTMLFLAGS) $(MAKEINFOFLAGS) -I $(srcdir) \
-o $(@:.html=.htp) $<; \
then \
rm -rf $@; \
if test ! -d $(@:.html=.htp) && test -d $(@:.html=); then \
mv $(@:.html=) $@; else mv $(@:.html=.htp) $@; fi; \
else \
if test ! -d $(@:.html=.htp) && test -d $(@:.html=); then \
rm -rf $(@:.html=); else rm -Rf $(@:.html=.htp) $@; fi; \
exit 1; \
fi
$(srcdir)/stow.info: stow.texi $(srcdir)/version.texi
stow.dvi: stow.texi $(srcdir)/version.texi
stow.pdf: stow.texi $(srcdir)/version.texi
stow.html: stow.texi $(srcdir)/version.texi
$(srcdir)/version.texi: $(srcdir)/stamp-vti
$(srcdir)/stamp-vti: stow.texi $(top_srcdir)/configure
@(dir=.; test -f ./stow.texi || dir=$(srcdir); \
set `$(SHELL) $(srcdir)/mdate-sh $$dir/stow.texi`; \
echo "@set UPDATED $$1 $$2 $$3"; \
echo "@set UPDATED-MONTH $$2 $$3"; \
echo "@set EDITION $(VERSION)"; \
echo "@set VERSION $(VERSION)") > vti.tmp
@cmp -s vti.tmp $(srcdir)/version.texi \
|| (echo "Updating $(srcdir)/version.texi"; \
cp vti.tmp $(srcdir)/version.texi)
-@rm -f vti.tmp
@cp $(srcdir)/version.texi $@
mostlyclean-vti:
-rm -f vti.tmp
maintainer-clean-vti:
-rm -f $(srcdir)/stamp-vti $(srcdir)/version.texi
.dvi.ps:
TEXINPUTS="$(am__TEXINFO_TEX_DIR)$(PATH_SEPARATOR)$$TEXINPUTS" \
$(DVIPS) -o $@ $<
uninstall-dvi-am:
@$(NORMAL_UNINSTALL)
@list='$(DVIS)'; for p in $$list; do \
f=$(am__strip_dir) \
echo " rm -f '$(DESTDIR)$(dvidir)/$$f'"; \
rm -f "$(DESTDIR)$(dvidir)/$$f"; \
done
uninstall-html-am:
@$(NORMAL_UNINSTALL)
@list='$(HTMLS)'; for p in $$list; do \
f=$(am__strip_dir) \
echo " rm -rf '$(DESTDIR)$(htmldir)/$$f'"; \
rm -rf "$(DESTDIR)$(htmldir)/$$f"; \
done
uninstall-info-am:
@$(PRE_UNINSTALL)
@if test -d '$(DESTDIR)$(infodir)' && \
(install-info --version && \
install-info --version 2>&1 | sed 1q | grep -i -v debian) >/dev/null 2>&1; then \
list='$(INFO_DEPS)'; \
for file in $$list; do \
relfile=`echo "$$file" | sed 's|^.*/||'`; \
echo " install-info --info-dir='$(DESTDIR)$(infodir)' --remove '$(DESTDIR)$(infodir)/$$relfile'"; \
install-info --info-dir="$(DESTDIR)$(infodir)" --remove "$(DESTDIR)$(infodir)/$$relfile"; \
done; \
else :; fi
@$(NORMAL_UNINSTALL)
@list='$(INFO_DEPS)'; \
for file in $$list; do \
relfile=`echo "$$file" | sed 's|^.*/||'`; \
relfile_i=`echo "$$relfile" | sed 's|\.info$$||;s|$$|.i|'`; \
(if test -d "$(DESTDIR)$(infodir)" && cd "$(DESTDIR)$(infodir)"; then \
echo " cd '$(DESTDIR)$(infodir)' && rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]"; \
rm -f $$relfile $$relfile-[0-9] $$relfile-[0-9][0-9] $$relfile_i[0-9] $$relfile_i[0-9][0-9]; \
else :; fi); \
done
uninstall-pdf-am:
@$(NORMAL_UNINSTALL)
@list='$(PDFS)'; for p in $$list; do \
f=$(am__strip_dir) \
echo " rm -f '$(DESTDIR)$(pdfdir)/$$f'"; \
rm -f "$(DESTDIR)$(pdfdir)/$$f"; \
done
uninstall-ps-am:
@$(NORMAL_UNINSTALL)
@list='$(PSS)'; for p in $$list; do \
f=$(am__strip_dir) \
echo " rm -f '$(DESTDIR)$(psdir)/$$f'"; \
rm -f "$(DESTDIR)$(psdir)/$$f"; \
done
dist-info: $(INFO_DEPS)
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
list='$(INFO_DEPS)'; \
for base in $$list; do \
case $$base in \
$(srcdir)/*) base=`echo "$$base" | sed "s|^$$srcdirstrip/||"`;; \
esac; \
if test -f $$base; then d=.; else d=$(srcdir); fi; \
base_i=`echo "$$base" | sed 's|\.info$$||;s|$$|.i|'`; \
for file in $$d/$$base $$d/$$base-[0-9] $$d/$$base-[0-9][0-9] $$d/$$base_i[0-9] $$d/$$base_i[0-9][0-9]; do \
if test -f $$file; then \
relfile=`expr "$$file" : "$$d/\(.*\)"`; \
test -f $(distdir)/$$relfile || \
cp -p $$file $(distdir)/$$relfile; \
else :; fi; \
done; \
done
mostlyclean-aminfo:
-rm -rf stow.aux stow.cp stow.cps stow.fn stow.fns stow.ky stow.kys stow.log \
stow.pg stow.pgs stow.tmp stow.toc stow.tp stow.tps stow.vr \
stow.vrs stow.dvi stow.pdf stow.ps stow.html
maintainer-clean-aminfo:
@list='$(INFO_DEPS)'; for i in $$list; do \
i_i=`echo "$$i" | sed 's|\.info$$||;s|$$|.i|'`; \
echo " rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]"; \
rm -f $$i $$i-[0-9] $$i-[0-9][0-9] $$i_i[0-9] $$i_i[0-9][0-9]; \
done
install-man8: $(man8_MANS) $(man_MANS)
@$(NORMAL_INSTALL)
test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)"
@list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
for i in $$l2; do \
case "$$i" in \
*.8*) list="$$list $$i" ;; \
esac; \
done; \
for i in $$list; do \
if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
else file=$$i; fi; \
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
case "$$ext" in \
8*) ;; \
*) ext='8' ;; \
esac; \
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
inst=`echo $$inst | sed -e 's/^.*\///'`; \
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \
$(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst"; \
done
uninstall-man8:
@$(NORMAL_UNINSTALL)
@list='$(man8_MANS) $(dist_man8_MANS) $(nodist_man8_MANS)'; \
l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
for i in $$l2; do \
case "$$i" in \
*.8*) list="$$list $$i" ;; \
esac; \
done; \
for i in $$list; do \
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
case "$$ext" in \
8*) ;; \
*) ext='8' ;; \
esac; \
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
inst=`echo $$inst | sed -e 's/^.*\///'`; \
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
echo " rm -f '$(DESTDIR)$(man8dir)/$$inst'"; \
rm -f "$(DESTDIR)$(man8dir)/$$inst"; \
done
install-dist_docDATA: $(dist_doc_DATA)
@$(NORMAL_INSTALL)
test -z "$(docdir)" || $(MKDIR_P) "$(DESTDIR)$(docdir)"
@list='$(dist_doc_DATA)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
f=$(am__strip_dir) \
echo " $(dist_docDATA_INSTALL) '$$d$$p' '$(DESTDIR)$(docdir)/$$f'"; \
$(dist_docDATA_INSTALL) "$$d$$p" "$(DESTDIR)$(docdir)/$$f"; \
done
uninstall-dist_docDATA:
@$(NORMAL_UNINSTALL)
@list='$(dist_doc_DATA)'; for p in $$list; do \
f=$(am__strip_dir) \
echo " rm -f '$(DESTDIR)$(docdir)/$$f'"; \
rm -f "$(DESTDIR)$(docdir)/$$f"; \
done
tags: TAGS
TAGS:
ctags: CTAGS
CTAGS:
check-TESTS: $(TESTS)
@failed=0; all=0; xfail=0; xpass=0; skip=0; ws='[ ]'; \
srcdir=$(srcdir); export srcdir; \
list=' $(TESTS) '; \
if test -n "$$list"; then \
for tst in $$list; do \
if test -f ./$$tst; then dir=./; \
elif test -f $$tst; then dir=; \
else dir="$(srcdir)/"; fi; \
if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
all=`expr $$all + 1`; \
case " $(XFAIL_TESTS) " in \
*$$ws$$tst$$ws*) \
xpass=`expr $$xpass + 1`; \
failed=`expr $$failed + 1`; \
echo "XPASS: $$tst"; \
;; \
*) \
echo "PASS: $$tst"; \
;; \
esac; \
elif test $$? -ne 77; then \
all=`expr $$all + 1`; \
case " $(XFAIL_TESTS) " in \
*$$ws$$tst$$ws*) \
xfail=`expr $$xfail + 1`; \
echo "XFAIL: $$tst"; \
;; \
*) \
failed=`expr $$failed + 1`; \
echo "FAIL: $$tst"; \
;; \
esac; \
else \
skip=`expr $$skip + 1`; \
echo "SKIP: $$tst"; \
fi; \
done; \
if test "$$failed" -eq 0; then \
if test "$$xfail" -eq 0; then \
banner="All $$all tests passed"; \
else \
banner="All $$all tests behaved as expected ($$xfail expected failures)"; \
fi; \
else \
if test "$$xpass" -eq 0; then \
banner="$$failed of $$all tests failed"; \
else \
banner="$$failed of $$all tests did not behave as expected ($$xpass unexpected passes)"; \
fi; \
fi; \
dashes="$$banner"; \
skipped=""; \
if test "$$skip" -ne 0; then \
skipped="($$skip tests were not run)"; \
test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
dashes="$$skipped"; \
fi; \
report=""; \
if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
report="Please report to $(PACKAGE_BUGREPORT)"; \
test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
dashes="$$report"; \
fi; \
dashes=`echo "$$dashes" | sed s/./=/g`; \
echo "$$dashes"; \
echo "$$banner"; \
test -z "$$skipped" || echo "$$skipped"; \
test -z "$$report" || echo "$$report"; \
echo "$$dashes"; \
test "$$failed" -eq 0; \
else :; fi
distdir: $(DISTFILES)
$(am__remove_distdir)
test -d $(distdir) || mkdir $(distdir)
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
list='$(DISTFILES)'; \
dist_files=`for file in $$list; do echo $$file; done | \
sed -e "s|^$$srcdirstrip/||;t" \
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
case $$dist_files in \
*/*) $(MKDIR_P) `echo "$$dist_files" | \
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
sort -u` ;; \
esac; \
for file in $$dist_files; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
if test -d $$d/$$file; then \
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
fi; \
cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
else \
test -f $(distdir)/$$file \
|| cp -p $$d/$$file $(distdir)/$$file \
|| exit 1; \
fi; \
done
$(MAKE) $(AM_MAKEFLAGS) \
top_distdir="$(top_distdir)" distdir="$(distdir)" \
dist-info
-find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \
! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
! -type d ! -perm -400 -exec chmod a+r {} \; -o \
! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
|| chmod -R a+r $(distdir)
dist-gzip: distdir
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
$(am__remove_distdir)
dist-bzip2: distdir
tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2
$(am__remove_distdir)
dist-tarZ: distdir
tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
$(am__remove_distdir)
dist-shar: distdir
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
$(am__remove_distdir)
dist-zip: distdir
-rm -f $(distdir).zip
zip -rq $(distdir).zip $(distdir)
$(am__remove_distdir)
dist dist-all: distdir
tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
$(am__remove_distdir)
# This target untars the dist file and tries a VPATH configuration. Then
# it guarantees that the distribution is self-contained by making another
# tarfile.
distcheck: dist
case '$(DIST_ARCHIVES)' in \
*.tar.gz*) \
GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\
*.tar.bz2*) \
bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\
*.tar.Z*) \
uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
*.shar.gz*) \
GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\
*.zip*) \
unzip $(distdir).zip ;;\
esac
chmod -R a-w $(distdir); chmod a+w $(distdir)
mkdir $(distdir)/_build
mkdir $(distdir)/_inst
chmod a-w $(distdir)
dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
&& dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
&& cd $(distdir)/_build \
&& ../configure --srcdir=.. --prefix="$$dc_install_base" \
$(DISTCHECK_CONFIGURE_FLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) \
&& $(MAKE) $(AM_MAKEFLAGS) dvi \
&& $(MAKE) $(AM_MAKEFLAGS) check \
&& $(MAKE) $(AM_MAKEFLAGS) install \
&& $(MAKE) $(AM_MAKEFLAGS) installcheck \
&& $(MAKE) $(AM_MAKEFLAGS) uninstall \
&& $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
distuninstallcheck \
&& chmod -R a-w "$$dc_install_base" \
&& ({ \
(cd ../.. && umask 077 && mkdir "$$dc_destdir") \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
&& $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
} || { rm -rf "$$dc_destdir"; exit 1; }) \
&& rm -rf "$$dc_destdir" \
&& $(MAKE) $(AM_MAKEFLAGS) dist \
&& rm -rf $(DIST_ARCHIVES) \
&& $(MAKE) $(AM_MAKEFLAGS) distcleancheck
$(am__remove_distdir)
@(echo "$(distdir) archives ready for distribution: "; \
list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
distuninstallcheck:
@cd $(distuninstallcheck_dir) \
&& test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \
|| { echo "ERROR: files left after uninstall:" ; \
if test -n "$(DESTDIR)"; then \
echo " (check DESTDIR support)"; \
fi ; \
$(distuninstallcheck_listfiles) ; \
exit 1; } >&2
distcleancheck: distclean
@if test '$(srcdir)' = . ; then \
echo "ERROR: distcleancheck can only run from a VPATH build" ; \
exit 1 ; \
fi
@test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
|| { echo "ERROR: files left in build directory after distclean:" ; \
$(distcleancheck_listfiles) ; \
exit 1; } >&2
check-am: all-am
$(MAKE) $(AM_MAKEFLAGS) check-TESTS
check: check-am
all-am: Makefile $(INFO_DEPS) $(SCRIPTS) $(MANS) $(DATA)
installdirs:
for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(infodir)" "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(docdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
clean-generic:
-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
distclean-generic:
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-local mostlyclean-am
distclean: distclean-am
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-rm -f Makefile
distclean-am: clean-am distclean-generic
dvi: dvi-am
dvi-am: $(DVIS)
html: html-am
html-am: $(HTMLS)
info: info-am
info-am: $(INFO_DEPS)
install-data-am: install-dist_docDATA install-info-am install-man
install-dvi: install-dvi-am
install-dvi-am: $(DVIS)
@$(NORMAL_INSTALL)
test -z "$(dvidir)" || $(MKDIR_P) "$(DESTDIR)$(dvidir)"
@list='$(DVIS)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
f=$(am__strip_dir) \
echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(dvidir)/$$f'"; \
$(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(dvidir)/$$f"; \
done
install-exec-am: install-binSCRIPTS
install-html: install-html-am
install-html-am: $(HTMLS)
@$(NORMAL_INSTALL)
test -z "$(htmldir)" || $(MKDIR_P) "$(DESTDIR)$(htmldir)"
@list='$(HTMLS)'; for p in $$list; do \
if test -f "$$p" || test -d "$$p"; then d=; else d="$(srcdir)/"; fi; \
f=$(am__strip_dir) \
if test -d "$$d$$p"; then \
echo " $(MKDIR_P) '$(DESTDIR)$(htmldir)/$$f'"; \
$(MKDIR_P) "$(DESTDIR)$(htmldir)/$$f" || exit 1; \
echo " $(INSTALL_DATA) '$$d$$p'/* '$(DESTDIR)$(htmldir)/$$f'"; \
$(INSTALL_DATA) "$$d$$p"/* "$(DESTDIR)$(htmldir)/$$f"; \
else \
echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(htmldir)/$$f'"; \
$(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(htmldir)/$$f"; \
fi; \
done
install-info: install-info-am
install-info-am: $(INFO_DEPS)
@$(NORMAL_INSTALL)
test -z "$(infodir)" || $(MKDIR_P) "$(DESTDIR)$(infodir)"
@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
list='$(INFO_DEPS)'; \
for file in $$list; do \
case $$file in \
$(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
esac; \
if test -f $$file; then d=.; else d=$(srcdir); fi; \
file_i=`echo "$$file" | sed 's|\.info$$||;s|$$|.i|'`; \
for ifile in $$d/$$file $$d/$$file-[0-9] $$d/$$file-[0-9][0-9] \
$$d/$$file_i[0-9] $$d/$$file_i[0-9][0-9] ; do \
if test -f $$ifile; then \
relfile=`echo "$$ifile" | sed 's|^.*/||'`; \
echo " $(INSTALL_DATA) '$$ifile' '$(DESTDIR)$(infodir)/$$relfile'"; \
$(INSTALL_DATA) "$$ifile" "$(DESTDIR)$(infodir)/$$relfile"; \
else : ; fi; \
done; \
done
@$(POST_INSTALL)
@if (install-info --version && \
install-info --version 2>&1 | sed 1q | grep -i -v debian) >/dev/null 2>&1; then \
list='$(INFO_DEPS)'; \
for file in $$list; do \
relfile=`echo "$$file" | sed 's|^.*/||'`; \
echo " install-info --info-dir='$(DESTDIR)$(infodir)' '$(DESTDIR)$(infodir)/$$relfile'";\
install-info --info-dir="$(DESTDIR)$(infodir)" "$(DESTDIR)$(infodir)/$$relfile" || :;\
done; \
else : ; fi
install-man: install-man8
install-pdf: install-pdf-am
install-pdf-am: $(PDFS)
@$(NORMAL_INSTALL)
test -z "$(pdfdir)" || $(MKDIR_P) "$(DESTDIR)$(pdfdir)"
@list='$(PDFS)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
f=$(am__strip_dir) \
echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(pdfdir)/$$f'"; \
$(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(pdfdir)/$$f"; \
done
install-ps: install-ps-am
install-ps-am: $(PSS)
@$(NORMAL_INSTALL)
test -z "$(psdir)" || $(MKDIR_P) "$(DESTDIR)$(psdir)"
@list='$(PSS)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
f=$(am__strip_dir) \
echo " $(INSTALL_DATA) '$$d$$p' '$(DESTDIR)$(psdir)/$$f'"; \
$(INSTALL_DATA) "$$d$$p" "$(DESTDIR)$(psdir)/$$f"; \
done
installcheck-am:
maintainer-clean: maintainer-clean-am
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
-rm -rf $(top_srcdir)/autom4te.cache
-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-aminfo \
maintainer-clean-generic maintainer-clean-vti
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-aminfo mostlyclean-generic mostlyclean-vti
pdf: pdf-am
pdf-am: $(PDFS)
ps: ps-am
ps-am: $(PSS)
uninstall-am: uninstall-binSCRIPTS uninstall-dist_docDATA \
uninstall-dvi-am uninstall-html-am uninstall-info-am \
uninstall-man uninstall-pdf-am uninstall-ps-am
uninstall-man: uninstall-man8
.MAKE: install-am install-strip
.PHONY: all all-am am--refresh check check-TESTS check-am clean \
clean-generic clean-local dist dist-all dist-bzip2 dist-gzip \
dist-info dist-shar dist-tarZ dist-zip distcheck distclean \
distclean-generic distcleancheck distdir distuninstallcheck \
dvi dvi-am html html-am info info-am install install-am \
install-binSCRIPTS install-data install-data-am \
install-dist_docDATA install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
install-info-am install-man install-man8 install-pdf \
install-pdf-am install-ps install-ps-am install-strip \
installcheck installcheck-am installdirs maintainer-clean \
maintainer-clean-aminfo maintainer-clean-generic \
maintainer-clean-vti mostlyclean mostlyclean-aminfo \
mostlyclean-generic mostlyclean-vti pdf pdf-am ps ps-am \
uninstall uninstall-am uninstall-binSCRIPTS \
uninstall-dist_docDATA uninstall-dvi-am uninstall-html-am \
uninstall-info-am uninstall-man uninstall-man8 \
uninstall-pdf-am uninstall-ps-am
# clean up files left behind by test suite
clean-local:
-rm -rf t/target t/stow
stow: stow.in Makefile
$(edit) < $< > $@
chmod +x $@
chkstow: chkstow.in Makefile
$(edit) < $< > $@
chmod +x $@
# The rules for manual.html and manual.texi are only used by
# the developer
manual.html: manual.texi
-rm -f $@
texi2html -expandinfo -menu -monolithic -verbose $<
manual.texi: stow.texi
-rm -f $@
cp $< $@
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:

734
NEWS
View file

@ -1,159 +1,667 @@
News file for Stow.
* Changes in version 2.0.1:
** Defer operations until all potential conflicts have been assessed.
* Changes in version 2.4.0
We do this by traversing the installation image(s) and recording the
actions that need to be performed. Redundant actions are factored out,
e.g., we don't want to create a link that we will later remove in order to
create a directory. Benefits of this approach
*** --dotfiles now works with directories
1. Get to see _all_ the conflicts that are blocking an installation:
you don't have to deal with them one at a time.
2. No operations are be performed if _any_ conflicts are detected:
a failed stow will not leave you with a partially installed
package.
3. Minimises the set of operations that need to be performed.
4. Operations are executed as a batch which is much faster
This can be an advantage when upgrading packages on a live system
where you want to minimise the amount of time when the package is
unavailable.
A long-standing bug preventing the --dotfiles option from working
correctly with directories has been fixed.
** The above fixes the false conflict problem mentioned in the info file.
It should also works in combination with the --compat option.
** It also fixes the two bugs mentioned in the man page.
*** Eliminated a spurious warning on unstowing
** Multiple stow directories will now cooperate in folding/unfolding.
2.3.1 introduced a benign but annoying warning when unstowing
in certain circumstances. It looked like:
** Conflict messages are more uniform and informative.
BUG in find_stowed_path? Absolute/relative mismatch between Stow dir X and path Y
** Verbosity and tracing is more extensive and uniform.
This was caused by erroneous logic, and has now been fixed.
** Implemented option parsing via Getopt::Long.
*** Unstowing logic has been improved in other cases
** Default command line arguments set via '.stowrc' and '~/.stowrc' files.
Several other improvements have been made internally to the
unstowing logic. These changes should all be either invisible
(except for changes to debug output) or improvements, but if you
encounter any unexpected behaviour, please report it as directed
in the manual.
Contents of these files are parsed as though they occurred first on the
command line.
*** Improved debug output
** Support multiple actions per invocation.
Extra output resulting from use of the -v / --verbose flag
now appears in a more logical and understandable way.
In order for this to work, we had to add a new (optional) command line arg
(-S) to specify packages to stow. For example, to update an installation
of emacs you can now do
*** Janitorial tasks
stow -D emacs-21.3 -S emacs-21.4a
Users are not substantially affected by these changes.
which will replace emacs-21.3 with emacs-21.4a.
You can mix and match any number of actions, e.g.,
***** Added some more information from the web page to the README
stow -S p1 p2 -D p3 p4 -S p5 -R p6
***** Made some improvements to the documentation
will unstow p3, p4 and p6, then stow p1, p2, p5 and p6.
***** Improve readability of source code
* New (repeatable) command line arg: --ignore='<regex>'
Quite a few extra details have been added in comments to clarify
how the code works. Many variable names have also been
improved. The comments of many Stow class methods have been
converted into Perl POD format.
This suppresses operating on a file matching the regex (suffix), e.g.,
***** Added a =CONTRIBUTING.md= file
--ignore='~' --ignore='\.#.*'
***** Add a =watch= target to =Makefile=
will ignore emacs and CVS backup files (suitable for ~/.stowrc file).
=make watch= provides easy continual pre-processing during
development, which reduces the risk of debugging the wrong code.
(I opted for Perl regular expressions because they are more powerful and
easier to implement).
***** Removed texinfo.tex from the distribution
** New (repeatable) command line arg: --defer='<regex>'
This eliminates existing and future bit-rot.
This defers stowing a file matching the regex (prefix) if that file is
already stowed to a different package, e.g.,
***** Updated aclocal.m4 from 1.15.1 to 1.16.5
--defer='man' --defer='info'
This mostly just updates copyright notices to 2021, and URLs to https.
will cause stow to skip over pre-existing man and info pages.
***** Replace broken gmane links with links to lists.gnu.org
Equivalently, you could use --defer='man|info' since the argument is just
a Perl regex.
[[https://lars.ingebrigtsen.no/2020/01/06/whatever-happened-to-news-gmane-org/][gmane has been dead for quite a while.]]
** New (repeatable) command line arg: --override='<regex>'
***** Improve support for navigating / editing source via emacs
This forces a file matching the regex (prefix) to be stowed even if the
file is already stowed to a different package, e.g.,
******* Support source navigation in emacs via [[https://github.com/jacktasia/dumb-jump][dumb-jump]].
--override='man' --override='info'
******* Configure cperl-mode to match existing coding style.
will unstow any pre-existing man and info pages that would conflict with
the file we are trying to stow.
*** Various maintainer tweaks
Equivalently, you could use --override='man|info' since the argument is
just a Perl regex.
Further improved the release process and its documentation in
various minor ways.
** The above gives the ability to manage packages with common content.
* Changes in version 2.3.1
For example, man pages that are shared by a number of CPAN packages.
Using multiple stow directories and .stowrc files can also simplify
things. In our setup we use the standard /usr/local/stow directory for
packages to be installed in /usr/local. Since we install a large number
of extra Perl packages (currently about 300) we use an additional stow
directory: /usr/local/stow/perl-5.8.8-extras. Both stow directories
contain a '.stow' file so that they collaborate appropriately. I then use
the following .stowrc file in /usr/local/stow/perl-5.8.8-extras
--dir=/usr/local/stow/perl-5.8.8-extras
--target=/usr/local
--override=bin
--override=man
--ignore='perllocal\.pod'
--ignore='\.packlist'
--ignore='\.bs'
*** Remove dependencies on Hash::Merge and Clone::Choose
When I stow packages from there, they automatically override any man pages
and binaries that may already have been stowed by another package or by
the core perl-5.8.8 installation. For example, if you want to upgrade the
Test-Simple package, you need to override all the man pages that would
have been installed by the core package. If you are upgrading CPAN, you
will also have to override the pre-existing cpan executable.
stow 2.3.0 added external runtime dependencies on Hash::Merge and
Clone::Choose. Historically stow hasn't had runtime dependencies
other than Perl itself, which is a useful property if you're
managing the installation of Perl using stow; the bootstrapping
instructions in stow's manual would need updating to describe how
to install these two modules (and any dependencies they have now
or in the future) as well.
** By default, search less aggressively for invalid symlinks when unstowing.
However, Hash::Merge is much more general than stow actually
needs, so replace the merge() call with a few lines of equivalent
code -- this avoids the external dependencies, and is clearer than
the merge() call.
That is, we only search for bad symlinks in the directories explicitly
mentioned in the installation image, and do not dig down into other
subdirs. Digging down into other directories can be very time consuming
if you have a really big tree (like with a couple of Oracle installations
lying around). In general the old behaviour is only necessary when you
have really stuffed up your installation by deleting a directory that has
already been stowed. Doing that on a live system is somewhat crazy and
hopefully rare. We provide an option '-p|--compat' to enable the old
behaviour for those needing to patch up mistakes.
Many thanks to Adam Sampson for this patch!
** Implement a test suite and support code.
https://lists.gnu.org/archive/html/bug-stow/2019-06/msg00001.html
This was built before implementing any of the extra features so I could
more easily check for equivalent functionality. The initial code base had
to be refactored substantially to allow for testing. The test suite is
not exhaustive, but it should provide enough to check for regressions.
*** Fix an issue with the test suite
t/cli.t was not testing with the right Perl executable, as
reported here:
* Changes in version 1.3.3:
** Now requires Perl 5.005 or later
** Initially empty directories are not removed anymore
** Removed buggy fastcwd (we use POSIX::getcwd instead)
** Fixed bug when the common Parent of Target dir and Stow dir was "/"
** Fixed bug when handling directories named "0"
** Stow now only warns the user if a directory is unreadable during unstowing.
https://rt.cpan.org/Ticket/Display.html?id=129944
* Changes in version 1.3:
** Added --restow option.
** Fixed handling of slashes in package names.
** Expanded configure-time search for Perl binary.
Thanks to Slaven Rezic for spotting this and reporting it!
* Changes in version 1.2:
** Dependency on `pwd' removed.
** Perl 4 compatibility fixes.
** Manual expanded even more.
*** Various maintainer tweaks
* Changes in version 1.1:
** Long and short options now accepted.
** Manual expanded.
** `make clean' removes stow (which is generated from stow.in).
Improved the release process and its documentation in various
minor ways.
* Initial public release (v1.0) of Stow.
* Changes in version 2.3.0
*** New features / changes in behaviour
***** New --dotfiles option
Enable special handling for "dotfiles" (files or folders whose name
begins with a period) in the package directory. If this option is
enabled, Stow will add a preprocessing step for each file or folder
whose name begins with "dot-", and replace the "dot-" prefix in the
name by a period ("."). This is useful when Stow is used to manage
collections of dotfiles, to avoid having a package directory full
of hidden files.
For example, suppose we have a package containing two files,
stow/dot-bashrc and stow/dot-emacs.d/init.el. With this option,
Stow will create symlinks from .bashrc to stow/dot-bashrc and from
.emacs.d/init.el to stow/dot-emacs.d/init.el. Any other files,
whose name does not begin with "dot-", will be processed as usual.
Thanks to Joris Vankerschaver for this feature!
***** Shell-like expansion in .stowrc files
For options within .stowrc files which describe file paths, "~" can
be included to expand to the current value of $HOME, and
environment variables can be referenced e.g. via "$FOO" or
"${FOO}". To prevent expansion, escape with a backslash.
Thanks a lot to Charles LeDoux for his diligent work on this
feature!
***** chkstow now honours the $STOW_DIR environment variable
The stow script already honoured the $STOW_DIR environment
variable. Now chkstow does too, for consistency.
***** Stow now has a non-zero exit code if option parsing failed
Thanks to Brice Waegeneire for reporting this.
*** License upgraded from GPL version 2 to version 3
Copyright and license notices were also added to the headers of
various files in accordance with GNU guidelines.
*** Documentation fixes and enhancements
***** Remove dependency on unmaintained texi2html
The dependency on the ancient and unmaintained texi2html for
building the single-page HTML version of the manual has been
removed, since it was difficult to get running on most distros
other than openSUSE.
Instead use the more modern "makeinfo --html --no-split" approach.
Rules have been kept for posterity in the Makefile for the old
approach and also an "in-between" approach based on texi2any;
however these are not triggered by default. Run
make manual-single-html-all
to compare the three versions.
***** Fixed naming of man page
The title of the generated man page was previously ending up as
something like:
IO::FILE=IO(0XA719C0)(1)
Thanks to @Corin-EU on GitHub highlighting this and proposing a
fix.
***** Convert README and INSTALL to Markdown
They are now named README.md and INSTALL.md, and render nicely
when viewed via git hosting services which support Markdown.
***** Update documentation to reflect more modern use cases
The README.md, stow(8) man page, and info manual have been updated
to de-emphasise the package management use, since these days almost
everyone prefers to use modern package managers such as rpm / dpkg
/ Nix for (system-wide) package management.
To compensate, more popular modern use cases for Stow have been
added, such as management of dotfiles and software compiled in the
user's $HOME directory.
***** Miscellaneous documentation fixes
- Various typos were fixed.
- The documentation for --verbose was updated to indicate that
verbosity levels now go up to 5.
- Erroneous glob examples in the --ignore documentation were fixed.
- The abbreviation "regex" was removed from the info manual for
consistency.
- INSTALL.md now also documents how to build directly from git.
*** Fixes for bugs, tests, and other technical debt
***** Add Docker files for convenient testing across multiple Perl versions
This is the first release which has been tested across 5 different
versions of Perl prior to release! The versions are:
perl-5.22.2
perl-5.20.3
perl-5.18.4
perl-5.16.3
perl-5.14.4
Thanks to Charles LeDoux for this!
***** Set up continuous testing via Travis CI
This means that the test suite will be automatically run on any
pull requests submitted to GitHub, as well as "make distcheck"
and "./Build distcheck".
***** Add Coveralls integration with GitHub
This means that test coverage analysis will be automatically be run
on any pull requests submitted to GitHub.
***** Miscellaneous improvements to the test suite
These include proper testing of the distinct impact of ~/.stowrc
and .stowrc in the directory from which Stow is invoked.
***** Fix for test suite on Cygwin
Thanks to Lucas Theisen for this fix!
***** aclocal.m4 was updated using aclocal 1.15.1.
***** Miscellaneous fixes to the build and distribution process
***** Improve handling of directories with unusual names
Various fixes for corner cases where directories are named "0"
or begin with a space character, or where STOW_DIR is empty.
Thanks to Cuong Manh Le for highlighting some of the issues and
proposing fixes!
* Changes in version 2.2.2
*** @VERSION@ substitution was set up for the Stow::Util module.
* Changes in version 2.2.1
Version 2.2.1 was not released since it was rejected by pause.perl.org
due to Stow::Util missing $VERSION.
*** Small improvements to documentation
***** The README has been revamped.
***** Some index points have been added to the manual.
***** Some typos were fixed.
***** @VERSION@ substitution was fixed in the stow(8) man page.
*** Fix Perl warnings
Stow no longer emits "v-string in use/require non-portable" and
"Possible precedence issue with control flow operator" warnings
with newer Perl versions. See https://savannah.gnu.org/bugs/?36478
and http://lists.gnu.org/archive/html/bug-stow/2014-06/msg00000.html
for full details.
*** Fix "Undefined subroutine &main::error" error
See https://rt.cpan.org/Public/Bug/Display.html?id=75349 for details.
*** Failed system calls now include error description
This should make errors easier to understand.
*** Default ignore list now ignores top-level README.*, LICENSE.*, and COPYING
These files are by definition specific to a given package, so if
they exist in the top-level directory, they should not be stowed.
*** Correctly handle the stow/target directories as non-canonical paths
Fix the case discovered by Hiroyuki Iwatsuki where stowing fails if
the stow / target directories are non-canonical paths. For
example, on FreeBSD /home is a symlink pointing to 'usr/home', so
running with the stow directory as /home/user/local/stow and the
target directory as /home/user/local previously resulted in the
stow directory path being calculated as
../../../usr/home/user/local/stow relative to the target.
See https://lists.gnu.org/archive/html/bug-stow/2013-04/msg00000.html for details.
*** Fix stowing of relative links when --no-folding is used.
With a tree like this:
.
|-- stow
| `-- pkg
| `-- lib
| |-- itk-current -> itk4.0.0
| `-- itk4.0.0
| `-- libitk4.0.0.so
`-- target
`-- lib
|-- itk4.0.0 -> ../../stow/pkg/lib/itk4.0.0
`-- libfoo-1.2.3.so
stowing pkg with the --no-folding option resulted in itk-current
being "unpacked":
.
`-- target
`-- lib
|-- itk-current
| `-- libitk4.0.0.so -> ../../../stow/pkg/lib/itk-current/libitk4.0.0.so
|-- itk4.0.0
| `-- libitk4.0.0.so -> ../../../stow/pkg/lib/itk4.0.0/libitk4.0.0.so
`-- libfoo-1.2.3.so
This commit fixes it so that it gets stowed as a symlink:
.
`-- target
`-- lib
...
|-- itk-current -> ../../stow/pkg/lib/itk-current
...
Thanks to Gabriele Balducci for reporting this problem:
https://lists.gnu.org/archive/html/help-stow/2014-09/msg00000.html
*** Internal code cleanups
***** aclocal was updated.
***** automake files were removed.
***** Trailing whitespace was removed.
***** Comments were added.
***** Debug messages were improved.
* Changes in version 2.2.0
*** New --no-folding option
Disables folding of newly stowed directories when stowing, and
refolding of newly foldable directories when unstowing.
*** Remove -a option (--adopt still available)
As --adopt is the only option which allows stow to modify files, it
is considered potentially dangerous (especially for stow package
directories which are not managed by a version control system).
Therefore it seems prudent to require a bit more effort from the
user to enable this option, minimising the change of enabling it
via a typo.
*** Improve error message when stow package is not found.
The error message displayed a path to the missing stow package
which was relative to the target directory rather than the cwd,
which was confusing for the user.
*** Test suite improvements
The test suite has been tightened up slightly.
*** Documentation improvements
Various fixes and cosmetic improvements have been made in the manual.
*** Remove "There are no outstanding operations to perform" warning.
* Changes in version 2.1.3
*** New --adopt / -a option
This allows plain files in the target to be "adopted" into the
package being stowed. See the manual has more details.
*** ./configure now checks for Perl modules required by the test suite.
* Changes in version 2.1.2
Many thanks to Stefano Lattarini for help with numerous autoconf and
automake issues which are addressed in this release.
*** Significantly improve the handling of --with-pmdir.
***** Calculation of the default value for --with-pmdir is now done safely in Perl.
Previously non-POSIX-compliant shells could cause issues.
***** The output of ./configure and make are now much more helpful.
***** The Makefile will now check whether pmdir is in Perl's built-in @INC.
If not, it will insert a
use lib "...";
line into the generated stow script to ensure that it can always
locate the Perl modules without needing to manually set PERL5LIB.
***** Updated INSTALL and HOWTO-RELEASE accordingly.
*** ./configure now aborts if Perl isn't found.
*** Ensured the ChangeLog is up-to-date when making a new distribution.
*** Fixed bug with `make clean' removing files which the user may not be able to rebuild.
* Changes in version 2.1.1
*** Fixed bug where ./configure --with-pmdir=X was ineffectual.
*** Calculated the correct default value for pmdir based on the local Perl installation.
*** Fixed some automake issues (thanks to Stefano Lattarini for spotting these!)
*** Improved various bits of documentation.
* Changes in version 2.1.0
*** Major refactoring of code into separate Stow and Stow::Util Perl modules.
*** Added support for ignore list files.
*** Added support for CPAN-style installation and distribution via Module::Build.
*** Introduced `make test' target and significantly tightened up test suite.
*** Very large number of code and documentation fixes (over 80 commits since version 2.0.1).
*** The '--conflicts' option has been removed.
Stow will always show conflicts if they are found during the scanning
phase.
*** Improved debugging output.
*** Converted man page to POD format.
*** Include PDF, and both split- and single-page HTML versions of manual in the distribution.
*** Fixed code style consistency issues.
*** Running configure from outside the source tree now works.
*** `make distcheck' now works.
* Changes in version 2.0.1
*** Defer operations until all potential conflicts have been assessed.
We do this by traversing the installation image(s) and recording the
actions that need to be performed. Redundant actions are factored out,
e.g., we don't want to create a link that we will later remove in order to
create a directory. Benefits of this approach:
1. Get to see _all_ the conflicts that are blocking an installation:
you don't have to deal with them one at a time.
2. No operations are be performed if _any_ conflicts are detected:
a failed stow will not leave you with a partially installed
package.
3. Minimises the set of operations that need to be performed.
4. Operations are executed as a batch which is much faster
This can be an advantage when upgrading packages on a live system
where you want to minimise the amount of time when the package is
unavailable.
*** The above fixes the false conflict problem mentioned in the info file.
*** It also fixes the two bugs mentioned in the man page.
*** Multiple stow directories will now cooperate in folding/unfolding.
*** Conflict messages are more uniform and informative.
*** Verbosity and tracing is more extensive and uniform.
*** Implemented option parsing via Getopt::Long.
*** Default command line arguments set via '.stowrc' and '~/.stowrc' files.
Contents of these files are parsed as though they occurred first on
the command line.
*** Support multiple actions per invocation.
In order for this to work, we had to add a new (optional) command line arg
(-S) to specify packages to stow. For example, to update an installation
of emacs you can now do
stow -D emacs-21.3 -S emacs-21.4a
which will replace emacs-21.3 with emacs-21.4a.
You can mix and match any number of actions, e.g.,
stow -S p1 p2 -D p3 p4 -S p5 -R p6
will unstow p3, p4 and p6, then stow p1, p2, p5 and p6.
*** New (repeatable) command line arg: --ignore='<regex>'
This suppresses operating on a file matching the regex (suffix),
e.g.
--ignore='~' --ignore='\.#.*'
will ignore emacs and CVS backup files (suitable for ~/.stowrc file).
(I opted for Perl regular expressions because they are more
powerful and easier to implement).
*** New (repeatable) command line arg: --defer='<regex>'
This defers stowing a file matching the regex (prefix) if that file
is already stowed to a different package, e.g.,
--defer='man' --defer='info'
will cause stow to skip over pre-existing man and info pages.
Equivalently, you could use --defer='man|info' since the argument
is just a Perl regex.
*** New (repeatable) command line arg: --override='<regex>'
This forces a file matching the regex (prefix) to be stowed even if
the file is already stowed to a different package, e.g.
--override='man' --override='info'
will unstow any pre-existing man and info pages that would conflict
with the file we are trying to stow.
Equivalently, you could use --override='man|info' since the
argument is just a Perl regex.
*** The above gives the ability to manage packages with common content.
For example, man pages that are shared by a number of CPAN
packages. Using multiple stow directories and .stowrc files can
also simplify things. In our setup we use the standard
/usr/local/stow directory for packages to be installed in
/usr/local. Since we install a large number of extra Perl packages
(currently about 300) we use an additional stow directory:
/usr/local/stow/perl-5.8.8-extras. Both stow directories contain a
'.stow' file so that they collaborate appropriately. I then use
the following .stowrc file in /usr/local/stow/perl-5.8.8-extras
--dir=/usr/local/stow/perl-5.8.8-extras
--target=/usr/local
--override=bin
--override=man
--ignore='perllocal\.pod'
--ignore='\.packlist'
--ignore='\.bs'
When I stow packages from there, they automatically override any
man pages and binaries that may already have been stowed by another
package or by the core perl-5.8.8 installation. For example, if
you want to upgrade the Test-Simple package, you need to override
all the man pages that would have been installed by the core
package. If you are upgrading CPAN, you will also have to override
the pre-existing cpan executable.
*** By default, search less aggressively for invalid symlinks when unstowing.
That is, we only search for bad symlinks in the directories
explicitly mentioned in the installation image, and do not dig down
into other subdirs. Digging down into other directories can be
very time consuming if you have a really big tree (like with a
couple of Oracle installations lying around). In general the old
behaviour is only necessary when you have really stuffed up your
installation by deleting a directory that has already been stowed.
Doing that on a live system is somewhat crazy and hopefully rare.
We provide an option '-p|--compat' to enable the old behaviour for
those needing to patch up mistakes.
*** New chkstow utility for checking the integrity of the target directory.
*** Implement a test suite and support code.
This was built before implementing any of the extra features so I
could more easily check for equivalent functionality. The initial
code base had to be refactored substantially to allow for testing.
The test suite is not exhaustive, but it should provide enough to
check for regressions.
* Changes in version 1.3.3
*** Now requires Perl 5.005 or later
*** Initially empty directories are not removed anymore
*** Removed buggy fastcwd (we use POSIX::getcwd instead)
*** Fixed bug when the common Parent of Target dir and Stow dir was "/"
*** Fixed bug when handling directories named "0"
*** Stow now only warns the user if a directory is unreadable during unstowing.
* Changes in version 1.3:
*** Added --restow option.
*** Fixed handling of slashes in package names.
*** Expanded configure-time search for Perl binary.
* Changes in version 1.2:
*** Dependency on `pwd' removed.
*** Perl 4 compatibility fixes.
*** Manual expanded even more.
* Changes in version 1.1:
*** Long and short options now accepted.
*** Manual expanded.
*** `make clean' removes stow (which is generated from stow.in).
* Initial public release (v1.0) of Stow.
* emacs local variables
Local Variables:
mode: org
org-export-with-toc: nil
org-export-with-author: nil
org-toc-odd-levels-only: t
org-blank-before-new-entry: ((heading . auto) (plain-list-item . auto))
End:

31
README
View file

@ -1,31 +0,0 @@
This is GNU Stow, a program for managing the installation of software
packages, keeping them separate (/usr/local/stow/emacs vs.
/usr/local/stow/perl, for example) while making them appear to be installed in
the same place (/usr/local). Stow doesn't store an extra state between runs,
so there's no danger of mangling directories when file hierarchies don't match
the database. Also, stow will never delete any files, directories, or links
that appear in a stow directory, so it is always possible to rebuild the
target tree.
Stow is a Perl script which should run correctly under Perl 4 and Perl 5. You
must install Perl before running Stow. For more information about Perl, see
http://www.perl.com/perl/.
You can get the latest information about Stow from
http://www.gnu.org/software/stow/stow.html
Stow was inspired by Carnegie Mellon's "Depot" program, but is substantially
simpler. Whereas Depot requires database files to keep things in sync, Stow
stores no extra state between runs, so there's no danger (as there is in
Depot) of mangling directories when file hierarchies don't match the database.
Also unlike Depot, Stow will never delete any files, directories, or links
that appear in a Stow directory (e.g., /usr/local/stow/emacs), so it's always
possible to rebuild the target tree (e.g., /usr/local).
Stow is free software, licensed under the GNU General Public License, which
can be found in the file COPYING.
See INSTALL for installation instructions.
Please mail comments, questions, and criticisms to the current maintainer,
Kahlil (Kal) Hodgson via help-stow@gnu.org or bug-stow@gnu.org.

139
README.md Normal file
View file

@ -0,0 +1,139 @@
[![Build Status](https://travis-ci.org/aspiers/stow.svg)](https://travis-ci.org/aspiers/stow)
[![Coverage Status](https://coveralls.io/repos/aspiers/stow/badge.svg?branch=master&service=github)](https://coveralls.io/github/aspiers/stow?branch=master)
README for GNU Stow
===================
This README describes GNU Stow. This is not the definitive
documentation for Stow; for that, see the [info
manual](https://www.gnu.org/software/stow/manual/).
Stow is a symlink farm manager program which takes distinct sets
of software and/or data located in separate directories on the
filesystem, and makes them all appear to be installed in a single
directory tree.
Originally Stow was born to address the need to administer, upgrade,
install, and remove files in independent software packages without
confusing them with other files sharing the same file system space.
For instance, many years ago it used to be common to compile programs
such as Perl and Emacs from source and install them in `/usr/local`.
By using Stow, `/usr/local/bin` could contain symlinks to files within
`/usr/local/stow/emacs/bin`, `/usr/local/stow/perl/bin` etc., and
likewise recursively for any other subdirectories such as `.../share`,
`.../man`, and so on.
While this is useful for keeping track of system-wide and per-user
installations of software built from source, in more recent times
software packages are often managed by more sophisticated package
management software such as
[`rpm`](https://en.wikipedia.org/wiki/Rpm_(software)),
[`dpkg`](https://en.wikipedia.org/wiki/Dpkg), and
[Nix](https://en.wikipedia.org/wiki/Nix_package_manager) / [GNU
Guix](https://en.wikipedia.org/wiki/GNU_Guix), or language-native
package managers such as Ruby's
[`gem`](https://en.wikipedia.org/wiki/RubyGems), Python's
[`pip`](https://en.wikipedia.org/wiki/Pip_(package_manager)),
Javascript's [`npm`](https://en.wikipedia.org/wiki/Npm_(software)),
and so on.
However Stow is still used not only for software package management,
but also for other purposes, such as facilitating [a more controlled
approach to management of configuration files in the user's home
directory](http://brandon.invergo.net/news/2012-05-26-using-gnu-stow-to-manage-your-dotfiles.html),
especially when [coupled with version control
systems](http://lists.gnu.org/archive/html/info-stow/2011-12/msg00000.html).
Stow was inspired by Carnegie Mellon's Depot program, but is
substantially simpler and safer. Whereas Depot required database files
to keep things in sync, Stow stores no extra state between runs, so
there's no danger (as there was in Depot) of mangling directories when
file hierarchies don't match the database. Also unlike Depot, Stow will
never delete any files, directories, or links that appear in a Stow
directory (e.g., `/usr/local/stow/emacs`), so it's always possible
to rebuild the target tree (e.g., `/usr/local`).
Stow is implemented as a combination of a Perl script providing a CLI
interface, and a backend Perl module which does most of the work.
You can get the latest information about Stow from the home page:
http://www.gnu.org/software/stow/
Installation
------------
See [`INSTALL.md`](INSTALL.md) for installation instructions.
Documentation
-------------
Documentation for Stow is available
[online](https://www.gnu.org/software/stow/manual/), as is
[documentation for most GNU
software](https://www.gnu.org/software/manual/). Once you have Stow
installed, you may also find more information about Stow by running
`info stow` or `man stow`, or by looking at `/usr/share/doc/stow/`,
`/usr/local/doc/stow/`, or similar directories on your system. A
brief summary is available by running `stow --help`.
Mailing lists
-------------
Stow has the following mailing lists:
- [help-stow](https://lists.gnu.org/mailman/listinfo/help-stow) is for
general user help and discussion.
- [stow-devel](https://lists.gnu.org/mailman/listinfo/stow-devel) is
used to discuss most aspects of Stow, including development and
enhancement requests.
- [bug-stow](https://lists.gnu.org/mailman/listinfo/bug-stow) is for
bug reports.
Announcements about Stow are posted to
[info-stow](http://lists.gnu.org/mailman/listinfo/info-stow) and also,
as with most other GNU software, to
[info-gnu](http://lists.gnu.org/mailman/listinfo/info-gnu)
([archive](http://lists.gnu.org/archive/html/info-gnu/)).
Security reports that should not be made immediately public can be
sent directly to the maintainer. If there is no response to an urgent
issue, you can escalate to the general
[security](http://lists.gnu.org/mailman/listinfo/security) mailing
list for advice.
The Savannah project also has a [mailing
lists](https://savannah.gnu.org/mail/?group=stow) page.
Getting involved
----------------
Please see the [`CONTRIBUTING.md` file](CONTRIBUTING.md).
License
-------
Stow is free software, licensed under the GNU General Public License,
which can be found in the file [`COPYING`](COPYING).
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. This file is offered as-is,
without any warranty.
Brief history and authorship
----------------------------
Stow was inspired by Carnegie Mellon's "Depot" program, but is
substantially simpler. Whereas Depot requires database files to keep
things in sync, Stow stores no extra state between runs, so there's no
danger (as there is in Depot) of mangling directories when file
hierarchies don't match the database. Also unlike Depot, Stow will
never delete any files, directories, or links that appear in a Stow
directory (e.g., `/usr/local/stow/emacs`), so it's always possible to
rebuild the target tree (e.g., `/usr/local`).
For a high-level overview of the contributions of the main developers
over the years, see [the `AUTHORS` file](AUTHORS).
For a more detailed history, please see the `ChangeLog` file.

29
THANKS
View file

@ -1,13 +1,13 @@
Bob Glickstein:
Thanks to the following people for testing, using, commenting on, and
otherwise aiding the creation of Stow:
Bob Glickstein (original author)
Miles Bader <miles@gnu.ai.mit.edu>
Greg Fox <fox@zanshin.com>
David Hartmann <davidh@zanshin.com>
Ben Liblit <liblit@well.com>
Gord Matzigkeit <gord@enci.ucalgary.ca>
Adam Lackorzynski <al10@inf.tu-dresden.de>
Roland McGrath <roland@gnu.ai.mit.edu>
Jim Meyering <meyering@asic.sc.ti.com>
Fritz Mueller <fritzm@netcom.com>
@ -16,7 +16,32 @@ Richard Stallman <rms@gnu.ai.mit.edu>
Spencer Sun <zorak@netcom.com>
Tom Tromey <tromey@cygnus.com>
Steve Webster <srw@zanshin.com>
Kahlil Hodgson <kahlil@internode.on.net>
Geoffrey Giesemann <geoffrey.giesemann@rmit.edu.au>
Emil Mikulic <emil.mikulic@rmit.edu.au>
Austin Wood <austin.wood@rmit.edu.au>
Christopher Hoobin <christopher.hoobin.edu.au>
Adam Spiers <stow@adamspiers.org>
Troy Will
Stefano Lattarini
Adam Sampson
Cuong Manh Le
Lucas Theisen
Charles LeDoux
Joris Vankerschaver
@Corin-EU on GitHub
Kristoffer Haugsbakk
Hongyi Zhao
Jean Louis
Daniel Shahaf
Matan Nassau
Brice Waegeneire
Slaven Rezic
Email addresses of new contributors are no longer being added by default
for privacy reasons; however please contact the maintainer if you are
happy for your email address to be listed here.
More authorship and contribution details can be found in the AUTHORS
and ChangeLog files, and of course also in the git version control
history.

51
TODO
View file

@ -1,24 +1,42 @@
* get account on fencepost.gnu.org (email accounts@gnu.org)
set up copyright papers?
'assign.future' and 'request-assign.future.manual'
* Add support for pre/post-(un)install hooks
* Update stow.texi
- The email address in 'Reporting Bugs' needs to be updated
This would allow correct handling of the Info dir file via
install-info, amongst other things:
* Figure out what needs the optin 'nostow' 'notstowed'. Can they be removed?
*** http://unix.stackexchange.com/questions/73426/dealing-with-gnu-stow-conflicts
*** https://lists.gnu.org/archive/html/help-stow/2013-04/msg00016.html
* _texi2man_ needs author/copyright/license to be completed
* Get permission for next documentation release to be under FDL 1.3
* Update http://directory.fsf.org/project/stow/
* Import a debian/ tree from an older package and update it.
* Update savanaugh CVS
* Import a .spec file from somewhere and update it.
* Check that all email addresses are working: need an account on fenchpost for
this bug-stow@gnu.org, help-stow@gnu.org
* Distinguish between .stow and (undocumented) .nonstow / .notstowed
* Get some pre-testers: need to find appropriate mailing list?
** .stow is for marking stow directories - avoids altering them
* Announce release on info-gnu@gnu.org.
but also allows --override to work
** .nonstow should be only for protecting non-stow directories against modification by stow
but currently allows modification via --override
** .notstowed is only honoured by chkstow
** Documentation needs to be clear on this.
* Prevent folding of directories which contain ignored files
* Honour .no-stow-folding and --no-folding
* Add semi-automatic conflict resolution
(This idea is possibly obsoleted via --override and --adopt.)
*** STOW_RESOLVE_CONFLICTS="non_stow_symlinks=t stow_symlinks=r"
*** Add documentation about conflict resolution
* Autodetect "foreign" stow directories
@ -45,5 +63,10 @@ From e-mail with meyering@na-net.ornl.gov:
Does Version 2 fix this? (Kal)
I think that because it never needs to create /usr/local/info,
it only needs to check th ownership of links that it _operatates_ on,
it only needs to check the ownership of links that it _operates_ on,
not on all the elements of the path.
* emacs local variables
Local Variables:
mode: org
End:

613
aclocal.m4 vendored
View file

@ -1,7 +1,7 @@
# generated automatically by aclocal 1.10 -*- Autoconf -*-
# generated automatically by aclocal 1.16.5 -*- Autoconf -*-
# Copyright (C) 1996-2021 Free Software Foundation, Inc.
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
# 2005, 2006 Free Software Foundation, Inc.
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
@ -11,12 +11,16 @@
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
m4_if(m4_PACKAGE_VERSION, [2.61],,
[m4_fatal([this file was generated for autoconf 2.61.
You have another version of autoconf. If you want to use that,
you should regenerate the build system entirely.], [63])])
m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.72],,
[m4_warning([this file was generated for autoconf 2.72.
You have another version of autoconf. It may work, but is not guaranteed to.
If you have problems, you may need to regenerate the build system entirely.
To do so, use the procedure documented by the package, typically 'autoreconf'.])])
# Copyright (C) 2002, 2003, 2005, 2006 Free Software Foundation, Inc.
# Copyright (C) 2002-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -28,10 +32,10 @@ you should regenerate the build system entirely.], [63])])
# generated from the m4 files accompanying Automake X.Y.
# (This private macro should not be called outside this file.)
AC_DEFUN([AM_AUTOMAKE_VERSION],
[am__api_version='1.10'
[am__api_version='1.16'
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
dnl require some minimum version. Point them to the right macro.
m4_if([$1], [1.10], [],
m4_if([$1], [1.16.5], [],
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
])
@ -45,22 +49,24 @@ m4_define([_AM_AUTOCONF_VERSION], [])
# AM_SET_CURRENT_AUTOMAKE_VERSION
# -------------------------------
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
[AM_AUTOMAKE_VERSION([1.10])dnl
_AM_AUTOCONF_VERSION(m4_PACKAGE_VERSION)])
[AM_AUTOMAKE_VERSION([1.16.5])dnl
m4_ifndef([AC_AUTOCONF_VERSION],
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
# Copyright (C) 2001-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to
# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
#
# Of course, Automake must honor this variable whenever it calls a
# tool from the auxiliary directory. The problem is that $srcdir (and
@ -79,7 +85,7 @@ _AM_AUTOCONF_VERSION(m4_PACKAGE_VERSION)])
#
# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
# are both prefixed by $srcdir. In an in-source build this is usually
# harmless because $srcdir is `.', but things will broke when you
# harmless because $srcdir is '.', but things will broke when you
# start a VPATH build or use an absolute $srcdir.
#
# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
@ -97,26 +103,28 @@ _AM_AUTOCONF_VERSION(m4_PACKAGE_VERSION)])
# configured tree to be moved without reconfiguration.
AC_DEFUN([AM_AUX_DIR_EXPAND],
[dnl Rely on autoconf to set up CDPATH properly.
AC_PREREQ([2.50])dnl
# expand $ac_aux_dir to an absolute path
am_aux_dir=`cd $ac_aux_dir && pwd`
[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
# Expand $ac_aux_dir to an absolute path.
am_aux_dir=`cd "$ac_aux_dir" && pwd`
])
# Do all the work for Automake. -*- Autoconf -*-
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
# 2005, 2006 Free Software Foundation, Inc.
# Copyright (C) 1996-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 12
# This macro actually does too much. Some checks are only needed if
# your package does certain things. But this isn't really a big deal.
dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.
m4_define([AC_PROG_CC],
m4_defn([AC_PROG_CC])
[_AM_PROG_CC_C_O
])
# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
# AM_INIT_AUTOMAKE([OPTIONS])
# -----------------------------------------------
@ -129,7 +137,11 @@ am_aux_dir=`cd $ac_aux_dir && pwd`
# arguments mandatory, and then we can depend on a new Autoconf
# release and drop the old call support.
AC_DEFUN([AM_INIT_AUTOMAKE],
[AC_PREREQ([2.60])dnl
[AC_PREREQ([2.65])dnl
m4_ifdef([_$0_ALREADY_INIT],
[m4_fatal([$0 expanded multiple times
]m4_defn([_$0_ALREADY_INIT]))],
[m4_define([_$0_ALREADY_INIT], m4_expansion_stack)])dnl
dnl Autoconf wants to disallow AM_ names. We explicitly allow
dnl the ones we care about.
m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
@ -158,55 +170,139 @@ AC_SUBST([CYGPATH_W])
# Define the identity of the package.
dnl Distinguish between old-style and new-style calls.
m4_ifval([$2],
[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
[AC_DIAGNOSE([obsolete],
[$0: two- and three-arguments forms are deprecated.])
m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
AC_SUBST([PACKAGE], [$1])dnl
AC_SUBST([VERSION], [$2])],
[_AM_SET_OPTIONS([$1])dnl
dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,,
m4_if(
m4_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]),
[ok:ok],,
[m4_fatal([AC_INIT should be called with package and version arguments])])dnl
AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
_AM_IF_OPTION([no-define],,
[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
# Some tools Automake needs.
AC_REQUIRE([AM_SANITY_CHECK])dnl
AC_REQUIRE([AC_ARG_PROGRAM])dnl
AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
AM_MISSING_PROG(AUTOCONF, autoconf)
AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
AM_MISSING_PROG(AUTOHEADER, autoheader)
AM_MISSING_PROG(MAKEINFO, makeinfo)
AM_PROG_INSTALL_SH
AM_PROG_INSTALL_STRIP
AC_REQUIRE([AM_PROG_MKDIR_P])dnl
# We need awk for the "check" target. The system "awk" is bad on
# some platforms.
AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
AM_MISSING_PROG([AUTOCONF], [autoconf])
AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
AM_MISSING_PROG([AUTOHEADER], [autoheader])
AM_MISSING_PROG([MAKEINFO], [makeinfo])
AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
AC_REQUIRE([AC_PROG_MKDIR_P])dnl
# For better backward compatibility. To be removed once Automake 1.9.x
# dies out for good. For more background, see:
# <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
# <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
# We need awk for the "check" target (and possibly the TAP driver). The
# system "awk" is bad on some platforms.
AC_REQUIRE([AC_PROG_AWK])dnl
AC_REQUIRE([AC_PROG_MAKE_SET])dnl
AC_REQUIRE([AM_SET_LEADING_DOT])dnl
_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
[_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
[_AM_PROG_TAR([v7])])])
[_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
[_AM_PROG_TAR([v7])])])
_AM_IF_OPTION([no-dependencies],,
[AC_PROVIDE_IFELSE([AC_PROG_CC],
[_AM_DEPENDENCIES(CC)],
[define([AC_PROG_CC],
defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
[_AM_DEPENDENCIES([CC])],
[m4_define([AC_PROG_CC],
m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
AC_PROVIDE_IFELSE([AC_PROG_CXX],
[_AM_DEPENDENCIES(CXX)],
[define([AC_PROG_CXX],
defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
[_AM_DEPENDENCIES([CXX])],
[m4_define([AC_PROG_CXX],
m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
AC_PROVIDE_IFELSE([AC_PROG_OBJC],
[_AM_DEPENDENCIES(OBJC)],
[define([AC_PROG_OBJC],
defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl
[_AM_DEPENDENCIES([OBJC])],
[m4_define([AC_PROG_OBJC],
m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
[_AM_DEPENDENCIES([OBJCXX])],
[m4_define([AC_PROG_OBJCXX],
m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
])
# Variables for tags utilities; see am/tags.am
if test -z "$CTAGS"; then
CTAGS=ctags
fi
AC_SUBST([CTAGS])
if test -z "$ETAGS"; then
ETAGS=etags
fi
AC_SUBST([ETAGS])
if test -z "$CSCOPE"; then
CSCOPE=cscope
fi
AC_SUBST([CSCOPE])
AC_REQUIRE([AM_SILENT_RULES])dnl
dnl The testsuite driver may need to know about EXEEXT, so add the
dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This
dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
AC_CONFIG_COMMANDS_PRE(dnl
[m4_provide_if([_AM_COMPILER_EXEEXT],
[AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
# POSIX will say in a future version that running "rm -f" with no argument
# is OK; and we want to be able to make that assumption in our Makefile
# recipes. So use an aggressive probe to check that the usage we want is
# actually supported "in the wild" to an acceptable degree.
# See automake bug#10828.
# To make any issue more visible, cause the running configure to be aborted
# by default if the 'rm' program in use doesn't match our expectations; the
# user can still override this though.
if rm -f && rm -fr && rm -rf; then : OK; else
cat >&2 <<'END'
Oops!
Your 'rm' program seems unable to run without file operands specified
on the command line, even when the '-f' option is present. This is contrary
to the behaviour of most rm programs out there, and not conforming with
the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
Please tell bug-automake@gnu.org about your system, including the value
of your $PATH and any error possibly output before this message. This
can help us improve future automake versions.
END
if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
echo 'Configuration will proceed anyway, since you have set the' >&2
echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
echo >&2
else
cat >&2 <<'END'
Aborting the configuration process, to ensure you take notice of the issue.
You can download and install GNU coreutils to get an 'rm' implementation
that behaves properly: <https://www.gnu.org/software/coreutils/>.
If you want to complete the configuration process using your problematic
'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
to "yes", and re-run configure.
END
AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
fi
fi
dnl The trailing newline in this macro's definition is deliberate, for
dnl backward compatibility and to allow trailing 'dnl'-style comments
dnl after the AM_INIT_AUTOMAKE invocation. See automake bug#16841.
])
dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
dnl mangled by Autoconf and run in a shell conditional statement.
m4_define([_AC_COMPILER_EXEEXT],
m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
# When config.status generates a header, we must update the stamp-h file.
# This file resides in the same directory as the config header
@ -217,18 +313,19 @@ AC_PROVIDE_IFELSE([AC_PROG_OBJC],
# our stamp files there.
AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
[# Compute $1's index in $config_headers.
_am_arg=$1
_am_stamp_count=1
for _am_header in $config_headers :; do
case $_am_header in
$1 | $1:* )
$_am_arg | $_am_arg:* )
break ;;
* )
_am_stamp_count=`expr $_am_stamp_count + 1` ;;
esac
done
echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
# Copyright (C) 2001-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -239,17 +336,22 @@ echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
# Define $install_sh.
AC_DEFUN([AM_PROG_INSTALL_SH],
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
install_sh=${install_sh-"\$(SHELL) $am_aux_dir/install-sh"}
AC_SUBST(install_sh)])
if test x"${install_sh+set}" != xset; then
case $am_aux_dir in
*\ * | *\ *)
install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
*)
install_sh="\${SHELL} $am_aux_dir/install-sh"
esac
fi
AC_SUBST([install_sh])])
# Copyright (C) 2003, 2005 Free Software Foundation, Inc.
# Copyright (C) 2003-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 2
# Check whether the underlying file-system supports filenames
# with a leading dot. For instance MS-DOS doesn't.
AC_DEFUN([AM_SET_LEADING_DOT],
@ -265,15 +367,12 @@ AC_SUBST([am__leading_dot])])
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005
# Free Software Foundation, Inc.
# Copyright (C) 1997-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 5
# AM_MISSING_PROG(NAME, PROGRAM)
# ------------------------------
AC_DEFUN([AM_MISSING_PROG],
@ -281,76 +380,49 @@ AC_DEFUN([AM_MISSING_PROG],
$1=${$1-"${am_missing_run}$2"}
AC_SUBST($1)])
# AM_MISSING_HAS_RUN
# ------------------
# Define MISSING if not defined so far and test if it supports --run.
# If it does, set am_missing_run to use it, otherwise, to nothing.
# Define MISSING if not defined so far and test if it is modern enough.
# If it is, set am_missing_run to use it, otherwise, to nothing.
AC_DEFUN([AM_MISSING_HAS_RUN],
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
AC_REQUIRE_AUX_FILE([missing])dnl
test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
if test x"${MISSING+set}" != xset; then
MISSING="\${SHELL} '$am_aux_dir/missing'"
fi
# Use eval to expand $SHELL
if eval "$MISSING --run true"; then
am_missing_run="$MISSING --run "
if eval "$MISSING --is-lightweight"; then
am_missing_run="$MISSING "
else
am_missing_run=
AC_MSG_WARN([`missing' script is too old or missing])
AC_MSG_WARN(['missing' script is too old or missing])
fi
])
# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# AM_PROG_MKDIR_P
# ---------------
# Check for `mkdir -p'.
AC_DEFUN([AM_PROG_MKDIR_P],
[AC_PREREQ([2.60])dnl
AC_REQUIRE([AC_PROG_MKDIR_P])dnl
dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P,
dnl while keeping a definition of mkdir_p for backward compatibility.
dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile.
dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of
dnl Makefile.ins that do not define MKDIR_P, so we do our own
dnl adjustment using top_builddir (which is defined more often than
dnl MKDIR_P).
AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl
case $mkdir_p in
[[\\/$]]* | ?:[[\\/]]*) ;;
*/*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
esac
])
# Helper functions for option handling. -*- Autoconf -*-
# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
# Copyright (C) 2001-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 3
# _AM_MANGLE_OPTION(NAME)
# -----------------------
AC_DEFUN([_AM_MANGLE_OPTION],
[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
# _AM_SET_OPTION(NAME)
# ------------------------------
# --------------------
# Set option NAME. Presently that only means defining a flag for this option.
AC_DEFUN([_AM_SET_OPTION],
[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
# _AM_SET_OPTIONS(OPTIONS)
# ----------------------------------
# ------------------------
# OPTIONS is a space-separated list of Automake options.
AC_DEFUN([_AM_SET_OPTIONS],
[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
# -------------------------------------------
@ -360,45 +432,60 @@ AC_DEFUN([_AM_IF_OPTION],
# Check to make sure that the build environment is sane. -*- Autoconf -*-
# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
# Free Software Foundation, Inc.
# Copyright (C) 1996-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 4
# AM_SANITY_CHECK
# ---------------
AC_DEFUN([AM_SANITY_CHECK],
[AC_MSG_CHECKING([whether build environment is sane])
# Just in case
sleep 1
echo timestamp > conftest.file
# Do `set' in a subshell so we don't clobber the current shell's
# Reject unsafe characters in $srcdir or the absolute working directory
# name. Accept space and tab only in the latter.
am_lf='
'
case `pwd` in
*[[\\\"\#\$\&\'\`$am_lf]]*)
AC_MSG_ERROR([unsafe absolute working directory name]);;
esac
case $srcdir in
*[[\\\"\#\$\&\'\`$am_lf\ \ ]]*)
AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
esac
# Do 'set' in a subshell so we don't clobber the current shell's
# arguments. Must try -L first in case configure is actually a
# symlink; some systems play weird games with the mod time of symlinks
# (eg FreeBSD returns the mod time of the symlink's containing
# directory).
if (
set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
if test "$[*]" = "X"; then
# -L didn't work.
set X `ls -t $srcdir/configure conftest.file`
fi
rm -f conftest.file
if test "$[*]" != "X $srcdir/configure conftest.file" \
&& test "$[*]" != "X conftest.file $srcdir/configure"; then
# If neither matched, then we have a broken ls. This can happen
# if, for instance, CONFIG_SHELL is bash and it inherits a
# broken ls alias from the environment. This has actually
# happened. Such a system could not be considered "sane".
AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
alias in your environment])
fi
am_has_slept=no
for am_try in 1 2; do
echo "timestamp, slept: $am_has_slept" > conftest.file
set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
if test "$[*]" = "X"; then
# -L didn't work.
set X `ls -t "$srcdir/configure" conftest.file`
fi
if test "$[*]" != "X $srcdir/configure conftest.file" \
&& test "$[*]" != "X conftest.file $srcdir/configure"; then
# If neither matched, then we have a broken ls. This can happen
# if, for instance, CONFIG_SHELL is bash and it inherits a
# broken ls alias from the environment. This has actually
# happened. Such a system could not be considered "sane".
AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
alias in your environment])
fi
if test "$[2]" = conftest.file || test $am_try -eq 2; then
break
fi
# Just in case.
sleep 1
am_has_slept=yes
done
test "$[2]" = conftest.file
)
then
@ -408,9 +495,85 @@ else
AC_MSG_ERROR([newly created file is older than distributed files!
Check your system clock])
fi
AC_MSG_RESULT(yes)])
AC_MSG_RESULT([yes])
# If we didn't sleep, we still need to ensure time stamps of config.status and
# generated files are strictly newer.
am_sleep_pid=
if grep 'slept: no' conftest.file >/dev/null 2>&1; then
( sleep 1 ) &
am_sleep_pid=$!
fi
AC_CONFIG_COMMANDS_PRE(
[AC_MSG_CHECKING([that generated files are newer than configure])
if test -n "$am_sleep_pid"; then
# Hide warnings about reused PIDs.
wait $am_sleep_pid 2>/dev/null
fi
AC_MSG_RESULT([done])])
rm -f conftest.file
])
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
# Copyright (C) 2009-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# AM_SILENT_RULES([DEFAULT])
# --------------------------
# Enable less verbose build rules; with the default set to DEFAULT
# ("yes" being less verbose, "no" or empty being verbose).
AC_DEFUN([AM_SILENT_RULES],
[AC_ARG_ENABLE([silent-rules], [dnl
AS_HELP_STRING(
[--enable-silent-rules],
[less verbose build output (undo: "make V=1")])
AS_HELP_STRING(
[--disable-silent-rules],
[verbose build output (undo: "make V=0")])dnl
])
case $enable_silent_rules in @%:@ (((
yes) AM_DEFAULT_VERBOSITY=0;;
no) AM_DEFAULT_VERBOSITY=1;;
*) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
esac
dnl
dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
dnl do not support nested variable expansions.
dnl See automake bug#9928 and bug#10237.
am_make=${MAKE-make}
AC_CACHE_CHECK([whether $am_make supports nested variables],
[am_cv_make_support_nested_variables],
[if AS_ECHO([['TRUE=$(BAR$(V))
BAR0=false
BAR1=true
V=1
am__doit:
@$(TRUE)
.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
am_cv_make_support_nested_variables=yes
else
am_cv_make_support_nested_variables=no
fi])
if test $am_cv_make_support_nested_variables = yes; then
dnl Using '$V' instead of '$(V)' breaks IRIX make.
AM_V='$(V)'
AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
else
AM_V=$AM_DEFAULT_VERBOSITY
AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
fi
AC_SUBST([AM_V])dnl
AM_SUBST_NOTMAKE([AM_V])dnl
AC_SUBST([AM_DEFAULT_V])dnl
AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
AM_BACKSLASH='\'
AC_SUBST([AM_BACKSLASH])dnl
_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
])
# Copyright (C) 2001-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -418,27 +581,27 @@ AC_MSG_RESULT(yes)])
# AM_PROG_INSTALL_STRIP
# ---------------------
# One issue with vendor `install' (even GNU) is that you can't
# One issue with vendor 'install' (even GNU) is that you can't
# specify the program used to strip binaries. This is especially
# annoying in cross-compiling environments, where the build's strip
# is unlikely to handle the host's binaries.
# Fortunately install-sh will honor a STRIPPROG variable, so we
# always use install-sh in `make install-strip', and initialize
# always use install-sh in "make install-strip", and initialize
# STRIPPROG with the value of the STRIP variable (set by the user).
AC_DEFUN([AM_PROG_INSTALL_STRIP],
[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
# Installed binaries are usually stripped using `strip' when the user
# run `make install-strip'. However `strip' might not be the right
# Installed binaries are usually stripped using 'strip' when the user
# run "make install-strip". However 'strip' might not be the right
# tool to use in cross-compilation environments, therefore Automake
# will honor the `STRIP' environment variable to overrule this program.
dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
# will honor the 'STRIP' environment variable to overrule this program.
dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
if test "$cross_compiling" != no; then
AC_CHECK_TOOL([STRIP], [strip], :)
fi
INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
AC_SUBST([INSTALL_STRIP_PROGRAM])])
# Copyright (C) 2006 Free Software Foundation, Inc.
# Copyright (C) 2006-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
@ -446,24 +609,27 @@ AC_SUBST([INSTALL_STRIP_PROGRAM])])
# _AM_SUBST_NOTMAKE(VARIABLE)
# ---------------------------
# Prevent Automake from outputing VARIABLE = @VARIABLE@ in Makefile.in.
# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
# This macro is traced by Automake.
AC_DEFUN([_AM_SUBST_NOTMAKE])
# AM_SUBST_NOTMAKE(VARIABLE)
# --------------------------
# Public sister of _AM_SUBST_NOTMAKE.
AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
# Check how to create a tarball. -*- Autoconf -*-
# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
# Copyright (C) 2004-2021 Free Software Foundation, Inc.
#
# This file is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# serial 2
# _AM_PROG_TAR(FORMAT)
# --------------------
# Check how to create a tarball in format FORMAT.
# FORMAT should be one of `v7', `ustar', or `pax'.
# FORMAT should be one of 'v7', 'ustar', or 'pax'.
#
# Substitute a variable $(am__tar) that is a command
# writing to stdout a FORMAT-tarball containing the directory
@ -473,75 +639,114 @@ AC_DEFUN([_AM_SUBST_NOTMAKE])
# Substitute a variable $(am__untar) that extract such
# a tarball read from stdin.
# $(am__untar) < result.tar
#
AC_DEFUN([_AM_PROG_TAR],
[# Always define AMTAR for backward compatibility.
AM_MISSING_PROG([AMTAR], [tar])
m4_if([$1], [v7],
[am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
[m4_case([$1], [ustar],, [pax],,
[m4_fatal([Unknown tar format])])
AC_MSG_CHECKING([how to create a $1 tar archive])
# Loop over all known methods to create a tar archive until one works.
[# Always define AMTAR for backward compatibility. Yes, it's still used
# in the wild :-( We should find a proper way to deprecate it ...
AC_SUBST([AMTAR], ['$${TAR-tar}'])
# We'll loop over all known methods to create a tar archive until one works.
_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
_am_tools=${am_cv_prog_tar_$1-$_am_tools}
# Do not fold the above two line into one, because Tru64 sh and
# Solaris sh will not grok spaces in the rhs of `-'.
for _am_tool in $_am_tools
do
case $_am_tool in
gnutar)
for _am_tar in tar gnutar gtar;
do
AM_RUN_LOG([$_am_tar --version]) && break
done
am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
am__untar="$_am_tar -xf -"
;;
plaintar)
# Must skip GNU tar: if it does not support --format= it doesn't create
# ustar tarball either.
(tar --version) >/dev/null 2>&1 && continue
am__tar='tar chf - "$$tardir"'
am__tar_='tar chf - "$tardir"'
am__untar='tar xf -'
;;
pax)
am__tar='pax -L -x $1 -w "$$tardir"'
am__tar_='pax -L -x $1 -w "$tardir"'
am__untar='pax -r'
;;
cpio)
am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
am__untar='cpio -i -H $1 -d'
;;
none)
am__tar=false
am__tar_=false
am__untar=false
;;
esac
# If the value was cached, stop now. We just wanted to have am__tar
# and am__untar set.
test -n "${am_cv_prog_tar_$1}" && break
m4_if([$1], [v7],
[am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
# tar/untar a dummy directory, and stop if the command works
[m4_case([$1],
[ustar],
[# The POSIX 1988 'ustar' format is defined with fixed-size fields.
# There is notably a 21 bits limit for the UID and the GID. In fact,
# the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
# and bug#13588).
am_max_uid=2097151 # 2^21 - 1
am_max_gid=$am_max_uid
# The $UID and $GID variables are not portable, so we need to resort
# to the POSIX-mandated id(1) utility. Errors in the 'id' calls
# below are definitely unexpected, so allow the users to see them
# (that is, avoid stderr redirection).
am_uid=`id -u || echo unknown`
am_gid=`id -g || echo unknown`
AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
if test $am_uid -le $am_max_uid; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
_am_tools=none
fi
AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
if test $am_gid -le $am_max_gid; then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
_am_tools=none
fi],
[pax],
[],
[m4_fatal([Unknown tar format])])
AC_MSG_CHECKING([how to create a $1 tar archive])
# Go ahead even if we have the value already cached. We do so because we
# need to set the values for the 'am__tar' and 'am__untar' variables.
_am_tools=${am_cv_prog_tar_$1-$_am_tools}
for _am_tool in $_am_tools; do
case $_am_tool in
gnutar)
for _am_tar in tar gnutar gtar; do
AM_RUN_LOG([$_am_tar --version]) && break
done
am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
am__untar="$_am_tar -xf -"
;;
plaintar)
# Must skip GNU tar: if it does not support --format= it doesn't create
# ustar tarball either.
(tar --version) >/dev/null 2>&1 && continue
am__tar='tar chf - "$$tardir"'
am__tar_='tar chf - "$tardir"'
am__untar='tar xf -'
;;
pax)
am__tar='pax -L -x $1 -w "$$tardir"'
am__tar_='pax -L -x $1 -w "$tardir"'
am__untar='pax -r'
;;
cpio)
am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
am__untar='cpio -i -H $1 -d'
;;
none)
am__tar=false
am__tar_=false
am__untar=false
;;
esac
# If the value was cached, stop now. We just wanted to have am__tar
# and am__untar set.
test -n "${am_cv_prog_tar_$1}" && break
# tar/untar a dummy directory, and stop if the command works.
rm -rf conftest.dir
mkdir conftest.dir
echo GrepMe > conftest.dir/file
AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
rm -rf conftest.dir
if test -s conftest.tar; then
AM_RUN_LOG([$am__untar <conftest.tar])
AM_RUN_LOG([cat conftest.dir/file])
grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
fi
done
rm -rf conftest.dir
mkdir conftest.dir
echo GrepMe > conftest.dir/file
AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
rm -rf conftest.dir
if test -s conftest.tar; then
AM_RUN_LOG([$am__untar <conftest.tar])
grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
fi
done
rm -rf conftest.dir
AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
AC_MSG_RESULT([$am_cv_prog_tar_$1])])
AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
AC_MSG_RESULT([$am_cv_prog_tar_$1])])
AC_SUBST([am__tar])
AC_SUBST([am__untar])
]) # _AM_PROG_TAR

5
automake/.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
install-sh
missing
mdate-sh
test-driver
texinfo.tex

57
chkstow.in → bin/chkstow.in Normal file → Executable file
View file

@ -1,15 +1,34 @@
#!@PERL@
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
use strict;
use warnings;
require 5.006_001;
use File::Find;
use Getopt::Long;
our $Wanted = \&bad_links;
our %Package=();
my $DEFAULT_TARGET = $ENV{STOW_DIR} || '/usr/local/';
our $Wanted = \&bad_links;
our %Package = ();
our $Stow_dir = '';
our $Target = q{/usr/local/};
our $Target = $DEFAULT_TARGET;
# put the main loop into a block so that tests can load this as a module
if ( not caller() ) {
@ -35,12 +54,14 @@ sub usage {
print <<"EOT";
USAGE: chkstow [options]
Options:
-b, --badlinks Report symlinks that point to non-existant files.
-a, --aliens Report non-symlinks in the target directory.
-l, --list List packages in the target directory.
-t DIR, --target=DIR Set the target directory to DIR (default
is /usr/local)
Options:
-t DIR, --target=DIR Set the target directory to DIR
(default is $DEFAULT_TARGET)
-b, --badlinks Report symlinks that point to non-existent files
-a, --aliens Report non-symlinks in the target directory
-l, --list List packages in the target directory
--badlinks is the default mode.
EOT
exit(0);
}
@ -49,7 +70,7 @@ sub check_stow {
#my ($Target, $Wanted) = @_;
my (%options) = (
wanted => $Wanted,
wanted => $Wanted,
preprocess => \&skip_dirs,
);
@ -60,8 +81,7 @@ sub check_stow {
delete $Package{'..'};
if (keys %Package) {
local $,="\n";
print sort(keys %Package), "\n";
print map "$_\n", sort(keys %Package);
}
}
return;
@ -80,15 +100,15 @@ sub skip_dirs {
# checking for files that do not link to anything
sub bad_links {
-l && !-e && print "Bogus link: $File::Find::name\n";
-l && !-e && print "Bogus link: $File::Find::name\n";
}
# checking for files that are not owned by stow
sub aliens {
!-l && !-d && print "Unstowed file: $File::Find::name\n";
sub aliens {
!-l && !-d && print "Unstowed file: $File::Find::name\n";
}
# just list the packages in the the target directory
# just list the packages in the target directory
# FIXME: what if the stow dir is not called 'stow'?
sub list {
if (-l) {
@ -101,4 +121,7 @@ sub list {
1; # Hey, it's a module!
# vim:ft=perl
# Local variables:
# mode: perl
# End:
# vim: ft=perl

852
bin/stow.in Executable file
View file

@ -0,0 +1,852 @@
#!@PERL@
# GNU Stow - manage farms of symbolic links
# Copyright (C) 1993, 1994, 1995, 1996 by Bob Glickstein
# Copyright (C) 2000, 2001 Guillaume Morin
# Copyright (C) 2007 Kahlil Hodgson
# Copyright (C) 2011 Adam Spiers
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
=head1 NAME
stow - manage farms of symbolic links
=head1 SYNOPSIS
stow [ options ] package ...
=head1 DESCRIPTION
This manual page describes GNU Stow @VERSION@. This is not the
definitive documentation for Stow; for that, see the accompanying info
manual, e.g. by typing C<info stow>.
Stow is a symlink farm manager which takes distinct sets of software
and/or data located in separate directories on the filesystem, and
makes them all appear to be installed in a single directory tree.
Originally Stow was born to address the need to administer, upgrade,
install, and remove files in independent software packages without
confusing them with other files sharing the same file system space.
For instance, many years ago it used to be common to compile programs
such as Perl and Emacs from source. By using Stow, F</usr/local/bin>
could contain symlinks to files within F</usr/local/stow/emacs/bin>,
F</usr/local/stow/perl/bin> etc., and likewise recursively for any
other subdirectories such as F<.../share>, F<.../man>, and so on.
While this is useful for keeping track of system-wide and per-user
installations of software built from source, in more recent times
software packages are often managed by more sophisticated package
management software such as rpm, dpkg, and Nix / GNU Guix, or
language-native package managers such as Ruby's gem, Python's pip,
Javascript's npm, and so on.
However Stow is still used not only for software package management,
but also for other purposes, such as facilitating a more controlled
approach to management of configuration files in the user's home
directory, especially when coupled with version control systems.
Stow was inspired by Carnegie Mellon's Depot program, but is
substantially simpler and safer. Whereas Depot required database files
to keep things in sync, Stow stores no extra state between runs, so
there's no danger (as there was in Depot) of mangling directories when
file hierarchies don't match the database. Also unlike Depot, Stow
will never delete any files, directories, or links that appear in a
Stow directory (e.g., F</usr/local/stow/emacs>), so it's always
possible to rebuild the target tree (e.g., F</usr/local>).
Stow is implemented as a combination of a Perl script providing a CLI
interface, and a backend Perl module which does most of the work.
=head1 TERMINOLOGY
A "package" is a related collection of files and directories that
you wish to administer as a unit -- e.g., Perl or Emacs -- and that
needs to be installed in a particular directory structure -- e.g.,
with F<bin>, F<lib>, and F<man> subdirectories.
A "target directory" is the root of a tree in which one or more
packages wish to B<appear> to be installed. A common, but by no means
the only such location is F</usr/local>. The examples in this manual
page will use F</usr/local> as the target directory.
A "stow directory" is the root of a tree containing separate
packages in private subtrees. When Stow runs, it uses the current
directory as the default stow directory. The examples in this manual
page will use F</usr/local/stow> as the stow directory, so that
individual packages will be, for example, F</usr/local/stow/perl> and
F</usr/local/stow/emacs>.
An "installation image" is the layout of files and directories
required by a package, relative to the target directory. Thus, the
installation image for Perl includes: a F<bin> directory containing
F<perl> and F<a2p> (among others); an F<info> directory containing
Texinfo documentation; a F<lib/perl> directory containing Perl
libraries; and a F<man/man1> directory containing man pages.
A "package directory" is the root of a tree containing the
installation image for a particular package. Each package directory
must reside in a stow directory -- e.g., the package directory
F</usr/local/stow/perl> must reside in the stow directory
F</usr/local/stow>. The "name" of a package is the name of its
directory within the stow directory -- e.g., F<perl>.
Thus, the Perl executable might reside in
F</usr/local/stow/perl/bin/perl>, where F</usr/local> is the target
directory, F</usr/local/stow> is the stow directory,
F</usr/local/stow/perl> is the package directory, and F<bin/perl>
within is part of the installation image.
A "symlink" is a symbolic link. A symlink can be "relative" or
"absolute". An absolute symlink names a full path; that is, one
starting from F</>. A relative symlink names a relative path; that
is, one not starting from F</>. The target of a relative symlink is
computed starting from the symlink's own directory. Stow only creates
relative symlinks.
=head1 OPTIONS
The stow directory is assumed to be the value of the C<STOW_DIR>
environment variable or if unset the current directory, and the target
directory is assumed to be the parent of the current directory (so it
is typical to execute F<stow> from the directory F</usr/local/stow>).
Each F<package> given on the command line is the name of a package in
the stow directory (e.g., F<perl>). By default, they are installed
into the target directory (but they can be deleted instead using
C<-D>).
=over 4
=item -n
=item --no
=item --simulate
Do not perform any operations that modify the filesystem; merely show
what would happen.
=item -d DIR
=item --dir=DIR
Set the stow directory to C<DIR> instead of the current directory.
This also has the effect of making the default target directory be the
parent of C<DIR>.
=item -t DIR
=item --target=DIR
Set the target directory to C<DIR> instead of the parent of the stow
directory.
=item -v
=item --verbose[=N]
Send verbose output to standard error describing what Stow is
doing. Verbosity levels are from 0 to 5; 0 is the default.
Using C<-v> or C<--verbose> increases the verbosity by one; using
`--verbose=N' sets it to N.
=item -S
=item --stow
Stow the packages that follow this option into the target directory.
This is the default action and so can be omitted if you are only
stowing packages rather than performing a mixture of
stow/delete/restow actions.
=item -D
=item --delete
Unstow the packages that follow this option from the target directory rather
than installing them.
=item -R
=item --restow
Restow packages (first unstow, then stow again). This is useful
for pruning obsolete symlinks from the target tree after updating
the software in a package.
=item --adopt
B<Warning!> This behaviour is specifically intended to alter the
contents of your stow directory. If you do not want that, this option
is not for you.
When stowing, if a target is encountered which already exists but is a
plain file (and hence not owned by any existing stow package), then
normally Stow will register this as a conflict and refuse to proceed.
This option changes that behaviour so that the file is moved to the
same relative place within the package's installation image within the
stow directory, and then stowing proceeds as before. So effectively,
the file becomes adopted by the stow package, without its contents
changing.
=item --no-folding
Disable folding of newly stowed directories when stowing, and
refolding of newly foldable directories when unstowing.
=item --ignore=REGEX
Ignore files ending in this Perl regex.
=item --defer=REGEX
Don't stow files beginning with this Perl regex if the file is already
stowed to another package.
=item --override=REGEX
Force stowing files beginning with this Perl regex if the file is
already stowed to another package.
=item --dotfiles
Enable special handling for "dotfiles" (files or folders whose name
begins with a period) in the package directory. If this option is
enabled, Stow will add a preprocessing step for each file or folder
whose name begins with "dot-", and replace the "dot-" prefix in the
name by a period (.). This is useful when Stow is used to manage
collections of dotfiles, to avoid having a package directory full of
hidden files.
For example, suppose we have a package containing two files,
F<stow/dot-bashrc> and F<stow/dot-emacs.d/init.el>. With this option,
Stow will create symlinks from F<.bashrc> to F<stow/dot-bashrc> and
from F<.emacs.d/init.el> to F<stow/dot-emacs.d/init.el>. Any other
files, whose name does not begin with "dot-", will be processed as usual.
=item -V
=item --version
Show Stow version number, and exit.
=item -h
=item --help
Show Stow command syntax, and exit.
=back
=head1 INSTALLING PACKAGES
The default action of Stow is to install a package. This means
creating symlinks in the target tree that point into the package tree.
Stow attempts to do this with as few symlinks as possible; in other
words, if Stow can create a single symlink that points to an entire
subtree within the package tree, it will choose to do that rather than
create a directory in the target tree and populate it with symlinks.
For example, suppose that no packages have yet been installed in
F</usr/local>; it's completely empty (except for the F<stow>
subdirectory, of course). Now suppose the Perl package is installed.
Recall that it includes the following directories in its installation
image: F<bin>; F<info>; F<lib/perl>; F<man/man1>. Rather than
creating the directory F</usr/local/bin> and populating it with
symlinks to F<../stow/perl/bin/perl> and F<../stow/perl/bin/a2p> (and
so on), Stow will create a single symlink, F</usr/local/bin>, which
points to F<stow/perl/bin>. In this way, it still works to refer to
F</usr/local/bin/perl> and F</usr/local/bin/a2p>, and fewer symlinks
have been created. This is called "tree folding", since an entire
subtree is "folded" into a single symlink.
To complete this example, Stow will also create the symlink
F</usr/local/info> pointing to F<stow/perl/info>; the symlink
F</usr/local/lib> pointing to F<stow/perl/lib>; and the symlink
F</usr/local/man> pointing to F<stow/perl/man>.
Now suppose that instead of installing the Perl package into an empty
target tree, the target tree is not empty to begin with. Instead, it
contains several files and directories installed under a different
system-administration philosophy. In particular, F</usr/local/bin>
already exists and is a directory, as are F</usr/local/lib> and
F</usr/local/man/man1>. In this case, Stow will descend into
F</usr/local/bin> and create symlinks to F<../stow/perl/bin/perl> and
F<../stow/perl/bin/a2p> (etc.), and it will descend into
F</usr/local/lib> and create the tree-folding symlink F<perl> pointing
to F<../stow/perl/lib/perl>, and so on. As a rule, Stow only descends
as far as necessary into the target tree when it can create a
tree-folding symlink.
The time often comes when a tree-folding symlink has to be undone
because another package uses one or more of the folded subdirectories
in its installation image. This operation is called "splitting open"
a folded tree. It involves removing the original symlink from the
target tree, creating a true directory in its place, and then
populating the new directory with symlinks to the newly-installed
package B<and> to the old package that used the old symlink. For
example, suppose that after installing Perl into an empty
F</usr/local>, we wish to install Emacs. Emacs's installation image
includes a F<bin> directory containing the F<emacs> and F<etags>
executables, among others. Stow must make these files appear to be
installed in F</usr/local/bin>, but presently F</usr/local/bin> is a
symlink to F<stow/perl/bin>. Stow therefore takes the following
steps: the symlink F</usr/local/bin> is deleted; the directory
F</usr/local/bin> is created; links are made from F</usr/local/bin> to
F<../stow/emacs/bin/emacs> and F<../stow/emacs/bin/etags>; and links
are made from F</usr/local/bin> to F<../stow/perl/bin/perl> and
F<../stow/perl/bin/a2p>.
When splitting open a folded tree, Stow makes sure that the symlink
it is about to remove points inside a valid package in the current stow
directory.
=head2 Stow will never delete anything that it doesn't own.
Stow "owns" everything living in the target tree that points into a
package in the stow directory. Anything Stow owns, it can recompute if
lost. Note that by this definition, Stow doesn't "own" anything
B<in> the stow directory or in any of the packages.
If Stow needs to create a directory or a symlink in the target tree
and it cannot because that name is already in use and is not owned by
Stow, then a conflict has arisen. See the "Conflicts" section in the
info manual.
=head1 DELETING PACKAGES
When the C<-D> option is given, the action of Stow is to delete a
package from the target tree. Note that Stow will not delete anything
it doesn't "own". Deleting a package does B<not> mean removing it from
the stow directory or discarding the package tree.
To delete a package, Stow recursively scans the target tree, skipping
over the stow directory (since that is usually a subdirectory of the
target tree) and any other stow directories it encounters (see
"Multiple stow directories" in the info manual). Any symlink it
finds that points into the package being deleted is removed. Any
directory that contained only symlinks to the package being deleted is
removed. Any directory that, after removing symlinks and empty
subdirectories, contains only symlinks to a single other package, is
considered to be a previously "folded" tree that was "split open."
Stow will re-fold the tree by removing the symlinks to the surviving
package, removing the directory, then linking the directory back to
the surviving package.
=head1 RESOURCE FILES
F<Stow> searches for default command line options at F<.stowrc> (current
directory) and F<~/.stowrc> (home directory) in that order. If both
locations are present, the files are effectively appended together.
The effect of options in the resource file is similar to simply prepending
the options to the command line. For options that provide a single value,
such as F<--target> or F<--dir>, the command line option will overwrite any
options in the resource file. For options that can be given more than once,
F<--ignore> for example, command line options and resource options are
appended together.
Environment variables and the tilde character (F<~>) will be expanded for
options that take a file path.
The options F<-D>, F<-R>, F<-S>, and any packages listed in the resource
file are ignored.
See the info manual for more information on how stow handles resource
file.
=head1 SEE ALSO
The full documentation for F<stow> is maintained as a Texinfo manual.
If the F<info> and F<stow> programs are properly installed at your site, the command
info stow
should give you access to the complete manual.
=head1 BUGS
Please report bugs in Stow using the Debian bug tracking system.
Currently known bugs include:
=over 4
=item * The empty-directory problem.
If package F<foo> includes an empty directory -- say, F<foo/bar> --
then if no other package has a F<bar> subdirectory, everything's fine.
If another stowed package F<quux>, has a F<bar> subdirectory, then
when stowing, F<targetdir/bar> will be "split open" and the contents
of F<quux/bar> will be individually stowed. So far, so good. But when
unstowing F<quux>, F<targetdir/bar> will be removed, even though
F<foo/bar> needs it to remain. A workaround for this problem is to
create a file in F<foo/bar> as a placeholder. If you name that file
F<.placeholder>, it will be easy to find and remove such files when
this bug is fixed.
=item *
When using multiple stow directories (see "Multiple stow directories"
in the info manual), Stow fails to "split open" tree-folding symlinks
(see "Installing packages" in the info manual) that point into a stow
directory which is not the one in use by the current Stow
command. Before failing, it should search the target of the link to
see whether any element of the path contains a F<.stow> file. If it
finds one, it can "learn" about the cooperating stow directory to
short-circuit the F<.stow> search the next time it encounters a
tree-folding symlink.
=back
=head1 AUTHOR
This man page was originally constructed by Charles Briscoe-Smith from
parts of Stow's info manual, and then converted to POD format by Adam
Spiers. The info manual contains the following notice, which, as it
says, applies to this manual page, too. The text of the section
entitled "GNU General Public License" can be found in the file
F</usr/share/common-licenses/GPL> on any Debian GNU/Linux system. If
you don't have access to a Debian system, or the GPL is not there,
write to the Free Software Foundation, Inc., 59 Temple Place, Suite
330, Boston, MA, 02111-1307, USA.
=head1 COPYRIGHT
Copyright (C)
1993, 1994, 1995, 1996 by Bob Glickstein <bobg+stow@zanshin.com>;
2000, 2001 by Guillaume Morin;
2007 by Kahlil Hodgson;
2011 by Adam Spiers;
and others.
Permission is granted to make and distribute verbatim copies of this
manual provided the copyright notice and this permission notice are
preserved on all copies.
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided also that
the section entitled "GNU General Public License" is included with the
modified manual, and provided that the entire resulting derived work
is distributed under the terms of a permission notice identical to
this one.
Permission is granted to copy and distribute translations of this
manual into another language, under the above conditions for modified
versions, except that this permission notice may be stated in a
translation approved by the Free Software Foundation.
=cut
use strict;
use warnings;
require 5.006_001;
use POSIX qw(getcwd);
use Getopt::Long qw(GetOptionsFromArray);
use Scalar::Util qw(reftype);
@USE_LIB_PMDIR@
use Stow;
use Stow::Util qw(parent error);
my $ProgramName = $0;
$ProgramName =~ s{.*/}{};
main() unless caller();
sub main {
my ($options, $pkgs_to_unstow, $pkgs_to_stow) = process_options();
my $stow = new Stow(%$options);
$stow->plan_unstow(@$pkgs_to_unstow);
$stow->plan_stow (@$pkgs_to_stow);
my %conflicts = $stow->get_conflicts;
if (%conflicts) {
foreach my $action ('unstow', 'stow') {
next unless $conflicts{$action};
foreach my $package (sort keys %{ $conflicts{$action} }) {
warn "WARNING! ${action}ing $package would cause conflicts:\n";
#if $stow->get_action_count > 1;
foreach my $message (sort @{ $conflicts{$action}{$package} }) {
warn " * $message\n";
}
}
}
warn "All operations aborted.\n";
exit 1;
}
else {
if ($options->{simulate}) {
warn "WARNING: in simulation mode so not modifying filesystem.\n";
return;
}
$stow->process_tasks();
}
}
#===== SUBROUTINE ===========================================================
# Name : process_options()
# Purpose : Parse and process command line and .stowrc file options
# Parameters: none
# Returns : (\%options, \@pkgs_to_unstow, \@pkgs_to_stow)
# Throws : a fatal error if a bad option is given
# Comments : checks @ARGV for valid package names
#============================================================================
sub process_options {
# Get cli options.
my ($cli_options,
$pkgs_to_unstow,
$pkgs_to_stow) = parse_options(@ARGV);
# Get the .stowrc options.
# Note that rc_pkgs_to_unstow and rc_pkgs_to_stow are ignored.
my ($rc_options,
$rc_pkgs_to_unstow,
$rc_pkgs_to_stow) = get_config_file_options();
# Merge .stowrc and command line options.
# Preference is given to cli options.
my %options = %$rc_options;
foreach my $option (keys %$cli_options) {
my $rc_value = $rc_options->{$option};
my $cli_value = $cli_options->{$option};
my $type = reftype($cli_value);
if (defined $type && $type eq 'ARRAY' && defined $rc_value) {
# rc options come first in merged arrays.
$options{$option} = [@{$rc_value}, @{$cli_value}];
} else {
# cli options overwrite conflicting rc options.
$options{$option} = $cli_value;
}
}
# Run checks on the merged options.
sanitize_path_options(\%options);
check_packages($pkgs_to_unstow, $pkgs_to_stow);
# Return merged and processed options.
return (\%options, $pkgs_to_unstow, $pkgs_to_stow);
}
#===== SUBROUTINE ===========================================================
# Name : parse_options()
# Purpose : parse command line options
# Parameters: @arg_array => array of options to parse
# Example: parse_options(@ARGV)
# Returns : (\%options, \@pkgs_to_unstow, \@pkgs_to_stow)
# Throws : a fatal error if a bad command line option is given
# Comments : Used for parsing both command line options and rc file. Used
# for parsing only. Sanity checks and post-processing belong in
# process_options().
#============================================================================
sub parse_options {
my %options = ();
my @pkgs_to_unstow = ();
my @pkgs_to_stow = ();
my $action = 'stow';
#$,="\n"; print @_,"\n"; # for debugging rc file
Getopt::Long::config('no_ignore_case', 'bundling', 'permute');
GetOptionsFromArray(
\@_,
\%options,
'verbose|v:+', 'help|h', 'simulate|n|no',
'version|V', 'compat|p', 'dir|d=s', 'target|t=s',
'adopt', 'no-folding', 'dotfiles',
# clean and pre-compile any regex's at parse time
'ignore=s' =>
sub {
my $regex = $_[1];
push @{$options{ignore}}, qr($regex\z);
},
'override=s' =>
sub {
my $regex = $_[1];
push @{$options{override}}, qr(\A$regex);
},
'defer=s' =>
sub {
my $regex = $_[1];
push @{$options{defer}}, qr(\A$regex);
},
# a little craziness so we can do different actions on the same line:
# a -D, -S, or -R changes the action that will be performed on the
# package arguments that follow it.
'D|delete' => sub { $action = 'unstow' },
'S|stow' => sub { $action = 'stow' },
'R|restow' => sub { $action = 'restow' },
# Handler for non-option arguments
'<>' =>
sub {
if ($action eq 'restow') {
push @pkgs_to_unstow, $_[0];
push @pkgs_to_stow, $_[0];
}
elsif ($action eq 'unstow') {
push @pkgs_to_unstow, $_[0];
}
else {
push @pkgs_to_stow, $_[0];
}
},
) or usage('');
usage() if $options{help};
version() if $options{version};
return (\%options, \@pkgs_to_unstow, \@pkgs_to_stow);
}
sub sanitize_path_options {
my ($options) = @_;
unless (exists $options->{dir}) {
$options->{dir} = length $ENV{STOW_DIR} ? $ENV{STOW_DIR} : getcwd();
}
usage("--dir value '$options->{dir}' is not a valid directory")
unless -d $options->{dir};
if (exists $options->{target}) {
usage("--target value '$options->{target}' is not a valid directory")
unless -d $options->{target};
}
else {
$options->{target} = parent($options->{dir}) || '.';
}
}
sub check_packages {
my ($pkgs_to_stow, $pkgs_to_unstow) = @_;
if (not @$pkgs_to_stow and not @$pkgs_to_unstow) {
usage("No packages to stow or unstow");
}
# check package arguments
for my $package (@$pkgs_to_stow, @$pkgs_to_unstow) {
$package =~ s{/+$}{}; # delete trailing slashes
if ($package =~ m{/}) {
error("Slashes are not permitted in package names");
}
}
}
#===== SUBROUTINE ============================================================
# Name : get_config_file_options()
# Purpose : search for default settings in any .stowrc files
# Parameters: none
# Returns : (\%rc_options, \@rc_pkgs_to_unstow, \@rc_pkgs_to_stow)
# Throws : a fatal error if a bad option is given
# Comments : Parses the contents of '~/.stowrc' and '.stowrc' with the same
# parser as the command line options. Additionally expands any
# environment variables or ~ character in --target or --dir
# options.
#=============================================================================
sub get_config_file_options {
my @defaults = ();
my @dirlist = ('.stowrc');
if (defined($ENV{HOME})) {
unshift(@dirlist, "$ENV{HOME}/.stowrc");
}
for my $file (@dirlist) {
if (-r $file) {
open my $FILE, '<', $file
or die "Could not open $file for reading\n";
while (my $line = <$FILE>){
chomp $line;
push @defaults, split " ", $line;
}
close $FILE or die "Could not close open file: $file\n";
}
}
# Parse the options
my ($rc_options, $rc_pkgs_to_unstow, $rc_pkgs_to_stow) = parse_options(@defaults);
# Expand environment variables and glob characters.
if (exists $rc_options->{target}) {
$rc_options->{target} =
expand_filepath($rc_options->{target}, '--target option');
}
if (exists $rc_options->{dir}) {
$rc_options->{dir} =
expand_filepath($rc_options->{dir}, '--dir option');
}
return ($rc_options, $rc_pkgs_to_unstow, $rc_pkgs_to_stow);
}
#===== SUBROUTINE ============================================================
# Name : expand_filepath()
# Purpose : Handles expansions that need to be applied to
# : file paths. Currently expands environment
# : variables and the tilde.
# Parameters: $path => string to perform expansion on.
# : $source => where the string came from
# Returns : String with replacements performed.
# Throws : n/a
# Comments : n/a
#=============================================================================
sub expand_filepath {
my ($path, $source) = @_;
$path = expand_environment($path, $source);
$path = expand_tilde($path);
return $path;
}
#===== SUBROUTINE ============================================================
# Name : expand_environment()
# Purpose : Expands evironment variables.
# Parameters: $path => string to perform expansion on.
# : $source => where the string came from
# Returns : String with replacements performed.
# Throws : n/a
# Comments : Variable replacement mostly based on SO answer
# : http://stackoverflow.com/a/24675093/558820
#=============================================================================
sub expand_environment {
my ($path, $source) = @_;
# Replace non-escaped $VAR and ${VAR} with $ENV{VAR}
# If $ENV{VAR} does not exist, perl will raise a warning
# and then happily treat it as an empty string.
$path =~ s/(?<!\\)\$\{((?:\w|\s)+)\}/
_safe_expand_env_var($1, $source)
/ge;
$path =~ s/(?<!\\)\$(\w+)/
_safe_expand_env_var($1, $source)
/ge;
# Remove \$ escapes.
$path =~ s/\\\$/\$/g;
return $path;
}
sub _safe_expand_env_var {
my ($var, $source) = @_;
unless (exists $ENV{$var}) {
die "$source references undefined environment variable \$$var; " .
"aborting!\n";
}
return $ENV{$var};
}
#===== SUBROUTINE ============================================================
# Name : expand_tilde()
# Purpose : Expands tilde to user's home directory path.
# Parameters: $path => string to perform expansion on.
# Returns : String with replacements performed.
# Throws : n/a
# Comments : http://docstore.mik.ua/orelly/perl4/cook/ch07_04.htm
#=============================================================================
sub expand_tilde {
my ($path) = @_;
# Replace tilde with home path.
$path =~ s{ ^ ~ ( [^/]* ) }
{ $1
? (getpwnam($1))[7]
: ( $ENV{HOME} || $ENV{LOGDIR}
|| (getpwuid($<))[7]
)
}ex;
# Replace espaced tilde with regular tilde.
$path =~ s/\\~/~/g;
return $path
}
#===== SUBROUTINE ===========================================================
# Name : usage()
# Purpose : print program usage message and exit
# Parameters: $msg => string to prepend to the usage message
# Returns : n/a
# Throws : n/a
# Comments : if 'msg' is given, then exit with non-zero status
#============================================================================
sub usage {
my ($msg) = @_;
if ($msg) {
warn "$ProgramName: $msg\n\n";
}
print <<"EOT";
$ProgramName (GNU Stow) version $Stow::VERSION
SYNOPSIS:
$ProgramName [OPTION ...] [-D|-S|-R] PACKAGE ... [-D|-S|-R] PACKAGE ...
OPTIONS:
-d DIR, --dir=DIR Set stow dir to DIR (default is current dir)
-t DIR, --target=DIR Set target to DIR (default is parent of stow dir)
-S, --stow Stow the package names that follow this option
-D, --delete Unstow the package names that follow this option
-R, --restow Restow (like stow -D followed by stow -S)
--ignore=REGEX Ignore files ending in this Perl regex
--defer=REGEX Don't stow files beginning with this Perl regex
if the file is already stowed to another package
--override=REGEX Force stowing files beginning with this Perl regex
if the file is already stowed to another package
--adopt (Use with care!) Import existing files into stow package
from target. Please read docs before using.
--dotfiles Enables special handling for dotfiles that are
Stow packages that start with "dot-" and not "."
-p, --compat Use legacy algorithm for unstowing
-n, --no, --simulate Do not actually make any filesystem changes
-v, --verbose[=N] Increase verbosity (levels are from 0 to 5;
-v or --verbose adds 1; --verbose=N sets level)
-V, --version Show stow version number
-h, --help Show this help
Report bugs to: bug-stow\@gnu.org
Stow home page: <http://www.gnu.org/software/stow/>
General help using GNU software: <http://www.gnu.org/gethelp/>
EOT
exit defined $msg ? 1 : 0;
}
sub version {
print "$ProgramName (GNU Stow) version $Stow::VERSION\n";
exit 0;
}
1; # This file is required by t/stow.t
# Local variables:
# mode: perl
# end:
# vim: ft=perl

12
build-docker.sh Executable file
View file

@ -0,0 +1,12 @@
#!/usr/bin/env bash
set -eu
version=$( tools/get-version )
imagename=stowtest
image=$imagename:$version
pushd docker
echo "Building Docker image $image ..."
docker build -t $image .
popd

3297
configure vendored

File diff suppressed because it is too large Load diff

View file

@ -1,17 +1,123 @@
dnl This file is part of GNU Stow.
dnl
dnl GNU Stow is free software: you can redistribute it and/or modify it
dnl under the terms of the GNU General Public License as published by
dnl the Free Software Foundation, either version 3 of the License, or
dnl (at your option) any later version.
dnl
dnl GNU Stow is distributed in the hope that it will be useful, but
dnl WITHOUT ANY WARRANTY; without even the implied warranty of
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
dnl General Public License for more details.
dnl
dnl You should have received a copy of the GNU General Public License
dnl along with this program. If not, see https://www.gnu.org/licenses/.
dnl Process this file with Autoconf to produce configure dnl
AC_INIT([stow], [2.0.2], [bug-stow@gnu.org])
AC_INIT([stow], [2.4.0], [bug-stow@gnu.org])
AC_PREREQ([2.61])
AM_INIT_AUTOMAKE([-Wall -Werror])
AC_CONFIG_AUX_DIR([automake])
# Unfortunately we have to disable warnings for overrides, because we
# need to override the built-in `check-TESTS' rule and also the TEXI2DVI
# variable.
AM_INIT_AUTOMAKE([-Wall -Werror -Wno-override dist-bzip2 foreign])
AC_PROG_INSTALL
dnl Check for perl on our system
dnl call to AC_SUBST(PERL) is implicit
dnl Check for perl on our system.
dnl Call to AC_SUBST(PERL) is implicit
AC_PATH_PROGS([PERL], [perl] [perl5], [false])
if test "x$PERL" = xfalse
then
AC_MSG_WARN([WARNING: Perl not found; you must edit line 1 of 'stow'])
AC_MSG_ERROR([Perl not found; check your \$PATH.])
fi
missing_test_deps=
for mod in Test::More Test::Output; do
AC_MSG_CHECKING([$mod])
if $PERL -M$mod -e 1 2>/dev/null
then
AC_MSG_RESULT([yes])
else
AC_MSG_RESULT([no])
missing_test_deps="$missing_test_deps $mod"
fi
done
# N.B. ${var#pattern} will not work with some shells, such as
# Solaris 10's /bin/sh :-(
#
# http://www.gnu.org/software/autoconf/manual/autoconf.html#Portable-Shell
#
# eval `$PERL -V:siteprefix -V:installsitelib`
# pmdir_relative_path="${installsitelib#$siteprefix/}"
#
# This will work:
#
# pmdir_relative_path=`echo "${installsitelib}" | sed -e "s!^$siteprefix/!!"`
#
# but this is cleaner:
pmdir_relative_path=`\
$PERL -MConfig \
-wle '($_ = $Config{installsitelib})
=~ s!^\Q$Config{siteprefix}/!!; \
print'`
AC_ARG_WITH(
[pmdir],
AS_HELP_STRING(
[--with-pmdir=DIR],
[Install Perl modules in DIR]),
[PMDIR=${withval}],
[PMDIR='${prefix}'/"$pmdir_relative_path"])
AC_ARG_ENABLE(
[relative],
AS_HELP_STRING(
[--enable-relative],
[Load Stow modules relative to the main script]),
[FINDBIN="$enable_relative"],
[FINDBIN=no])
AC_CONFIG_COMMANDS_POST([[
eval pmdir="$PMDIR"
cat <<EOF
# Perl modules will be installed to $PMDIR
EOF
if [ "$pmdir" != "$PMDIR" ]; then
cat <<EOF
# which will expand to
#
# $pmdir
#
# unless you override the value of prefix at make-time.
EOF
echo
fi
if test -n "$missing_test_deps"; then
cat <<EOF >&2
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! WARNING! $PERL was missing modules:
!
! $missing_test_deps
!
! The test suite will fail. 'make install' may still render
! a working installation, but this cannot be guaranteed.
!
! Please (re-)read INSTALL, then install the missing modules
! and try again.
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
EOF
if test -n "$STRICT_TESTS"; then
exit 1
fi
fi
]])
AC_SUBST([PMDIR])
AC_SUBST([FINDBIN])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

23
default-ignore-list Normal file
View file

@ -0,0 +1,23 @@
# Comments and blank lines are allowed.
RCS
.+,v
CVS
\.\#.+ # CVS conflict files / emacs lock files
\.cvsignore
\.svn
_darcs
\.hg
\.git
\.gitignore
\.gitmodules
.+~ # emacs backup files
\#.*\# # emacs autosave files
^/README.*
^/LICENSE.*
^/COPYING

View file

@ -1,4 +1,4 @@
2008-01-31 Kahlil Hodgson <kal@grebo.cs.rmit.edu.au>
Thu Jan 31 2008 Kahlil Hodgson <kal@grebo.cs.rmit.edu.au>
* stow.texi: Austin Wood and Chris Hoobin clean this up for version 2.
@ -49,6 +49,10 @@ Sun Nov 25 19:31:32 2007 Kahlil Hodgson <kahlil@internode.con.net>
* stow.8: update to reflect Version 2 changes.
Sat Jan 26 16:15:21 2002 Guillaume Morin <gmorin@gnu.org>
* stow.in: if $ENV{'STOW_DIR'} is set, this becomes the default
Stow directory.
Sun Jan 06 12:18:50 2002 Guillaume Morin <gmorin@gnu.org>

173
doc/HOWTO-RELEASE Normal file
View file

@ -0,0 +1,173 @@
How to make a new release of GNU Stow
=====================================
Prerequisite reading
--------------------
First read the official information for maintainers of GNU software:
https://www.gnu.org/prep/maintain/
Release procedure
-----------------
- Ensure configure.ac contains the number of the new unreleased
version. This should follow Semantic Versioning as described at:
http://semver.org/
- To make the following steps easier, set the $version shell variable
to the same version number as above, e.g.
version=$( tools/get-version ) && echo $version
- Ensure NEWS contains the latest changes. If necessary, commit
any additions:
git commit -m "Prepare NEWS for $version release"
- Check CPAN distribution will work via Module::Build:
- Start from a clean slate:
make maintainer-clean
autoreconf -iv
- Generate stow, chkstow, and lib/Stow.pm via:
eval `perl -V:siteprefix`
automake --add-missing
./configure --prefix=$siteprefix && make
(N.B. the CPAN distribution will contain these files, whereas
the GNU distribution will not.)
- Make sure all the following commands all run successfully:
perl Build.PL --prefix=/tmp/stow-test
./Build test
./Build install
./Build distcheck
./Build distmeta
./Build dist
- Check META.yml and META.json have the new version number.
They already should if the final step of this document was
carried out after the previous release was publised, but
if not:
git commit -m "Bump version to $version"
- Ensure all changes are committed to git.
- Run make distcheck and ensure that everything looks good.
It should generate the distribution files for you.
- Run the tests on various Perl versions via Docker:
./build-docker.sh
./test-docker.sh
Obviously if there are any failures, they will need to be fixed
first, and then repeat the above steps.
- At this point we have a release candidate. Tag the current git HEAD
with the new version number:
git tag -s v$version -m "Release $version"
- Upload the resulting Stow-v7.8.9.tar.gz to CPAN via https://pause.perl.org/
- Wait until PAUSE has accepted the upload as a valid module. If you
are the maintainer of the module, you should receive two email
notifications: a CPAN upload confirmation, and a PAUSE indexer
report. This provides some valuable final validation, as learnt the
hard way during the non-release of 2.2.1.
- Push HEAD and tag to savannah and GitHub:
git push savannah master
git push --tags savannah
git push github master
git push --tags github
- Upload the new release to ftp.gnu.org. This is easiest using gnupload:
- git clone git://git.savannah.gnu.org/gnulib.git
- Copy gnulib/build-aux/gnupload to somewhere on your $PATH
- Run gnupload --to ftp.gnu.org:stow --symlink-regex stow-7.8.9.tar.*
- Regenerate the documentation for the website:
# First check out gnulib repository via:
# git clone git://git.savannah.gnu.org/gnulib.git
# and stow-web CVS repository via the instructions here:
# https://savannah.gnu.org/cvs/?group=stow
# Set paths:
stow_repo=/path/to/stow/git/repo
stow_web_repo=/path/to/stow-web/CVS/working/dir
gnulib_repo=/path/to/gnulib/git/repo
cd $stow_repo
export GENDOCS_TEMPLATE_DIR=$gnulib_repo/doc
$gnulib_repo/util/gendocs.sh \
-s doc/stow.texi \
-o $stow_web_repo/manual \
--email bug-stow@gnu.org \
stow "GNU Stow manual"
cd $stow_web_repo
# Check that the changes look OK
cvs diff
# Then commit
cvs commit -m "Update manual to v$version"
- Update the news section of stow.html in the stow-web CVS repository
to mention the new release.
cd $stow_web_repo
# Check that the changes look OK
cvs diff
# Then commit
cvs commit -m "Update home page to v$version"
- Send release announcements to
- info-stow@gnu.org
- stow-devel@gnu.org
- info-gnu@gnu.org
- https://savannah.gnu.org/news/?group=stow
See http://www.gnu.org/prep/maintain/html_node/Announcements.html for
more on making release announcements.
Excerpts of NEWS can be formatted for inclusion in the email by
selecting the relevant version subtree via M-x org-mark-element,
minus the "* Changes in version x.y.z", running M-x
org-export-dispatch, and exporting as plain text.
- Update the git repositories to the next expected version, so that anyone
who builds from git gets a version of Stow which is higher than the release
which was just cut:
- Increment the patchlevel of the version number in configure.ac.
- Run this again:
version=$( tools/get-version ) && echo $version
- In order to update META.yml and META.json, repeat the same
procedure listed above, starting at "make distclean" and
finishing after "./Build distmeta".
- Check META.yml and META.json now have the new versions.
- git add configure.ac META.{yml,json}
- git commit -m "Bump version to $version for development of next release"
- git push savannah master
- git push github master

2136
doc/stow.texi Normal file

File diff suppressed because it is too large Load diff

62
docker/Dockerfile Normal file
View file

@ -0,0 +1,62 @@
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
# Build docker image: `docker build -t stowtest`
# Run tests: (from stow src directory)
# `docker run --rm -it -v $(pwd):$(pwd) -w $(pwd) stowtest`
FROM debian:bookworm
RUN DEBIAN_FRONTEND=noninteractive apt-get update -qq
RUN DEBIAN_FRONTEND=noninteractive \
apt-get install -y -q \
autoconf \
bzip2 \
cpanminus \
gawk \
git \
libssl-dev \
make \
patch \
perlbrew \
texinfo \
texlive \
texi2html \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
# Set up perlbrew
ENV HOME=/root \
PERLBREW_ROOT=/usr/local/perlbrew \
PERLBREW_HOME=/root/.perlbrew \
PERLBREW_PATH=/usr/local/perlbrew/bin
RUN mkdir -p /usr/local/perlbrew /root \
&& perlbrew init \
&& perlbrew install-cpanm \
&& perlbrew install-patchperl
RUN perlbrew install-multiple -j 4 --notest \
perl-5.22.2 \
perl-5.20.3 \
perl-5.18.4 \
perl-5.16.3 \
perl-5.14.4 \
&& perlbrew clean
# Bootstrap the perl environments
COPY ./bootstrap-perls.sh /bootstrap-perls.sh
RUN /bootstrap-perls.sh && rm /bootstrap-perls.sh
# Add test script to container filesystem
COPY ./run-stow-tests.sh /run-stow-tests.sh
ENTRYPOINT ["/run-stow-tests.sh"]

30
docker/bootstrap-perls.sh Executable file
View file

@ -0,0 +1,30 @@
#!/bin/bash
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
# Load perlbrew environment
. /usr/local/perlbrew/etc/bashrc
# For each perl version installed.
for p_version in $(perlbrew list | sed 's/ //g'); do
# Switch to it.
perlbrew use $p_version
# and install the needed modules.
/usr/local/perlbrew/bin/cpanm -n Devel::Cover::Report::Coveralls Test::More Test::Output
done
# Cleanup to remove any temp files.
perlbrew clean

73
docker/run-stow-tests.sh Executable file
View file

@ -0,0 +1,73 @@
#!/bin/bash
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
# Load perlbrew environment
# Load before setting safety to keep
# perlbrew scripts from breaking due to
# unset variables.
. /usr/local/perlbrew/etc/bashrc
# Standard safety protocol
set -ef -o pipefail
IFS=$'\n\t'
test_perl_version () {
perl_version="$1"
perlbrew use $perl_version
echo $(perl --version)
# Install stow
autoreconf --install
eval `perl -V:siteprefix`
./configure --prefix=$siteprefix && make
make cpanm
# Run tests
make distcheck
perl Build.PL && ./Build build && cover -test
./Build distcheck
}
if [[ -n "$LIST_PERL_VERSIONS" ]]; then
echo "Listing Perl versions available from perlbrew ..."
perlbrew list
elif [[ -z "$PERL_VERSION" ]]; then
echo "Testing all versions ..."
for perl_version in $(perlbrew list | sed 's/ //g'); do
test_perl_version $perl_version
done
make distclean
else
echo "Testing with Perl $PERL_VERSION"
# Test a specific version requested via $PERL_VERSION environment
# variable. Make sure set -e doesn't cause us to bail on failure
# before we start an interactive shell.
test_perl_version $PERL_VERSION || :
# N.B. Don't distclean since we probably want to debug this Perl
# version interactively.
cat <<EOF
To run a specific test, type something like:
perl -Ilib -Ibin -It t/cli_options.t
Code can be edited on the host and will immediately take effect inside
this container.
EOF
bash
fi

View file

@ -1,507 +0,0 @@
#!/bin/sh
# install - install a program, script, or datafile
scriptversion=2006-10-14.15
# This originates from X11R5 (mit/util/scripts/install.sh), which was
# later released in X11R6 (xc/config/util/install.sh) with the
# following copyright and license.
#
# Copyright (C) 1994 X Consortium
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# Except as contained in this notice, the name of the X Consortium shall not
# be used in advertising or otherwise to promote the sale, use or other deal-
# ings in this Software without prior written authorization from the X Consor-
# tium.
#
#
# FSF changes to this file are in the public domain.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
nl='
'
IFS=" "" $nl"
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
if test -z "$doit"; then
doit_exec=exec
else
doit_exec=$doit
fi
# Put in absolute file names if you don't have them in your path;
# or use environment vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
posix_glob=
posix_mkdir=
# Desired mode of installed file.
mode=0755
chmodcmd=$chmodprog
chowncmd=
chgrpcmd=
stripcmd=
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=
dst=
dir_arg=
dstarg=
no_target_directory=
usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
or: $0 [OPTION]... SRCFILES... DIRECTORY
or: $0 [OPTION]... -t DIRECTORY SRCFILES...
or: $0 [OPTION]... -d DIRECTORIES...
In the 1st form, copy SRCFILE to DSTFILE.
In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
In the 4th, create DIRECTORIES.
Options:
-c (ignored)
-d create directories instead of installing files.
-g GROUP $chgrpprog installed files to GROUP.
-m MODE $chmodprog installed files to MODE.
-o USER $chownprog installed files to USER.
-s $stripprog installed files.
-t DIRECTORY install into DIRECTORY.
-T report an error if DSTFILE is a directory.
--help display this help and exit.
--version display version info and exit.
Environment variables override the default commands:
CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG
"
while test $# -ne 0; do
case $1 in
-c) shift
continue;;
-d) dir_arg=true
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
--help) echo "$usage"; exit $?;;
-m) mode=$2
shift
shift
case $mode in
*' '* | *' '* | *'
'* | *'*'* | *'?'* | *'['*)
echo "$0: invalid mode: $mode" >&2
exit 1;;
esac
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-s) stripcmd=$stripprog
shift
continue;;
-t) dstarg=$2
shift
shift
continue;;
-T) no_target_directory=true
shift
continue;;
--version) echo "$0 $scriptversion"; exit $?;;
--) shift
break;;
-*) echo "$0: invalid option: $1" >&2
exit 1;;
*) break;;
esac
done
if test $# -ne 0 && test -z "$dir_arg$dstarg"; then
# When -d is used, all remaining arguments are directories to create.
# When -t is used, the destination is already specified.
# Otherwise, the last argument is the destination. Remove it from $@.
for arg
do
if test -n "$dstarg"; then
# $@ is not empty: it contains at least $arg.
set fnord "$@" "$dstarg"
shift # fnord
fi
shift # arg
dstarg=$arg
done
fi
if test $# -eq 0; then
if test -z "$dir_arg"; then
echo "$0: no input file specified." >&2
exit 1
fi
# It's OK to call `install-sh -d' without argument.
# This can happen when creating conditional directories.
exit 0
fi
if test -z "$dir_arg"; then
trap '(exit $?); exit' 1 2 13 15
# Set umask so as not to create temps with too-generous modes.
# However, 'strip' requires both read and write access to temps.
case $mode in
# Optimize common cases.
*644) cp_umask=133;;
*755) cp_umask=22;;
*[0-7])
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw='% 200'
fi
cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
*)
if test -z "$stripcmd"; then
u_plus_rw=
else
u_plus_rw=,u+rw
fi
cp_umask=$mode$u_plus_rw;;
esac
fi
for src
do
# Protect names starting with `-'.
case $src in
-*) src=./$src ;;
esac
if test -n "$dir_arg"; then
dst=$src
dstdir=$dst
test -d "$dstdir"
dstdir_status=$?
else
# Waiting for this to be detected by the "$cpprog $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if test ! -f "$src" && test ! -d "$src"; then
echo "$0: $src does not exist." >&2
exit 1
fi
if test -z "$dstarg"; then
echo "$0: no destination specified." >&2
exit 1
fi
dst=$dstarg
# Protect names starting with `-'.
case $dst in
-*) dst=./$dst ;;
esac
# If destination is a directory, append the input filename; won't work
# if double slashes aren't ignored.
if test -d "$dst"; then
if test -n "$no_target_directory"; then
echo "$0: $dstarg: Is a directory" >&2
exit 1
fi
dstdir=$dst
dst=$dstdir/`basename "$src"`
dstdir_status=0
else
# Prefer dirname, but fall back on a substitute if dirname fails.
dstdir=`
(dirname "$dst") 2>/dev/null ||
expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
X"$dst" : 'X\(//\)[^/]' \| \
X"$dst" : 'X\(//\)$' \| \
X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
echo X"$dst" |
sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
s//\1/
q
}
/^X\(\/\/\)[^/].*/{
s//\1/
q
}
/^X\(\/\/\)$/{
s//\1/
q
}
/^X\(\/\).*/{
s//\1/
q
}
s/.*/./; q'
`
test -d "$dstdir"
dstdir_status=$?
fi
fi
obsolete_mkdir_used=false
if test $dstdir_status != 0; then
case $posix_mkdir in
'')
# Create intermediate dirs using mode 755 as modified by the umask.
# This is like FreeBSD 'install' as of 1997-10-28.
umask=`umask`
case $stripcmd.$umask in
# Optimize common cases.
*[2367][2367]) mkdir_umask=$umask;;
.*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
*[0-7])
mkdir_umask=`expr $umask + 22 \
- $umask % 100 % 40 + $umask % 20 \
- $umask % 10 % 4 + $umask % 2
`;;
*) mkdir_umask=$umask,go-w;;
esac
# With -d, create the new directory with the user-specified mode.
# Otherwise, rely on $mkdir_umask.
if test -n "$dir_arg"; then
mkdir_mode=-m$mode
else
mkdir_mode=
fi
posix_mkdir=false
case $umask in
*[123567][0-7][0-7])
# POSIX mkdir -p sets u+wx bits regardless of umask, which
# is incompatible with FreeBSD 'install' when (umask & 300) != 0.
;;
*)
tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0
if (umask $mkdir_umask &&
exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1
then
if test -z "$dir_arg" || {
# Check for POSIX incompatibilities with -m.
# HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
# other-writeable bit of parent directory when it shouldn't.
# FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
ls_ld_tmpdir=`ls -ld "$tmpdir"`
case $ls_ld_tmpdir in
d????-?r-*) different_mode=700;;
d????-?--*) different_mode=755;;
*) false;;
esac &&
$mkdirprog -m$different_mode -p -- "$tmpdir" && {
ls_ld_tmpdir_1=`ls -ld "$tmpdir"`
test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
}
}
then posix_mkdir=:
fi
rmdir "$tmpdir/d" "$tmpdir"
else
# Remove any dirs left behind by ancient mkdir implementations.
rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null
fi
trap '' 0;;
esac;;
esac
if
$posix_mkdir && (
umask $mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
)
then :
else
# The umask is ridiculous, or mkdir does not conform to POSIX,
# or it failed possibly due to a race condition. Create the
# directory the slow way, step by step, checking for races as we go.
case $dstdir in
/*) prefix=/ ;;
-*) prefix=./ ;;
*) prefix= ;;
esac
case $posix_glob in
'')
if (set -f) 2>/dev/null; then
posix_glob=true
else
posix_glob=false
fi ;;
esac
oIFS=$IFS
IFS=/
$posix_glob && set -f
set fnord $dstdir
shift
$posix_glob && set +f
IFS=$oIFS
prefixes=
for d
do
test -z "$d" && continue
prefix=$prefix$d
if test -d "$prefix"; then
prefixes=
else
if $posix_mkdir; then
(umask=$mkdir_umask &&
$doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
# Don't fail if two instances are running concurrently.
test -d "$prefix" || exit 1
else
case $prefix in
*\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
*) qprefix=$prefix;;
esac
prefixes="$prefixes '$qprefix'"
fi
fi
prefix=$prefix/
done
if test -n "$prefixes"; then
# Don't fail if two instances are running concurrently.
(umask $mkdir_umask &&
eval "\$doit_exec \$mkdirprog $prefixes") ||
test -d "$dstdir" || exit 1
obsolete_mkdir_used=true
fi
fi
fi
if test -n "$dir_arg"; then
{ test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
{ test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
{ test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
else
# Make a couple of temp file names in the proper directory.
dsttmp=$dstdir/_inst.$$_
rmtmp=$dstdir/_rm.$$_
# Trap to clean up those temp files at exit.
trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
# Copy the file name to the temp name.
(umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
# and set any options; do chmod last to preserve setuid bits.
#
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $cpprog $src $dsttmp" command.
#
{ test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \
&& { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \
&& { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \
&& { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
# Now rename the file to the real destination.
{ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \
|| {
# The rename failed, perhaps because mv can't rename something else
# to itself, or perhaps because mv is so ancient that it does not
# support -f.
# Now remove or move aside any old file at destination location.
# We try this two ways since rm can't unlink itself on some
# systems and the destination file might be busy for other
# reasons. In this case, the final cleanup might fail but the new
# file should still install successfully.
{
if test -f "$dst"; then
$doit $rmcmd -f "$dst" 2>/dev/null \
|| { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \
&& { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\
|| {
echo "$0: cannot unlink or rename $dst" >&2
(exit 1); exit 1
}
else
:
fi
} &&
# Now rename the file to the real destination.
$doit $mvcmd "$dsttmp" "$dst"
}
} || exit 1
trap '' 0
fi
done
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End:

2506
lib/Stow.pm.in Executable file

File diff suppressed because it is too large Load diff

267
lib/Stow/Util.pm.in Normal file
View file

@ -0,0 +1,267 @@
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
package Stow::Util;
=head1 NAME
Stow::Util - general utilities
=head1 SYNOPSIS
use Stow::Util qw(debug set_debug_level error ...);
=head1 DESCRIPTION
Supporting utility routines for L<Stow>.
=cut
use strict;
use warnings;
use File::Spec;
use POSIX qw(getcwd);
use base qw(Exporter);
our @EXPORT_OK = qw(
error debug set_debug_level set_test_mode
join_paths parent canon_path restore_cwd
adjust_dotfile unadjust_dotfile
);
our $ProgramName = 'stow';
our $VERSION = '@VERSION@';
#############################################################################
#
# General Utilities: nothing stow specific here.
#
#############################################################################
=head1 IMPORTABLE SUBROUTINES
=head2 error($format, @args)
Outputs an error message in a consistent form and then dies.
=cut
sub error {
my ($format, @args) = @_;
die "$ProgramName: ERROR: " . sprintf($format, @args) . "\n";
}
=head2 set_debug_level($level)
Sets verbosity level for C<debug()>.
=cut
our $debug_level = 0;
sub set_debug_level {
my ($level) = @_;
$debug_level = $level;
}
=head2 set_test_mode($on_or_off)
Sets testmode on or off.
=cut
our $test_mode = 0;
sub set_test_mode {
my ($on_or_off) = @_;
if ($on_or_off) {
$test_mode = 1;
}
else {
$test_mode = 0;
}
}
=head2 debug($level[, $indent_level], $msg)
Logs to STDERR based on C<$debug_level> setting. C<$level> is the
minimum verbosity level required to output C<$msg>. All output is to
STDERR to preserve backward compatibility, except for in test mode,
when STDOUT is used instead. In test mode, the verbosity can be
overridden via the C<TEST_VERBOSE> environment variable.
Verbosity rules:
=over 4
=item 0: errors only
=item >= 1: print operations: LINK/UNLINK/MKDIR/RMDIR/MV
=item >= 2: print operation exceptions
e.g. "_this_ already points to _that_", skipping, deferring,
overriding, fixing invalid links
=item >= 3: print trace detail: trace: stow/unstow/package/contents/node
=item >= 4: debug helper routines
=item >= 5: debug ignore lists
=back
=cut
sub debug {
my $level = shift;
my $indent_level;
# Maintain backwards-compatibility in case anyone's relying on this.
$indent_level = $_[0] =~ /^\d+$/ ? shift : 0;
my $msg = shift;
if ($debug_level >= $level) {
my $indent = ' ' x $indent_level;
if ($test_mode) {
print "# $indent$msg\n";
}
else {
warn "$indent$msg\n";
}
}
}
#===== METHOD ===============================================================
# Name : join_paths()
# Purpose : concatenates given paths
# Parameters: path1, path2, ... => paths
# Returns : concatenation of given paths
# Throws : n/a
# Comments : Factors out some redundant path elements:
# : '//' => '/', and 'a/b/../c' => 'a/c'. We need this function
# : with this behaviour, even though b could be a symlink to
# : elsewhere, as noted in the perldoc for File::Spec->canonpath().
# : This behaviour is deliberately different to
# : Stow::Util::canon_path(), because the way join_paths() is used
# : relies on this. Firstly, there is no guarantee that the paths
# : exist, so a filesystem check is inappropriate.
# :
# : For example, it's used to determine the path from the target
# : directory to a symlink destination. So if a symlink
# : path/to/target/a/b/c points to ../../../stow/pkg/a/b/c,
# : then joining path/to/target/a/b with ../../../stow/pkg/a/b/c
# : yields path/to/stow/pkg/a/b/c, and it's crucial that the
# : path/to/stow prefix matches a recognisable stow directory.
#============================================================================
sub join_paths {
my @paths = @_;
debug(5, 5, "| Joining: @paths");
my $result = '';
for my $part (@paths) {
next if ! length $part; # probably shouldn't happen?
$part = File::Spec->canonpath($part);
if (substr($part, 0, 1) eq '/') {
$result = $part; # absolute path, so ignore all previous parts
}
else {
$result .= '/' if length $result && $result ne '/';
$result .= $part;
}
debug(7, 6, "| Join now: $result");
}
debug(6, 5, "| Joined: $result");
# Need this to remove any initial ./
$result = File::Spec->canonpath($result);
# remove foo/..
1 while $result =~ s,(^|/)(?!\.\.)[^/]+/\.\.(/|$),$1,;
debug(6, 5, "| After .. removal: $result");
$result = File::Spec->canonpath($result);
debug(5, 5, "| Final join: $result");
return $result;
}
#===== METHOD ===============================================================
# Name : parent
# Purpose : find the parent of the given path
# Parameters: @path => components of the path
# Returns : returns a path string
# Throws : n/a
# Comments : allows you to send multiple chunks of the path
# : (this feature is currently not used)
#============================================================================
sub parent {
my @path = @_;
my $path = join '/', @_;
my @elts = split m{/+}, $path;
pop @elts;
return join '/', @elts;
}
#===== METHOD ===============================================================
# Name : canon_path
# Purpose : find absolute canonical path of given path
# Parameters: $path
# Returns : absolute canonical path
# Throws : n/a
# Comments : is this significantly different from File::Spec->rel2abs?
#============================================================================
sub canon_path {
my ($path) = @_;
my $cwd = getcwd();
chdir($path) or error("canon_path: cannot chdir to $path from $cwd");
my $canon_path = getcwd();
restore_cwd($cwd);
return $canon_path;
}
sub restore_cwd {
my ($prev) = @_;
chdir($prev) or error("Your current directory $prev seems to have vanished");
}
sub adjust_dotfile {
my ($pkg_node) = @_;
(my $adjusted = $pkg_node) =~ s/^dot-([^.])/.$1/;
return $adjusted;
}
# Needed when unstowing with --compat and --dotfiles
sub unadjust_dotfile {
my ($target_node) = @_;
return $target_node if $target_node =~ /^\.\.?$/;
(my $adjusted = $target_node) =~ s/^\./dot-/;
return $adjusted;
}
=head1 BUGS
=head1 SEE ALSO
=cut
1;
# Local variables:
# mode: perl
# end:
# vim: ft=perl

201
mdate-sh
View file

@ -1,201 +0,0 @@
#!/bin/sh
# Get modification time of a file or directory and pretty-print it.
scriptversion=2005-06-29.22
# Copyright (C) 1995, 1996, 1997, 2003, 2004, 2005 Free Software
# Foundation, Inc.
# written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, June 1995
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
# This file is maintained in Automake, please report
# bugs to <bug-automake@gnu.org> or send patches to
# <automake-patches@gnu.org>.
case $1 in
'')
echo "$0: No file. Try \`$0 --help' for more information." 1>&2
exit 1;
;;
-h | --h*)
cat <<\EOF
Usage: mdate-sh [--help] [--version] FILE
Pretty-print the modification time of FILE.
Report bugs to <bug-automake@gnu.org>.
EOF
exit $?
;;
-v | --v*)
echo "mdate-sh $scriptversion"
exit $?
;;
esac
# Prevent date giving response in another language.
LANG=C
export LANG
LC_ALL=C
export LC_ALL
LC_TIME=C
export LC_TIME
# GNU ls changes its time format in response to the TIME_STYLE
# variable. Since we cannot assume `unset' works, revert this
# variable to its documented default.
if test "${TIME_STYLE+set}" = set; then
TIME_STYLE=posix-long-iso
export TIME_STYLE
fi
save_arg1=$1
# Find out how to get the extended ls output of a file or directory.
if ls -L /dev/null 1>/dev/null 2>&1; then
ls_command='ls -L -l -d'
else
ls_command='ls -l -d'
fi
# A `ls -l' line looks as follows on OS/2.
# drwxrwx--- 0 Aug 11 2001 foo
# This differs from Unix, which adds ownership information.
# drwxrwx--- 2 root root 4096 Aug 11 2001 foo
#
# To find the date, we split the line on spaces and iterate on words
# until we find a month. This cannot work with files whose owner is a
# user named `Jan', or `Feb', etc. However, it's unlikely that `/'
# will be owned by a user whose name is a month. So we first look at
# the extended ls output of the root directory to decide how many
# words should be skipped to get the date.
# On HPUX /bin/sh, "set" interprets "-rw-r--r--" as options, so the "x" below.
set x`ls -l -d /`
# Find which argument is the month.
month=
command=
until test $month
do
shift
# Add another shift to the command.
command="$command shift;"
case $1 in
Jan) month=January; nummonth=1;;
Feb) month=February; nummonth=2;;
Mar) month=March; nummonth=3;;
Apr) month=April; nummonth=4;;
May) month=May; nummonth=5;;
Jun) month=June; nummonth=6;;
Jul) month=July; nummonth=7;;
Aug) month=August; nummonth=8;;
Sep) month=September; nummonth=9;;
Oct) month=October; nummonth=10;;
Nov) month=November; nummonth=11;;
Dec) month=December; nummonth=12;;
esac
done
# Get the extended ls output of the file or directory.
set dummy x`eval "$ls_command \"\$save_arg1\""`
# Remove all preceding arguments
eval $command
# Because of the dummy argument above, month is in $2.
#
# On a POSIX system, we should have
#
# $# = 5
# $1 = file size
# $2 = month
# $3 = day
# $4 = year or time
# $5 = filename
#
# On Darwin 7.7.0 and 7.6.0, we have
#
# $# = 4
# $1 = day
# $2 = month
# $3 = year or time
# $4 = filename
# Get the month.
case $2 in
Jan) month=January; nummonth=1;;
Feb) month=February; nummonth=2;;
Mar) month=March; nummonth=3;;
Apr) month=April; nummonth=4;;
May) month=May; nummonth=5;;
Jun) month=June; nummonth=6;;
Jul) month=July; nummonth=7;;
Aug) month=August; nummonth=8;;
Sep) month=September; nummonth=9;;
Oct) month=October; nummonth=10;;
Nov) month=November; nummonth=11;;
Dec) month=December; nummonth=12;;
esac
case $3 in
???*) day=$1;;
*) day=$3; shift;;
esac
# Here we have to deal with the problem that the ls output gives either
# the time of day or the year.
case $3 in
*:*) set `date`; eval year=\$$#
case $2 in
Jan) nummonthtod=1;;
Feb) nummonthtod=2;;
Mar) nummonthtod=3;;
Apr) nummonthtod=4;;
May) nummonthtod=5;;
Jun) nummonthtod=6;;
Jul) nummonthtod=7;;
Aug) nummonthtod=8;;
Sep) nummonthtod=9;;
Oct) nummonthtod=10;;
Nov) nummonthtod=11;;
Dec) nummonthtod=12;;
esac
# For the first six month of the year the time notation can also
# be used for files modified in the last year.
if (expr $nummonth \> $nummonthtod) > /dev/null;
then
year=`expr $year - 1`
fi;;
*) year=$3;;
esac
# The result.
echo $day $month $year
# Local Variables:
# mode: shell-script
# sh-indentation: 2
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End:

367
missing
View file

@ -1,367 +0,0 @@
#! /bin/sh
# Common stub for a few missing GNU programs while installing.
scriptversion=2006-05-10.23
# Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006
# Free Software Foundation, Inc.
# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
if test $# -eq 0; then
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
fi
run=:
sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p'
sed_minuso='s/.* -o \([^ ]*\).*/\1/p'
# In the cases where this matters, `missing' is being run in the
# srcdir already.
if test -f configure.ac; then
configure_ac=configure.ac
else
configure_ac=configure.in
fi
msg="missing on your system"
case $1 in
--run)
# Try to run requested program, and just exit if it succeeds.
run=
shift
"$@" && exit 0
# Exit code 63 means version mismatch. This often happens
# when the user try to use an ancient version of a tool on
# a file that requires a minimum version. In this case we
# we should proceed has if the program had been absent, or
# if --run hadn't been passed.
if test $? = 63; then
run=:
msg="probably too old"
fi
;;
-h|--h|--he|--hel|--help)
echo "\
$0 [OPTION]... PROGRAM [ARGUMENT]...
Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an
error status if there is no known handling for PROGRAM.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
--run try to run the given command, and emulate it if it fails
Supported PROGRAM values:
aclocal touch file \`aclocal.m4'
autoconf touch file \`configure'
autoheader touch file \`config.h.in'
autom4te touch the output file, or create a stub one
automake touch all \`Makefile.in' files
bison create \`y.tab.[ch]', if possible, from existing .[ch]
flex create \`lex.yy.c', if possible, from existing .c
help2man touch the output file
lex create \`lex.yy.c', if possible, from existing .c
makeinfo touch the output file
tar try tar, gnutar, gtar, then tar without non-portable flags
yacc create \`y.tab.[ch]', if possible, from existing .[ch]
Send bug reports to <bug-automake@gnu.org>."
exit $?
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing $scriptversion (GNU Automake)"
exit $?
;;
-*)
echo 1>&2 "$0: Unknown \`$1' option"
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
;;
esac
# Now exit if we have it, but it failed. Also exit now if we
# don't have it and --version was passed (most likely to detect
# the program).
case $1 in
lex|yacc)
# Not GNU programs, they don't have --version.
;;
tar)
if test -n "$run"; then
echo 1>&2 "ERROR: \`tar' requires --run"
exit 1
elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
exit 1
fi
;;
*)
if test -z "$run" && ($1 --version) > /dev/null 2>&1; then
# We have it, but it failed.
exit 1
elif test "x$2" = "x--version" || test "x$2" = "x--help"; then
# Could not run --version or --help. This is probably someone
# running `$TOOL --version' or `$TOOL --help' to check whether
# $TOOL exists and not knowing $TOOL uses missing.
exit 1
fi
;;
esac
# If it does not exist, or fails to run (possibly an outdated version),
# try to emulate it.
case $1 in
aclocal*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`acinclude.m4' or \`${configure_ac}'. You might want
to install the \`Automake' and \`Perl' packages. Grab them from
any GNU archive site."
touch aclocal.m4
;;
autoconf)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`${configure_ac}'. You might want to install the
\`Autoconf' and \`GNU m4' packages. Grab them from any GNU
archive site."
touch configure
;;
autoheader)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`acconfig.h' or \`${configure_ac}'. You might want
to install the \`Autoconf' and \`GNU m4' packages. Grab them
from any GNU archive site."
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
test -z "$files" && files="config.h"
touch_files=
for f in $files; do
case $f in
*:*) touch_files="$touch_files "`echo "$f" |
sed -e 's/^[^:]*://' -e 's/:.*//'`;;
*) touch_files="$touch_files $f.in";;
esac
done
touch $touch_files
;;
automake*)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
You might want to install the \`Automake' and \`Perl' packages.
Grab them from any GNU archive site."
find . -type f -name Makefile.am -print |
sed 's/\.am$/.in/' |
while read f; do touch "$f"; done
;;
autom4te)
echo 1>&2 "\
WARNING: \`$1' is needed, but is $msg.
You might have modified some files without having the
proper tools for further handling them.
You can get \`$1' as part of \`Autoconf' from any GNU
archive site."
file=`echo "$*" | sed -n "$sed_output"`
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
if test -f "$file"; then
touch $file
else
test -z "$file" || exec >$file
echo "#! /bin/sh"
echo "# Created by GNU Automake missing as a replacement of"
echo "# $ $@"
echo "exit 0"
chmod +x $file
exit 1
fi
;;
bison|yacc)
echo 1>&2 "\
WARNING: \`$1' $msg. You should only need it if
you modified a \`.y' file. You may need the \`Bison' package
in order for those modifications to take effect. You can get
\`Bison' from any GNU archive site."
rm -f y.tab.c y.tab.h
if test $# -ne 1; then
eval LASTARG="\${$#}"
case $LASTARG in
*.y)
SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'`
if test -f "$SRCFILE"; then
cp "$SRCFILE" y.tab.c
fi
SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'`
if test -f "$SRCFILE"; then
cp "$SRCFILE" y.tab.h
fi
;;
esac
fi
if test ! -f y.tab.h; then
echo >y.tab.h
fi
if test ! -f y.tab.c; then
echo 'main() { return 0; }' >y.tab.c
fi
;;
lex|flex)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a \`.l' file. You may need the \`Flex' package
in order for those modifications to take effect. You can get
\`Flex' from any GNU archive site."
rm -f lex.yy.c
if test $# -ne 1; then
eval LASTARG="\${$#}"
case $LASTARG in
*.l)
SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'`
if test -f "$SRCFILE"; then
cp "$SRCFILE" lex.yy.c
fi
;;
esac
fi
if test ! -f lex.yy.c; then
echo 'main() { return 0; }' >lex.yy.c
fi
;;
help2man)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a dependency of a manual page. You may need the
\`Help2man' package in order for those modifications to take
effect. You can get \`Help2man' from any GNU archive site."
file=`echo "$*" | sed -n "$sed_output"`
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
if test -f "$file"; then
touch $file
else
test -z "$file" || exec >$file
echo ".ab help2man is required to generate this page"
exit 1
fi
;;
makeinfo)
echo 1>&2 "\
WARNING: \`$1' is $msg. You should only need it if
you modified a \`.texi' or \`.texinfo' file, or any other file
indirectly affecting the aspect of the manual. The spurious
call might also be the consequence of using a buggy \`make' (AIX,
DU, IRIX). You might want to install the \`Texinfo' package or
the \`GNU make' package. Grab either from any GNU archive site."
# The file to touch is that specified with -o ...
file=`echo "$*" | sed -n "$sed_output"`
test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"`
if test -z "$file"; then
# ... or it is the one specified with @setfilename ...
infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'`
file=`sed -n '
/^@setfilename/{
s/.* \([^ ]*\) *$/\1/
p
q
}' $infile`
# ... or it is derived from the source name (dir/f.texi becomes f.info)
test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info
fi
# If the file does not exist, the user really needs makeinfo;
# let's fail without touching anything.
test -f $file || exit 1
touch $file
;;
tar)
shift
# We have already tried tar in the generic part.
# Look for gnutar/gtar before invocation to avoid ugly error
# messages.
if (gnutar --version > /dev/null 2>&1); then
gnutar "$@" && exit 0
fi
if (gtar --version > /dev/null 2>&1); then
gtar "$@" && exit 0
fi
firstarg="$1"
if shift; then
case $firstarg in
*o*)
firstarg=`echo "$firstarg" | sed s/o//`
tar "$firstarg" "$@" && exit 0
;;
esac
case $firstarg in
*h*)
firstarg=`echo "$firstarg" | sed s/h//`
tar "$firstarg" "$@" && exit 0
;;
esac
fi
echo 1>&2 "\
WARNING: I can't seem to be able to run \`tar' with the given arguments.
You may want to install GNU tar or Free paxutils, or check the
command line arguments."
exit 1
;;
*)
echo 1>&2 "\
WARNING: \`$1' is needed, and is $msg.
You might have modified some files without having the
proper tools for further handling them. Check the \`README' file,
it often tells you about the needed prerequisites for installing
this package. You may also peek at any GNU archive site, in case
some other package would contain this missing \`$1' program."
exit 1
;;
esac
exit 0
# Local variables:
# eval: (add-hook 'write-file-hooks 'time-stamp)
# time-stamp-start: "scriptversion="
# time-stamp-format: "%:y-%02m-%02d.%02H"
# time-stamp-end: "$"
# End:

View file

@ -1,4 +0,0 @@
@set UPDATED 20 February 2008
@set UPDATED-MONTH February 2008
@set EDITION 2.0.2
@set VERSION 2.0.2

448
stow.8
View file

@ -1,448 +0,0 @@
.TH STOW 8 "28 March 1998"
.SH NAME
stow \- software package installation manager
.SH SYNOPSIS
.B stow
.RI [ options ]
.IR package ...
.SH DESCRIPTION
This manual page describes GNU Stow 1.3.3, a program for managing the
installation of software packages. This is not the definitive
documentation for stow; for that, see the info manual.
.PP
Stow is a tool for managing the installation of multiple software
packages in the same run-time directory tree. One historical difficulty
of this task has been the need to administer, upgrade, install, and
remove files in independent packages without confusing them with other
files sharing the same filesystem space. For instance, it is common to
install Perl and Emacs in
.IR /usr/local .
When one does so, one winds up
(as of Perl 4.036 and Emacs 19.22)
with the following files in
.IR /usr/local/man/man1 :
.IR a2p.1 ;
.IR ctags.1 ;
.IR emacs.1 ;
.IR etags.1 ;
.IR h2ph.1 ;
.IR perl.1 ;
and
.IR s2p.1 .
Now
suppose it's time to uninstall Perl. Which man pages get removed?
Obviously
.I perl.1
is one of them, but it should not be the
administrator's responsibility to memorize the ownership of individual
files by separate packages.
.PP
The approach used by Stow is to install each package into its own
tree, then use symbolic links to make it appear as though the files are
installed in the common tree. Administration can be performed in the
package's private tree in isolation from clutter from other packages.
Stow can then be used to update the symbolic links. The structure of
each private tree should reflect the desired structure in the common
tree; i.e. (in the typical case) there should be a
.I bin
directory
containing executables, a
.I man/man1
directory containing section 1 man
pages, and so on.
.PP
Stow was inspired by Carnegie Mellon's Depot program, but is
substantially simpler and safer. Whereas Depot required database files
to keep things in sync, Stow stores no extra state between runs, so
there's no danger (as there was in Depot) of mangling directories when
file hierarchies don't match the database. Also unlike Depot, Stow will
never delete any files, directories, or links that appear in a Stow
directory (e.g.,
.IR /usr/local/stow/emacs ),
so it's always possible to
rebuild the target tree (e.g.,
.IR /usr/local ).
.SH TERMINOLOGY
A ``package'' is a related collection of files and directories that
you wish to administer as a unit--e.g., Perl or Emacs--and that needs
to be installed in a particular directory structure--e.g., with
.IR bin ,
.IR lib ,
and
.I man
subdirectories.
.PP
A ``target directory'' is the root of a tree in which one or more
packages wish to
.B appear
to be installed. A common, but by no means
the only such location is
.IR /usr/local .
The examples in this manual page
will use
.I /usr/local
as the target directory.
.PP
A ``stow directory'' is the root of a tree containing separate
packages in private subtrees. When Stow runs, it uses the current
directory as the default stow directory. The examples in this manual
page will use
.I /usr/local/stow
as the stow directory, so that individual
packages will be, for example,
.I /usr/local/stow/perl
and
.IR /usr/local/stow/emacs .
.PP
An ``installation image'' is the layout of files and directories
required by a package, relative to the target directory. Thus, the
installation image for Perl includes: a
.I bin
directory containing
.I perl
and
.I a2p
(among others); an
.I info
directory containing Texinfo
documentation; a
.I lib/perl
directory containing Perl libraries; and a
.I man/man1
directory containing man pages.
.PP
A ``package directory'' is the root of a tree containing the
installation image for a particular package. Each package directory
must reside in a stow directory--e.g., the package directory
.I /usr/local/stow/perl
must reside in the stow directory
.IR /usr/local/stow .
The ``name'' of a package is the name of its
directory within the stow directory--e.g.,
.IR perl .
.PP
Thus, the Perl executable might reside in
.IR /usr/local/stow/perl/bin/perl ,
where
.I /usr/local
is the target
directory,
.I /usr/local/stow
is the stow directory,
.I /usr/local/stow/perl
is the package directory, and
.I bin/perl
within
is part of the installation image.
.PP
A ``symlink'' is a symbolic link. A symlink can be ``relative'' or
``absolute''. An absolute symlink names a full path; that is, one
starting from
.IR / .
A relative symlink names a relative path; that is,
one not starting from
.IR / .
The target of a relative symlink is
computed starting from the symlink's own directory. Stow only creates
relative symlinks.
.SH OPTIONS
The stow directory is assumed to be the current directory, and the
target directory is assumed to be the parent of the current directory
(so it is typical to execute
.I stow
from the directory
.IR /usr/local/stow ).
Each
.I package
given on the command line is the name of a package in the stow
directory (e.g.,
.IR perl ).
By default, they are installed into the
target directory (but they can be deleted instead using `-D').
.TP
.I -n
.TP
.I --no
Do not perform any operations that modify the filesystem; merely
show what would happen. Since no actual operations are performed,
.I stow -n
could report conflicts when none would actually take
place (see ``Conflicts'' in the info manual);
but it won't fail to report conflicts
that
.B would
take place.
.TP
.I -c
.TP
.I --conflicts
Do not exit immediately when a conflict is encountered. This
option implies `-n', and is used to search for all conflicts that
might arise from an actual Stow operation. As with `-n', however,
false conflicts might be reported (see ``Conflicts'' in the info manual).
.TP
.I "-d DIR"
.TP
.I --dir=DIR
Set the stow directory to DIR instead of the current directory.
This also has the effect of making the default target directory be
the parent of DIR.
.TP
.I "-t DIR"
.TP
.I --target=DIR
Set the target directory to DIR instead of the parent of the stow
directory.
.TP
.I -v
.TP
.I --verbose[=N]
Send verbose output to standard error describing what Stow is
doing. Verbosity levels are 0, 1, 2, and 3; 0 is the default.
Using `-v' or `--verbose' increases the verbosity by one; using
`--verbose=N' sets it to N.
.TP
.I -D
.TP
.I --delete
Delete packages from the target directory rather than installing
them.
.TP
.I -R
.TP
.I --restow
Restow packages (first unstow, then stow again). This is useful
for pruning obsolete symlinks from the target tree after updating
the software in a package.
.TP
.I -V
.TP
.I --version
Show Stow version number, and exit.
.TP
.I -h
.TP
.I --help
Show Stow command syntax, and exit.
.SH "INSTALLING PACKAGES"
The default action of Stow is to install a package. This means
creating symlinks in the target tree that point into the package tree.
Stow attempts to do this with as few symlinks as possible; in other
words, if Stow can create a single symlink that points to an entire
subtree within the package tree, it will choose to do that rather than
create a directory in the target tree and populate it with symlinks.
.PP
For example, suppose that no packages have yet been installed in
.IR /usr/local ;
it's completely empty (except for the
.I stow
subdirectory, of course). Now suppose the Perl package is installed.
Recall that it includes the following directories in its installation
image:
.IR bin ;
.IR info ;
.IR lib/perl ;
.IR man/man1 .
Rather than creating
the directory
.I /usr/local/bin
and populating it with symlinks to
.I ../stow/perl/bin/perl
and
.I ../stow/perl/bin/a2p
(and so on), Stow
will create a single symlink,
.IR /usr/local/bin ,
which points to
.IR stow/perl/bin .
In this way, it still works to refer to
.I /usr/local/bin/perl
and
.IR /usr/local/bin/a2p ,
and fewer symlinks have
been created. This is called ``tree folding'', since an entire subtree
is ``folded'' into a single symlink.
.PP
To complete this example, Stow will also create the symlink
.I /usr/local/info
pointing to
.IR stow/perl/info ;
the symlink
.I /usr/local/lib
pointing to
.IR stow/perl/lib ;
and the symlink
.I /usr/local/man
pointing to
.IR stow/perl/man .
.PP
Now suppose that instead of installing the Perl package into an empty
target tree, the target tree is not empty to begin with. Instead, it
contains several files and directories installed under a different
system-administration philosophy. In particular,
.I /usr/local/bin
already exists and is a directory, as are
.I /usr/local/lib
and
.IR /usr/local/man/man1 .
In this case, Stow will descend into
.I /usr/local/bin
and create symlinks to
.I ../stow/perl/bin/perl
and
.I ../stow/perl/bin/a2p
(etc.), and it will descend into
.I /usr/local/lib
and create the tree-folding symlink
.I perl
pointing to
.IR ../stow/perl/lib/perl ,
and so on. As a rule, Stow only descends as
far as necessary into the target tree when it can create a tree-folding
symlink.
.PP
The time often comes when a tree-folding symlink has to be undone
because another package uses one or more of the folded subdirectories in
its installation image. This operation is called ``splitting open'' a
folded tree. It involves removing the original symlink from the target
tree, creating a true directory in its place, and then populating the
new directory with symlinks to the newly-installed package
.B and
to the
old package that used the old symlink. For example, suppose that after
installing Perl into an empty
.IR /usr/local ,
we wish to install Emacs.
Emacs's installation image includes a
.I bin
directory containing the
.I emacs
and
.I etags
executables, among others. Stow must make these
files appear to be installed in
.IR /usr/local/bin ,
but presently
.I /usr/local/bin
is a symlink to
.IR stow/perl/bin .
Stow therefore takes
the following steps: the symlink
.I /usr/local/bin
is deleted; the
directory
.I /usr/local/bin
is created; links are made from
.I /usr/local/bin
to
.I ../stow/emacs/bin/emacs
and
.IR ../stow/emacs/bin/etags ;
and links are made from
.I /usr/local/bin
to
.I ../stow/perl/bin/perl
and
.IR ../stow/perl/bin/a2p .
.PP
When splitting open a folded tree, Stow makes sure that the symlink
it is about to remove points inside a valid package in the current stow
directory.
.BR "Stow will never delete anything that it doesn't own" .
Stow ``owns'' everything living in the target tree that points into a
package in the stow directory. Anything Stow owns, it can recompute if
lost. Note that by this definition, Stow doesn't ``own'' anything
.B in
the stow directory or in any of the packages.
.PP
If Stow needs to create a directory or a symlink in the target tree
and it cannot because that name is already in use and is not owned by
Stow, then a conflict has arisen. See ``Conflicts'' in the info manual.
.SH "DELETING PACKAGES"
When the `-D' option is given, the action of Stow is to delete a
package from the target tree. Note that Stow will not delete anything
it doesn't ``own''. Deleting a package does
.B not
mean removing it from
the stow directory or discarding the package tree.
.PP
To delete a package, Stow recursively scans the target tree,
skipping over the stow directory (since that is usually a subdirectory
of the target tree) and any other stow directories it encounters (see
``Multiple stow directories'' in the info manual). Any symlink it finds that points into
the package being deleted is removed. Any directory that contained
only symlinks to the package being deleted is removed. Any directory
that, after removing symlinks and empty subdirectories, contains only
symlinks to a single other package, is considered to be a previously
``folded'' tree that was ``split open.'' Stow will re-fold the tree by
removing the symlinks to the surviving package, removing the directory,
then linking the directory back to the surviving package.
.SH "SEE ALSO"
The info manual ``Stow 1.3.3:
Managing the installation of software packages''
by Bob Glickstein, Zanshin Software, Inc.
.SH BUGS
Please report bugs in Stow using the Debian bug tracking system.
.PP
Currently known bugs include:
.IP *
The empty-directory problem. If package FOO includes an empty
directory--say, FOO/BAR--then:
.IP
1.
if no other package has a BAR subdirectory, everything's fine.
.IP
2.
if another stowed package, QUUX, has a BAR subdirectory, then
when stowing, TARGETDIR/BAR will be ``split open'' and the
contents of QUUX/BAR will be individually stowed. So far, so
good. But when unstowing QUUX, TARGETDIR/BAR will be
removed, even though FOO/BAR needs it to remain. A
workaround for this problem is to create a file in FOO/BAR as
a placeholder. If you name that file
.IR .placeholder ,
it will
be easy to find and remove such files when this bug is fixed.
.IP *
When using multiple stow directories (see ``Multiple stow
directories'' in the info manual), Stow fails to ``split open'' tree-folding symlinks
(see ``Installing packages'' in the info manual) that point into a stow directory
which is not the one in use by the current Stow command. Before
failing, it should search the target of the link to see whether
any element of the path contains a
.I .stow
file. If it finds one,
it can ``learn'' about the cooperating stow directory to
short-circuit the
.I .stow
search the next time it encounters a
tree-folding symlink.
.SH AUTHOR
This man page was constructed by Charles Briscoe-Smith from
parts of Stow's info manual. That manual contained the following
notice, which, as it says, applied to this manual page, too. The text
of the section entitled ``GNU General Public License'' can be found in
the file
.I /usr/share/common-licenses/GPL
on any Debian GNU/Linux system. If you don't have access to a Debian
system, or the GPL is not there, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307, USA.
.IP
Software and documentation Copyright (C) 1993, 1994, 1995, 1996 by
Bob Glickstein <bobg+stow@zanshin.com>.
.IP
Permission is granted to make and distribute verbatim copies of this
manual provided the copyright notice and this permission notice are
preserved on all copies.
.IP
Permission is granted to copy and distribute modified versions of
this manual under the conditions for verbatim copying, provided also
that the section entitled ``GNU General Public License'' is included with
the modified manual, and provided that the entire resulting derived
work is distributed under the terms of a permission notice identical to
this one.
.IP
Permission is granted to copy and distribute translations of this
manual into another language, under the above conditions for modified
versions, except that this permission notice may be stated in a
translation approved by the Free Software Foundation.

1794
stow.in

File diff suppressed because it is too large Load diff

1335
stow.info

File diff suppressed because it is too large Load diff

1440
stow.texi

File diff suppressed because it is too large Load diff

View file

@ -1,64 +1,75 @@
#!/usr/local/bin/perl
#!/usr/bin/perl
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
#
# Testing cleanup_invalid_links()
#
# load as a library
BEGIN {
use lib qw(.);
require "t/util.pm";
require "chkstow";
}
use strict;
use warnings;
use testutil;
require "chkstow";
use Test::More tests => 7;
use Test::Output;
use English qw(-no_match_vars);
### setup
eval { remove_dir('t/target'); };
make_dir('t/target');
chdir 't/target';
init_test_dirs();
cd("$TEST_DIR/target");
# setup stow directory
make_dir('stow');
make_path('stow');
make_file('stow/.stow');
# perl
make_dir('stow/perl/bin');
make_path('stow/perl/bin');
make_file('stow/perl/bin/perl');
make_file('stow/perl/bin/a2p');
make_dir('stow/perl/info');
make_path('stow/perl/info');
make_file('stow/perl/info/perl');
make_dir('stow/perl/lib/perl');
make_dir('stow/perl/man/man1');
make_path('stow/perl/lib/perl');
make_path('stow/perl/man/man1');
make_file('stow/perl/man/man1/perl.1');
# emacs
make_dir('stow/emacs/bin');
make_path('stow/emacs/bin');
make_file('stow/emacs/bin/emacs');
make_file('stow/emacs/bin/etags');
make_dir('stow/emacs/info');
make_path('stow/emacs/info');
make_file('stow/emacs/info/emacs');
make_dir('stow/emacs/libexec/emacs');
make_dir('stow/emacs/man/man1');
make_path('stow/emacs/libexec/emacs');
make_path('stow/emacs/man/man1');
make_file('stow/emacs/man/man1/emacs.1');
#setup target directory
make_dir('bin');
make_path('bin');
make_link('bin/a2p', '../stow/perl/bin/a2p');
make_link('bin/emacs', '../stow/emacs/bin/emacs');
make_link('bin/etags', '../stow/emacs/bin/etags');
make_link('bin/perl', '../stow/perl/bin/perl');
make_dir('info');
make_path('info');
make_link('info/emacs', '../stow/emacs/info/emacs');
make_link('info/perl', '../stow/perl/info/perl');
make_link('lib', 'stow/perl/lib');
make_link('libexec', 'stow/emacs/libexec');
make_dir('man');
make_dir('man/man1');
make_path('man');
make_path('man/man1');
make_link('man/man1/emacs', '../../stow/emacs/man/man1/emacs.1');
make_link('man/man1/perl', '../../stow/perl/man/man1/perl.1');
@ -67,28 +78,28 @@ sub run_chkstow() {
check_stow();
}
local @ARGV = ('-t', '.', '-b',);
local @ARGV = ('-t', '.', '-b');
stderr_like(
\&run_chkstow,
qr{\Askipping .*stow.*\z}xms,
"Skip directories containing .stow");
# squelch warn so that check_stow doesn't carp about skipping .stow all the time
$SIG{'__WARN__'} = sub { };
$SIG{__WARN__} = sub { };
@ARGV = ('-t', '.', '-l',);
@ARGV = ('-t', '.', '-l');
stdout_like(
\&run_chkstow,
qr{emacs$perl$stow}xms,
qr{emacs\nperl\nstow\n}xms,
"List packages");
@ARGV = ('-t', '.', '-b',);
@ARGV = ('-t', '.', '-b');
stdout_like(
\&run_chkstow,
qr{\A\z}xms,
"No bogus links exist");
@ARGV = ('-t', '.', '-a',);
@ARGV = ('-t', '.', '-a');
stdout_like(
\&run_chkstow,
qr{\A\z}xms,
@ -96,20 +107,21 @@ stdout_like(
# Create an alien
make_file('bin/alien');
@ARGV = ('-t', '.', '-a',);
@ARGV = ('-t', '.', '-a');
stdout_like(
\&run_chkstow,
qr{Unstowed\ file:\ ./bin/alien}xms,
"Aliens exist");
make_link('bin/link', 'ireallyhopethisfiledoesn/t.exist');
@ARGV = ('-t', '.', '-b',);
make_invalid_link('bin/link', 'ireallyhopethisfiledoesn/t.exist');
@ARGV = ('-t', '.', '-b');
stdout_like(
\&run_chkstow,
qr{Bogus\ link:\ ./bin/link}xms,
"Bogus links exist");
@ARGV = ('-b',);
@ARGV = ('-b');
process_options();
our $Target;
ok($Target == q{/usr/local},
"Default target is /usr/local/");

142
t/cleanup_invalid_links.t Normal file → Executable file
View file

@ -1,92 +1,98 @@
#!/usr/local/bin/perl
#!/usr/bin/perl
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
#
# Testing cleanup_invalid_links()
#
# load as a library
BEGIN { use lib qw(.); require "t/util.pm"; require "stow"; }
use strict;
use warnings;
use Test::More tests => 3;
use Test::More tests => 4;
use English qw(-no_match_vars);
# local utility
sub reset_state {
@Tasks = ();
@Conflicts = ();
%Link_Task_For = ();
%Dir_Task_For = ();
%Options = ();
return;
}
use testutil;
use Stow::Util;
### setup
eval { remove_dir('t/target'); };
eval { remove_dir('t/stow'); };
make_dir('t/target');
make_dir('t/stow');
init_test_dirs();
cd("$TEST_DIR/target");
chdir 't/target';
$Stow_Path= '../stow';
my $stow;
# Note that each of the following tests use a distinct set of files
#
# nothing to clean in a simple tree
#
reset_state();
$Option{'verbose'} = 1;
subtest('nothing to clean in a simple tree' => sub {
plan tests => 1;
make_dir('../stow/pkg1/bin1');
make_file('../stow/pkg1/bin1/file1');
make_link('bin1','../stow/pkg1/bin1');
make_path('../stow/pkg1/bin1');
make_file('../stow/pkg1/bin1/file1');
make_link('bin1', '../stow/pkg1/bin1');
cleanup_invalid_links('./');
is(
scalar @Tasks, 0
=> 'nothing to clean'
);
$stow = new_Stow();
$stow->cleanup_invalid_links('./');
is(
scalar($stow->get_tasks), 0
=> 'nothing to clean'
);
});
#
# cleanup a bad link in a simple tree
#
reset_state();
$Option{'verbose'} = 0;
subtest('cleanup an orphaned owned link in a simple tree' => sub {
plan tests => 3;
make_dir('bin2');
make_dir('../stow/pkg2/bin2');
make_file('../stow/pkg2/bin2/file2a');
make_link('bin2/file2a','../../stow/pkg2/bin2/file2a');
make_link('bin2/file2b','../../stow/pkg2/bin2/file2b');
make_path('bin2');
make_path('../stow/pkg2/bin2');
make_file('../stow/pkg2/bin2/file2a');
make_link('bin2/file2a', '../../stow/pkg2/bin2/file2a');
make_invalid_link('bin2/file2b', '../../stow/pkg2/bin2/file2b');
cleanup_invalid_links('bin2');
ok(
scalar(@Conflicts) == 0 &&
scalar @Tasks == 1 &&
$Link_Task_For{'bin2/file2b'}->{'action'} eq 'remove'
=> 'cleanup a bad link'
);
$stow = new_Stow();
$stow->cleanup_invalid_links('bin2');
is($stow->get_conflict_count, 0, 'no conflicts cleaning up bad link');
is(scalar($stow->get_tasks), 1, 'one task cleaning up bad link');
is($stow->link_task_action('bin2/file2b'), 'remove', 'removal task for bad link');
});
#use Data::Dumper;
#print Dumper(\@Tasks,\%Link_Task_For,\%Dir_Task_For);
subtest("don't cleanup a bad link not owned by stow" => sub {
plan tests => 2;
#
# dont cleanup a bad link not owned by stow
#
reset_state();
$Option{'verbose'} = 0;
make_path('bin3');
make_path('../stow/pkg3/bin3');
make_file('../stow/pkg3/bin3/file3a');
make_link('bin3/file3a', '../../stow/pkg3/bin3/file3a');
make_invalid_link('bin3/file3b', '../../empty');
make_dir('bin3');
make_dir('../stow/pkg3/bin3');
make_file('../stow/pkg3/bin3/file3a');
make_link('bin3/file3a','../../stow/pkg3/bin3/file3a');
make_link('bin3/file3b','../../empty');
$stow = new_Stow();
$stow->cleanup_invalid_links('bin3');
is($stow->get_conflict_count, 0, 'no conflicts cleaning up bad link not owned by stow');
is(scalar($stow->get_tasks), 0, 'no tasks cleaning up bad link not owned by stow');
});
cleanup_invalid_links('bin3');
ok(
scalar(@Conflicts) == 0 &&
scalar @Tasks == 0
=> 'dont cleanup a bad link not owned by stow'
);
subtest("don't cleanup a valid link in the target not owned by stow" => sub {
plan tests => 2;
make_path('bin4');
make_path('../stow/pkg4/bin4');
make_file('../stow/pkg4/bin4/file3a');
make_link('bin4/file3a', '../../stow/pkg4/bin4/file3a');
make_file("unowned");
make_link('bin4/file3b', '../unowned');
$stow = new_Stow();
$stow->cleanup_invalid_links('bin4');
is($stow->get_conflict_count, 0, 'no conflicts cleaning up bad link not owned by stow');
is(scalar($stow->get_tasks), 0, 'no tasks cleaning up bad link not owned by stow');
});

69
t/cli.t Executable file
View file

@ -0,0 +1,69 @@
#!/usr/bin/perl
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
#
# Test processing of CLI options.
#
use strict;
use warnings;
use File::Basename;
use Test::More tests => 3;
use testutil;
#init_test_dirs();
# Since here we're doing black-box testing on the stow executable,
# this looks like it should be robust:
#
#my $STOW = dirname(__FILE__) . '/../bin/stow';
#
# but unfortunately it breaks things like "make distcheck", which
# builds the stow script into a separate path like
#
# stow-2.3.0/_build/sub/bin
#
# before cd'ing to something like
#
# stow-2.3.0/_build/sub
#
# and then running the tests via:
#
# make check-TESTS
# make[2]: Entering directory '/path/to/stow/src/stow-2.3.0/_build/sub'
# dir=../../t; \
# /usr/bin/perl -Ibin -Ilib -I../../t -MTest::Harness -e 'runtests(@ARGV)' "${dir#./}"/*.t
#
# So the simplest solution is to hardcode an assumption that we run
# tests either from somewhere like this during distcheck:
#
# stow-2.3.0/_build/sub
#
# or from the top of the source tree during development. This can be done
# via the following, which also follows the KISS principle:
my $STOW = "$^X bin/stow";
`$STOW --help`;
is($?, 0, "--help should return 0 exit code");
my $err = `$STOW --foo 2>&1`;
is($? >> 8, 1, "unrecognised option should return 1 exit code");
like($err, qr/^Unknown option: foo$/m, "unrecognised option should be listed");
# vim:ft=perl

112
t/cli_options.t Executable file
View file

@ -0,0 +1,112 @@
#!/usr/bin/perl
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
#
# Test processing of CLI options.
#
use strict;
use warnings;
use Test::More tests => 10;
use testutil;
require 'stow';
init_test_dirs();
local @ARGV = (
'-v',
'-d', "$TEST_DIR/stow",
'-t', "$TEST_DIR/target",
'dummy'
);
my ($options, $pkgs_to_delete, $pkgs_to_stow) = process_options();
is($options->{verbose}, 1, 'verbose option');
is($options->{dir}, "$TEST_DIR/stow", 'stow dir option');
my $stow = new_Stow(%$options);
is($stow->{stow_path}, "../stow" => 'stow dir');
is_deeply($pkgs_to_stow, [ 'dummy' ] => 'default to stow');
#
# Check mixed up package options
#
local @ARGV = (
'-v',
'-D', 'd1', 'd2',
'-S', 's1',
'-R', 'r1',
'-D', 'd3',
'-S', 's2', 's3',
'-R', 'r2',
);
($options, $pkgs_to_delete, $pkgs_to_stow) = process_options();
is_deeply($pkgs_to_delete, [ 'd1', 'd2', 'r1', 'd3', 'r2' ] => 'mixed deletes');
is_deeply($pkgs_to_stow, [ 's1', 'r1', 's2', 's3', 'r2' ] => 'mixed stows');
#
# Check setting deferred paths
#
local @ARGV = (
'--defer=man',
'--defer=info',
'dummy'
);
($options, $pkgs_to_delete, $pkgs_to_stow) = process_options();
is_deeply($options->{defer}, [ qr(\Aman), qr(\Ainfo) ] => 'defer man and info');
#
# Check setting override paths
#
local @ARGV = (
'--override=man',
'--override=info',
'dummy'
);
($options, $pkgs_to_delete, $pkgs_to_stow) = process_options();
is_deeply($options->{override}, [qr(\Aman), qr(\Ainfo)] => 'override man and info');
#
# Check setting ignored paths
#
local @ARGV = (
'--ignore=~',
'--ignore=\.#.*',
'dummy'
);
($options, $pkgs_to_delete, $pkgs_to_stow) = process_options();
is_deeply($options->{ignore}, [ qr(~\z), qr(\.#.*\z) ] => 'ignore temp files');
#
# Check that expansion not applied.
#
local @ARGV = (
"--target=$TEST_DIR/".'$HOME',
'dummy'
);
make_path("$TEST_DIR/".'$HOME');
($options, $pkgs_to_delete, $pkgs_to_stow) = process_options();
is($options->{target}, "$TEST_DIR/".'$HOME', 'no expansion');
remove_dir("$TEST_DIR/".'$HOME');
# vim:ft=perl

44
t/defer.t Normal file → Executable file
View file

@ -1,22 +1,44 @@
#!/usr/local/bin/perl
#!/usr/bin/perl
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
#
# Testing defer().
#
# load as a library
BEGIN { use lib qw(. ..); require "stow"; }
use strict;
use warnings;
use testutil;
use Test::More tests => 4;
$Option{'defer'} = [ 'man' ];
ok(defer('man/man1/file.1') => 'simple success');
init_test_dirs();
cd("$TEST_DIR/target");
$Option{'defer'} = [ 'lib' ];
ok(!defer('man/man1/file.1') => 'simple failure');
my $stow;
$Option{'defer'} = [ 'lib', 'man', 'share' ];
ok(defer('man/man1/file.1') => 'complex success');
$stow = new_Stow(defer => [ 'man' ]);
ok($stow->defer('man/man1/file.1') => 'simple success');
$Option{'defer'} = [ 'lib', 'man', 'share' ];
ok(!defer('bin/file') => 'complex failure');
$stow = new_Stow(defer => [ 'lib' ]);
ok(! $stow->defer('man/man1/file.1') => 'simple failure');
$stow = new_Stow(defer => [ 'lib', 'man', 'share' ]);
ok($stow->defer('man/man1/file.1') => 'complex success');
$stow = new_Stow(defer => [ 'lib', 'man', 'share' ]);
ok(! $stow->defer('bin/file') => 'complex failure');

235
t/dotfiles.t Executable file
View file

@ -0,0 +1,235 @@
#!/usr/bin/perl
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
#
# Test case for dotfiles special processing
#
use strict;
use warnings;
use Test::More tests => 12;
use English qw(-no_match_vars);
use Stow::Util qw(adjust_dotfile unadjust_dotfile);
use testutil;
init_test_dirs();
cd("$TEST_DIR/target");
subtest('adjust_dotfile()', sub {
plan tests => 4;
my @TESTS = (
['file'],
['dot-'],
['dot-.'],
['dot-file', '.file'],
);
for my $test (@TESTS) {
my ($input, $expected) = @$test;
$expected ||= $input;
is(adjust_dotfile($input), $expected);
}
});
subtest('unadjust_dotfile()', sub {
plan tests => 4;
my @TESTS = (
['file'],
['.'],
['..'],
['.file', 'dot-file'],
);
for my $test (@TESTS) {
my ($input, $expected) = @$test;
$expected ||= $input;
is(unadjust_dotfile($input), $expected);
}
});
my $stow;
subtest("stow dot-foo as .foo", sub {
plan tests => 1;
$stow = new_Stow(dir => '../stow', dotfiles => 1);
make_path('../stow/dotfiles');
make_file('../stow/dotfiles/dot-foo');
$stow->plan_stow('dotfiles');
$stow->process_tasks();
is(
readlink('.foo'),
'../stow/dotfiles/dot-foo',
=> 'processed dotfile'
);
});
subtest("stow dot-foo as dot-foo without --dotfile enabled", sub {
plan tests => 1;
$stow = new_Stow(dir => '../stow', dotfiles => 0);
make_path('../stow/dotfiles');
make_file('../stow/dotfiles/dot-foo');
$stow->plan_stow('dotfiles');
$stow->process_tasks();
is(
readlink('dot-foo'),
'../stow/dotfiles/dot-foo',
=> 'unprocessed dotfile'
);
});
subtest("stow dot-emacs dir as .emacs", sub {
plan tests => 1;
$stow = new_Stow(dir => '../stow', dotfiles => 1);
make_path('../stow/dotfiles/dot-emacs');
make_file('../stow/dotfiles/dot-emacs/init.el');
$stow->plan_stow('dotfiles');
$stow->process_tasks();
is(
readlink('.emacs'),
'../stow/dotfiles/dot-emacs',
=> 'processed dotfile dir'
);
});
subtest("stow dir marked with 'dot' prefix when directory exists in target", sub {
plan tests => 1;
$stow = new_Stow(dir => '../stow', dotfiles => 1);
make_path('../stow/dotfiles/dot-emacs.d');
make_file('../stow/dotfiles/dot-emacs.d/init.el');
make_path('.emacs.d');
$stow->plan_stow('dotfiles');
$stow->process_tasks();
is(
readlink('.emacs.d/init.el'),
'../../stow/dotfiles/dot-emacs.d/init.el',
=> 'processed dotfile dir when dir exists (1 level)'
);
});
subtest("stow dir marked with 'dot' prefix when directory exists in target (2 levels)", sub {
plan tests => 1;
$stow = new_Stow(dir => '../stow', dotfiles => 1);
make_path('../stow/dotfiles/dot-emacs.d/dot-emacs.d');
make_file('../stow/dotfiles/dot-emacs.d/dot-emacs.d/init.el');
make_path('.emacs.d');
$stow->plan_stow('dotfiles');
$stow->process_tasks();
is(
readlink('.emacs.d/.emacs.d'),
'../../stow/dotfiles/dot-emacs.d/dot-emacs.d',
=> 'processed dotfile dir exists (2 levels)'
);
});
subtest("stow dir marked with 'dot' prefix when directory exists in target", sub {
plan tests => 1;
$stow = new_Stow(dir => '../stow', dotfiles => 1);
make_path('../stow/dotfiles/dot-one/dot-two');
make_file('../stow/dotfiles/dot-one/dot-two/three');
make_path('.one/.two');
$stow->plan_stow('dotfiles');
$stow->process_tasks();
is(
readlink('./.one/.two/three'),
'../../../stow/dotfiles/dot-one/dot-two/three',
=> 'processed dotfile 2 dir exists (2 levels)'
);
});
subtest("dot-. should not have that part expanded.", sub {
plan tests => 2;
$stow = new_Stow(dir => '../stow', dotfiles => 1);
make_path('../stow/dotfiles');
make_file('../stow/dotfiles/dot-');
make_path('../stow/dotfiles/dot-.');
make_file('../stow/dotfiles/dot-./foo');
$stow->plan_stow('dotfiles');
$stow->process_tasks();
is(
readlink('dot-'),
'../stow/dotfiles/dot-',
=> 'processed dotfile'
);
is(
readlink('dot-.'),
'../stow/dotfiles/dot-.',
=> 'unprocessed dotfile'
);
});
subtest("unstow .bar from dot-bar", sub {
plan tests => 3;
$stow = new_Stow(dir => '../stow', dotfiles => 1);
make_path('../stow/dotfiles');
make_file('../stow/dotfiles/dot-bar');
make_link('.bar', '../stow/dotfiles/dot-bar');
$stow->plan_unstow('dotfiles');
$stow->process_tasks();
is($stow->get_conflict_count, 0);
ok(-f '../stow/dotfiles/dot-bar', 'package file untouched');
ok(! -e '.bar' => '.bar was unstowed');
});
subtest("unstow dot-emacs.d/init.el when .emacs.d/init.el in target", sub {
plan tests => 4;
$stow = new_Stow(dir => '../stow', dotfiles => 1);
make_path('../stow/dotfiles/dot-emacs.d');
make_file('../stow/dotfiles/dot-emacs.d/init.el');
make_path('.emacs.d');
make_link('.emacs.d/init.el', '../../stow/dotfiles/dot-emacs.d/init.el');
$stow->plan_unstow('dotfiles');
$stow->process_tasks();
is($stow->get_conflict_count, 0);
ok(-f '../stow/dotfiles/dot-emacs.d/init.el');
ok(! -e '.emacs.d/init.el', '.emacs.d/init.el unstowed');
ok(-d '.emacs.d/' => '.emacs.d left behind');
});
subtest("unstow dot-emacs.d/init.el in --compat mode", sub {
plan tests => 4;
$stow = new_compat_Stow(dir => '../stow', dotfiles => 1);
make_path('../stow/dotfiles/dot-emacs.d');
make_file('../stow/dotfiles/dot-emacs.d/init.el');
make_path('.emacs.d');
make_link('.emacs.d/init.el', '../../stow/dotfiles/dot-emacs.d/init.el');
$stow->plan_unstow('dotfiles');
$stow->process_tasks();
is($stow->get_conflict_count, 0);
ok(-f '../stow/dotfiles/dot-emacs.d/init.el');
ok(! -e '.emacs.d/init.el', '.emacs.d/init.el unstowed');
ok(-d '.emacs.d/' => '.emacs.d left behind');
});

145
t/examples.t Normal file → Executable file
View file

@ -1,72 +1,68 @@
#!/usr/local/bin/perl
#!/usr/bin/perl
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
#
# Testing examples from the documentation
#
# load as a library
BEGIN { use lib qw(.); require "t/util.pm"; require "stow"; }
use strict;
use warnings;
use Test::More tests => 4;
use testutil;
use Test::More tests => 10;
use English qw(-no_match_vars);
# local utility
sub reset_state {
@Tasks = ();
@Conflicts = ();
%Link_Task_For = ();
%Dir_Task_For = ();
%Options = ();
return;
}
init_test_dirs();
cd("$TEST_DIR/target");
### setup
eval { remove_dir('t/target'); };
make_dir('t/target/stow');
chdir 't/target';
$Stow_Path= 'stow';
my $stow;
## set up some fake packages to stow
# perl
make_dir('stow/perl/bin');
make_path('stow/perl/bin');
make_file('stow/perl/bin/perl');
make_file('stow/perl/bin/a2p');
make_dir('stow/perl/info');
make_path('stow/perl/info');
make_file('stow/perl/info/perl');
make_dir('stow/perl/lib/perl');
make_dir('stow/perl/man/man1');
make_path('stow/perl/lib/perl');
make_path('stow/perl/man/man1');
make_file('stow/perl/man/man1/perl.1');
# emacs
make_dir('stow/emacs/bin');
make_path('stow/emacs/bin');
make_file('stow/emacs/bin/emacs');
make_file('stow/emacs/bin/etags');
make_dir('stow/emacs/info');
make_path('stow/emacs/info');
make_file('stow/emacs/info/emacs');
make_dir('stow/emacs/libexec/emacs');
make_dir('stow/emacs/man/man1');
make_path('stow/emacs/libexec/emacs');
make_path('stow/emacs/man/man1');
make_file('stow/emacs/man/man1/emacs.1');
#
# stow perl into an empty target
#
reset_state();
$Option{'verbose'} = 0;
make_dir('stow/perl/bin');
make_file('stow/perl/bin/perl');
make_file('stow/perl/bin/a2p');
make_dir('stow/perl/info');
make_dir('stow/perl/lib/perl');
make_dir('stow/perl/man/man1');
make_file('stow/perl/man/man1/perl.1');
stow_contents('stow/perl','./','stow/perl');
process_tasks();
$stow = new_Stow(dir => 'stow');
$stow->plan_stow('perl');
$stow->process_tasks();
ok(
scalar(@Conflicts) == 0 &&
$stow->get_conflict_count == 0 &&
-l 'bin' && -l 'info' && -l 'lib' && -l 'man' &&
readlink('bin') eq 'stow/perl/bin' &&
readlink('info') eq 'stow/perl/info' &&
@ -75,12 +71,9 @@ ok(
=> 'stow perl into an empty target'
);
#
# stow perl into a non-empty target
#
reset_state();
$Option{'verbose'} = 0;
# clean up previous stow
remove_link('bin');
@ -88,14 +81,15 @@ remove_link('info');
remove_link('lib');
remove_link('man');
make_dir('bin');
make_dir('lib');
make_dir('man/man1');
make_path('bin');
make_path('lib');
make_path('man/man1');
stow_contents('stow/perl','./','stow/perl');
process_tasks();
$stow = new_Stow(dir => 'stow');
$stow->plan_stow('perl');
$stow->process_tasks();
ok(
scalar(@Conflicts) == 0 &&
$stow->get_conflict_count == 0 &&
-d 'bin' && -d 'lib' && -d 'man' && -d 'man/man1' &&
-l 'info' && -l 'bin/perl' && -l 'bin/a2p' &&
-l 'lib/perl' && -l 'man/man1/perl.1' &&
@ -111,8 +105,6 @@ ok(
#
# Install perl into an empty target and then install emacs
#
reset_state();
$Option{'verbose'} = 0;
# clean up previous stow
remove_link('info');
@ -120,11 +112,11 @@ remove_dir('bin');
remove_dir('lib');
remove_dir('man');
stow_contents('stow/perl', './','stow/perl');
stow_contents('stow/emacs','./','stow/emacs');
process_tasks();
$stow = new_Stow(dir => 'stow');
$stow->plan_stow('perl', 'emacs');
$stow->process_tasks();
is($stow->get_conflict_count, 0, 'no conflicts');
ok(
scalar(@Conflicts) == 0 &&
-d 'bin' &&
-l 'bin/perl' &&
-l 'bin/emacs' &&
@ -164,41 +156,38 @@ ok(
# Q. the original empty directory should remain
# behaviour is the same as if the empty directory had nothing to do with stow
#
reset_state();
$Option{'verbose'} = 0;
make_dir('stow/pkg1a/bin1');
make_dir('stow/pkg1b/bin1');
make_path('stow/pkg1a/bin1');
make_path('stow/pkg1b/bin1');
make_file('stow/pkg1b/bin1/file1b');
stow_contents('stow/pkg1a', './', 'stow/pkg1a');
stow_contents('stow/pkg1b', './', 'stow/pkg1b');
unstow_contents('stow/pkg1b', './', 'stow/pkg1b');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
-d 'bin1'
=> 'bug 1: stowing empty dirs'
);
$stow = new_Stow(dir => 'stow');
$stow->plan_stow('pkg1a', 'pkg1b');
$stow->plan_unstow('pkg1b');
$stow->process_tasks();
is($stow->get_conflict_count, 0, 'no conflicts stowing empty dirs');
ok(-d 'bin1' => 'bug 1: stowing empty dirs');
#
# BUG 2: split open tree-folding symlinks pointing inside different stow
# directories
#
reset_state();
$Option{'verbose'} = 0;
make_dir('stow2a/pkg2a/bin2');
make_path('stow2a/pkg2a/bin2');
make_file('stow2a/pkg2a/bin2/file2a');
make_file('stow2a/.stow');
make_dir('stow2b/pkg2b/bin2');
make_path('stow2b/pkg2b/bin2');
make_file('stow2b/pkg2b/bin2/file2b');
make_file('stow2b/.stow');
stow_contents('stow2a/pkg2a','./', 'stow2a/pkg2a');
stow_contents('stow2b/pkg2b','./', 'stow2b/pkg2b');
process_tasks();
$stow = new_Stow(dir => 'stow2a');
$stow->plan_stow('pkg2a');
$stow->set_stow_dir('stow2b');
$stow->plan_stow('pkg2b');
$stow->process_tasks();
is($stow->get_conflict_count, 0, 'no conflicts splitting tree-folding symlinks');
ok(-d 'bin2' => 'tree got split by packages from multiple stow directories');
ok(-f 'bin2/file2a' => 'file from 1st stow dir');
ok(-f 'bin2/file2b' => 'file from 2nd stow dir');
## Finish this test

173
t/find_stowed_path.t Normal file → Executable file
View file

@ -1,51 +1,148 @@
#!/usr/local/bin/perl
#!/usr/bin/perl
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
#
# Testing find_stowed_path()
# Testing Stow:: find_stowed_path()
#
BEGIN { require "t/util.pm"; require "stow"; }
use strict;
use warnings;
use Test::More tests => 5;
use Test::More tests => 10;
eval { remove_dir('t/target'); };
eval { remove_dir('t/stow'); };
make_dir('t/target');
make_dir('t/stow');
use testutil;
use Stow::Util qw(set_debug_level);
$Stow_Path = 't/stow';
is(
find_stowed_path('t/target/a/b/c', '../../../stow/a/b/c'),
't/stow/a/b/c',
=> 'from root'
);
init_test_dirs();
$Stow_Path = '../stow';
is(
find_stowed_path('a/b/c','../../../stow/a/b/c'),
'../stow/a/b/c',
=> 'from target directory'
);
subtest("find link to a stowed path with relative target" => sub {
plan tests => 3;
$Stow_Path = 't/target/stow';
# This is a relative path, unlike $ABS_TEST_DIR below.
my $target = "$TEST_DIR/target";
is(
find_stowed_path('t/target/a/b/c', '../../stow/a/b/c'),
't/target/stow/a/b/c',
=> 'stow is subdir of target directory'
);
my $stow = new_Stow(dir => "$TEST_DIR/stow", target => $target);
my ($path, $stow_path, $package) =
$stow->find_stowed_path("a/b/c", "../../../stow/a/b/c");
is($path, "../stow/a/b/c", "path");
is($stow_path, "../stow", "stow path");
is($package, "a", "package");
});
is(
find_stowed_path('t/target/a/b/c','../../empty'),
'',
=> 'target is not stowed'
);
my $stow = new_Stow(dir => "$ABS_TEST_DIR/stow", target => "$ABS_TEST_DIR/target");
make_dir('t/target/stow2');
make_file('t/target/stow2/.stow');
# Required by creation of stow2 and stow2/.stow below
cd("$ABS_TEST_DIR/target");
is(
find_stowed_path('t/target/a/b/c','../../stow2/a/b/c'),
't/target/stow2/a/b/c'
=> q(detect alternate stow directory)
);
subtest("find link to a stowed path" => sub {
plan tests => 3;
my ($path, $stow_path, $package) =
$stow->find_stowed_path("a/b/c", "../../../stow/a/b/c");
is($path, "../stow/a/b/c", "path from target directory");
is($stow_path, "../stow", "stow path from target directory");
is($package, "a", "from target directory");
});
subtest("find link to alien path not owned by Stow" => sub {
plan tests => 3;
my ($path, $stow_path, $package) =
$stow->find_stowed_path("a/b/c", "../../alien");
is($path, "", "alien is not stowed, so path is empty");
is($stow_path, "", "alien, so stow path is empty");
is($package, "", "alien is not stowed in any package");
});
# Make a second stow directory within the target directory, so that we
# can check that links to package files within that stow directory are
# detected correctly.
make_path("stow2");
# However this second stow directory is still "alien" to stow until we
# put a .stow file in it. So first test a symlink pointing to a path
# within this second stow directory
subtest("second stow dir still alien without .stow" => sub {
plan tests => 3;
my ($path, $stow_path, $package) =
$stow->find_stowed_path("a/b/c", "../../stow2/a/b/c");
is($path, "", "stow2 not a stow dir yet, so path is empty");
is($stow_path, "", "stow2 not a stow dir yet so stow path is empty");
is($package, "", "not stowed in any recognised package yet");
});
# Now make stow2 a secondary stow directory and test that
make_file("stow2/.stow");
subtest(".stow makes second stow dir owned by Stow" => sub {
plan tests => 3;
my ($path, $stow_path, $package) =
$stow->find_stowed_path("a/b/c", "../../stow2/a/b/c");
is($path, "stow2/a/b/c", "path");
is($stow_path, "stow2", "stow path");
is($package, "a", "detect alternate stow directory");
});
subtest("relative symlink pointing to target dir" => sub {
plan tests => 3;
my ($path, $stow_path, $package) =
$stow->find_stowed_path("a/b/c", "../../..");
# Technically the target dir is not owned by Stow, since
# Stow won't touch the target dir itself, only its contents.
is($path, "", "path");
is($stow_path, "", "stow path");
is($package, "", "corner case - link points to target dir");
});
subtest("relative symlink pointing to parent of target dir" => sub {
plan tests => 3;
my ($path, $stow_path, $package) =
$stow->find_stowed_path("a/b/c", "../../../..");
is($path, "", "path");
is($stow_path, "", "stow path");
is($package, "", "corner case - link points to parent of target dir");
});
subtest("unowned symlink pointing to absolute path inside target" => sub {
plan tests => 3;
my ($path, $stow_path, $package) =
$stow->find_stowed_path("a/b/c", "$ABS_TEST_DIR/target/d");
is($path, "", "path");
is($stow_path, "", "stow path");
is($package, "", "symlink unowned by Stow points to absolute path outside target directory");
});
subtest("unowned symlink pointing to absolute path outside target" => sub {
plan tests => 3;
my ($path, $stow_path, $package) =
$stow->find_stowed_path("a/b/c", "/dev/null");
is($path, "", "path");
is($stow_path, "", "stow path");
is($package, "", "symlink unowned by Stow points to absolute path outside target directory");
});
# Now make stow2 the primary stow directory and test that it still
# works when the stow directory is under the target directory
$stow->set_stow_dir("$ABS_TEST_DIR/target/stow2");
subtest("stow2 becomes the primary stow directory" => sub {
plan tests => 3;
my ($path, $stow_path, $package) =
$stow->find_stowed_path("a/b/c", "../../stow2/a/b/c");
is($path, "stow2/a/b/c", "path in stow2");
is($stow_path, "stow2", "stow path for stow2");
is($package, "a", "stow2 is subdir of target directory");
});

64
t/foldable.t Normal file → Executable file
View file

@ -1,74 +1,82 @@
#!/usr/local/bin/perl
#!/usr/bin/perl
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
#
# Testing foldable()
#
# load as a library
BEGIN { use lib qw(.); require "t/util.pm"; require "stow"; }
use strict;
use warnings;
use testutil;
use Test::More tests => 4;
use English qw(-no_match_vars);
### setup
# be very careful with these
eval { remove_dir('t/target'); };
eval { remove_dir('t/stow'); };
make_dir('t/target');
make_dir('t/stow');
init_test_dirs();
cd("$TEST_DIR/target");
chdir 't/target';
$Stow_Path= '../stow';
my $stow = new_Stow(dir => '../stow');
# Note that each of the following tests use a distinct set of files
#
# can fold a simple tree
#
$Option{'verbose'} = 0;
make_dir('../stow/pkg1/bin1');
make_path('../stow/pkg1/bin1');
make_file('../stow/pkg1/bin1/file1');
make_dir('bin1');
make_path('bin1');
make_link('bin1/file1','../../stow/pkg1/bin1/file1');
is( foldable('bin1'), '../stow/pkg1/bin1' => q(can fold a simple tree) );
is( $stow->foldable('bin1'), '../stow/pkg1/bin1' => q(can fold a simple tree) );
#
# can't fold an empty directory
#
$Option{'verbose'} = 0;
make_dir('../stow/pkg2/bin2');
make_path('../stow/pkg2/bin2');
make_file('../stow/pkg2/bin2/file2');
make_dir('bin2');
make_path('bin2');
is( foldable('bin2'), '' => q(can't fold an empty directory) );
is( $stow->foldable('bin2'), '' => q(can't fold an empty directory) );
#
# can't fold if dir contains a non-link
#
$Option{'verbose'} = 0;
make_dir('../stow/pkg3/bin3');
make_path('../stow/pkg3/bin3');
make_file('../stow/pkg3/bin3/file3');
make_dir('bin3');
make_path('bin3');
make_link('bin3/file3','../../stow/pkg3/bin3/file3');
make_file('bin3/non-link');
is( foldable('bin3'), '' => q(can't fold a dir containing non-links) );
is( $stow->foldable('bin3'), '' => q(can't fold a dir containing non-links) );
#
# can't fold if links point to different directories
#
$Option{'verbose'} = 0;
make_dir('bin4');
make_dir('../stow/pkg4a/bin4');
make_path('bin4');
make_path('../stow/pkg4a/bin4');
make_file('../stow/pkg4a/bin4/file4a');
make_link('bin4/file4a','../../stow/pkg4a/bin4/file4a');
make_dir('../stow/pkg4b/bin4');
make_path('../stow/pkg4b/bin4');
make_file('../stow/pkg4b/bin4/file4b');
make_link('bin4/file4b','../../stow/pkg4b/bin4/file4b');
is( foldable('bin4'), '' => q(can't fold if links point to different dirs) );
is( $stow->foldable('bin4'), '' => q(can't fold if links point to different dirs) );

306
t/ignore.t Executable file
View file

@ -0,0 +1,306 @@
#!/usr/bin/perl
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
#
# Testing ignore lists.
#
use strict;
use warnings;
use File::Temp qw(tempdir);
use Test::More tests => 287;
use testutil;
use Stow::Util qw(join_paths);
init_test_dirs();
cd("$TEST_DIR/target");
my $stow = new_Stow();
sub test_ignores {
my ($stow_path, $package, $context, @tests) = @_;
$context ||= '';
while (@tests) {
my $path = shift @tests;
my $should_ignore = shift @tests;
my $not = $should_ignore ? '' : ' not';
my $was_ignored = $stow->ignore($stow_path, $package, $path);
is(
$was_ignored, $should_ignore,
"Should$not ignore $path $context"
);
}
}
sub test_local_ignore_list_always_ignored_at_top_level {
my ($stow_path, $package, $context) = @_;
test_ignores(
$stow_path, $package, $context,
$Stow::LOCAL_IGNORE_FILE => 1,
"subdir/" . $Stow::LOCAL_IGNORE_FILE => 0,
);
}
sub test_built_in_list {
my ($stow_path, $package, $context, $expect_ignores) = @_;
for my $ignored ('CVS', '.cvsignore', '#autosave#') {
for my $path ($ignored, "foo/bar/$ignored") {
my $suffix = "$path.suffix";
(my $prefix = $path) =~ s!([^/]+)$!prefix.$1!;
test_ignores(
$stow_path, $package, $context,
$path => $expect_ignores,
$prefix => 0,
$suffix => 0,
);
}
}
# The pattern catching lock files allows suffixes but not prefixes
for my $ignored ('.#lock-file') {
for my $path ($ignored, "foo/bar/$ignored") {
my $suffix = "$path.suffix";
(my $prefix = $path) =~ s!([^/]+)$!prefix.$1!;
test_ignores(
$stow_path, $package, $context,
$path => $expect_ignores,
$prefix => 0,
$suffix => $expect_ignores,
);
}
}
}
sub test_user_global_list {
my ($stow_path, $package, $context, $expect_ignores) = @_;
for my $path ('', 'foo/bar/') {
test_ignores(
$stow_path, $package, $context,
$path . 'exact' => $expect_ignores,
$path . '0exact' => 0,
$path . 'exact1' => 0,
$path . '0exact1' => 0,
$path . 'substring' => 0,
$path . '0substring' => 0,
$path . 'substring1' => 0,
$path . '0substring1' => $expect_ignores,
);
}
}
sub setup_user_global_list {
# Now test with global ignore list in home directory
$ENV{HOME} = tempdir();
make_file(join_paths($ENV{HOME}, $Stow::GLOBAL_IGNORE_FILE), <<EOF);
exact
.+substring.+ # here's a comment
.+\.extension
myprefix.+ #hi mum
EOF
}
sub setup_package_local_list {
my ($stow_path, $package, $list) = @_;
my $package_path = join_paths($stow_path, $package);
make_path($package_path);
my $local_ignore = join_paths($package_path, $Stow::LOCAL_IGNORE_FILE);
make_file($local_ignore, $list);
$stow->invalidate_memoized_regexp($local_ignore);
return $local_ignore;
}
sub main {
my $stow_path = '../stow';
my $package;
my $context;
# Test built-in list first. init_test_dirs() already set
# $ENV{HOME} to ensure that we're not using the user's global
# ignore list.
$package = 'non-existent-package';
$context = "when using built-in list";
test_local_ignore_list_always_ignored_at_top_level($stow_path, $package, $context);
test_built_in_list($stow_path, $package, $context, 1);
# Test ~/.stow-global-ignore
setup_user_global_list();
$context = "when using ~/$Stow::GLOBAL_IGNORE_FILE";
test_local_ignore_list_always_ignored_at_top_level($stow_path, $package, $context);
test_built_in_list($stow_path, $package, $context, 0);
test_user_global_list($stow_path, $package, $context, 1);
# Test empty package-local .stow-local-ignore
$package = 'ignorepkg';
my $local_ignore = setup_package_local_list($stow_path, $package, "");
$context = "when using empty $local_ignore";
test_local_ignore_list_always_ignored_at_top_level($stow_path, $package, $context);
test_built_in_list($stow_path, $package, $context, 0);
test_user_global_list($stow_path, $package, $context, 0);
test_ignores(
$stow_path, $package, $context,
'random' => 0,
'foo2/bar' => 0,
'foo2/bars' => 0,
'foo2/bar/random' => 0,
'foo2/bazqux' => 0,
'xfoo2/bazqux' => 0,
);
# Test package-local .stow-local-ignore with only path segment regexps
$local_ignore = setup_package_local_list($stow_path, $package, <<EOF);
random
EOF
$context = "when using $local_ignore with only path segment regexps";
test_local_ignore_list_always_ignored_at_top_level($stow_path, $package, $context);
test_built_in_list($stow_path, $package, $context, 0);
test_user_global_list($stow_path, $package, $context, 0);
test_ignores(
$stow_path, $package, $context,
'random' => 1,
'foo2/bar' => 0,
'foo2/bars' => 0,
'foo2/bar/random' => 1,
'foo2/bazqux' => 0,
'xfoo2/bazqux' => 0,
);
# Test package-local .stow-local-ignore with only full path regexps
$local_ignore = setup_package_local_list($stow_path, $package, <<EOF);
foo2/bar
EOF
$context = "when using $local_ignore with only full path regexps";
test_local_ignore_list_always_ignored_at_top_level($stow_path, $package, $context);
test_built_in_list($stow_path, $package, $context, 0);
test_user_global_list($stow_path, $package, $context, 0);
test_ignores(
$stow_path, $package, $context,
'random' => 0,
'foo2/bar' => 1,
'foo2/bars' => 0,
'foo2/bar/random' => 1,
'foo2/bazqux' => 0,
'xfoo2/bazqux' => 0,
);
# Test package-local .stow-local-ignore with a mixture of regexps
$local_ignore = setup_package_local_list($stow_path, $package, <<EOF);
foo2/bar
random
foo2/baz.+
EOF
$context = "when using $local_ignore with mixture of regexps";
test_local_ignore_list_always_ignored_at_top_level($stow_path, $package, $context);
test_built_in_list($stow_path, $package, $context, 0);
test_user_global_list($stow_path, $package, $context, 0);
test_ignores(
$stow_path, $package, $context,
'random' => 1,
'foo2/bar' => 1,
'foo2/bars' => 0,
'foo2/bar/random' => 1,
'foo2/bazqux' => 1,
'xfoo2/bazqux' => 0,
);
test_examples_in_manual($stow_path);
test_invalid_regexp($stow_path, "Invalid segment regexp in list", <<EOF);
this one's ok
this one isn't|*!
but this one is
EOF
test_invalid_regexp($stow_path, "Invalid full path regexp in list", <<EOF);
this one's ok
this/one isn't|*!
but this one is
EOF
test_ignore_via_stow($stow_path);
}
sub test_examples_in_manual {
my ($stow_path) = @_;
my $package = 'ignorepkg';
my $context = "(example from manual)";
for my $re ('bazqux', 'baz.*', '.*qux', 'bar/.*x', '^/foo/.*qux') {
my $local_ignore = setup_package_local_list($stow_path, $package, "$re\n");
test_ignores(
$stow_path, $package, $context,
"foo/bar/bazqux" => 1,
);
}
for my $re ('bar', 'baz', 'qux', 'o/bar/b') {
my $local_ignore = setup_package_local_list($stow_path, $package, "$re\n");
test_ignores(
$stow_path, $package, $context,
"foo/bar/bazqux" => 0,
);
}
}
sub test_invalid_regexp {
my ($stow_path, $context, $list) = @_;
my $package = 'ignorepkg';
my $local_ignore = setup_package_local_list($stow_path, $package, $list);
eval {
test_ignores(
$stow_path, $package, $context,
"foo/bar/bazqux" => 1,
);
};
like($@, qr/^Failed to compile regexp: Quantifier follows nothing in regex;/,
$context);
}
sub test_ignore_via_stow {
my ($stow_path) = @_;
my $package = 'pkg1';
make_path("$stow_path/$package/foo/bar");
make_file("$stow_path/$package/foo/bar/baz");
setup_package_local_list($stow_path, $package, 'foo');
$stow->plan_stow($package);
is($stow->get_tasks(), 0, 'top dir ignored');
is($stow->get_conflicts(), 0, 'top dir ignored, no conflicts');
make_path("foo");
for my $ignore ('bar', 'foo/bar', '/foo/bar', '^/foo/bar', '^/fo.+ar') {
setup_package_local_list($stow_path, $package, $ignore);
$stow->plan_stow($package);
is($stow->get_tasks(), 0, "bar ignored via $ignore");
is($stow->get_conflicts(), 0, 'bar ignored, no conflicts');
}
make_file("$stow_path/$package/foo/qux");
$stow->plan_stow($package);
$stow->process_tasks();
is($stow->get_conflicts(), 0, 'no conflicts stowing qux');
ok(! -e "foo/bar", "bar ignore prevented stow");
ok(-l "foo/qux", "qux not ignored and stowed");
is(readlink("foo/qux"), "../$stow_path/$package/foo/qux", "qux stowed correctly");
}
main();

132
t/join_paths.t Normal file → Executable file
View file

@ -1,89 +1,61 @@
#!/usr/local/bin/perl
#!/usr/bin/perl
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
#
# Testing join_paths();
#
# load as a library
BEGIN { use lib qw(. ..); require "stow"; }
use strict;
use warnings;
use Test::More tests => 13;
use Stow::Util qw(join_paths set_debug_level);
is(
join_paths('a/b/c', 'd/e/f'),
'a/b/c/d/e/f',
=> 'simple'
#set_debug_level(4);
use Test::More tests => 22;
my @TESTS = (
[['a/b/c', 'd/e/f'], 'a/b/c/d/e/f' => 'simple'],
[['a/b/c', '/d/e/f'], '/d/e/f' => 'relative then absolute'],
[['/a/b/c', 'd/e/f'], '/a/b/c/d/e/f' => 'absolute then relative'],
[['/a/b/c', '/d/e/f'], '/d/e/f' => 'two absolutes'],
[['/a/b/c/', '/d/e/f/'], '/d/e/f' => 'two absolutes with trailing /'],
[['///a/b///c//', '/d///////e/f'], '/d/e/f' => "multiple /'s, absolute"],
[['///a/b///c//', 'd///////e/f'], '/a/b/c/d/e/f' => "multiple /'s, relative"],
[['', 'a/b/c'], 'a/b/c' => 'first empty'],
[['a/b/c', ''], 'a/b/c' => 'second empty'],
[['/', 'a/b/c'], '/a/b/c' => 'first is /'],
[['a/b/c', '/'], '/' => 'second is /'],
[['../a1/b1/../c1/', 'a2/../b2/e2'], '../a1/c1/b2/e2' => 'relative with ../'],
[['../a1/b1/../c1/', '/a2/../b2/e2'], '/b2/e2' => 'absolute with ../'],
[['../a1/../../c1', 'a2/../../'], '../..' => 'lots of ../'],
[['./', '../a2'], '../a2' => 'drop any "./"'],
[['./a1', '../../a2'], '../a2' => 'drop any "./foo"'],
[['a/b/c', '.'], 'a/b/c' => '. on RHS'],
[['a/b/c', '.', 'd/e'], 'a/b/c/d/e' => '. in middle'],
[['0', 'a/b'], '0/a/b' => '0 at start'],
[['/0', 'a/b'], '/0/a/b' => '/0 at start'],
[['a/b/c', '0', 'd/e'], 'a/b/c/0/d/e' => '0 in middle'],
[['a/b', '0'], 'a/b/0' => '0 at end'],
);
is(
join_paths('/a/b/c', '/d/e/f'),
'/a/b/c/d/e/f',
=> 'leading /'
);
is(
join_paths('/a/b/c/', '/d/e/f/'),
'/a/b/c/d/e/f',
=> 'trailing /'
);
is(
join_paths('///a/b///c//', '/d///////e/f'),
'/a/b/c/d/e/f',
=> 'mltiple /\'s'
);
is(
join_paths('', 'a/b/c'),
'a/b/c',
=> 'first empty'
);
is(
join_paths('a/b/c', ''),
'a/b/c',
=> 'second empty'
);
is(
join_paths('/', 'a/b/c'),
'/a/b/c',
=> 'first is /'
);
is(
join_paths('a/b/c', '/'),
'a/b/c',
=> 'second is /'
);
is(
join_paths('///a/b///c//', '/d///////e/f'),
'/a/b/c/d/e/f',
=> 'multiple /\'s'
);
is(
join_paths('../a1/b1/../c1/', '/a2/../b2/e2'),
'../a1/c1/b2/e2',
=> 'simple deref ".."'
);
is(
join_paths('../a1/b1/../c1/d1/e1', '../a2/../b2/c2/d2/../e2'),
'../a1/c1/d1/b2/c2/e2',
=> 'complex deref ".."'
);
is(
join_paths('../a1/../../c1', 'a2/../../'),
'../..',
=> 'too many ".."'
);
is(
join_paths('./a1', '../../a2'),
'../a2',
=> 'drop any "./"'
);
for my $test (@TESTS) {
my ($inputs, $expected, $scenario) = @$test;
my $got = join_paths(@$inputs);
my $descr = "$scenario: in=[" . join(', ', map "'$_'", @$inputs) . "] exp=[$expected] got=[$got]";
is($got, $expected, $descr);
}

88
t/link_dest_within_stow_dir.t Executable file
View file

@ -0,0 +1,88 @@
#!/usr/bin/perl
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
#
# Testing Stow::link_dest_within_stow_dir()
#
use strict;
use warnings;
use Test::More tests => 6;
use testutil;
use Stow::Util;
init_test_dirs();
# This is a relative path, unlike $ABS_TEST_DIR below.
my $stow = new_Stow(dir => "$TEST_DIR/stow",
target => "$TEST_DIR/target");
subtest("relative stow dir, link to top-level package file" => sub {
plan tests => 2;
my ($package, $path) =
$stow->link_dest_within_stow_dir("../stow/pkg/dir/file");
is($package, "pkg", "package");
is($path, "dir/file", "path");
});
subtest("relative stow dir, link to second-level package file" => sub {
plan tests => 2;
my ($package, $path) =
$stow->link_dest_within_stow_dir("../stow/pkg/dir/subdir/file");
is($package, "pkg", "package");
is($path, "dir/subdir/file", "path");
});
# This is an absolute path, unlike $TEST_DIR above.
$stow = new_Stow(dir => "$ABS_TEST_DIR/stow",
target => "$ABS_TEST_DIR/target");
subtest("relative stow dir, link to second-level package file" => sub {
plan tests => 2;
my ($package, $path) =
$stow->link_dest_within_stow_dir("../stow/pkg/dir/file");
is($package, "pkg", "package");
is($path, "dir/file", "path");
});
subtest("absolute stow dir, link to top-level package file" => sub {
plan tests => 2;
my ($package, $path) =
$stow->link_dest_within_stow_dir("../stow/pkg/dir/subdir/file");
is($package, "pkg", "package");
is($path, "dir/subdir/file", "path");
});
# Links with destination in the target are not pointing within
# the stow dir, so they're not owned by stow.
subtest("link to path in target" => sub {
plan tests => 2;
my ($package, $path) =
$stow->link_dest_within_stow_dir("./alien");
is($path, "", "alien is in target, so path is empty");
is($package, "", "alien is in target, so package is empty");
});
subtest("link to path outside target and stow dir" => sub {
plan tests => 2;
my ($package, $path) =
$stow->link_dest_within_stow_dir("../alien");
is($path, "", "alien is outside, so path is empty");
is($package, "", "alien is outside, so package is empty");
});

31
t/parent.t Normal file → Executable file
View file

@ -1,35 +1,52 @@
#!/usr/local/bin/perl
#!/usr/bin/perl
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
#
# Testing parent()
#
# load as a library
BEGIN { use lib qw(. ..); require "stow"; }
use strict;
use warnings;
use Stow::Util qw(parent);
use Test::More tests => 5;
is(
parent('a/b/c'),
'a/b',
'a/b'
=> 'no leading or trailing /'
);
is(
parent('/a/b/c'),
'/a/b',
'/a/b'
=> 'leading /'
);
is(
parent('a/b/c/'),
'a/b',
'a/b'
=> 'trailing /'
);
is(
parent('/////a///b///c///'),
'/a/b',
'/a/b'
=> 'multiple /'
);

266
t/rc_options.t Executable file
View file

@ -0,0 +1,266 @@
#!/usr/bin/perl
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
#
# Test processing of stowrc file.
#
use strict;
use warnings;
use Test::More tests => 34;
use testutil;
require 'stow';
# .stowrc files used for testing, relative to run_from/
my $CWD_RC_FILE = ".stowrc";
my $HOME_RC_FILE = "../.stowrc";
# Take the safe route and cowardly refuse to continue if there's
# already a file at $HOME_RC_FILE.
if (-e $HOME_RC_FILE) {
die "RC file location $HOME_RC_FILE already exists!\n";
}
my ($options, $pkgs_to_delete, $pkgs_to_stow);
# Init testing directory structure and overwrite ENV{HOME} to prevent
# squashing existing .stowrc file.
init_test_dirs();
# =========== RC Loading Tests ===========
# Basic parsing and loading rc file tests.
# ========================================
my $orig_HOME = $ENV{HOME};
#
# Test no .stowrc file anywhere
#
delete $ENV{HOME};
local @ARGV = ('dummy');
cd("$TEST_DIR/run_from");
($options, $pkgs_to_delete, $pkgs_to_stow) = process_options();
is($options->{target}, "$ABS_TEST_DIR", "default --target with no .stowrc");
is($options->{dir}, "$ABS_TEST_DIR/run_from", "default -d with no .stowrc");
#
# Test .stowrc file in cwd with relative paths, and $HOME not defined
#
make_file($CWD_RC_FILE, <<HERE);
-d ../stow
--target ../target
HERE
($options, $pkgs_to_delete, $pkgs_to_stow) = process_options();
is($options->{target}, "../target"
=> "relative --target from \$PWD/.stowrc");
is($options->{dir}, "../stow"
=> "relative -d from \$PWD/.stowrc");
$ENV{HOME} = $orig_HOME;
remove_file($CWD_RC_FILE);
#
# Test .stowrc file in cwd with absolute paths, and $HOME not defined
#
make_file($CWD_RC_FILE, <<HERE);
-d $ABS_TEST_DIR/stow
--target $ABS_TEST_DIR/target
HERE
($options, $pkgs_to_delete, $pkgs_to_stow) = process_options();
is($options->{target}, "$ABS_TEST_DIR/target"
=> "absolute --target from \$PWD/.stowrc");
is($options->{dir}, "$ABS_TEST_DIR/stow"
=> "abs_test_dir -d from \$PWD/.stowrc");
$ENV{HOME} = $orig_HOME;
remove_file($CWD_RC_FILE);
#
# Test ~/.stowrc file with one relative option per line.
#
local @ARGV = ('dummy');
make_file($HOME_RC_FILE, <<HERE);
-d ../stow
--target ../target
HERE
($options, $pkgs_to_delete, $pkgs_to_stow) = process_options();
is($options->{target}, "../target", "--target from \$HOME/.stowrc");
is($options->{dir}, "../stow", "-d from \$HOME/.stowrc");
#
# Test ~/.stowrc file with one absolute option per line.
#
local @ARGV = ('dummy');
make_file($HOME_RC_FILE, <<HERE);
-d $ABS_TEST_DIR/stow
--target $ABS_TEST_DIR/target
HERE
($options, $pkgs_to_delete, $pkgs_to_stow) = process_options();
is($options->{target}, "$ABS_TEST_DIR/target"
=> "--target from \$HOME/.stowrc");
is($options->{dir}, "$ABS_TEST_DIR/stow"
=> "-d from \$HOME/.stowrc");
#
# Test that some but not all options ~/.stowrc file are overridden by
# .stowrc in cwd.
#
local @ARGV = ('dummy');
make_file($HOME_RC_FILE, <<HERE);
-d $ABS_TEST_DIR/stow-will-be-overridden
--target $ABS_TEST_DIR/target-will-be-overridden
--defer=info
HERE
make_file($CWD_RC_FILE, <<HERE);
-d $ABS_TEST_DIR/stow
--target $ABS_TEST_DIR/target
--defer=man
HERE
($options, $pkgs_to_delete, $pkgs_to_stow) = process_options();
is($options->{target}, "$ABS_TEST_DIR/target"
=> "--target overridden by \$PWD/.stowrc");
is($options->{dir}, "$ABS_TEST_DIR/stow"
=> "-d overridden \$PWD/.stowrc");
is_deeply($options->{defer}, [qr(\Ainfo), qr(\Aman)],
'defer man and info');
unlink($CWD_RC_FILE) or die "Failed to unlink $CWD_RC_FILE";
#
# Test that scalar cli option overwrites conflicting ~/.stowrc option.
#
local @ARGV = ('-d', "$ABS_TEST_DIR/stow", 'dummy');
make_file($HOME_RC_FILE, <<HERE);
-d bad/path
HERE
($options, $pkgs_to_delete, $pkgs_to_stow) = process_options();
is($options->{dir}, "$ABS_TEST_DIR/stow", "cli overwrite scalar rc option.");
#
# Test that list cli option merges with conflicting .stowrc option.
# Documentation states that .stowrc options are prepended to cli options.
#
local @ARGV = (
'--defer=man',
'dummy'
);
make_file($HOME_RC_FILE, <<HERE);
--defer=info
HERE
($options, $pkgs_to_delete, $pkgs_to_stow) = process_options();
is_deeply($options->{defer}, [qr(\Ainfo), qr(\Aman)],
'defer man and info');
# ======== Filepath Expansion Tests ========
# Test proper filepath expansion in rc file.
# Expansion is only applied to options that
# take a filepath, namely target and dir.
# ==========================================
#
# Test environment variable expansion function.
#
# Basic expansion
is(expand_environment('$HOME/stow'), "$ABS_TEST_DIR/stow", 'expand $HOME');
is(expand_environment('${HOME}/stow'), "$ABS_TEST_DIR/stow", 'expand ${HOME}');
delete $ENV{UNDEFINED}; # just in case
foreach my $var ('$UNDEFINED', '${UNDEFINED}') {
eval {
expand_environment($var, "--foo option");
};
is(
$@,
"--foo option references undefined environment variable \$UNDEFINED; " .
"aborting!\n",
"expand $var"
);
}
# Expansion with an underscore.
$ENV{'WITH_UNDERSCORE'} = 'test string';
is(expand_environment('${WITH_UNDERSCORE}'), 'test string',
'expand ${WITH_UNDERSCORE}');
delete $ENV{'WITH_UNDERSCORE'};
# Expansion with escaped $
is(expand_environment('\$HOME/stow'), '$HOME/stow', 'expand \$HOME');
#
# Test tilde (~) expansion
#
# Basic expansion
is(expand_tilde('~/path'), "$ENV{HOME}/path", 'tilde expansion to $HOME');
# Should not expand if middle of path
is(expand_tilde('/path/~/here'), '/path/~/here', 'middle ~ not expanded');
# Test escaped ~
is(expand_tilde('\~/path'), '~/path', 'escaped tilde');
#
# Test that environment variable expansion is applied.
#
make_file($HOME_RC_FILE, <<'HERE');
--dir=$HOME/stow
--target=$HOME/stow
--ignore=\$HOME
--defer=\$HOME
--override=\$HOME
HERE
($options, $pkgs_to_delete, $pkgs_to_stow) = get_config_file_options();
is($options->{dir}, "$ABS_TEST_DIR/stow",
"apply environment expansion on \$HOME/.stowrc --dir");
is($options->{target}, "$ABS_TEST_DIR/stow",
"apply environment expansion on \$HOME/.stowrc --target");
is_deeply($options->{ignore}, [qr(\$HOME\z)],
"environment expansion not applied on --ignore");
is_deeply($options->{defer}, [qr(\A\$HOME)],
"environment expansion not applied on --defer");
is_deeply($options->{override}, [qr(\A\$HOME)],
"environment expansion not applied on --override");
#
# Test that tilde expansion is applied in correct places.
#
make_file($HOME_RC_FILE, <<'HERE');
--dir=~/stow
--target=~/stow
--ignore=~/stow
--defer=~/stow
--override=~/stow
HERE
($options, $pkgs_to_delete, $pkgs_to_stow) = get_config_file_options();
is($options->{dir}, "$ABS_TEST_DIR/stow",
"apply tilde expansion on \$HOME/.stowrc --dir");
is($options->{target}, "$ABS_TEST_DIR/stow",
"apply tilde expansion on \$HOME/.stowrc --target");
is_deeply($options->{ignore}, [qr(~/stow\z)],
"tilde expansion not applied on --ignore");
is_deeply($options->{defer}, [qr(\A~/stow)],
"tilde expansion not applied on --defer");
is_deeply($options->{override}, [qr(\A~/stow)],
"tilde expansion not applied on --override");
#
# Clean up files used for testing.
#
unlink $HOME_RC_FILE or die "Unable to clean up $HOME_RC_FILE.\n";
remove_dir($ABS_TEST_DIR);

View file

@ -1,41 +0,0 @@
#!/usr/local/bin/perl
#
# Testing relative_path();
#
# load as a library
BEGIN { use lib qw(. ..); require "stow"; }
use Test::More tests => 5;
is(
relative_path('a/b/c', 'a/b/d'),
'../d',
=> 'diferent branches'
);
is(
relative_path('/a/b/c', '/a/b/c/d'),
'd',
=> 'lower same branch'
);
is(
relative_path('a/b/c', 'a/b'),
'..',
=> 'higher, same branch'
);
is(
relative_path('/a/b/c', '/d/e/f'),
'../../../d/e/f',
=> 'common parent is /'
);
is(
relative_path('///a//b//c////', '/a////b/c/d////'),
'd',
=> 'extra /\'s '
);

632
t/stow.t Normal file → Executable file
View file

@ -1,97 +1,571 @@
#!/usr/local/bin/perl
#!/usr/bin/perl
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
#
# Testing core application
# Test stowing packages.
#
# load as a library
BEGIN { use lib qw(.); require "t/util.pm"; require "stow"; }
use strict;
use warnings;
use Test::More tests => 10;
use Test::More tests => 22;
use Test::Output;
use English qw(-no_match_vars);
local @ARGV = (
'-v',
'-d t/stow',
'-t t/target',
'dummy'
);
use Stow::Util qw(canon_path set_debug_level);
use testutil;
### setup
eval { remove_dir('t/target'); };
eval { remove_dir('t/stow'); };
make_dir('t/target');
make_dir('t/stow');
init_test_dirs();
cd("$TEST_DIR/target");
ok eval {process_options(); 1} => 'process options';
ok eval {set_stow_path(); 1} => 'set stow path';
my $stow;
my %conflicts;
is($Stow_Path,"../stow" => 'stow dir');
is_deeply(\@Pkgs_To_Stow, [ 'dummy' ] => 'default to stow');
# Note that each of the following tests use a distinct set of files
subtest('stow a simple tree minimally', sub {
plan tests => 2;
my $stow = new_Stow(dir => '../stow');
#
# Check mixed up package options
#
%Option=();
local @ARGV = (
'-v',
'-D', 'd1', 'd2',
'-S', 's1',
'-R', 'r1',
'-D', 'd3',
'-S', 's2', 's3',
'-R', 'r2',
);
make_path('../stow/pkg1/bin1');
make_file('../stow/pkg1/bin1/file1');
@Pkgs_To_Stow = ();
@Pkgs_To_Delete = ();
process_options();
is_deeply(\@Pkgs_To_Delete, [ 'd1', 'd2', 'r1', 'd3', 'r2' ] => 'mixed deletes');
is_deeply(\@Pkgs_To_Stow, [ 's1', 'r1', 's2', 's3', 'r2' ] => 'mixed stows');
$stow->plan_stow('pkg1');
$stow->process_tasks();
is_deeply([ $stow->get_conflicts ], [], 'no conflicts with minimal stow');
is(
readlink('bin1'),
'../stow/pkg1/bin1',
=> 'minimal stow of a simple tree'
);
});
#
# Check setting defered paths
#
%Option=();
local @ARGV = (
'--defer=man',
'--defer=info'
);
process_options();
is_deeply($Option{'defer'}, [ qr(\Aman), qr(\Ainfo) ] => 'defer man and info');
subtest('stow a simple tree into an existing directory', sub {
plan tests => 1;
my $stow = new_Stow();
#
# Check setting override paths
#
%Option=();
local @ARGV = (
'--override=man',
'--override=info'
);
process_options();
is_deeply($Option{'override'}, [qr(\Aman), qr(\Ainfo)] => 'override man and info');
make_path('../stow/pkg2/lib2');
make_file('../stow/pkg2/lib2/file2');
make_path('lib2');
#
# Check stripping any matched quotes
#
%Option=();
local @ARGV = (
"--override='man'",
'--override="info"',
);
process_options();
is_deeply($Option{'override'}, [qr(\Aman), qr(\Ainfo)] => 'strip shell quoting');
$stow->plan_stow('pkg2');
$stow->process_tasks();
is(
readlink('lib2/file2'),
'../../stow/pkg2/lib2/file2',
=> 'stow simple tree to existing directory'
);
});
#
# Check setting ignored paths
#
%Option=();
local @ARGV = (
'--ignore="~"',
'--ignore="\.#.*'
);
process_options();
is_deeply($Option{'ignore'}, [ qr(~\z), qr(\.#.*\z) ] => 'ignore temp files');
subtest('unfold existing tree', sub {
plan tests => 3;
my $stow = new_Stow();
make_path('../stow/pkg3a/bin3');
make_file('../stow/pkg3a/bin3/file3a');
make_link('bin3' => '../stow/pkg3a/bin3'); # emulate stow
# vim:ft=perl
make_path('../stow/pkg3b/bin3');
make_file('../stow/pkg3b/bin3/file3b');
$stow->plan_stow('pkg3b');
$stow->process_tasks();
ok(-d 'bin3');
is(readlink('bin3/file3a'), '../../stow/pkg3a/bin3/file3a');
is(readlink('bin3/file3b'), '../../stow/pkg3b/bin3/file3b'
=> 'target already has 1 stowed package');
});
subtest("Package dir 'bin4' conflicts with existing non-dir so can't unfold", sub {
plan tests => 2;
my $stow = new_Stow();
make_file('bin4'); # this is a file but named like a directory
make_path('../stow/pkg4/bin4');
make_file('../stow/pkg4/bin4/file4');
$stow->plan_stow('pkg4');
%conflicts = $stow->get_conflicts();
is($stow->get_conflict_count, 1);
like(
$conflicts{stow}{pkg4}[0],
qr!cannot stow ../stow/pkg4/bin4 over existing target bin4 since neither a link nor a directory and --adopt not specified!
=> 'link to new dir bin4 conflicts with existing non-directory'
);
});
subtest("Package dir 'bin4a' conflicts with existing non-dir " .
"so can't unfold even with --adopt", sub {
plan tests => 2;
my $stow = new_Stow(adopt => 1);
make_file('bin4a'); # this is a file but named like a directory
make_path('../stow/pkg4a/bin4a');
make_file('../stow/pkg4a/bin4a/file4a');
$stow->plan_stow('pkg4a');
%conflicts = $stow->get_conflicts();
is($stow->get_conflict_count, 1);
like(
$conflicts{stow}{pkg4a}[0],
qr!cannot stow directory ../stow/pkg4a/bin4a over existing non-directory target bin4a!
=> 'link to new dir bin4a conflicts with existing non-directory'
);
});
subtest("Package files 'file4b' and 'bin4b' conflict with existing files", sub {
plan tests => 3;
my $stow = new_Stow();
# Populate target
make_file('file4b', 'file4b - version originally in target');
make_path('bin4b');
make_file('bin4b/file4b', 'bin4b/file4b - version originally in target');
# Populate stow package
make_path('../stow/pkg4b');
make_file('../stow/pkg4b/file4b', 'file4b - version originally in stow package');
make_path('../stow/pkg4b/bin4b');
make_file('../stow/pkg4b/bin4b/file4b', 'bin4b/file4b - version originally in stow package');
$stow->plan_stow('pkg4b');
%conflicts = $stow->get_conflicts();
is($stow->get_conflict_count, 2 => 'conflict per file');
for my $i (0, 1) {
my $target = $i ? 'file4b' : 'bin4b/file4b';
like(
$conflicts{stow}{pkg4b}[$i],
qr,cannot stow ../stow/pkg4b/$target over existing target $target since neither a link nor a directory and --adopt not specified,
=> 'link to file4b conflicts with existing non-directory'
);
}
});
subtest("Package files 'file4d' conflicts with existing directories", sub {
plan tests => 3;
my $stow = new_Stow();
# Populate target
make_path('file4d'); # this is a directory but named like a file to create the conflict
make_path('bin4d/file4d'); # same here
# Populate stow package
make_path('../stow/pkg4d');
make_file('../stow/pkg4d/file4d', 'file4d - version originally in stow package');
make_path('../stow/pkg4d/bin4d');
make_file('../stow/pkg4d/bin4d/file4d', 'bin4d/file4d - version originally in stow package');
$stow->plan_stow('pkg4d');
%conflicts = $stow->get_conflicts();
is($stow->get_conflict_count, 2 => 'conflict per file');
for my $i (0, 1) {
my $target = $i ? 'file4d' : 'bin4d/file4d';
like(
$conflicts{stow}{pkg4d}[$i],
qr!cannot stow non-directory ../stow/pkg4d/$target over existing directory target $target!
=> 'link to file4d conflicts with existing non-directory'
);
}
});
subtest("Package files 'file4c' and 'bin4c' can adopt existing versions", sub {
plan tests => 8;
my $stow = new_Stow(adopt => 1);
# Populate target
make_file('file4c', "file4c - version originally in target\n");
make_path ('bin4c');
make_file('bin4c/file4c', "bin4c/file4c - version originally in target\n");
# Populate stow package
make_path('../stow/pkg4c');
make_file('../stow/pkg4c/file4c', "file4c - version originally in stow package\n");
make_path ('../stow/pkg4c/bin4c');
make_file('../stow/pkg4c/bin4c/file4c', "bin4c/file4c - version originally in stow package\n");
$stow->plan_stow('pkg4c');
is($stow->get_conflict_count, 0 => 'no conflicts with --adopt');
is($stow->get_tasks, 4 => 'two tasks per file');
$stow->process_tasks();
for my $file ('file4c', 'bin4c/file4c') {
ok(-l $file, "$file turned into a symlink");
is(
readlink $file,
(index($file, '/') == -1 ? '' : '../' )
. "../stow/pkg4c/$file" => "$file points to right place"
);
is(cat_file($file), "$file - version originally in target\n" => "$file has right contents");
}
});
subtest("Target already exists but is not owned by stow", sub {
plan tests => 1;
my $stow = new_Stow();
make_path('bin5');
make_invalid_link('bin5/file5','../../empty');
make_path('../stow/pkg5/bin5/file5');
$stow->plan_stow('pkg5');
%conflicts = $stow->get_conflicts();
like(
$conflicts{stow}{pkg5}[-1],
qr/not owned by stow/
=> 'target already exists but is not owned by stow'
);
});
subtest("Replace existing but invalid target", sub {
plan tests => 1;
my $stow = new_Stow();
make_invalid_link('file6','../stow/path-does-not-exist');
make_path('../stow/pkg6');
make_file('../stow/pkg6/file6');
$stow->plan_stow('pkg6');
$stow->process_tasks();
is(
readlink('file6'),
'../stow/pkg6/file6'
=> 'replace existing but invalid target'
);
});
subtest("Target already exists, is owned by stow, but points to a non-directory", sub {
plan tests => 1;
my $stow = new_Stow();
#set_debug_level(4);
make_path('bin7');
make_path('../stow/pkg7a/bin7');
make_file('../stow/pkg7a/bin7/node7');
make_link('bin7/node7','../../stow/pkg7a/bin7/node7');
make_path('../stow/pkg7b/bin7/node7');
make_file('../stow/pkg7b/bin7/node7/file7');
$stow->plan_stow('pkg7b');
%conflicts = $stow->get_conflicts();
like(
$conflicts{stow}{pkg7b}[-1],
qr/existing target is stowed to a different package/
=> 'link to new dir conflicts with existing stowed non-directory'
);
});
subtest("stowing directories named 0", sub {
plan tests => 4;
my $stow = new_Stow();
make_path('../stow/pkg8a/0');
make_file('../stow/pkg8a/0/file8a');
make_link('0' => '../stow/pkg8a/0'); # emulate stow
make_path('../stow/pkg8b/0');
make_file('../stow/pkg8b/0/file8b');
$stow->plan_stow('pkg8b');
$stow->process_tasks();
is($stow->get_conflict_count, 0);
ok(-d '0');
is(readlink('0/file8a'), '../../stow/pkg8a/0/file8a');
is(readlink('0/file8b'), '../../stow/pkg8b/0/file8b'
=> 'stowing directories named 0'
);
});
subtest("overriding already stowed documentation", sub {
plan tests => 2;
my $stow = new_Stow(override => ['man9', 'info9']);
make_path('../stow/pkg9a/man9/man1');
make_file('../stow/pkg9a/man9/man1/file9.1');
make_path('man9/man1');
make_link('man9/man1/file9.1' => '../../../stow/pkg9a/man9/man1/file9.1'); # emulate stow
make_path('../stow/pkg9b/man9/man1');
make_file('../stow/pkg9b/man9/man1/file9.1');
$stow->plan_stow('pkg9b');
$stow->process_tasks();
is($stow->get_conflict_count, 0);
is(readlink('man9/man1/file9.1'), '../../../stow/pkg9b/man9/man1/file9.1'
=> 'overriding existing documentation files'
);
});
subtest("deferring to already stowed documentation", sub {
plan tests => 3;
my $stow = new_Stow(defer => ['man10', 'info10']);
make_path('../stow/pkg10a/man10/man1');
make_file('../stow/pkg10a/man10/man1/file10.1');
make_path('man10/man1');
make_link('man10/man1/file10.1' => '../../../stow/pkg10a/man10/man1/file10.1'); # emulate stow
make_path('../stow/pkg10b/man10/man1');
make_file('../stow/pkg10b/man10/man1/file10.1');
$stow->plan_stow('pkg10b');
is($stow->get_tasks, 0, 'no tasks to process');
is($stow->get_conflict_count, 0);
is(readlink('man10/man1/file10.1'), '../../../stow/pkg10a/man10/man1/file10.1'
=> 'defer to existing documentation files'
);
});
subtest("Ignore temp files", sub {
plan tests => 4;
my $stow = new_Stow(ignore => ['~', '\.#.*']);
make_path('../stow/pkg11/man11/man1');
make_file('../stow/pkg11/man11/man1/file11.1');
make_file('../stow/pkg11/man11/man1/file11.1~');
make_file('../stow/pkg11/man11/man1/.#file11.1');
make_path('man11/man1');
$stow->plan_stow('pkg11');
$stow->process_tasks();
is($stow->get_conflict_count, 0);
is(readlink('man11/man1/file11.1'), '../../../stow/pkg11/man11/man1/file11.1');
ok(!-e 'man11/man1/file11.1~');
ok(!-e 'man11/man1/.#file11.1'
=> 'ignore temp files'
);
});
subtest("stowing links library files", sub {
plan tests => 3;
my $stow = new_Stow();
make_path('../stow/pkg12/lib12/');
make_file('../stow/pkg12/lib12/lib.so.1');
make_link('../stow/pkg12/lib12/lib.so', 'lib.so.1');
make_path('lib12/');
$stow->plan_stow('pkg12');
$stow->process_tasks();
is($stow->get_conflict_count, 0);
is(readlink('lib12/lib.so.1'), '../../stow/pkg12/lib12/lib.so.1');
is(readlink('lib12/lib.so'), '../../stow/pkg12/lib12/lib.so'
=> 'stow links to libraries'
);
});
subtest("unfolding to stow links to library files", sub {
plan tests => 5;
my $stow = new_Stow();
make_path('../stow/pkg13a/lib13/');
make_file('../stow/pkg13a/lib13/liba.so.1');
make_link('../stow/pkg13a/lib13/liba.so', 'liba.so.1');
make_link('lib13','../stow/pkg13a/lib13');
make_path('../stow/pkg13b/lib13/');
make_file('../stow/pkg13b/lib13/libb.so.1');
make_link('../stow/pkg13b/lib13/libb.so', 'libb.so.1');
$stow->plan_stow('pkg13b');
$stow->process_tasks();
is($stow->get_conflict_count, 0);
is(readlink('lib13/liba.so.1'), '../../stow/pkg13a/lib13/liba.so.1');
is(readlink('lib13/liba.so' ), '../../stow/pkg13a/lib13/liba.so');
is(readlink('lib13/libb.so.1'), '../../stow/pkg13b/lib13/libb.so.1');
is(readlink('lib13/libb.so' ), '../../stow/pkg13b/lib13/libb.so'
=> 'unfolding to stow links to libraries'
);
});
subtest("stowing to stow dir should fail", sub {
plan tests => 4;
make_path('stow');
$stow = new_Stow(dir => 'stow');
make_path('stow/pkg14/stow/pkg15');
make_file('stow/pkg14/stow/pkg15/node15');
stderr_like(
sub { $stow->plan_stow('pkg14'); },
qr/WARNING: skipping target which was current stow directory stow/,
"stowing to stow dir should give warning"
);
is($stow->get_tasks, 0, 'no tasks to process');
is($stow->get_conflict_count, 0);
ok(
! -l 'stow/pkg15'
=> "stowing to stow dir should fail"
);
});
subtest("stow a simple tree minimally when cwd isn't target", sub {
plan tests => 2;
cd('../..');
$stow = new_Stow(dir => "$TEST_DIR/stow", target => "$TEST_DIR/target");
make_path("$TEST_DIR/stow/pkg16/bin16");
make_file("$TEST_DIR/stow/pkg16/bin16/file16");
$stow->plan_stow('pkg16');
$stow->process_tasks();
is_deeply([ $stow->get_conflicts ], [], 'no conflicts with minimal stow');
is(
readlink("$TEST_DIR/target/bin16"),
'../stow/pkg16/bin16',
=> "minimal stow of a simple tree when cwd isn't target"
);
});
subtest("stow a simple tree minimally to absolute stow dir when cwd isn't", sub {
plan tests => 2;
my $stow = new_Stow(dir => canon_path("$TEST_DIR/stow"),
target => "$TEST_DIR/target");
make_path("$TEST_DIR/stow/pkg17/bin17");
make_file("$TEST_DIR/stow/pkg17/bin17/file17");
$stow->plan_stow('pkg17');
$stow->process_tasks();
is_deeply([ $stow->get_conflicts ], [], 'no conflicts with minimal stow');
is(
readlink("$TEST_DIR/target/bin17"),
'../stow/pkg17/bin17',
=> "minimal stow of a simple tree with absolute stow dir"
);
});
subtest("stow a simple tree minimally with absolute stow AND target dirs when", sub {
plan tests => 2;
my $stow = new_Stow(dir => canon_path("$TEST_DIR/stow"),
target => canon_path("$TEST_DIR/target"));
make_path("$TEST_DIR/stow/pkg18/bin18");
make_file("$TEST_DIR/stow/pkg18/bin18/file18");
$stow->plan_stow('pkg18');
$stow->process_tasks();
is_deeply([ $stow->get_conflicts ], [], 'no conflicts with minimal stow');
is(
readlink("$TEST_DIR/target/bin18"),
'../stow/pkg18/bin18',
=> "minimal stow of a simple tree with absolute stow and target dirs"
);
});
subtest("stow a tree with no-folding enabled", sub {
plan tests => 82;
# folded directories should be split open (unfolded) where
# (and only where) necessary
#
cd("$TEST_DIR/target");
sub create_pkg {
my ($id, $pkg) = @_;
my $stow_pkg = "../stow/$id-$pkg";
make_path ($stow_pkg);
make_file("$stow_pkg/$id-file-$pkg");
# create a shallow hierarchy specific to this package which isn't
# yet stowed
make_path ("$stow_pkg/$id-$pkg-only-new");
make_file("$stow_pkg/$id-$pkg-only-new/$id-file-$pkg");
# create a deeper hierarchy specific to this package which isn't
# yet stowed
make_path ("$stow_pkg/$id-$pkg-only-new2/subdir");
make_file("$stow_pkg/$id-$pkg-only-new2/subdir/$id-file-$pkg");
make_link("$stow_pkg/$id-$pkg-only-new2/current", "subdir");
# create a hierarchy specific to this package which is already
# stowed via a folded tree
make_path ("$stow_pkg/$id-$pkg-only-old");
make_link("$id-$pkg-only-old", "$stow_pkg/$id-$pkg-only-old");
make_file("$stow_pkg/$id-$pkg-only-old/$id-file-$pkg");
# create a shared hierarchy which this package uses
make_path ("$stow_pkg/$id-shared");
make_file("$stow_pkg/$id-shared/$id-file-$pkg");
# create a partially shared hierarchy which this package uses
make_path ("$stow_pkg/$id-shared2/subdir-$pkg");
make_file("$stow_pkg/$id-shared2/$id-file-$pkg");
make_file("$stow_pkg/$id-shared2/subdir-$pkg/$id-file-$pkg");
}
foreach my $pkg (qw{a b}) {
create_pkg('no-folding', $pkg);
}
$stow = new_Stow('no-folding' => 1);
$stow->plan_stow('no-folding-a');
is_deeply([ $stow->get_conflicts ], [] => 'no conflicts with --no-folding');
my @tasks = $stow->get_tasks;
use Data::Dumper;
is(scalar(@tasks), 13 => "6 dirs, 7 links") || warn Dumper(\@tasks);
$stow->process_tasks();
sub check_no_folding {
my ($pkg) = @_;
my $stow_pkg = "../stow/no-folding-$pkg";
is_link("no-folding-file-$pkg", "$stow_pkg/no-folding-file-$pkg");
# check existing folded tree is untouched
is_link("no-folding-$pkg-only-old", "$stow_pkg/no-folding-$pkg-only-old");
# check newly stowed shallow tree is not folded
is_dir_not_symlink("no-folding-$pkg-only-new");
is_link("no-folding-$pkg-only-new/no-folding-file-$pkg",
"../$stow_pkg/no-folding-$pkg-only-new/no-folding-file-$pkg");
# check newly stowed deeper tree is not folded
is_dir_not_symlink("no-folding-$pkg-only-new2");
is_dir_not_symlink("no-folding-$pkg-only-new2/subdir");
is_link("no-folding-$pkg-only-new2/subdir/no-folding-file-$pkg",
"../../$stow_pkg/no-folding-$pkg-only-new2/subdir/no-folding-file-$pkg");
is_link("no-folding-$pkg-only-new2/current",
"../$stow_pkg/no-folding-$pkg-only-new2/current");
# check shared tree is not folded. first time round this will be
# newly stowed.
is_dir_not_symlink('no-folding-shared');
is_link("no-folding-shared/no-folding-file-$pkg",
"../$stow_pkg/no-folding-shared/no-folding-file-$pkg");
# check partially shared tree is not folded. first time round this
# will be newly stowed.
is_dir_not_symlink('no-folding-shared2');
is_link("no-folding-shared2/no-folding-file-$pkg",
"../$stow_pkg/no-folding-shared2/no-folding-file-$pkg");
is_link("no-folding-shared2/no-folding-file-$pkg",
"../$stow_pkg/no-folding-shared2/no-folding-file-$pkg");
}
check_no_folding('a');
$stow = new_Stow('no-folding' => 1);
$stow->plan_stow('no-folding-b');
is_deeply([ $stow->get_conflicts ], [] => 'no conflicts with --no-folding');
@tasks = $stow->get_tasks;
is(scalar(@tasks), 11 => '4 dirs, 7 links') || warn Dumper(\@tasks);
$stow->process_tasks();
check_no_folding('a');
check_no_folding('b');
});

View file

@ -1,283 +0,0 @@
#!/usr/local/bin/perl
#
# Testing
#
# load as a library
BEGIN { use lib qw(.); require "t/util.pm"; require "stow"; }
use Test::More tests => 13;
use English qw(-no_match_vars);
# local utility
sub reset_state {
@Tasks = ();
@Conflicts = ();
%Link_Task_For = ();
%Dir_Task_For = ();
%Options = ();
return;
}
### setup
eval { remove_dir('t/target'); };
eval { remove_dir('t/stow'); };
make_dir('t/target');
make_dir('t/stow');
chdir 't/target';
$Stow_Path= '../stow';
# Note that each of the following tests use a distinct set of files
#
# stow a simple tree minimally
#
reset_state();
$Option{'verbose'} = 0;
make_dir('../stow/pkg1/bin1');
make_file('../stow/pkg1/bin1/file1');
stow_contents('../stow/pkg1', './', '../stow/pkg1');
process_tasks();
is(
readlink('bin1'),
'../stow/pkg1/bin1',
=> 'minimal stow of a simple tree'
);
#
# stow a simple tree into an existing directory
#
reset_state();
$Option{'verbose'} = 0;
make_dir('../stow/pkg2/lib2');
make_file('../stow/pkg2/lib2/file2');
make_dir('lib2');
stow_contents('../stow/pkg2', './', '../stow/pkg2');
process_tasks();
is(
readlink('lib2/file2'),
'../../stow/pkg2/lib2/file2',
=> 'stow simple tree to existing directory'
);
#
# unfold existing tree
#
reset_state();
$Option{'verbose'} = 0;
make_dir('../stow/pkg3a/bin3');
make_file('../stow/pkg3a/bin3/file3a');
make_link('bin3' => '../stow/pkg3a/bin3'); # emulate stow
make_dir('../stow/pkg3b/bin3');
make_file('../stow/pkg3b/bin3/file3b');
stow_contents('../stow/pkg3b', './', '../stow/pkg3b');
process_tasks();
ok(
-d 'bin3' &&
readlink('bin3/file3a') eq '../../stow/pkg3a/bin3/file3a' &&
readlink('bin3/file3b') eq '../../stow/pkg3b/bin3/file3b'
=> 'target already has 1 stowed package'
);
#
# Link to a new dir conflicts with existing non-dir (can't unfold)
#
reset_state();
$Option{'verbose'} = 0;
make_file('bin4'); # this is a file but named like a directory
make_dir('../stow/pkg4/bin4');
make_file('../stow/pkg4/bin4/file4');
stow_contents('../stow/pkg4', './', '../stow/pkg4');
like(
$Conflicts[-1], qr(CONFLICT:.*existing target is neither a link nor a directory)
=> 'link to new dir conflicts with existing non-directory'
);
#
# Target already exists but is not owned by stow
#
reset_state();
$Option{'verbose'} = 0;
make_dir('bin5');
make_link('bin5/file5','../../empty');
make_dir('../stow/pkg5/bin5/file5');
stow_contents('../stow/pkg5', './', '../stow/pkg5');
like(
$Conflicts[-1], qr(CONFLICT:.*not owned by stow)
=> 'target already exists but is not owned by stow'
);
#
# Replace existing but invalid target
#
reset_state();
$Option{'verbose'} = 0;
make_link('file6','../stow/path-does-not-exist');
make_dir('../stow/pkg6');
make_file('../stow/pkg6/file6');
eval{ stow_contents('../stow/pkg6', './', '../stow/pkg6'); process_tasks() };
is(
readlink('file6'),
'../stow/pkg6/file6'
=> 'replace existing but invalid target'
);
#
# Target already exists, is owned by stow, but points to a non-directory
# (can't unfold)
#
reset_state();
$Option{'verbose'} = 0;
make_dir('bin7');
make_dir('../stow/pkg7a/bin7');
make_file('../stow/pkg7a/bin7/node7');
make_link('bin7/node7','../../stow/pkg7a/bin7/node7');
make_dir('../stow/pkg7b/bin7/node7');
make_file('../stow/pkg7b/bin7/node7/file7');
stow_contents('../stow/pkg7b', './', '../stow/pkg7b');
like(
$Conflicts[-1], qr(CONFLICT:.*existing target is stowed to a different package)
=> 'link to new dir conflicts with existing stowed non-directory'
);
#
# stowing directories named 0
#
reset_state();
$Option{'verbose'} = 0;
make_dir('../stow/pkg8a/0');
make_file('../stow/pkg8a/0/file8a');
make_link('0' => '../stow/pkg8a/0'); # emulate stow
make_dir('../stow/pkg8b/0');
make_file('../stow/pkg8b/0/file8b');
stow_contents('../stow/pkg8b', './', '../stow/pkg8b');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
-d '0' &&
readlink('0/file8a') eq '../../stow/pkg8a/0/file8a' &&
readlink('0/file8b') eq '../../stow/pkg8b/0/file8b'
=> 'stowing directories named 0'
);
#
# overriding already stowed documentation
#
reset_state();
$Option{'verbose'} = 0;
$Option{'override'} = ['man9', 'info9'];
make_dir('../stow/pkg9a/man9/man1');
make_file('../stow/pkg9a/man9/man1/file9.1');
make_dir('man9/man1');
make_link('man9/man1/file9.1' => '../../../stow/pkg9a/man9/man1/file9.1'); # emulate stow
make_dir('../stow/pkg9b/man9/man1');
make_file('../stow/pkg9b/man9/man1/file9.1');
stow_contents('../stow/pkg9b', './', '../stow/pkg9b');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
readlink('man9/man1/file9.1') eq '../../../stow/pkg9b/man9/man1/file9.1'
=> 'overriding existing documentation files'
);
#
# deferring to already stowed documentation
#
reset_state();
$Option{'verbose'} = 0;
$Option{'defer'} = ['man10', 'info10'];
make_dir('../stow/pkg10a/man10/man1');
make_file('../stow/pkg10a/man10/man1/file10.1');
make_dir('man10/man1');
make_link('man10/man1/file10.1' => '../../../stow/pkg10a/man10/man1/file10.1'); # emulate stow
make_dir('../stow/pkg10b/man10/man1');
make_file('../stow/pkg10b/man10/man1/file10.1');
stow_contents('../stow/pkg10b', './', '../stow/pkg10b');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
readlink('man10/man1/file10.1') eq '../../../stow/pkg10a/man10/man1/file10.1'
=> 'defer to existing documentation files'
);
#
# Ignore temp files
#
reset_state();
$Option{'verbose'} = 0;
$Option{'ignore'} = ['~', '\.#.*'];
make_dir('../stow/pkg11/man11/man1');
make_file('../stow/pkg11/man11/man1/file11.1');
make_file('../stow/pkg11/man11/man1/file11.1~');
make_file('../stow/pkg11/man11/man1/.#file11.1');
make_dir('man11/man1');
stow_contents('../stow/pkg11', './', '../stow/pkg11');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
readlink('man11/man1/file11.1') eq '../../../stow/pkg11/man11/man1/file11.1' &&
!-e 'man11/man1/file11.1~' &&
!-e 'man11/man1/.#file11.1'
=> 'ignore temp files'
);
#
# stowing links library files
#
reset_state();
$Option{'verbose'} = 0;
make_dir('../stow/pkg12/lib12/');
make_file('../stow/pkg12/lib12/lib.so');
make_link('../stow/pkg12/lib12/lib.so.1','lib.so');
make_dir('lib12/');
stow_contents('../stow/pkg12', './', '../stow/pkg12');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
readlink('lib12/lib.so.1') eq '../../stow/pkg12/lib12/lib.so.1'
=> 'stow links to libraries'
);
#
# unfolding to stow links to library files
#
reset_state();
$Option{'verbose'} = 0;
make_dir('../stow/pkg13a/lib13/');
make_file('../stow/pkg13a/lib13/liba.so');
make_link('../stow/pkg13a/lib13/liba.so.1', 'liba.so');
make_link('lib13','../stow/pkg13a/lib13');
make_dir('../stow/pkg13b/lib13/');
make_file('../stow/pkg13b/lib13/libb.so');
make_link('../stow/pkg13b/lib13/libb.so.1', 'libb.so');
stow_contents('../stow/pkg13b', './', '../stow/pkg13b');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
readlink('lib13/liba.so.1') eq '../../stow/pkg13a/lib13/liba.so.1' &&
readlink('lib13/libb.so.1') eq '../../stow/pkg13b/lib13/libb.so.1'
=> 'unfolding to stow links to libraries'
);

307
t/testutil.pm Executable file
View file

@ -0,0 +1,307 @@
#!/usr/bin/perl
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
#
# Utilities shared by test scripts
#
package testutil;
use strict;
use warnings;
use Carp qw(confess croak);
use File::Basename;
use File::Path qw(make_path remove_tree);
use File::Spec;
use Test::More;
use Stow;
use Stow::Util qw(parent canon_path);
use base qw(Exporter);
our @EXPORT = qw(
$ABS_TEST_DIR
$TEST_DIR
init_test_dirs
cd
new_Stow new_compat_Stow
make_path make_link make_invalid_link make_file
remove_dir remove_file remove_link
cat_file
is_link is_dir_not_symlink is_nonexistent_path
);
our $TEST_DIR = 'tmp-testing-trees';
our $ABS_TEST_DIR = File::Spec->rel2abs('tmp-testing-trees');
sub init_test_dirs {
my $test_dir = shift || $TEST_DIR;
my $abs_test_dir = File::Spec->rel2abs($test_dir);
# Create a run_from/ subdirectory for tests which want to run
# from a separate directory outside the Stow directory or
# target directory.
for my $dir ("target", "stow", "run_from") {
my $path = "$test_dir/$dir";
-d $path and remove_tree($path);
make_path($path);
}
# Don't let user's ~/.stow-global-ignore affect test results
$ENV{HOME} = $abs_test_dir;
return $abs_test_dir;
}
sub new_Stow {
my %opts = @_;
# These default paths assume that execution will be triggered from
# within the target directory.
$opts{dir} ||= '../stow';
$opts{target} ||= '.';
$opts{test_mode} = 1;
my $stow = eval { new Stow(%opts) };
if ($@) {
confess "Error while trying to instantiate new Stow(%opts): $@";
}
return $stow;
}
sub new_compat_Stow {
my %opts = @_;
$opts{compat} = 1;
return new_Stow(%opts);
}
#===== SUBROUTINE ===========================================================
# Name : make_link()
# Purpose : safely create a link
# Parameters: $link_src => path to the link
# : $link_dest => where the new link should point
# : $invalid => true iff $link_dest refers to non-existent file
# Returns : n/a
# Throws : fatal error if the link can not be safely created
# Comments : checks for existing nodes
#============================================================================
sub make_link {
my ($link_src, $link_dest, $invalid) = @_;
if (-l $link_src) {
my $old_source = readlink join('/', parent($link_src), $link_dest)
or croak "$link_src is already a link but could not read link $link_src/$link_dest";
if ($old_source ne $link_dest) {
croak "$link_src already exists but points elsewhere\n";
}
}
croak "$link_src already exists and is not a link\n" if -e $link_src;
my $abs_target = File::Spec->rel2abs($link_src);
my $link_src_container = dirname($abs_target);
my $abs_source = File::Spec->rel2abs($link_dest, $link_src_container);
#warn "t $link_src c $link_src_container as $abs_source";
if (-e $abs_source) {
croak "Won't make invalid link pointing to existing $abs_target"
if $invalid;
}
else {
croak "Won't make link pointing to non-existent $abs_target"
unless $invalid;
}
symlink $link_dest, $link_src
or croak "could not create link $link_src => $link_dest ($!)\n";
}
#===== SUBROUTINE ===========================================================
# Name : make_invalid_link()
# Purpose : safely create an invalid link
# Parameters: $target => path to the link
# : $source => the non-existent source where the new link should point
# Returns : n/a
# Throws : fatal error if the link can not be safely created
# Comments : checks for existing nodes
#============================================================================
sub make_invalid_link {
my ($target, $source, $allow_invalid) = @_;
make_link($target, $source, 1);
}
#===== SUBROUTINE ===========================================================
# Name : create_file()
# Purpose : create an empty file
# Parameters: $path => proposed path to the file
# : $contents => (optional) contents to write to file
# Returns : n/a
# Throws : fatal error if the file could not be created
# Comments : detects clash with an existing non-file
#============================================================================
sub make_file {
my ($path, $contents) = @_;
if (-e $path and ! -f $path) {
croak "a non-file already exists at $path\n";
}
open my $FILE ,'>', $path
or croak "could not create file: $path ($!)\n";
print $FILE $contents if defined $contents;
close $FILE;
}
#===== SUBROUTINE ===========================================================
# Name : remove_link()
# Purpose : remove an esiting symbolic link
# Parameters: $path => path to the symbolic link
# Returns : n/a
# Throws : fatal error if the operation fails or if passed the path to a
# : non-link
# Comments : none
#============================================================================
sub remove_link {
my ($path) = @_;
if (not -l $path) {
croak qq(remove_link() called with a non-link: $path);
}
unlink $path or croak "could not remove link: $path ($!)\n";
return;
}
#===== SUBROUTINE ===========================================================
# Name : remove_file()
# Purpose : remove an existing empty file
# Parameters: $path => the path to the empty file
# Returns : n/a
# Throws : fatal error if given file is non-empty or the operation fails
# Comments : none
#============================================================================
sub remove_file {
my ($path) = @_;
if (-z $path) {
croak "file at $path is non-empty\n";
}
unlink $path or croak "could not remove empty file: $path ($!)\n";
return;
}
#===== SUBROUTINE ===========================================================
# Name : remove_dir()
# Purpose : safely remove a tree of test files
# Parameters: $dir => path to the top of the tree
# Returns : n/a
# Throws : fatal error if the tree contains a non-link or non-empty file
# Comments : recursively removes directories containing softlinks empty files
#============================================================================
sub remove_dir {
my ($dir) = @_;
if (not -d $dir) {
croak "$dir is not a directory";
}
opendir my $DIR, $dir or croak "cannot read directory: $dir ($!)\n";
my @listing = readdir $DIR;
closedir $DIR;
NODE:
for my $node (@listing) {
next NODE if $node eq '.';
next NODE if $node eq '..';
my $path = "$dir/$node";
if (-l $path or (-f $path and -z $path) or $node eq $Stow::LOCAL_IGNORE_FILE) {
unlink $path or croak "cannot unlink $path ($!)\n";
}
elsif (-d "$path") {
remove_dir($path);
}
else {
croak "$path is not a link, directory, or empty file\n";
}
}
rmdir $dir or croak "cannot rmdir $dir ($!)\n";
return;
}
#===== SUBROUTINE ===========================================================
# Name : cd()
# Purpose : wrapper around chdir
# Parameters: $dir => path to chdir to
# Returns : n/a
# Throws : fatal error if the chdir fails
# Comments : none
#============================================================================
sub cd {
my ($dir) = @_;
chdir $dir or croak "Failed to chdir($dir): $!\n";
}
#===== SUBROUTINE ===========================================================
# Name : cat_file()
# Purpose : return file contents
# Parameters: $file => file to read
# Returns : n/a
# Throws : fatal error if the open fails
# Comments : none
#============================================================================
sub cat_file {
my ($file) = @_;
open F, $file or croak "Failed to open($file): $!\n";
my $contents = join '', <F>;
close(F);
return $contents;
}
#===== SUBROUTINE ===========================================================
# Name : is_link()
# Purpose : assert path is a symlink
# Parameters: $path => path to check
# : $dest => target symlink should point to
#============================================================================
sub is_link {
my ($path, $dest) = @_;
ok(-l $path => "$path should be symlink");
is(readlink $path, $dest => "$path symlinks to $dest");
}
#===== SUBROUTINE ===========================================================
# Name : is_dir_not_symlink()
# Purpose : assert path is a directory not a symlink
# Parameters: $path => path to check
#============================================================================
sub is_dir_not_symlink {
my ($path) = @_;
ok(! -l $path => "$path should not be symlink");
ok(-d _ => "$path should be a directory");
}
#===== SUBROUTINE ===========================================================
# Name : is_nonexistent_path()
# Purpose : assert path does not exist
# Parameters: $path => path to check
#============================================================================
sub is_nonexistent_path {
my ($path) = @_;
ok(! -l $path => "$path should not be symlink");
ok(! -e _ => "$path should not exist");
}
1;
# Local variables:
# mode: perl
# end:
# vim: ft=perl

549
t/unstow.t Executable file
View file

@ -0,0 +1,549 @@
#!/usr/bin/perl
#
# This file is part of GNU Stow.
#
# GNU Stow is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNU Stow is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see https://www.gnu.org/licenses/.
#
# Test unstowing packages
#
use strict;
use warnings;
use File::Spec qw(make_path);
use POSIX qw(getcwd);
use Test::More tests => 35;
use Test::Output;
use English qw(-no_match_vars);
use testutil;
use Stow::Util qw(canon_path);
my $repo = getcwd();
init_test_dirs($TEST_DIR);
our $COMPAT_TEST_DIR = "${TEST_DIR}-compat";
our $COMPAT_ABS_TEST_DIR = init_test_dirs($COMPAT_TEST_DIR);
sub init_stow2 {
make_path('stow2'); # make our alternate stow dir a subdir of target
make_file('stow2/.stow');
}
sub create_unowned_files {
# Make things harder for Stow to figure out, by adding
# a bunch of alien files unrelated to Stow.
my @UNOWNED_DIRS = ('unowned-dir', '.unowned-dir', 'dot-unowned-dir');
for my $dir ('.', @UNOWNED_DIRS) {
for my $subdir ('.', @UNOWNED_DIRS) {
make_path("$dir/$subdir");
make_file("$dir/$subdir/unowned");
make_file("$dir/$subdir/.unowned");
make_file("$dir/$subdir/dot-unowned");
}
}
}
# Run a subtest twice, with compat off then on, in parallel test trees.
#
# Params: $name[, $setup], $test_code
#
# $setup is an optional ref to an options hash to pass into the new
# Stow() constructor, or a ref to a sub which performs setup before
# the constructor gets called and then returns that options hash.
sub subtests {
my $name = shift;
my $setup = @_ == 2 ? shift : {};
my $code = shift;
$ENV{HOME} = $ABS_TEST_DIR;
cd($repo);
cd("$TEST_DIR/target");
create_unowned_files();
# cd first to allow setup to cd somewhere else.
my $opts = ref($setup) eq 'HASH' ? $setup : $setup->($TEST_DIR);
subtest($name, sub {
make_path($opts->{dir}) if $opts->{dir};
my $stow = new_Stow(%$opts);
$code->($stow, $TEST_DIR);
});
$ENV{HOME} = $COMPAT_ABS_TEST_DIR;
cd($repo);
cd("$COMPAT_TEST_DIR/target");
create_unowned_files();
# cd first to allow setup to cd somewhere else.
$opts = ref $setup eq 'HASH' ? $setup : $setup->($COMPAT_TEST_DIR);
subtest("$name (compat mode)", sub {
make_path($opts->{dir}) if $opts->{dir};
my $stow = new_compat_Stow(%$opts);
$code->($stow, $COMPAT_TEST_DIR);
});
}
sub plan_tests {
my ($stow, $count) = @_;
plan tests => $stow->{compat} ? $count + 2 : $count;
}
subtests("unstow a simple tree minimally", sub {
my ($stow) = @_;
plan tests => 3;
make_path('../stow/pkg1/bin1');
make_file('../stow/pkg1/bin1/file1');
make_link('bin1', '../stow/pkg1/bin1');
$stow->plan_unstow('pkg1');
$stow->process_tasks();
is($stow->get_conflict_count, 0, 'conflict count');
ok(-f '../stow/pkg1/bin1/file1');
ok(! -e 'bin1' => 'unstow a simple tree');
});
subtests("unstow a simple tree from an existing directory", sub {
my ($stow) = @_;
plan tests => 3;
make_path('lib2');
make_path('../stow/pkg2/lib2');
make_file('../stow/pkg2/lib2/file2');
make_link('lib2/file2', '../../stow/pkg2/lib2/file2');
$stow->plan_unstow('pkg2');
$stow->process_tasks();
is($stow->get_conflict_count, 0, 'conflict count');
ok(-f '../stow/pkg2/lib2/file2');
ok(-d 'lib2'
=> 'unstow simple tree from a pre-existing directory'
);
});
subtests("fold tree after unstowing", sub {
my ($stow) = @_;
plan tests => 3;
make_path('bin3');
make_path('../stow/pkg3a/bin3');
make_file('../stow/pkg3a/bin3/file3a');
make_link('bin3/file3a' => '../../stow/pkg3a/bin3/file3a'); # emulate stow
make_path('../stow/pkg3b/bin3');
make_file('../stow/pkg3b/bin3/file3b');
make_link('bin3/file3b' => '../../stow/pkg3b/bin3/file3b'); # emulate stow
$stow->plan_unstow('pkg3b');
$stow->process_tasks();
is($stow->get_conflict_count, 0, 'conflict count');
ok(-l 'bin3');
is(readlink('bin3'), '../stow/pkg3a/bin3'
=> 'fold tree after unstowing'
);
});
subtests("existing link is owned by stow but is invalid so it gets removed anyway", sub {
my ($stow) = @_;
plan tests => 2;
make_path('bin4');
make_path('../stow/pkg4/bin4');
make_file('../stow/pkg4/bin4/file4');
make_invalid_link('bin4/file4', '../../stow/pkg4/bin4/does-not-exist');
$stow->plan_unstow('pkg4');
$stow->process_tasks();
is($stow->get_conflict_count, 0, 'conflict count');
ok(! -e 'bin4/file4'
=> q(remove invalid link owned by stow)
);
});
subtests("Existing invalid link is not owned by stow", sub {
my ($stow) = @_;
plan tests => 3;
make_path('../stow/pkg5/bin5');
make_invalid_link('bin5', '../not-stow');
$stow->plan_unstow('pkg5');
is($stow->get_conflict_count, 0, 'conflict count');
ok(-l 'bin5', 'invalid link not removed');
is(readlink('bin5'), '../not-stow' => "invalid link not changed");
});
subtests("Target already exists, is owned by stow, but points to a different package", sub {
my ($stow) = @_;
plan tests => 3;
make_path('bin6');
make_path('../stow/pkg6a/bin6');
make_file('../stow/pkg6a/bin6/file6');
make_link('bin6/file6', '../../stow/pkg6a/bin6/file6');
make_path('../stow/pkg6b/bin6');
make_file('../stow/pkg6b/bin6/file6');
$stow->plan_unstow('pkg6b');
is($stow->get_conflict_count, 0, 'conflict count');
ok(-l 'bin6/file6');
is(
readlink('bin6/file6'),
'../../stow/pkg6a/bin6/file6'
=> q(ignore existing link that points to a different package)
);
});
subtests("Don't unlink anything under the stow directory",
sub {
make_path('stow');
return { dir => 'stow' };
# target dir defaults to parent of stow, which is target directory
},
sub {
plan tests => 5;
my ($stow) = @_;
# Emulate stowing into ourself (bizarre corner case or accident):
make_path('stow/pkg7a/stow/pkg7b');
make_file('stow/pkg7a/stow/pkg7b/file7b');
# Make a package be a link to a package of the same name inside another package.
make_link('stow/pkg7b', '../stow/pkg7a/stow/pkg7b');
stderr_like(
sub { $stow->plan_unstow('pkg7b'); },
$stow->{compat} ? qr/WARNING: skipping target which was current stow directory stow/ : qr//
=> "warn when unstowing from ourself"
);
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg7b');
is($stow->get_conflict_count, 0, 'conflict count');
ok(-l 'stow/pkg7b');
is(
readlink('stow/pkg7b'),
'../stow/pkg7a/stow/pkg7b'
=> q(don't unlink any nodes under the stow directory)
);
});
subtests("Don't unlink any nodes under another stow directory",
sub {
make_path('stow');
return { dir => 'stow' };
},
sub {
my ($stow) = @_;
plan tests => 5;
init_stow2();
# emulate stowing into ourself (bizarre corner case or accident)
make_path('stow/pkg8a/stow2/pkg8b');
make_file('stow/pkg8a/stow2/pkg8b/file8b');
make_link('stow2/pkg8b', '../stow/pkg8a/stow2/pkg8b');
stderr_like(
sub { $stow->plan_unstow('pkg8a'); },
qr/WARNING: skipping marked Stow directory stow2/
=> "warn when skipping unstowing"
);
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg8a');
is($stow->get_conflict_count, 0, 'conflict count');
ok(-l 'stow2/pkg8b');
is(
readlink('stow2/pkg8b'),
'../stow/pkg8a/stow2/pkg8b'
=> q(don't unlink any nodes under another stow directory)
);
});
# This will be used by subsequent tests
sub check_protected_dirs_skipped {
my ($stderr) = @_;
for my $dir (qw{stow stow2}) {
like($stderr,
qr/WARNING: skipping marked Stow directory $dir/
=> "warn when skipping marked directory $dir");
}
}
subtests("overriding already stowed documentation",
{override => ['man9', 'info9']},
sub {
my ($stow) = @_;
plan_tests($stow, 2);
make_file('stow/.stow');
init_stow2();
make_path('../stow/pkg9a/man9/man1');
make_file('../stow/pkg9a/man9/man1/file9.1');
make_path('man9/man1');
make_link('man9/man1/file9.1' => '../../../stow/pkg9a/man9/man1/file9.1'); # emulate stow
make_path('../stow/pkg9b/man9/man1');
make_file('../stow/pkg9b/man9/man1/file9.1');
my $stderr = stderr_from { $stow->plan_unstow('pkg9b') };
check_protected_dirs_skipped($stderr) if $stow->{compat};
$stow->process_tasks();
is($stow->get_conflict_count, 0, 'conflict count');
ok(!-l 'man9/man1/file9.1'
=> 'overriding existing documentation files'
);
});
subtests("deferring to already stowed documentation",
{defer => ['man10', 'info10']},
sub {
my ($stow) = @_;
plan_tests($stow, 3);
init_stow2();
make_path('../stow/pkg10a/man10/man1');
make_file('../stow/pkg10a/man10/man1/file10a.1');
make_path('man10/man1');
make_link('man10/man1/file10a.1' => '../../../stow/pkg10a/man10/man1/file10a.1');
# need this to block folding
make_path('../stow/pkg10b/man10/man1');
make_file('../stow/pkg10b/man10/man1/file10b.1');
make_link('man10/man1/file10b.1' => '../../../stow/pkg10b/man10/man1/file10b.1');
make_path('../stow/pkg10c/man10/man1');
make_file('../stow/pkg10c/man10/man1/file10a.1');
my $stderr = stderr_from { $stow->plan_unstow('pkg10c') };
check_protected_dirs_skipped($stderr) if $stow->{compat};
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg10c');
is($stow->get_conflict_count, 0, 'conflict count');
is(
readlink('man10/man1/file10a.1'),
'../../../stow/pkg10a/man10/man1/file10a.1'
=> 'defer to existing documentation files'
);
});
subtests("Ignore temp files",
{ignore => ['~', '\.#.*']},
sub {
my ($stow) = @_;
plan_tests($stow, 2);
init_stow2();
make_path('../stow/pkg12/man12/man1');
make_file('../stow/pkg12/man12/man1/file12.1');
make_file('../stow/pkg12/man12/man1/file12.1~');
make_file('../stow/pkg12/man12/man1/.#file12.1');
make_path('man12/man1');
make_link('man12/man1/file12.1' => '../../../stow/pkg12/man12/man1/file12.1');
my $stderr = stderr_from { $stow->plan_unstow('pkg12') };
check_protected_dirs_skipped($stderr) if $stow->{compat};
$stow->process_tasks();
is($stow->get_conflict_count, 0, 'conflict count');
ok(! -e 'man12/man1/file12.1' => 'man12/man1/file12.1 was unstowed');
});
subtests("Unstow an already unstowed package", sub {
my ($stow) = @_;
plan_tests($stow, 2);
my $stderr = stderr_from { $stow->plan_unstow('pkg12') };
check_protected_dirs_skipped($stderr) if $stow->{compat};
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg12');
is($stow->get_conflict_count, 0, 'conflict count');
});
subtests("Unstow a never stowed package", sub {
my ($stow) = @_;
plan tests => 2;
eval { remove_dir($stow->{target}); };
mkdir($stow->{target});
$stow->plan_unstow('pkg12');
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg12 which was never stowed');
is($stow->get_conflict_count, 0, 'conflict count');
});
subtests("Unstowing when target contains real files shouldn't be an issue", sub {
my ($stow) = @_;
plan tests => 4;
# Test both a file which do / don't overlap with the package
make_path('man12/man1');
make_file('man12/man1/alien');
make_file('man12/man1/file12.1');
$stow->plan_unstow('pkg12');
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg12 for third time');
is($stow->get_conflict_count, 0, 'conflict count');
ok(-f 'man12/man1/alien', 'alien untouched');
ok(-f 'man12/man1/file12.1', 'file overlapping with pkg untouched');
});
subtests("unstow a simple tree minimally when cwd isn't target",
sub {
my $test_dir = shift;
cd($repo);
return {
dir => "$test_dir/stow",
target => "$test_dir/target"
}
},
sub {
my ($stow, $test_dir) = @_;
plan tests => 3;
make_path("$test_dir/stow/pkg13/bin13");
make_file("$test_dir/stow/pkg13/bin13/file13");
make_link("$test_dir/target/bin13", '../stow/pkg13/bin13');
$stow->plan_unstow('pkg13');
$stow->process_tasks();
is($stow->get_conflict_count, 0, 'conflict count');
ok(-f "$test_dir/stow/pkg13/bin13/file13", 'package file untouched');
ok(! -e "$test_dir/target/bin13" => 'bin13/ unstowed');
});
subtests("unstow a simple tree minimally with absolute stow dir when cwd isn't target",
sub {
my $test_dir = shift;
cd($repo);
return {
dir => canon_path("$test_dir/stow"),
target => "$test_dir/target"
};
},
sub {
plan tests => 3;
my ($stow, $test_dir) = @_;
make_path("$test_dir/stow/pkg14/bin14");
make_file("$test_dir/stow/pkg14/bin14/file14");
make_link("$test_dir/target/bin14", '../stow/pkg14/bin14');
$stow->plan_unstow('pkg14');
$stow->process_tasks();
is($stow->get_conflict_count, 0, 'conflict count');
ok(-f "$test_dir/stow/pkg14/bin14/file14");
ok(! -e "$test_dir/target/bin14"
=> 'unstow a simple tree with absolute stow dir'
);
});
subtests("unstow a simple tree minimally with absolute stow AND target dirs when cwd isn't target",
sub {
my $test_dir = shift;
cd($repo);
return {
dir => canon_path("$test_dir/stow"),
target => canon_path("$test_dir/target")
};
},
sub {
my ($stow, $test_dir) = @_;
plan tests => 3;
make_path("$test_dir/stow/pkg15/bin15");
make_file("$test_dir/stow/pkg15/bin15/file15");
make_link("$test_dir/target/bin15", '../stow/pkg15/bin15');
$stow->plan_unstow('pkg15');
$stow->process_tasks();
is($stow->get_conflict_count, 0, 'conflict count');
ok(-f "$test_dir/stow/pkg15/bin15/file15");
ok(! -e "$test_dir/target/bin15"
=> 'unstow a simple tree with absolute stow and target dirs'
);
});
sub create_and_stow_pkg {
my ($id, $pkg) = @_;
my $stow_pkg = "../stow/$id-$pkg";
make_path($stow_pkg);
make_file("$stow_pkg/$id-file-$pkg");
# create a shallow hierarchy specific to this package and stow
# via folding
make_path("$stow_pkg/$id-$pkg-only-folded");
make_file("$stow_pkg/$id-$pkg-only-folded/file-$pkg");
make_link("$id-$pkg-only-folded", "$stow_pkg/$id-$pkg-only-folded");
# create a deeper hierarchy specific to this package and stow
# via folding
make_path("$stow_pkg/$id-$pkg-only-folded2/subdir");
make_file("$stow_pkg/$id-$pkg-only-folded2/subdir/file-$pkg");
make_link("$id-$pkg-only-folded2",
"$stow_pkg/$id-$pkg-only-folded2");
# create a shallow hierarchy specific to this package and stow
# without folding
make_path("$stow_pkg/$id-$pkg-only-unfolded");
make_file("$stow_pkg/$id-$pkg-only-unfolded/file-$pkg");
make_path("$id-$pkg-only-unfolded");
make_link("$id-$pkg-only-unfolded/file-$pkg",
"../$stow_pkg/$id-$pkg-only-unfolded/file-$pkg");
# create a deeper hierarchy specific to this package and stow
# without folding
make_path("$stow_pkg/$id-$pkg-only-unfolded2/subdir");
make_file("$stow_pkg/$id-$pkg-only-unfolded2/subdir/file-$pkg");
make_path("$id-$pkg-only-unfolded2/subdir");
make_link("$id-$pkg-only-unfolded2/subdir/file-$pkg",
"../../$stow_pkg/$id-$pkg-only-unfolded2/subdir/file-$pkg");
# create a shallow shared hierarchy which this package uses, and stow
# its contents without folding
make_path("$stow_pkg/$id-shared");
make_file("$stow_pkg/$id-shared/file-$pkg");
make_path("$id-shared");
make_link("$id-shared/file-$pkg",
"../$stow_pkg/$id-shared/file-$pkg");
# create a deeper shared hierarchy which this package uses, and stow
# its contents without folding
make_path("$stow_pkg/$id-shared2/subdir");
make_file("$stow_pkg/$id-shared2/file-$pkg");
make_file("$stow_pkg/$id-shared2/subdir/file-$pkg");
make_path("$id-shared2/subdir");
make_link("$id-shared2/file-$pkg",
"../$stow_pkg/$id-shared2/file-$pkg");
make_link("$id-shared2/subdir/file-$pkg",
"../../$stow_pkg/$id-shared2/subdir/file-$pkg");
}
subtest("unstow a tree with no-folding enabled - no refolding should take place", sub {
cd("$TEST_DIR/target");
plan tests => 15;
foreach my $pkg (qw{a b}) {
create_and_stow_pkg('no-folding', $pkg);
}
my $stow = new_Stow('no-folding' => 1);
$stow->plan_unstow('no-folding-b');
is_deeply([ $stow->get_conflicts ], [] => 'no conflicts with --no-folding');
$stow->process_tasks();
is_nonexistent_path('no-folding-b-only-folded');
is_nonexistent_path('no-folding-b-only-folded2');
is_nonexistent_path('no-folding-b-only-unfolded/file-b');
is_nonexistent_path('no-folding-b-only-unfolded2/subdir/file-b');
is_dir_not_symlink('no-folding-shared');
is_dir_not_symlink('no-folding-shared2');
is_dir_not_symlink('no-folding-shared2/subdir');
});
# subtests("Test cleaning up subdirs with --paranoid option", sub {
# TODO
# });

View file

@ -1,276 +0,0 @@
#!/usr/local/bin/perl
#
# Testing unstow_contents()
#
# load as a library
BEGIN { use lib qw(.); require "t/util.pm"; require "stow"; }
use Test::More tests => 11;
use English qw(-no_match_vars);
# local utility
sub reset_state {
@Tasks = ();
@Conflicts = ();
%Link_Task_For = ();
%Dir_Task_For = ();
%Options = ();
return;
}
### setup
eval { remove_dir('t/target'); };
eval { remove_dir('t/stow'); };
make_dir('t/target');
make_dir('t/stow');
chdir 't/target';
$Stow_Path= '../stow';
# Note that each of the following tests use a distinct set of files
#
# unstow a simple tree minimally
#
reset_state();
$Option{'verbose'} = 0;
make_dir('../stow/pkg1/bin1');
make_file('../stow/pkg1/bin1/file1');
make_link('bin1','../stow/pkg1/bin1');
unstow_contents('../stow/pkg1','./');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
-f '../stow/pkg1/bin1/file1' && ! -e 'bin1'
=> 'unstow a simple tree'
);
#
# unstow a simple tree from an existing directory
#
reset_state();
$Option{'verbose'} = 0;
make_dir('lib2');
make_dir('../stow/pkg2/lib2');
make_file('../stow/pkg2/lib2/file2');
make_link('lib2/file2', '../../stow/pkg2/lib2/file2');
unstow_contents('../stow/pkg2','./');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
-f '../stow/pkg2/lib2/file2' && -d 'lib2'
=> 'unstow simple tree from a pre-existing directory'
);
#
# fold tree after unstowing
#
reset_state();
$Option{'verbose'} = 0;
make_dir('bin3');
make_dir('../stow/pkg3a/bin3');
make_file('../stow/pkg3a/bin3/file3a');
make_link('bin3/file3a' => '../../stow/pkg3a/bin3/file3a'); # emulate stow
make_dir('../stow/pkg3b/bin3');
make_file('../stow/pkg3b/bin3/file3b');
make_link('bin3/file3b' => '../../stow/pkg3b/bin3/file3b'); # emulate stow
unstow_contents('../stow/pkg3b', './');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
-l 'bin3' &&
readlink('bin3') eq '../stow/pkg3a/bin3'
=> 'fold tree after unstowing'
);
#
# existing link is owned by stow but is invalid so it gets removed anyway
#
reset_state();
$Option{'verbose'} = 0;
make_dir('bin4');
make_dir('../stow/pkg4/bin4');
make_file('../stow/pkg4/bin4/file4');
make_link('bin4/file4', '../../stow/pkg4/bin4/does-not-exist');
unstow_contents('../stow/pkg4', './');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
! -e 'bin4/file4'
=> q(remove invalid link owned by stow)
);
#
# Existing link is not owned by stow
#
reset_state();
$Option{'verbose'} = 0;
make_dir('../stow/pkg5/bin5');
make_link('bin5', '../not-stow');
unstow_contents('../stow/pkg5', './');
like(
$Conflicts[-1], qr(CONFLICT:.*existing target is not owned by stow)
=> q(existing link not owned by stow)
);
#
# Target already exists, is owned by stow, but points to a different package
#
reset_state();
$Option{'verbose'} = 0;
make_dir('bin6');
make_dir('../stow/pkg6a/bin6');
make_file('../stow/pkg6a/bin6/file6');
make_link('bin6/file6', '../../stow/pkg6a/bin6/file6');
make_dir('../stow/pkg6b/bin6');
make_file('../stow/pkg6b/bin6/file6');
unstow_contents('../stow/pkg6b', './');
ok(
scalar(@Conflicts) == 0 &&
-l 'bin6/file6' &&
readlink('bin6/file6') eq '../../stow/pkg6a/bin6/file6'
=> q(ignore existing link that points to a different package)
);
#
# Don't unlink anything under the stow directory
#
reset_state();
$Option{'verbose'} = 0;
make_dir('stow'); # make out stow dir a subdir of target
$Stow_Path = 'stow';
# emulate stowing into ourself (bizzare corner case or accident)
make_dir('stow/pkg7a/stow/pkg7b');
make_file('stow/pkg7a/stow/pkg7b/file7b');
make_link('stow/pkg7b', '../stow/pkg7a/stow/pkg7b');
unstow_contents('stow/pkg7b', './');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
-l 'stow/pkg7b' &&
readlink('stow/pkg7b') eq '../stow/pkg7a/stow/pkg7b'
=> q(don't unlink any nodes under the stow directory)
);
#
# Don't unlink any nodes under another stow directory
#
reset_state();
$Option{'verbose'} = 0;
make_dir('stow'); # make out stow dir a subdir of target
$Stow_Path = 'stow';
make_dir('stow2'); # make our alternate stow dir a subdir of target
make_file('stow2/.stow');
# emulate stowing into ourself (bizzare corner case or accident)
make_dir('stow/pkg8a/stow2/pkg8b');
make_file('stow/pkg8a/stow2/pkg8b/file8b');
make_link('stow2/pkg8b', '../stow/pkg8a/stow2/pkg8b');
unstow_contents('stow/pkg8a', './');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
-l 'stow2/pkg8b' &&
readlink('stow2/pkg8b') eq '../stow/pkg8a/stow2/pkg8b'
=> q(don't unlink any nodes under another stow directory)
);
#
# overriding already stowed documentation
#
reset_state();
$Stow_Path = '../stow';
$Option{'verbose'} = 0;
$Option{'override'} = ['man9', 'info9'];
make_dir('../stow/pkg9a/man9/man1');
make_file('../stow/pkg9a/man9/man1/file9.1');
make_dir('man9/man1');
make_link('man9/man1/file9.1' => '../../../stow/pkg9a/man9/man1/file9.1'); # emulate stow
make_dir('../stow/pkg9b/man9/man1');
make_file('../stow/pkg9b/man9/man1/file9.1');
unstow_contents('../stow/pkg9b', './');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
!-l 'man9/man1/file9.1'
=> 'overriding existing documentation files'
);
#
# deferring to already stowed documentation
#
reset_state();
$Option{'verbose'} = 0;
$Option{'defer'} = ['man10', 'info10'];
make_dir('../stow/pkg10a/man10/man1');
make_file('../stow/pkg10a/man10/man1/file10a.1');
make_dir('man10/man1');
make_link('man10/man1/file10a.1' => '../../../stow/pkg10a/man10/man1/file10a.1');
# need this to block folding
make_dir('../stow/pkg10b/man10/man1');
make_file('../stow/pkg10b/man10/man1/file10b.1');
make_link('man10/man1/file10b.1' => '../../../stow/pkg10b/man10/man1/file10b.1');
make_dir('../stow/pkg10c/man10/man1');
make_file('../stow/pkg10c/man10/man1/file10a.1');
unstow_contents('../stow/pkg10c', './');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
readlink('man10/man1/file10a.1') eq '../../../stow/pkg10a/man10/man1/file10a.1'
=> 'defer to existing documentation files'
);
#
# Ignore temp files
#
reset_state();
$Option{'verbose'} = 0;
$Option{'ignore'} = ['~', '\.#.*'];
make_dir('../stow/pkg12/man12/man1');
make_file('../stow/pkg12/man12/man1/file12.1');
make_file('../stow/pkg12/man12/man1/file12.1~');
make_file('../stow/pkg12/man12/man1/.#file12.1');
make_dir('man12/man1');
make_link('man12/man1/file12.1' => '../../../stow/pkg12/man12/man1/file12.1');
unstow_contents('../stow/pkg12', './');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
!-e 'man12/man1/file12.1'
=> 'ignore temp files'
);
# Todo
#
# Test cleaning up subdirs with --paranoid option

View file

@ -1,277 +0,0 @@
#!/usr/local/bin/perl
#
# Testing unstow_contents_orig()
#
# load as a library
BEGIN { use lib qw(.); require "t/util.pm"; require "stow"; }
use Test::More tests => 11;
use English qw(-no_match_vars);
# local utility
sub reset_state {
@Tasks = ();
@Conflicts = ();
%Link_Task_For = ();
%Dir_Task_For = ();
%Options = ();
return;
}
### setup
eval { remove_dir('t/target'); };
eval { remove_dir('t/stow'); };
make_dir('t/target');
make_dir('t/stow');
chdir 't/target';
$Stow_Path= '../stow';
# Note that each of the following tests use a distinct set of files
#
# unstow a simple tree minimally
#
reset_state();
$Option{'verbose'} = 0;
make_dir('../stow/pkg1/bin1');
make_file('../stow/pkg1/bin1/file1');
make_link('bin1','../stow/pkg1/bin1');
unstow_contents_orig('../stow/pkg1','./');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
-f '../stow/pkg1/bin1/file1' && ! -e 'bin1'
=> 'unstow a simple tree'
);
#
# unstow a simple tree from an existing directory
#
reset_state();
$Option{'verbose'} = 0;
make_dir('lib2');
make_dir('../stow/pkg2/lib2');
make_file('../stow/pkg2/lib2/file2');
make_link('lib2/file2', '../../stow/pkg2/lib2/file2');
unstow_contents_orig('../stow/pkg2','./');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
-f '../stow/pkg2/lib2/file2' && -d 'lib2'
=> 'unstow simple tree from a pre-existing directory'
);
#
# fold tree after unstowing
#
reset_state();
$Option{'verbose'} = 0;
make_dir('bin3');
make_dir('../stow/pkg3a/bin3');
make_file('../stow/pkg3a/bin3/file3a');
make_link('bin3/file3a' => '../../stow/pkg3a/bin3/file3a'); # emulate stow
make_dir('../stow/pkg3b/bin3');
make_file('../stow/pkg3b/bin3/file3b');
make_link('bin3/file3b' => '../../stow/pkg3b/bin3/file3b'); # emulate stow
unstow_contents_orig('../stow/pkg3b', './');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
-l 'bin3' &&
readlink('bin3') eq '../stow/pkg3a/bin3'
=> 'fold tree after unstowing'
);
#
# existing link is owned by stow but is invalid so it gets removed anyway
#
reset_state();
$Option{'verbose'} = 0;
make_dir('bin4');
make_dir('../stow/pkg4/bin4');
make_file('../stow/pkg4/bin4/file4');
make_link('bin4/file4', '../../stow/pkg4/bin4/does-not-exist');
unstow_contents_orig('../stow/pkg4', './');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
! -e 'bin4/file4'
=> q(remove invalid link owned by stow)
);
#
# Existing link is not owned by stow
#
reset_state();
$Option{'verbose'} = 0;
make_dir('../stow/pkg5/bin5');
make_link('bin5', '../not-stow');
unstow_contents_orig('../stow/pkg5', './');
#like(
# $Conflicts[-1], qr(CONFLICT:.*can't unlink.*not owned by stow)
# => q(existing link not owned by stow)
#);
ok(
-l 'bin5' && readlink('bin5') eq '../not-stow'
=> q(existing link not owned by stow)
);
#
# Target already exists, is owned by stow, but points to a different package
#
reset_state();
$Option{'verbose'} = 0;
make_dir('bin6');
make_dir('../stow/pkg6a/bin6');
make_file('../stow/pkg6a/bin6/file6');
make_link('bin6/file6', '../../stow/pkg6a/bin6/file6');
make_dir('../stow/pkg6b/bin6');
make_file('../stow/pkg6b/bin6/file6');
unstow_contents_orig('../stow/pkg6b', './');
ok(
-l 'bin6/file6' && readlink('bin6/file6') eq '../../stow/pkg6a/bin6/file6'
=> q(existing link owned by stow but points to a different package)
);
#
# Don't unlink anything under the stow directory
#
reset_state();
$Option{'verbose'} = 0;
make_dir('stow'); # make out stow dir a subdir of target
$Stow_Path = 'stow';
# emulate stowing into ourself (bizzare corner case or accident)
make_dir('stow/pkg7a/stow/pkg7b');
make_file('stow/pkg7a/stow/pkg7b/file7b');
make_link('stow/pkg7b', '../stow/pkg7a/stow/pkg7b');
unstow_contents_orig('stow/pkg7b', './');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
-l 'stow/pkg7b' &&
readlink('stow/pkg7b') eq '../stow/pkg7a/stow/pkg7b'
=> q(don't unlink any nodes under the stow directory)
);
#
# Don't unlink any nodes under another stow directory
#
reset_state();
$Option{'verbose'} = 0;
make_dir('stow'); # make out stow dir a subdir of target
$Stow_Path = 'stow';
make_dir('stow2'); # make our alternate stow dir a subdir of target
make_file('stow2/.stow');
# emulate stowing into ourself (bizzare corner case or accident)
make_dir('stow/pkg8a/stow2/pkg8b');
make_file('stow/pkg8a/stow2/pkg8b/file8b');
make_link('stow2/pkg8b', '../stow/pkg8a/stow2/pkg8b');
unstow_contents_orig('stow/pkg8a', './');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
-l 'stow2/pkg8b' &&
readlink('stow2/pkg8b') eq '../stow/pkg8a/stow2/pkg8b'
=> q(don't unlink any nodes under another stow directory)
);
#
# overriding already stowed documentation
#
reset_state();
$Stow_Path = '../stow';
$Option{'verbose'} = 0;
$Option{'override'} = ['man9', 'info9'];
make_dir('../stow/pkg9a/man9/man1');
make_file('../stow/pkg9a/man9/man1/file9.1');
make_dir('man9/man1');
make_link('man9/man1/file9.1' => '../../../stow/pkg9a/man9/man1/file9.1'); # emulate stow
make_dir('../stow/pkg9b/man9/man1');
make_file('../stow/pkg9b/man9/man1/file9.1');
unstow_contents_orig('../stow/pkg9b', './');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
!-l 'man9/man1/file9.1'
=> 'overriding existing documentation files'
);
#
# deferring to already stowed documentation
#
reset_state();
$Option{'verbose'} = 0;
$Option{'defer'} = ['man10', 'info10'];
make_dir('../stow/pkg10a/man10/man1');
make_file('../stow/pkg10a/man10/man1/file10a.1');
make_dir('man10/man1');
make_link('man10/man1/file10a.1' => '../../../stow/pkg10a/man10/man1/file10a.1');
# need this to block folding
make_dir('../stow/pkg10b/man10/man1');
make_file('../stow/pkg10b/man10/man1/file10b.1');
make_link('man10/man1/file10b.1' => '../../../stow/pkg10b/man10/man1/file10b.1');
make_dir('../stow/pkg10c/man10/man1');
make_file('../stow/pkg10c/man10/man1/file10a.1');
unstow_contents_orig('../stow/pkg10c', './');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
readlink('man10/man1/file10a.1') eq '../../../stow/pkg10a/man10/man1/file10a.1'
=> 'defer to existing documentation files'
);
#
# Ignore temp files
#
reset_state();
$Option{'verbose'} = 0;
$Option{'ignore'} = ['~', '\.#.*'];
make_dir('../stow/pkg12/man12/man1');
make_file('../stow/pkg12/man12/man1/file12.1');
make_file('../stow/pkg12/man12/man1/file12.1~');
make_file('../stow/pkg12/man12/man1/.#file12.1');
make_dir('man12/man1');
make_link('man12/man1/file12.1' => '../../../stow/pkg12/man12/man1/file12.1');
unstow_contents_orig('../stow/pkg12', './');
process_tasks();
ok(
scalar(@Conflicts) == 0 &&
!-e 'man12/man1/file12.1'
=> 'ignore temp files'
);
# Todo
#
# Test cleaning up subdirs with --paranoid option

157
t/util.pm
View file

@ -1,157 +0,0 @@
#
# Utilities shared by test scripts
#
use strict;
use warnings;
#===== SUBROUTINE ===========================================================
# Name : make_link()
# Purpose : safely create a link
# Parameters: $target => path to the link
# : $source => where the new link should point
# Returns : n/a
# Throws : fatal error if the link can not be safely created
# Comments : checks for existing nodes
#============================================================================
sub make_link {
my ($target, $source) = @_;
if (-l $target) {
my $old_source = readlink join('/',parent($target),$source)
or die "could not read link $target/$source";
if ($old_source ne $source) {
die "$target already exists but points elsewhere\n";
}
}
elsif (-e $target ) {
die "$target already exists and is not a link\n";
}
else {
symlink $source, $target
or die "could not create link $target => $source ($!)\n";
}
return;
}
#===== SUBROUTINE ===========================================================
# Name : make_dir()
# Purpose : create a directory and any requiste parents
# Parameters: $dir => path to the new directory
# Returns : n/a
# Throws : fatal error if the directory or any of its parents cannot be
# : created
# Comments : none
#============================================================================
sub make_dir {
my ($dir) = @_;
my @parents = ();
for my $part (split '/', $dir) {
my $path = join '/', @parents, $part;
if (not -d $path and not mkdir $path) {
die "could not create directory: $path ($!)\n";
}
push @parents, $part;
}
return;
}
#===== SUBROUTINE ===========================================================
# Name : create_file()
# Purpose : create an empty file
# Parameters: $path => proposed path to the file
# Returns : n/a
# Throws : fatal error if the file could not be created
# Comments : detects clash with an existing non-file
#============================================================================
sub make_file {
my ($path) =@_;
if (not -e $path) {
open my $FILE ,'>', $path
or die "could not create file: $path ($!)\n";
close $FILE;
}
elsif ( not -f $path) {
die "a non-file already exists at $path\n";
}
return;
}
#===== SUBROUTINE ===========================================================
# Name : remove_link()
# Purpose : remove an esiting symbolic link
# Parameters: $path => path to the symbolic link
# Returns : n/a
# Throws : fatal error if the operation fails or if passed the path to a
# : non-link
# Comments : none
#============================================================================
sub remove_link {
my ($path) = @_;
if (not -l $path) {
die qq(remove_link() called with a non-link: $path);
}
unlink $path or die "could not remove link: $path ($!)\n";
return;
}
#===== SUBROUTINE ===========================================================
# Name : remove_file()
# Purpose : remove an existing empty file
# Parameters: $path => the path to the empty file
# Returns : n/a
# Throws : fatal error if given file is non-empty or the operation fails
# Comments : none
#============================================================================
sub remove_file {
my ($path) = @_;
if (-z $path) {
die "file at $path is non-empty\n";
}
unlink $path or die "could not remove empty file: $path ($!)\n";
return;
}
#===== SUBROUTINE ===========================================================
# Name : remove_dir()
# Purpose : safely remove a tree of test files
# Parameters: $dir => path to the top of the tree
# Returns : n/a
# Throws : fatal error if the tree contains a non-link or non-empty file
# Comments : recursively removes directories containing softlinks empty files
#============================================================================
sub remove_dir {
my ($dir) = @_;
if (not -d $dir) {
die "$dir is not a directory";
}
opendir my $DIR, $dir or die "cannot read directory: $dir ($!)\n";
my @listing = readdir $DIR;
closedir $DIR;
NODE:
for my $node (@listing) {
next NODE if $node eq '.';
next NODE if $node eq '..';
my $path = "$dir/$node";
if (-l $path or -z $path) {
unlink $path or die "cannot unlink $path ($!)\n";
}
elsif (-d "$path") {
remove_dir($path);
}
else {
die "$path is not a link, directory, or empty file\n";
}
}
rmdir $dir or die "cannot rmdir $dir ($!)\n";
return;
}
1;

37
test-docker.sh Executable file
View file

@ -0,0 +1,37 @@
#!/usr/bin/env bash
# Test Stow across multiple Perl versions, by executing the
# Docker image built via build-docker.sh.
#
# Usage: ./test-docker.sh [list | PERL_VERSION]
#
# If the first argument is 'list', list available Perl versions.
# If the first argument is a Perl version, test just that version interactively.
# If no arguments are given test all available Perl versions non-interactively.
version=$( tools/get-version )
if [ -z "$1" ]; then
# Normal non-interactive run
docker run --rm -it \
-v $(pwd):$(pwd) \
-w $(pwd) \
stowtest:$version
elif [ "$1" == list ]; then
# List available Perl versions
docker run --rm -it \
-v $(pwd):$(pwd) \
-v $(pwd)/docker/run-stow-tests.sh:/run-stow-tests.sh \
-w $(pwd) \
-e LIST_PERL_VERSIONS=1 \
stowtest:$version
else
# Interactive run for testing / debugging a particular version
perl_version="$1"
docker run --rm -it \
-v $(pwd):$(pwd) \
-v $(pwd)/docker/run-stow-tests.sh:/run-stow-tests.sh \
-w $(pwd) \
-e PERL_VERSION=$perl_version \
stowtest:$version
fi

File diff suppressed because it is too large Load diff

15
tools/get-version Executable file
View file

@ -0,0 +1,15 @@
#!/usr/bin/perl
use strict;
use warnings;
open(CONF, "configure.ac") or die "Couldn't open configure.ac: $!\n";
while (<CONF>) {
if (/^AC_INIT\(\[stow\], \[(.+?)\]/) {
print "$1\n";
exit 0;
}
}
exit 1;

View file

@ -1,4 +0,0 @@
@set UPDATED 20 February 2008
@set UPDATED-MONTH February 2008
@set EDITION 2.0.2
@set VERSION 2.0.2