Merge pull request #106 from aspiers/dev
This commit is contained in:
commit
fee2225dc9
29 changed files with 3148 additions and 9741 deletions
6
.dir-locals.el
Normal file
6
.dir-locals.el
Normal 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
2
.dumbjump
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
+bin/*.in
|
||||||
|
+lib/*.pm.in
|
4
AUTHORS
4
AUTHORS
|
@ -1,3 +1,7 @@
|
||||||
|
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.
|
||||||
|
|
||||||
Stow was originally written by Bob Glickstein <bobg+stow@zanshin.com>,
|
Stow was originally written by Bob Glickstein <bobg+stow@zanshin.com>,
|
||||||
Zanshin Software, Inc.
|
Zanshin Software, Inc.
|
||||||
|
|
||||||
|
|
106
CONTRIBUTING.md
Normal file
106
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
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`.
|
||||||
|
|
||||||
|
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/).
|
4
MANIFEST
4
MANIFEST
|
@ -3,6 +3,7 @@ aclocal.m4
|
||||||
automake/install-sh
|
automake/install-sh
|
||||||
automake/mdate-sh
|
automake/mdate-sh
|
||||||
automake/missing
|
automake/missing
|
||||||
|
automake/texinfo.tex
|
||||||
bin/chkstow
|
bin/chkstow
|
||||||
bin/chkstow.in
|
bin/chkstow.in
|
||||||
bin/stow
|
bin/stow
|
||||||
|
@ -11,6 +12,7 @@ Build.PL
|
||||||
ChangeLog
|
ChangeLog
|
||||||
configure
|
configure
|
||||||
configure.ac
|
configure.ac
|
||||||
|
CONTRIBUTING.md
|
||||||
COPYING
|
COPYING
|
||||||
default-ignore-list
|
default-ignore-list
|
||||||
doc/ChangeLog.OLD
|
doc/ChangeLog.OLD
|
||||||
|
@ -19,7 +21,6 @@ doc/manual.pdf
|
||||||
doc/stow.8
|
doc/stow.8
|
||||||
doc/stow.info
|
doc/stow.info
|
||||||
doc/stow.texi
|
doc/stow.texi
|
||||||
doc/texinfo.tex
|
|
||||||
doc/version.texi
|
doc/version.texi
|
||||||
INSTALL.md
|
INSTALL.md
|
||||||
lib/Stow.pm
|
lib/Stow.pm
|
||||||
|
@ -43,6 +44,7 @@ t/find_stowed_path.t
|
||||||
t/foldable.t
|
t/foldable.t
|
||||||
t/ignore.t
|
t/ignore.t
|
||||||
t/join_paths.t
|
t/join_paths.t
|
||||||
|
t/link_dest_within_stow_dir.t
|
||||||
t/parent.t
|
t/parent.t
|
||||||
t/stow.t
|
t/stow.t
|
||||||
t/rc_options.t
|
t/rc_options.t
|
||||||
|
|
|
@ -89,3 +89,10 @@ tmp-testing-trees
|
||||||
.travis.yml
|
.travis.yml
|
||||||
^docker/
|
^docker/
|
||||||
^[a-zA-Z]*-docker.sh
|
^[a-zA-Z]*-docker.sh
|
||||||
|
|
||||||
|
# Avoid development config
|
||||||
|
.dir-locals.el
|
||||||
|
.dumbjump
|
||||||
|
|
||||||
|
# Avoid CI
|
||||||
|
.github/
|
42
Makefile.am
42
Makefile.am
|
@ -32,24 +32,24 @@ pmstowdir = $(pmdir)/Stow
|
||||||
pm_DATA = lib/Stow.pm
|
pm_DATA = lib/Stow.pm
|
||||||
pmstow_DATA = lib/Stow/Util.pm
|
pmstow_DATA = lib/Stow/Util.pm
|
||||||
|
|
||||||
TEXINFO_TEX = doc/texinfo.tex
|
|
||||||
export TEXI2DVI_BUILD_MODE = clean
|
export TEXI2DVI_BUILD_MODE = clean
|
||||||
AM_MAKEINFOFLAGS = -I $(srcdir)
|
AM_MAKEINFOFLAGS = -I $(srcdir)
|
||||||
|
|
||||||
# We require this -I parameter to ensure that the include of the
|
# We require this -I parameter to ensure that the include of the
|
||||||
# default ignore list in the manual works. Unfortunately this is
|
# default ignore list in the manual works correctly, even when the
|
||||||
# the only way to do it:
|
# manual is being built via make distcheck from a different directory.
|
||||||
|
# Unfortunately this is the only way to do it:
|
||||||
#
|
#
|
||||||
# http://article.gmane.org/gmane.comp.sysutils.automake.bugs/4334/match=passing+parameters
|
# https://lists.gnu.org/archive/html/bug-automake/2008-09/msg00040.html
|
||||||
#
|
#
|
||||||
# even though it annoyingly produces a warning with the -Wall option
|
# even though it annoyingly produces a warning with the -Wall option
|
||||||
# to AM_INIT_AUTOMAKE which has to be silenced via -Wno-override.
|
# to AM_INIT_AUTOMAKE which has to be silenced via -Wno-override.
|
||||||
TEXI2DVI = texi2dvi $(AM_MAKEINFOFLAGS)
|
TEXI2DVI = texi2dvi $(AM_MAKEINFOFLAGS)
|
||||||
|
|
||||||
doc_deps = $(info_TEXINFOS) doc/version.texi
|
|
||||||
|
|
||||||
DEFAULT_IGNORE_LIST = $(srcdir)/default-ignore-list
|
DEFAULT_IGNORE_LIST = $(srcdir)/default-ignore-list
|
||||||
|
|
||||||
|
doc_deps = $(info_TEXINFOS) doc/version.texi $(DEFAULT_IGNORE_LIST)
|
||||||
|
|
||||||
TESTS_DIR = $(srcdir)/t
|
TESTS_DIR = $(srcdir)/t
|
||||||
TESTS_OUT = tmp-testing-trees
|
TESTS_OUT = tmp-testing-trees
|
||||||
TESTS_ENVIRONMENT = $(PERL) -Ibin -Ilib -I$(TESTS_DIR)
|
TESTS_ENVIRONMENT = $(PERL) -Ibin -Ilib -I$(TESTS_DIR)
|
||||||
|
@ -77,7 +77,7 @@ check_DATA = $(TESTS_OUT)
|
||||||
# Note that automake's `check' rule cannot be overridden
|
# Note that automake's `check' rule cannot be overridden
|
||||||
# for some weird reason:
|
# for some weird reason:
|
||||||
#
|
#
|
||||||
# http://thread.gmane.org/gmane.comp.sysutils.automake.general/13040/focus=13041
|
# https://lists.gnu.org/archive/html/automake/2011-09/msg00029.html
|
||||||
#
|
#
|
||||||
# so we override check-TESTS instead which is where the real work is
|
# so we override check-TESTS instead which is where the real work is
|
||||||
# done anyway. Unfortunately this produces a warning with the -Wall
|
# done anyway. Unfortunately this produces a warning with the -Wall
|
||||||
|
@ -95,7 +95,6 @@ EXTRA_DIST = \
|
||||||
bin/stow.in bin/chkstow.in lib/Stow.pm.in lib/Stow/Util.pm.in \
|
bin/stow.in bin/chkstow.in lib/Stow.pm.in lib/Stow/Util.pm.in \
|
||||||
doc/manual-split \
|
doc/manual-split \
|
||||||
$(TESTS) t/testutil.pm \
|
$(TESTS) t/testutil.pm \
|
||||||
$(TEXINFO_TEX) \
|
|
||||||
$(DEFAULT_IGNORE_LIST) \
|
$(DEFAULT_IGNORE_LIST) \
|
||||||
$(CPAN_FILES)
|
$(CPAN_FILES)
|
||||||
CLEANFILES = $(bin_SCRIPTS) $(pm_DATA) $(pmstow_DATA)
|
CLEANFILES = $(bin_SCRIPTS) $(pm_DATA) $(pmstow_DATA)
|
||||||
|
@ -190,7 +189,7 @@ doc/stow.8: bin/stow.in Makefile.am
|
||||||
#
|
#
|
||||||
# If it were not for a troublesome dependency on doc/$(am__dirstamp):
|
# If it were not for a troublesome dependency on doc/$(am__dirstamp):
|
||||||
#
|
#
|
||||||
# http://article.gmane.org/gmane.comp.sysutils.automake.general/13192
|
# https://lists.gnu.org/archive/html/automake/2011-11/msg00107.html
|
||||||
#
|
#
|
||||||
# we could have achieved this using the built-in rules combined with
|
# 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-data-hook to rename from stow.pdf to manual.pdf etc. on
|
||||||
|
@ -299,3 +298,28 @@ ChangeLog: doc/ChangeLog.OLD
|
||||||
else \
|
else \
|
||||||
echo "Not in a git repository; can't update ChangeLog."; \
|
echo "Not in a git repository; can't update ChangeLog."; \
|
||||||
fi
|
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 '
|
||||||
|
|
67
NEWS
67
NEWS
|
@ -1,5 +1,66 @@
|
||||||
News file for Stow.
|
News file for Stow.
|
||||||
|
|
||||||
|
* Changes in version 2.3.2
|
||||||
|
|
||||||
|
*** Eliminated a spurious warning on unstowing
|
||||||
|
|
||||||
|
2.3.1 introduced a benign but annoying warning when unstowing
|
||||||
|
in certain circumstances. It looked like:
|
||||||
|
|
||||||
|
BUG in find_stowed_path? Absolute/relative mismatch between Stow dir X and path Y
|
||||||
|
|
||||||
|
This was caused by erroneous logic, and has now been fixed.
|
||||||
|
|
||||||
|
*** Improved debug output
|
||||||
|
|
||||||
|
Extra output resulting from use of the -v / --verbose flag
|
||||||
|
now appears in a more logical and understandable way.
|
||||||
|
|
||||||
|
*** Janitorial tasks
|
||||||
|
|
||||||
|
Users are not substantially affected by these changes.
|
||||||
|
|
||||||
|
***** Added some more information from the web page to the README
|
||||||
|
|
||||||
|
***** Made some improvements to the documentation
|
||||||
|
|
||||||
|
***** Improve readability of source code
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
***** Added a =CONTRIBUTING.md= file
|
||||||
|
|
||||||
|
***** Add a =watch= target to =Makefile=
|
||||||
|
|
||||||
|
=make watch= provides easy continual pre-processing during
|
||||||
|
development, which reduces the risk of debugging the wrong code.
|
||||||
|
|
||||||
|
***** Removed texinfo.tex from the distribution
|
||||||
|
|
||||||
|
This eliminates existing and future bit-rot.
|
||||||
|
|
||||||
|
***** Updated aclocal.m4 from 1.15.1 to 1.16.5
|
||||||
|
|
||||||
|
This mostly just updates copyright notices to 2021, and URLs to https.
|
||||||
|
|
||||||
|
***** Replace broken gmane links with links to lists.gnu.org
|
||||||
|
|
||||||
|
[[https://lars.ingebrigtsen.no/2020/01/06/whatever-happened-to-news-gmane-org/][gmane has been dead for quite a while.]]
|
||||||
|
|
||||||
|
***** Improve support for navigating / editing source via emacs
|
||||||
|
|
||||||
|
******* Support source navigation in emacs via [[https://github.com/jacktasia/dumb-jump][dumb-jump]].
|
||||||
|
|
||||||
|
******* Configure cperl-mode to match existing coding style.
|
||||||
|
|
||||||
|
*** Various maintainer tweaks
|
||||||
|
|
||||||
|
Further improved the release process and its documentation in
|
||||||
|
various minor ways.
|
||||||
|
|
||||||
* Changes in version 2.3.1
|
* Changes in version 2.3.1
|
||||||
|
|
||||||
*** Remove dependencies on Hash::Merge and Clone::Choose
|
*** Remove dependencies on Hash::Merge and Clone::Choose
|
||||||
|
@ -138,6 +199,7 @@ News file for Stow.
|
||||||
consistency.
|
consistency.
|
||||||
|
|
||||||
- INSTALL.md now also documents how to build directly from git.
|
- INSTALL.md now also documents how to build directly from git.
|
||||||
|
|
||||||
*** Fixes for bugs, tests, and other technical debt
|
*** Fixes for bugs, tests, and other technical debt
|
||||||
|
|
||||||
***** Add Docker files for convenient testing across multiple Perl versions
|
***** Add Docker files for convenient testing across multiple Perl versions
|
||||||
|
@ -235,7 +297,7 @@ due to Stow::Util missing $VERSION.
|
||||||
stow directory path being calculated as
|
stow directory path being calculated as
|
||||||
../../../usr/home/user/local/stow relative to the target.
|
../../../usr/home/user/local/stow relative to the target.
|
||||||
|
|
||||||
See http://article.gmane.org/gmane.comp.gnu.stow.bugs/8820 for details.
|
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.
|
*** Fix stowing of relative links when --no-folding is used.
|
||||||
|
|
||||||
|
@ -276,7 +338,7 @@ due to Stow::Util missing $VERSION.
|
||||||
|
|
||||||
Thanks to Gabriele Balducci for reporting this problem:
|
Thanks to Gabriele Balducci for reporting this problem:
|
||||||
|
|
||||||
http://thread.gmane.org/gmane.comp.gnu.stow.general/6676
|
https://lists.gnu.org/archive/html/help-stow/2014-09/msg00000.html
|
||||||
|
|
||||||
*** Internal code cleanups
|
*** Internal code cleanups
|
||||||
|
|
||||||
|
@ -586,4 +648,5 @@ due to Stow::Util missing $VERSION.
|
||||||
org-export-with-toc: nil
|
org-export-with-toc: nil
|
||||||
org-export-with-author: nil
|
org-export-with-author: nil
|
||||||
org-toc-odd-levels-only: t
|
org-toc-odd-levels-only: t
|
||||||
|
org-blank-before-new-entry: ((heading . auto) (plain-list-item . auto))
|
||||||
End:
|
End:
|
||||||
|
|
62
README.md
62
README.md
|
@ -60,6 +60,56 @@ You can get the latest information about Stow from the home page:
|
||||||
|
|
||||||
http://www.gnu.org/software/stow/
|
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
|
License
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
@ -71,18 +121,6 @@ are permitted in any medium without royalty provided the copyright
|
||||||
notice and this notice are preserved. This file is offered as-is,
|
notice and this notice are preserved. This file is offered as-is,
|
||||||
without any warranty.
|
without any warranty.
|
||||||
|
|
||||||
Installation
|
|
||||||
------------
|
|
||||||
|
|
||||||
See [`INSTALL.md`](INSTALL.md) for installation instructions.
|
|
||||||
|
|
||||||
Feedback
|
|
||||||
--------
|
|
||||||
|
|
||||||
Please do send comments, questions, and constructive criticism. The
|
|
||||||
mailing lists and any other communication channels are detailed on the
|
|
||||||
above home page.
|
|
||||||
|
|
||||||
Brief history and authorship
|
Brief history and authorship
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|
||||||
|
|
2
TODO
2
TODO
|
@ -4,7 +4,7 @@
|
||||||
install-info, amongst other things:
|
install-info, amongst other things:
|
||||||
|
|
||||||
*** http://unix.stackexchange.com/questions/73426/dealing-with-gnu-stow-conflicts
|
*** http://unix.stackexchange.com/questions/73426/dealing-with-gnu-stow-conflicts
|
||||||
*** http://article.gmane.org/gmane.comp.gnu.stow.general/6661
|
*** https://lists.gnu.org/archive/html/help-stow/2013-04/msg00016.html
|
||||||
|
|
||||||
* Get permission for next documentation release to be under FDL 1.3
|
* Get permission for next documentation release to be under FDL 1.3
|
||||||
|
|
||||||
|
|
71
aclocal.m4
vendored
71
aclocal.m4
vendored
|
@ -1,6 +1,6 @@
|
||||||
# generated automatically by aclocal 1.15.1 -*- Autoconf -*-
|
# generated automatically by aclocal 1.16.5 -*- Autoconf -*-
|
||||||
|
|
||||||
# Copyright (C) 1996-2017 Free Software Foundation, Inc.
|
# Copyright (C) 1996-2021 Free Software Foundation, Inc.
|
||||||
|
|
||||||
# This file is free software; the Free Software Foundation
|
# This file is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
@ -14,13 +14,13 @@
|
||||||
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_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_ifndef([AC_AUTOCONF_VERSION],
|
||||||
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
|
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
|
||||||
m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
|
m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.71],,
|
||||||
[m4_warning([this file was generated for autoconf 2.69.
|
[m4_warning([this file was generated for autoconf 2.71.
|
||||||
You have another version of autoconf. It may work, but is not guaranteed to.
|
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.
|
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'.])])
|
To do so, use the procedure documented by the package, typically 'autoreconf'.])])
|
||||||
|
|
||||||
# Copyright (C) 2002-2017 Free Software Foundation, Inc.
|
# Copyright (C) 2002-2021 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This file is free software; the Free Software Foundation
|
# This file is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
@ -32,10 +32,10 @@ To do so, use the procedure documented by the package, typically 'autoreconf'.])
|
||||||
# generated from the m4 files accompanying Automake X.Y.
|
# generated from the m4 files accompanying Automake X.Y.
|
||||||
# (This private macro should not be called outside this file.)
|
# (This private macro should not be called outside this file.)
|
||||||
AC_DEFUN([AM_AUTOMAKE_VERSION],
|
AC_DEFUN([AM_AUTOMAKE_VERSION],
|
||||||
[am__api_version='1.15'
|
[am__api_version='1.16'
|
||||||
dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
|
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.
|
dnl require some minimum version. Point them to the right macro.
|
||||||
m4_if([$1], [1.15.1], [],
|
m4_if([$1], [1.16.5], [],
|
||||||
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
|
[AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
|
||||||
])
|
])
|
||||||
|
|
||||||
|
@ -51,14 +51,14 @@ m4_define([_AM_AUTOCONF_VERSION], [])
|
||||||
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
|
# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
|
||||||
# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
|
# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
|
||||||
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
|
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
|
||||||
[AM_AUTOMAKE_VERSION([1.15.1])dnl
|
[AM_AUTOMAKE_VERSION([1.16.5])dnl
|
||||||
m4_ifndef([AC_AUTOCONF_VERSION],
|
m4_ifndef([AC_AUTOCONF_VERSION],
|
||||||
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
|
[m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
|
||||||
_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
|
_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
|
||||||
|
|
||||||
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
|
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
|
||||||
|
|
||||||
# Copyright (C) 2001-2017 Free Software Foundation, Inc.
|
# Copyright (C) 2001-2021 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This file is free software; the Free Software Foundation
|
# This file is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
@ -110,7 +110,7 @@ am_aux_dir=`cd "$ac_aux_dir" && pwd`
|
||||||
|
|
||||||
# Do all the work for Automake. -*- Autoconf -*-
|
# Do all the work for Automake. -*- Autoconf -*-
|
||||||
|
|
||||||
# Copyright (C) 1996-2017 Free Software Foundation, Inc.
|
# Copyright (C) 1996-2021 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This file is free software; the Free Software Foundation
|
# This file is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
@ -138,6 +138,10 @@ m4_defn([AC_PROG_CC])
|
||||||
# release and drop the old call support.
|
# release and drop the old call support.
|
||||||
AC_DEFUN([AM_INIT_AUTOMAKE],
|
AC_DEFUN([AM_INIT_AUTOMAKE],
|
||||||
[AC_PREREQ([2.65])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 Autoconf wants to disallow AM_ names. We explicitly allow
|
||||||
dnl the ones we care about.
|
dnl the ones we care about.
|
||||||
m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
|
m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
|
||||||
|
@ -174,7 +178,7 @@ m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
|
||||||
[_AM_SET_OPTIONS([$1])dnl
|
[_AM_SET_OPTIONS([$1])dnl
|
||||||
dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
|
dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
|
||||||
m4_if(
|
m4_if(
|
||||||
m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
|
m4_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]),
|
||||||
[ok:ok],,
|
[ok:ok],,
|
||||||
[m4_fatal([AC_INIT should be called with package and version arguments])])dnl
|
[m4_fatal([AC_INIT should be called with package and version arguments])])dnl
|
||||||
AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
|
AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
|
||||||
|
@ -197,8 +201,8 @@ AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
|
||||||
AC_REQUIRE([AC_PROG_MKDIR_P])dnl
|
AC_REQUIRE([AC_PROG_MKDIR_P])dnl
|
||||||
# For better backward compatibility. To be removed once Automake 1.9.x
|
# For better backward compatibility. To be removed once Automake 1.9.x
|
||||||
# dies out for good. For more background, see:
|
# dies out for good. For more background, see:
|
||||||
# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
|
# <https://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
|
||||||
# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
|
# <https://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
|
||||||
AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
|
AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
|
||||||
# We need awk for the "check" target (and possibly the TAP driver). The
|
# We need awk for the "check" target (and possibly the TAP driver). The
|
||||||
# system "awk" is bad on some platforms.
|
# system "awk" is bad on some platforms.
|
||||||
|
@ -226,6 +230,20 @@ AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
|
||||||
[m4_define([AC_PROG_OBJCXX],
|
[m4_define([AC_PROG_OBJCXX],
|
||||||
m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
|
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
|
AC_REQUIRE([AM_SILENT_RULES])dnl
|
||||||
dnl The testsuite driver may need to know about EXEEXT, so add the
|
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 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This
|
||||||
|
@ -265,7 +283,7 @@ END
|
||||||
Aborting the configuration process, to ensure you take notice of the issue.
|
Aborting the configuration process, to ensure you take notice of the issue.
|
||||||
|
|
||||||
You can download and install GNU coreutils to get an 'rm' implementation
|
You can download and install GNU coreutils to get an 'rm' implementation
|
||||||
that behaves properly: <http://www.gnu.org/software/coreutils/>.
|
that behaves properly: <https://www.gnu.org/software/coreutils/>.
|
||||||
|
|
||||||
If you want to complete the configuration process using your problematic
|
If you want to complete the configuration process using your problematic
|
||||||
'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
|
'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
|
||||||
|
@ -307,7 +325,7 @@ for _am_header in $config_headers :; do
|
||||||
done
|
done
|
||||||
echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
|
echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
|
||||||
|
|
||||||
# Copyright (C) 2001-2017 Free Software Foundation, Inc.
|
# Copyright (C) 2001-2021 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This file is free software; the Free Software Foundation
|
# This file is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
@ -328,7 +346,7 @@ if test x"${install_sh+set}" != xset; then
|
||||||
fi
|
fi
|
||||||
AC_SUBST([install_sh])])
|
AC_SUBST([install_sh])])
|
||||||
|
|
||||||
# Copyright (C) 2003-2017 Free Software Foundation, Inc.
|
# Copyright (C) 2003-2021 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This file is free software; the Free Software Foundation
|
# This file is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
@ -349,7 +367,7 @@ AC_SUBST([am__leading_dot])])
|
||||||
|
|
||||||
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
|
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
|
||||||
|
|
||||||
# Copyright (C) 1997-2017 Free Software Foundation, Inc.
|
# Copyright (C) 1997-2021 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This file is free software; the Free Software Foundation
|
# This file is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
@ -370,12 +388,7 @@ AC_DEFUN([AM_MISSING_HAS_RUN],
|
||||||
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
|
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
|
||||||
AC_REQUIRE_AUX_FILE([missing])dnl
|
AC_REQUIRE_AUX_FILE([missing])dnl
|
||||||
if test x"${MISSING+set}" != xset; then
|
if test x"${MISSING+set}" != xset; then
|
||||||
case $am_aux_dir in
|
MISSING="\${SHELL} '$am_aux_dir/missing'"
|
||||||
*\ * | *\ *)
|
|
||||||
MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
|
|
||||||
*)
|
|
||||||
MISSING="\${SHELL} $am_aux_dir/missing" ;;
|
|
||||||
esac
|
|
||||||
fi
|
fi
|
||||||
# Use eval to expand $SHELL
|
# Use eval to expand $SHELL
|
||||||
if eval "$MISSING --is-lightweight"; then
|
if eval "$MISSING --is-lightweight"; then
|
||||||
|
@ -388,7 +401,7 @@ fi
|
||||||
|
|
||||||
# Helper functions for option handling. -*- Autoconf -*-
|
# Helper functions for option handling. -*- Autoconf -*-
|
||||||
|
|
||||||
# Copyright (C) 2001-2017 Free Software Foundation, Inc.
|
# Copyright (C) 2001-2021 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This file is free software; the Free Software Foundation
|
# This file is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
@ -419,7 +432,7 @@ AC_DEFUN([_AM_IF_OPTION],
|
||||||
|
|
||||||
# Check to make sure that the build environment is sane. -*- Autoconf -*-
|
# Check to make sure that the build environment is sane. -*- Autoconf -*-
|
||||||
|
|
||||||
# Copyright (C) 1996-2017 Free Software Foundation, Inc.
|
# Copyright (C) 1996-2021 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This file is free software; the Free Software Foundation
|
# This file is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
@ -500,7 +513,7 @@ AC_CONFIG_COMMANDS_PRE(
|
||||||
rm -f conftest.file
|
rm -f conftest.file
|
||||||
])
|
])
|
||||||
|
|
||||||
# Copyright (C) 2009-2017 Free Software Foundation, Inc.
|
# Copyright (C) 2009-2021 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This file is free software; the Free Software Foundation
|
# This file is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
@ -560,7 +573,7 @@ AC_SUBST([AM_BACKSLASH])dnl
|
||||||
_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
|
_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
|
||||||
])
|
])
|
||||||
|
|
||||||
# Copyright (C) 2001-2017 Free Software Foundation, Inc.
|
# Copyright (C) 2001-2021 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This file is free software; the Free Software Foundation
|
# This file is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
@ -588,7 +601,7 @@ fi
|
||||||
INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
|
INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
|
||||||
AC_SUBST([INSTALL_STRIP_PROGRAM])])
|
AC_SUBST([INSTALL_STRIP_PROGRAM])])
|
||||||
|
|
||||||
# Copyright (C) 2006-2017 Free Software Foundation, Inc.
|
# Copyright (C) 2006-2021 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This file is free software; the Free Software Foundation
|
# This file is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
@ -607,7 +620,7 @@ AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
|
||||||
|
|
||||||
# Check how to create a tarball. -*- Autoconf -*-
|
# Check how to create a tarball. -*- Autoconf -*-
|
||||||
|
|
||||||
# Copyright (C) 2004-2017 Free Software Foundation, Inc.
|
# Copyright (C) 2004-2021 Free Software Foundation, Inc.
|
||||||
#
|
#
|
||||||
# This file is free software; the Free Software Foundation
|
# This file is free software; the Free Software Foundation
|
||||||
# gives unlimited permission to copy and/or distribute it,
|
# gives unlimited permission to copy and/or distribute it,
|
||||||
|
|
1
automake/.gitignore
vendored
1
automake/.gitignore
vendored
|
@ -2,3 +2,4 @@ install-sh
|
||||||
missing
|
missing
|
||||||
mdate-sh
|
mdate-sh
|
||||||
test-driver
|
test-driver
|
||||||
|
texinfo.tex
|
||||||
|
|
|
@ -123,6 +123,5 @@ sub list {
|
||||||
|
|
||||||
# Local variables:
|
# Local variables:
|
||||||
# mode: perl
|
# mode: perl
|
||||||
# cperl-indent-level: 4
|
|
||||||
# End:
|
# End:
|
||||||
# vim: ft=perl
|
# vim: ft=perl
|
||||||
|
|
|
@ -849,6 +849,5 @@ sub version {
|
||||||
|
|
||||||
# Local variables:
|
# Local variables:
|
||||||
# mode: perl
|
# mode: perl
|
||||||
# cperl-indent-level: 4
|
|
||||||
# end:
|
# end:
|
||||||
# vim: ft=perl
|
# vim: ft=perl
|
||||||
|
|
|
@ -19,7 +19,7 @@ AC_INIT([stow], [2.3.2], [bug-stow@gnu.org])
|
||||||
AC_PREREQ([2.61])
|
AC_PREREQ([2.61])
|
||||||
AC_CONFIG_AUX_DIR([automake])
|
AC_CONFIG_AUX_DIR([automake])
|
||||||
# Unfortunately we have to disable warnings for overrides, because we
|
# Unfortunately we have to disable warnings for overrides, because we
|
||||||
# need to override the built-in `check' rule and also the TEXI2DVI
|
# need to override the built-in `check-TESTS' rule and also the TEXI2DVI
|
||||||
# variable.
|
# variable.
|
||||||
AM_INIT_AUTOMAKE([-Wall -Werror -Wno-override dist-bzip2 foreign])
|
AM_INIT_AUTOMAKE([-Wall -Werror -Wno-override dist-bzip2 foreign])
|
||||||
AC_PROG_INSTALL
|
AC_PROG_INSTALL
|
||||||
|
|
|
@ -31,7 +31,7 @@ Release procedure
|
||||||
|
|
||||||
- Start from a clean slate:
|
- Start from a clean slate:
|
||||||
|
|
||||||
make distclean
|
make maintainer-clean
|
||||||
autoreconf -iv
|
autoreconf -iv
|
||||||
|
|
||||||
- Generate stow, chkstow, and lib/Stow.pm via:
|
- Generate stow, chkstow, and lib/Stow.pm via:
|
||||||
|
|
182
doc/stow.texi
182
doc/stow.texi
|
@ -19,13 +19,13 @@ This manual describes GNU Stow version @value{VERSION}
|
||||||
|
|
||||||
Software and documentation is copyrighted by the following:
|
Software and documentation is copyrighted by the following:
|
||||||
|
|
||||||
@copyright{} 1993, 1994, 1995, 1996 Bob Glickstein <bobg+stow@@zanshin.com>
|
@copyright{} 1993, 1994, 1995, 1996 Bob Glickstein @email{bobg+stow@@zanshin.com}
|
||||||
@*
|
@*
|
||||||
@copyright{} 2000, 2001 Guillaume Morin <gmorin@@gnu.org>
|
@copyright{} 2000, 2001 Guillaume Morin @email{gmorin@@gnu.org}
|
||||||
@*
|
@*
|
||||||
@copyright{} 2007 Kahlil (Kal) Hodgson <kahlil@@internode.on.net>
|
@copyright{} 2007 Kahlil (Kal) Hodgson @email{kahlil@@internode.on.net}
|
||||||
@*
|
@*
|
||||||
@copyright{} 2011 Adam Spiers <stow@@adamspiers.org>
|
@copyright{} 2011 Adam Spiers @email{stow@@adamspiers.org}
|
||||||
|
|
||||||
@quotation
|
@quotation
|
||||||
Permission is granted to make and distribute verbatim copies of this
|
Permission is granted to make and distribute verbatim copies of this
|
||||||
|
@ -99,7 +99,7 @@ appear to be installed in a single directory tree.
|
||||||
* Multiple Stow Directories:: Further segregating software.
|
* Multiple Stow Directories:: Further segregating software.
|
||||||
* Target Maintenance:: Cleaning up mistakes.
|
* Target Maintenance:: Cleaning up mistakes.
|
||||||
* Resource Files:: Setting default command line options.
|
* Resource Files:: Setting default command line options.
|
||||||
* Compile-time vs Install-time:: Faking out `make install'.
|
* Compile-time vs. Install-time:: Faking out `make install'.
|
||||||
* Bootstrapping:: When stow and perl are not yet stowed.
|
* Bootstrapping:: When stow and perl are not yet stowed.
|
||||||
* Reporting Bugs:: How, what, where, and when to report.
|
* Reporting Bugs:: How, what, where, and when to report.
|
||||||
* Known Bugs:: Don't report any of these.
|
* Known Bugs:: Don't report any of these.
|
||||||
|
@ -220,9 +220,12 @@ to be installed in a particular directory structure --- e.g., with
|
||||||
|
|
||||||
@cindex target directory
|
@cindex target directory
|
||||||
A @dfn{target directory} is the root of a tree in which one or more
|
A @dfn{target directory} is the root of a tree in which one or more
|
||||||
packages wish to @emph{appear} to be installed. A common, but by no
|
packages wish to @emph{appear} to be installed. @file{/usr/local} is a
|
||||||
means the only such location is @file{/usr/local}. The examples in this
|
common choice for this, but by no means the only such location. Another
|
||||||
manual will use @file{/usr/local} as the target directory.
|
common choice is @file{~} (i.e.@: the user's @code{$HOME} directory) in
|
||||||
|
the case where Stow is being used to manage the user's configuration
|
||||||
|
(``dotfiles'') and other files in their @code{$HOME}. The examples in
|
||||||
|
this manual will use @file{/usr/local} as the target directory.
|
||||||
|
|
||||||
@cindex stow directory
|
@cindex stow directory
|
||||||
A @dfn{stow directory} is the root of a tree containing separate
|
A @dfn{stow directory} is the root of a tree containing separate
|
||||||
|
@ -240,6 +243,11 @@ installation image for Perl includes: a @file{bin} directory containing
|
||||||
containing Texinfo documentation; a @file{lib/perl} directory containing
|
containing Texinfo documentation; a @file{lib/perl} directory containing
|
||||||
Perl libraries; and a @file{man/man1} directory containing man pages.
|
Perl libraries; and a @file{man/man1} directory containing man pages.
|
||||||
|
|
||||||
|
@quotation Note
|
||||||
|
This is a @emph{pre-}installation image which exists even before Stow
|
||||||
|
has installed any symlinks into the target directory which point to it.
|
||||||
|
@end quotation
|
||||||
|
|
||||||
@cindex package directory
|
@cindex package directory
|
||||||
@cindex package name
|
@cindex package name
|
||||||
A @dfn{package directory} is the root of a tree containing the
|
A @dfn{package directory} is the root of a tree containing the
|
||||||
|
@ -255,15 +263,68 @@ target directory, @file{/usr/local/stow} is the stow directory,
|
||||||
@file{/usr/local/stow/perl} is the package directory, and
|
@file{/usr/local/stow/perl} is the package directory, and
|
||||||
@file{bin/perl} within is part of the installation image.
|
@file{bin/perl} within is part of the installation image.
|
||||||
|
|
||||||
|
@anchor{symlink}
|
||||||
@cindex symlink
|
@cindex symlink
|
||||||
|
@cindex symlink source
|
||||||
|
@cindex symlink destination
|
||||||
@cindex relative symlink
|
@cindex relative symlink
|
||||||
@cindex absolute symlink
|
@cindex absolute symlink
|
||||||
A @dfn{symlink} is a symbolic link. A symlink can be @dfn{relative} or
|
A @dfn{symlink} is a symbolic link, i.e.@: an entry on the filesystem
|
||||||
@dfn{absolute}. An absolute symlink names a full path; that is, one
|
whose path is sometimes called the @dfn{symlink source}, which points to
|
||||||
starting from @file{/}. A relative symlink names a relative path; that
|
another location on the filesystem called the @dfn{symlink destination}.
|
||||||
is, one not starting from @file{/}. The target of a relative symlink is
|
There is no guarantee that the destination actually exists.
|
||||||
computed starting from the symlink's own directory. Stow only
|
|
||||||
creates relative symlinks.
|
In general, symlinks can be @dfn{relative} or @dfn{absolute}. A symlink
|
||||||
|
is absolute when the destination names a full path; that is, one
|
||||||
|
starting from @file{/}. A symlink is relative when the destination
|
||||||
|
names a relative path; that is, one not starting from @file{/}. The
|
||||||
|
destination of a relative symlink is computed starting from the
|
||||||
|
symlink's own directory, i.e.@: the directory containing the symlink
|
||||||
|
source.
|
||||||
|
|
||||||
|
@quotation Note
|
||||||
|
Stow only creates symlinks within the target directory which point to
|
||||||
|
locations @emph{outside} the target directory and inside the stow
|
||||||
|
directory.
|
||||||
|
|
||||||
|
Consequently, we avoid referring to symlink destinations as symlink
|
||||||
|
@emph{targets}, since this would result in the word ``target'' having
|
||||||
|
two different meanings:
|
||||||
|
|
||||||
|
@enumerate
|
||||||
|
|
||||||
|
@item
|
||||||
|
the target directory, i.e.@: the directory into which Stow targets
|
||||||
|
installation, where symlinks are managed by Stow, and
|
||||||
|
|
||||||
|
@item
|
||||||
|
the destinations of those symlinks.
|
||||||
|
|
||||||
|
@end enumerate
|
||||||
|
|
||||||
|
If we did not avoid the second meaning of ``target'', then it would lead
|
||||||
|
to confusing language, such as describing Stow as installing symlinks
|
||||||
|
into the target directory which point to targets @emph{outside} the
|
||||||
|
target directory.
|
||||||
|
|
||||||
|
Similarly, the word ``source'' can have two different meanings in this
|
||||||
|
context:
|
||||||
|
|
||||||
|
@enumerate
|
||||||
|
|
||||||
|
@item
|
||||||
|
the installation image, or some of its contents, and
|
||||||
|
|
||||||
|
@item
|
||||||
|
the location of symlinks (the ``source'' of the link, vs.@: its
|
||||||
|
destination).
|
||||||
|
|
||||||
|
@end enumerate
|
||||||
|
|
||||||
|
Therefore it should also be avoided, or at least care taken to ensure
|
||||||
|
that the meaning is not ambiguous.
|
||||||
|
|
||||||
|
@end quotation
|
||||||
|
|
||||||
@c ===========================================================================
|
@c ===========================================================================
|
||||||
@node Invoking Stow, Ignore Lists, Terminology, Top
|
@node Invoking Stow, Ignore Lists, Terminology, Top
|
||||||
|
@ -383,7 +444,7 @@ refolding (@pxref{tree refolding}). If a new subdirectory is
|
||||||
encountered whilst stowing a new package, the subdirectory is created
|
encountered whilst stowing a new package, the subdirectory is created
|
||||||
within the target, and its contents are symlinked, rather than just
|
within the target, and its contents are symlinked, rather than just
|
||||||
creating a symlink for the directory. If removal of symlinks whilst
|
creating a symlink for the directory. If removal of symlinks whilst
|
||||||
unstowing a package causes a subtree to be foldable (i.e. only
|
unstowing a package causes a subtree to be foldable (i.e.@: only
|
||||||
containing symlinks to a single package), that subtree will not be
|
containing symlinks to a single package), that subtree will not be
|
||||||
removed and replaced with a symlink.
|
removed and replaced with a symlink.
|
||||||
|
|
||||||
|
@ -428,13 +489,15 @@ doing. Verbosity levels are from 0 to 5; 0 is the default. Using
|
||||||
|
|
||||||
@item -p
|
@item -p
|
||||||
@itemx --compat
|
@itemx --compat
|
||||||
Scan the whole target tree when unstowing. By default, only
|
Scan the whole target tree when unstowing. By default, only directories
|
||||||
directories specified in the @dfn{installation image} are scanned
|
specified in the @dfn{installation image} are scanned during an unstow
|
||||||
during an unstow operation. Scanning the whole tree can be
|
operation. Previously Stow scanned the whole tree, which can be
|
||||||
prohibitive if your target tree is very large. This option restores
|
prohibitive if your target tree is very large, but on the other hand has
|
||||||
the legacy behaviour; however, the @option{--badlinks} option to the
|
the advantage of unstowing previously stowed links which are no longer
|
||||||
@command{chkstow} utility may be a better way of ensuring that your
|
present in the installation image and therefore orphaned. This option
|
||||||
installation does not have any dangling symlinks (@pxref{Target
|
restores the legacy behaviour; however, the @option{--badlinks} option
|
||||||
|
to the @command{chkstow} utility may be a better way of ensuring that
|
||||||
|
your installation does not have any dangling symlinks (@pxref{Target
|
||||||
Maintenance}).
|
Maintenance}).
|
||||||
|
|
||||||
@item -V
|
@item -V
|
||||||
|
@ -813,7 +876,7 @@ This is much faster and cleaner than performing two separate
|
||||||
invocations of stow, because redundant folding/unfolding operations
|
invocations of stow, because redundant folding/unfolding operations
|
||||||
can be factored out. In addition, all the operations are calculated
|
can be factored out. In addition, all the operations are calculated
|
||||||
and merged before being executed (@pxref{Deferred Operation}), so the
|
and merged before being executed (@pxref{Deferred Operation}), so the
|
||||||
amount of of time in which GNU Emacs is unavailable is minimised.
|
amount of time in which GNU Emacs is unavailable is minimised.
|
||||||
|
|
||||||
You can mix and match any number of actions, for example,
|
You can mix and match any number of actions, for example,
|
||||||
|
|
||||||
|
@ -893,7 +956,7 @@ directory.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@c ===========================================================================
|
@c ===========================================================================
|
||||||
@node Resource Files, Compile-time vs Install-time, Target Maintenance, Top
|
@node Resource Files, Compile-time vs. Install-time, Target Maintenance, Top
|
||||||
@chapter Resource Files
|
@chapter Resource Files
|
||||||
@cindex resource files
|
@cindex resource files
|
||||||
@cindex configuration files
|
@cindex configuration files
|
||||||
|
@ -960,8 +1023,8 @@ resource files. This is also true of any package names given in the
|
||||||
resource file.
|
resource file.
|
||||||
|
|
||||||
@c ===========================================================================
|
@c ===========================================================================
|
||||||
@node Compile-time vs Install-time, Bootstrapping, Resource Files, Top
|
@node Compile-time vs. Install-time, Bootstrapping, Resource Files, Top
|
||||||
@chapter Compile-time vs Install-time
|
@chapter Compile-time vs. Install-time
|
||||||
|
|
||||||
Software whose installation is managed with Stow needs to be installed
|
Software whose installation is managed with Stow needs to be installed
|
||||||
in one place (the package directory, e.g. @file{/usr/local/stow/perl})
|
in one place (the package directory, e.g. @file{/usr/local/stow/perl})
|
||||||
|
@ -1043,7 +1106,7 @@ following sections.
|
||||||
@end menu
|
@end menu
|
||||||
|
|
||||||
@c ---------------------------------------------------------------------------
|
@c ---------------------------------------------------------------------------
|
||||||
@node GNU Emacs, Other FSF Software, Compile-time vs Install-time, Compile-time vs Install-time
|
@node GNU Emacs, Other FSF Software, Compile-time vs. Install-time, Compile-time vs. Install-time
|
||||||
@section GNU Emacs
|
@section GNU Emacs
|
||||||
|
|
||||||
Although the Free Software Foundation has many enlightened practices
|
Although the Free Software Foundation has many enlightened practices
|
||||||
|
@ -1076,7 +1139,7 @@ make do-install prefix=/usr/local/stow/emacs
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
@c ---------------------------------------------------------------------------
|
@c ---------------------------------------------------------------------------
|
||||||
@node Other FSF Software, Cygnus Software, GNU Emacs, Compile-time vs Install-time
|
@node Other FSF Software, Cygnus Software, GNU Emacs, Compile-time vs. Install-time
|
||||||
@section Other FSF Software
|
@section Other FSF Software
|
||||||
|
|
||||||
The Free Software Foundation, the organization behind the GNU project,
|
The Free Software Foundation, the organization behind the GNU project,
|
||||||
|
@ -1097,7 +1160,7 @@ and @samp{make install} steps to work correctly without needing to
|
||||||
``fool'' the build process.
|
``fool'' the build process.
|
||||||
|
|
||||||
@c ---------------------------------------------------------------------------
|
@c ---------------------------------------------------------------------------
|
||||||
@node Cygnus Software, Perl and Perl 5 Modules, Other FSF Software, Compile-time vs Install-time
|
@node Cygnus Software, Perl and Perl 5 Modules, Other FSF Software, Compile-time vs. Install-time
|
||||||
@section Cygnus Software
|
@section Cygnus Software
|
||||||
|
|
||||||
Cygnus is a commercial supplier and supporter of GNU software. It has
|
Cygnus is a commercial supplier and supporter of GNU software. It has
|
||||||
|
@ -1126,7 +1189,7 @@ is recompiling files. Usually it will work just fine; otherwise,
|
||||||
install manually.
|
install manually.
|
||||||
|
|
||||||
@c ---------------------------------------------------------------------------
|
@c ---------------------------------------------------------------------------
|
||||||
@node Perl and Perl 5 Modules, , Cygnus Software, Compile-time vs Install-time
|
@node Perl and Perl 5 Modules, , Cygnus Software, Compile-time vs. Install-time
|
||||||
@section Perl and Perl 5 Modules
|
@section Perl and Perl 5 Modules
|
||||||
|
|
||||||
Perl 4.036 allows you to specify different locations for installation
|
Perl 4.036 allows you to specify different locations for installation
|
||||||
|
@ -1229,7 +1292,7 @@ find cpan.* \( -name .exists -o -name perllocal.pod \) -print | \
|
||||||
|
|
||||||
|
|
||||||
@c ---------------------------------------------------------------------------
|
@c ---------------------------------------------------------------------------
|
||||||
@node Bootstrapping, Reporting Bugs, Compile-time vs Install-time, Top
|
@node Bootstrapping, Reporting Bugs, Compile-time vs. Install-time, Top
|
||||||
@chapter Bootstrapping
|
@chapter Bootstrapping
|
||||||
|
|
||||||
Suppose you have a stow directory all set up and ready to go:
|
Suppose you have a stow directory all set up and ready to go:
|
||||||
|
@ -1264,9 +1327,32 @@ perl/bin/perl stow/bin/stow -vv *
|
||||||
@node Reporting Bugs, Known Bugs, Bootstrapping, Top
|
@node Reporting Bugs, Known Bugs, Bootstrapping, Top
|
||||||
@chapter Reporting Bugs
|
@chapter Reporting Bugs
|
||||||
|
|
||||||
Please send bug reports to the current maintainers by electronic
|
You can report bugs to the current maintainers in one of three ways:
|
||||||
mail. The address to use is @samp{<bug-stow@@gnu.org>}. Please
|
|
||||||
include:
|
@enumerate
|
||||||
|
@item
|
||||||
|
Send e-mail to @email{bug-stow@@gnu.org}.
|
||||||
|
|
||||||
|
@item
|
||||||
|
File an issue in @uref{https://savannah.gnu.org/bugs/?group=stow,
|
||||||
|
the Savannah bug tracker}.
|
||||||
|
|
||||||
|
@item
|
||||||
|
File an issue in
|
||||||
|
@uref{https://github.com/aspiers/stow/issues/, the GitHub project}.
|
||||||
|
@end enumerate
|
||||||
|
|
||||||
|
While GitHub is arguably the most convenient of these three options, it
|
||||||
|
@uref{https://www.gnu.org/software/repo-criteria-evaluation.html#GitHub,
|
||||||
|
is not the most ethical or freedom-preserving way to host software
|
||||||
|
projects}. Therefore the GitHub project may be
|
||||||
|
@uref{https://github.com/aspiers/stow/issues/43, moved to a more ethical
|
||||||
|
hosting service} in the future.
|
||||||
|
|
||||||
|
Before reporting a bug, it is recommended to check whether it is already
|
||||||
|
known, so please first @pxref{Known Bugs}.
|
||||||
|
|
||||||
|
When reporting a new bug, please include:
|
||||||
|
|
||||||
@itemize @bullet
|
@itemize @bullet
|
||||||
@item
|
@item
|
||||||
|
@ -1287,12 +1373,13 @@ the precise command you gave;
|
||||||
|
|
||||||
@item
|
@item
|
||||||
the output from the command (preferably verbose output, obtained by
|
the output from the command (preferably verbose output, obtained by
|
||||||
adding @samp{--verbose=3} to the Stow command line).
|
adding @samp{--verbose=5} to the Stow command line).
|
||||||
@end itemize
|
@end itemize
|
||||||
|
|
||||||
If you are really keen, consider developing a minimal test case and
|
If you are really keen, consider developing a minimal test case and
|
||||||
creating a new test. See the @file{t/} directory in the source for
|
creating a new test. See the @file{t/} directory in the source for lots
|
||||||
lots of examples.
|
of examples, and the @file{CONTRIBUTING.md} file for a guide on how to
|
||||||
|
contribute.
|
||||||
|
|
||||||
Before reporting a bug, please read the manual carefully, especially
|
Before reporting a bug, please read the manual carefully, especially
|
||||||
@ref{Known Bugs}, to see whether you're encountering
|
@ref{Known Bugs}, to see whether you're encountering
|
||||||
|
@ -1303,13 +1390,22 @@ something that doesn't need reporting.
|
||||||
@node Known Bugs, GNU General Public License, Reporting Bugs, Top
|
@node Known Bugs, GNU General Public License, Reporting Bugs, Top
|
||||||
@chapter Known Bugs
|
@chapter Known Bugs
|
||||||
|
|
||||||
There are no known bugs in Stow version @value{VERSION}!
|
Known bugs can be found in the following locations:
|
||||||
If you think you have found one, please @pxref{Reporting Bugs}.
|
|
||||||
|
|
||||||
@c @itemize @bullet
|
@itemize
|
||||||
@c @item
|
@item
|
||||||
@c Put known bugs here
|
@uref{https://github.com/aspiers/stow/issues/, the GitHub issue tracker}
|
||||||
@c @end itemize
|
|
||||||
|
@item
|
||||||
|
@uref{https://savannah.gnu.org/bugs/?group=stow, the Savannah bug
|
||||||
|
tracker}
|
||||||
|
|
||||||
|
@item
|
||||||
|
the @uref{https://lists.gnu.org/archive/html/bug-stow/, bug-stow list
|
||||||
|
archives}
|
||||||
|
@end itemize
|
||||||
|
|
||||||
|
If you think you have found a new bug, please @pxref{Reporting Bugs}.
|
||||||
|
|
||||||
@c ===========================================================================
|
@c ===========================================================================
|
||||||
@node GNU General Public License, Index, Known Bugs, Top
|
@node GNU General Public License, Index, Known Bugs, Top
|
||||||
|
|
7482
doc/texinfo.tex
7482
doc/texinfo.tex
File diff suppressed because it is too large
Load diff
1960
lib/Stow.pm.in
1960
lib/Stow.pm.in
File diff suppressed because it is too large
Load diff
|
@ -32,6 +32,7 @@ Supporting utility routines for L<Stow>.
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
use File::Spec;
|
||||||
use POSIX qw(getcwd);
|
use POSIX qw(getcwd);
|
||||||
|
|
||||||
use base qw(Exporter);
|
use base qw(Exporter);
|
||||||
|
@ -93,7 +94,7 @@ sub set_test_mode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
=head2 debug($level, $msg)
|
=head2 debug($level[, $indent_level], $msg)
|
||||||
|
|
||||||
Logs to STDERR based on C<$debug_level> setting. C<$level> is the
|
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
|
minimum verbosity level required to output C<$msg>. All output is to
|
||||||
|
@ -125,13 +126,18 @@ overriding, fixing invalid links
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
sub debug {
|
sub debug {
|
||||||
my ($level, $msg) = @_;
|
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) {
|
if ($debug_level >= $level) {
|
||||||
|
my $indent = ' ' x $indent_level;
|
||||||
if ($test_mode) {
|
if ($test_mode) {
|
||||||
print "# $msg\n";
|
print "# $indent$msg\n";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
warn "$msg\n";
|
warn "$indent$msg\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,29 +148,53 @@ sub debug {
|
||||||
# Parameters: path1, path2, ... => paths
|
# Parameters: path1, path2, ... => paths
|
||||||
# Returns : concatenation of given paths
|
# Returns : concatenation of given paths
|
||||||
# Throws : n/a
|
# Throws : n/a
|
||||||
# Comments : factors out redundant path elements:
|
# Comments : Factors out some redundant path elements:
|
||||||
# : '//' => '/' and 'a/b/../c' => 'a/c'
|
# : '//' => '/', 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 {
|
sub join_paths {
|
||||||
my @paths = @_;
|
my @paths = @_;
|
||||||
|
|
||||||
# weed out empty components and concatenate
|
debug(5, 5, "| Joining: @paths");
|
||||||
my $result = join '/', grep {! /\A\z/} @paths;
|
my $result = '';
|
||||||
|
for my $part (@paths) {
|
||||||
|
next if ! length $part; # probably shouldn't happen?
|
||||||
|
$part = File::Spec->canonpath($part);
|
||||||
|
|
||||||
# factor out back references and remove redundant /'s)
|
if (substr($part, 0, 1) eq '/') {
|
||||||
my @result = ();
|
$result = $part; # absolute path, so ignore all previous parts
|
||||||
PART:
|
|
||||||
for my $part (split m{/+}, $result) {
|
|
||||||
next PART if $part eq '.';
|
|
||||||
if (@result && $part eq '..' && $result[-1] ne '..') {
|
|
||||||
pop @result;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
push @result, $part;
|
$result .= '/' if length $result && $result ne '/';
|
||||||
|
$result .= $part;
|
||||||
}
|
}
|
||||||
|
debug(7, 6, "| Join now: $result");
|
||||||
}
|
}
|
||||||
|
debug(6, 5, "| Joined: $result");
|
||||||
|
|
||||||
return join '/', @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 ===============================================================
|
#===== METHOD ===============================================================
|
||||||
|
@ -181,7 +211,7 @@ sub parent {
|
||||||
my $path = join '/', @_;
|
my $path = join '/', @_;
|
||||||
my @elts = split m{/+}, $path;
|
my @elts = split m{/+}, $path;
|
||||||
pop @elts;
|
pop @elts;
|
||||||
return join '/', @elts;
|
return join '/', @elts;
|
||||||
}
|
}
|
||||||
|
|
||||||
#===== METHOD ===============================================================
|
#===== METHOD ===============================================================
|
||||||
|
@ -209,10 +239,10 @@ sub restore_cwd {
|
||||||
}
|
}
|
||||||
|
|
||||||
sub adjust_dotfile {
|
sub adjust_dotfile {
|
||||||
my ($target) = @_;
|
my ($link_dest) = @_;
|
||||||
|
|
||||||
my @result = ();
|
my @result = ();
|
||||||
for my $part (split m{/+}, $target) {
|
for my $part (split m{/+}, $link_dest) {
|
||||||
if (($part ne "dot-") && ($part ne "dot-.")) {
|
if (($part ne "dot-") && ($part ne "dot-.")) {
|
||||||
$part =~ s/^dot-/./;
|
$part =~ s/^dot-/./;
|
||||||
}
|
}
|
||||||
|
@ -232,6 +262,5 @@ sub adjust_dotfile {
|
||||||
|
|
||||||
# Local variables:
|
# Local variables:
|
||||||
# mode: perl
|
# mode: perl
|
||||||
# cperl-indent-level: 4
|
|
||||||
# end:
|
# end:
|
||||||
# vim: ft=perl
|
# vim: ft=perl
|
||||||
|
|
|
@ -22,10 +22,11 @@
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Test::More tests => 6;
|
use Test::More tests => 4;
|
||||||
use English qw(-no_match_vars);
|
use English qw(-no_match_vars);
|
||||||
|
|
||||||
use testutil;
|
use testutil;
|
||||||
|
use Stow::Util;
|
||||||
|
|
||||||
init_test_dirs();
|
init_test_dirs();
|
||||||
cd("$TEST_DIR/target");
|
cd("$TEST_DIR/target");
|
||||||
|
@ -34,48 +35,64 @@ my $stow;
|
||||||
|
|
||||||
# Note that each of the following tests use a distinct set of files
|
# Note that each of the following tests use a distinct set of files
|
||||||
|
|
||||||
#
|
subtest('nothing to clean in a simple tree' => sub {
|
||||||
# nothing to clean in a simple tree
|
plan tests => 1;
|
||||||
#
|
|
||||||
|
|
||||||
|
make_path('../stow/pkg1/bin1');
|
||||||
|
make_file('../stow/pkg1/bin1/file1');
|
||||||
|
make_link('bin1', '../stow/pkg1/bin1');
|
||||||
|
|
||||||
make_path('../stow/pkg1/bin1');
|
$stow = new_Stow();
|
||||||
make_file('../stow/pkg1/bin1/file1');
|
$stow->cleanup_invalid_links('./');
|
||||||
make_link('bin1', '../stow/pkg1/bin1');
|
is(
|
||||||
|
scalar($stow->get_tasks), 0
|
||||||
|
=> 'nothing to clean'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
$stow = new_Stow();
|
subtest('cleanup an orphaned owned link in a simple tree' => sub {
|
||||||
$stow->cleanup_invalid_links('./');
|
plan tests => 3;
|
||||||
is(
|
|
||||||
scalar($stow->get_tasks), 0
|
|
||||||
=> 'nothing to clean'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
make_path('bin2');
|
||||||
# cleanup a bad link in a simple tree
|
make_path('../stow/pkg2/bin2');
|
||||||
#
|
make_file('../stow/pkg2/bin2/file2a');
|
||||||
make_path('bin2');
|
make_link('bin2/file2a', '../../stow/pkg2/bin2/file2a');
|
||||||
make_path('../stow/pkg2/bin2');
|
make_invalid_link('bin2/file2b', '../../stow/pkg2/bin2/file2b');
|
||||||
make_file('../stow/pkg2/bin2/file2a');
|
|
||||||
make_link('bin2/file2a', '../../stow/pkg2/bin2/file2a');
|
|
||||||
make_invalid_link('bin2/file2b', '../../stow/pkg2/bin2/file2b');
|
|
||||||
|
|
||||||
$stow = new_Stow();
|
$stow = new_Stow();
|
||||||
$stow->cleanup_invalid_links('bin2');
|
$stow->cleanup_invalid_links('bin2');
|
||||||
is($stow->get_conflict_count, 0, 'no conflicts cleaning up bad link');
|
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(scalar($stow->get_tasks), 1, 'one task cleaning up bad link');
|
||||||
is($stow->link_task_action('bin2/file2b'), 'remove', 'removal task for bad link');
|
is($stow->link_task_action('bin2/file2b'), 'remove', 'removal task for bad link');
|
||||||
|
});
|
||||||
|
|
||||||
#
|
subtest("don't cleanup a bad link not owned by stow" => sub {
|
||||||
# dont cleanup a bad link not owned by stow
|
plan tests => 2;
|
||||||
#
|
|
||||||
|
|
||||||
make_path('bin3');
|
make_path('bin3');
|
||||||
make_path('../stow/pkg3/bin3');
|
make_path('../stow/pkg3/bin3');
|
||||||
make_file('../stow/pkg3/bin3/file3a');
|
make_file('../stow/pkg3/bin3/file3a');
|
||||||
make_link('bin3/file3a', '../../stow/pkg3/bin3/file3a');
|
make_link('bin3/file3a', '../../stow/pkg3/bin3/file3a');
|
||||||
make_invalid_link('bin3/file3b', '../../empty');
|
make_invalid_link('bin3/file3b', '../../empty');
|
||||||
|
|
||||||
$stow = new_Stow();
|
$stow = new_Stow();
|
||||||
$stow->cleanup_invalid_links('bin3');
|
$stow->cleanup_invalid_links('bin3');
|
||||||
is($stow->get_conflict_count, 0, 'no conflicts cleaning up bad link not owned by stow');
|
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');
|
is(scalar($stow->get_tasks), 0, 'no tasks cleaning up 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');
|
||||||
|
});
|
||||||
|
|
232
t/dotfiles.t
232
t/dotfiles.t
|
@ -22,110 +22,188 @@
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use testutil;
|
use Test::More tests => 10;
|
||||||
|
|
||||||
use Test::More tests => 6;
|
|
||||||
use English qw(-no_match_vars);
|
use English qw(-no_match_vars);
|
||||||
|
|
||||||
|
use Stow::Util qw(adjust_dotfile);
|
||||||
use testutil;
|
use testutil;
|
||||||
|
|
||||||
init_test_dirs();
|
init_test_dirs();
|
||||||
cd("$TEST_DIR/target");
|
cd("$TEST_DIR/target");
|
||||||
|
|
||||||
|
subtest('adjust_dotfile()', sub {
|
||||||
|
plan tests => 9;
|
||||||
|
my @TESTS = (
|
||||||
|
['file'],
|
||||||
|
['dot-file', '.file'],
|
||||||
|
['dir1/file'],
|
||||||
|
['dir1/dir2/file'],
|
||||||
|
['dir1/dir2/dot-file', 'dir1/dir2/.file'],
|
||||||
|
['dir1/dot-dir2/file', 'dir1/.dir2/file'],
|
||||||
|
['dir1/dot-dir2/dot-file', 'dir1/.dir2/.file'],
|
||||||
|
['dot-dir1/dot-dir2/dot-file', '.dir1/.dir2/.file'],
|
||||||
|
['dot-dir1/dot-dir2/file', '.dir1/.dir2/file'],
|
||||||
|
);
|
||||||
|
for my $test (@TESTS) {
|
||||||
|
my ($input, $expected) = @$test;
|
||||||
|
$expected ||= $input;
|
||||||
|
is(adjust_dotfile($input), $expected);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
my $stow;
|
my $stow;
|
||||||
|
|
||||||
#
|
subtest("stow a dotfile marked with 'dot' prefix", sub {
|
||||||
# process a dotfile marked with 'dot' prefix
|
plan tests => 1;
|
||||||
#
|
$stow = new_Stow(dir => '../stow', dotfiles => 1);
|
||||||
|
make_path('../stow/dotfiles');
|
||||||
|
make_file('../stow/dotfiles/dot-foo');
|
||||||
|
|
||||||
$stow = new_Stow(dir => '../stow', dotfiles => 1);
|
$stow->plan_stow('dotfiles');
|
||||||
|
$stow->process_tasks();
|
||||||
|
is(
|
||||||
|
readlink('.foo'),
|
||||||
|
'../stow/dotfiles/dot-foo',
|
||||||
|
=> 'processed dotfile'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
make_path('../stow/dotfiles');
|
subtest("ensure that turning off dotfile processing links files as usual", sub {
|
||||||
make_file('../stow/dotfiles/dot-foo');
|
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->plan_stow('dotfiles');
|
||||||
$stow->process_tasks();
|
$stow->process_tasks();
|
||||||
is(
|
is(
|
||||||
readlink('.foo'),
|
readlink('dot-foo'),
|
||||||
'../stow/dotfiles/dot-foo',
|
'../stow/dotfiles/dot-foo',
|
||||||
=> 'processed dotfile'
|
=> 'unprocessed dotfile'
|
||||||
);
|
);
|
||||||
|
|
||||||
#
|
});
|
||||||
# ensure that turning off dotfile processing links files as usual
|
|
||||||
#
|
|
||||||
|
|
||||||
$stow = new_Stow(dir => '../stow', dotfiles => 0);
|
subtest("stow folder marked with 'dot' prefix", sub {
|
||||||
|
plan tests => 1;
|
||||||
|
$stow = new_Stow(dir => '../stow', dotfiles => 1);
|
||||||
|
|
||||||
make_path('../stow/dotfiles');
|
make_path('../stow/dotfiles/dot-emacs');
|
||||||
make_file('../stow/dotfiles/dot-foo');
|
make_file('../stow/dotfiles/dot-emacs/init.el');
|
||||||
|
|
||||||
$stow->plan_stow('dotfiles');
|
$stow->plan_stow('dotfiles');
|
||||||
$stow->process_tasks();
|
$stow->process_tasks();
|
||||||
is(
|
is(
|
||||||
readlink('dot-foo'),
|
readlink('.emacs'),
|
||||||
'../stow/dotfiles/dot-foo',
|
'../stow/dotfiles/dot-emacs',
|
||||||
=> 'unprocessed dotfile'
|
=> 'processed dotfile folder'
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
subtest("process folder marked with 'dot' prefix when directory exists is target", sub {
|
||||||
|
plan tests => 1;
|
||||||
|
$stow = new_Stow(dir => '../stow', dotfiles => 1);
|
||||||
|
|
||||||
#
|
make_path('../stow/dotfiles/dot-emacs.d');
|
||||||
# process folder marked with 'dot' prefix
|
make_file('../stow/dotfiles/dot-emacs.d/init.el');
|
||||||
#
|
make_path('.emacs.d');
|
||||||
|
|
||||||
$stow = new_Stow(dir => '../stow', dotfiles => 1);
|
$stow->plan_stow('dotfiles');
|
||||||
|
$stow->process_tasks();
|
||||||
|
is(
|
||||||
|
readlink('.emacs.d/init.el'),
|
||||||
|
'../../stow/dotfiles/dot-emacs.d/init.el',
|
||||||
|
=> 'processed dotfile folder when folder exists (1 level)'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
make_path('../stow/dotfiles/dot-emacs');
|
subtest("process folder marked with 'dot' prefix when directory exists is target (2 levels)", sub {
|
||||||
make_file('../stow/dotfiles/dot-emacs/init.el');
|
plan tests => 1;
|
||||||
|
$stow = new_Stow(dir => '../stow', dotfiles => 1);
|
||||||
|
|
||||||
$stow->plan_stow('dotfiles');
|
make_path('../stow/dotfiles/dot-emacs.d/dot-emacs.d');
|
||||||
$stow->process_tasks();
|
make_file('../stow/dotfiles/dot-emacs.d/dot-emacs.d/init.el');
|
||||||
is(
|
make_path('.emacs.d');
|
||||||
readlink('.emacs'),
|
|
||||||
'../stow/dotfiles/dot-emacs',
|
|
||||||
=> 'processed dotfile folder'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
$stow->plan_stow('dotfiles');
|
||||||
# corner case: paths that have a part in them that's just "$DOT_PREFIX" or
|
$stow->process_tasks();
|
||||||
# "$DOT_PREFIX." should not have that part expanded.
|
is(
|
||||||
#
|
readlink('.emacs.d/.emacs.d'),
|
||||||
|
'../../stow/dotfiles/dot-emacs.d/dot-emacs.d',
|
||||||
|
=> 'processed dotfile folder exists (2 levels)'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
$stow = new_Stow(dir => '../stow', dotfiles => 1);
|
subtest("process folder marked with 'dot' prefix when directory exists is target", sub {
|
||||||
|
plan tests => 1;
|
||||||
|
$stow = new_Stow(dir => '../stow', dotfiles => 1);
|
||||||
|
|
||||||
make_path('../stow/dotfiles');
|
make_path('../stow/dotfiles/dot-one/dot-two');
|
||||||
make_file('../stow/dotfiles/dot-');
|
make_file('../stow/dotfiles/dot-one/dot-two/three');
|
||||||
|
make_path('.one/.two');
|
||||||
|
|
||||||
make_path('../stow/dotfiles/dot-.');
|
$stow->plan_stow('dotfiles');
|
||||||
make_file('../stow/dotfiles/dot-./foo');
|
$stow->process_tasks();
|
||||||
|
is(
|
||||||
|
readlink('./.one/.two/three'),
|
||||||
|
'../../../stow/dotfiles/dot-one/dot-two/three',
|
||||||
|
=> 'processed dotfile 2 folder exists (2 levels)'
|
||||||
|
);
|
||||||
|
|
||||||
$stow->plan_stow('dotfiles');
|
});
|
||||||
$stow->process_tasks();
|
|
||||||
is(
|
|
||||||
readlink('dot-'),
|
|
||||||
'../stow/dotfiles/dot-',
|
|
||||||
=> 'processed dotfile'
|
|
||||||
);
|
|
||||||
is(
|
|
||||||
readlink('dot-.'),
|
|
||||||
'../stow/dotfiles/dot-.',
|
|
||||||
=> 'unprocessed dotfile'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
subtest("dot-. should not have that part expanded.", sub {
|
||||||
# simple unstow scenario
|
plan tests => 2;
|
||||||
#
|
$stow = new_Stow(dir => '../stow', dotfiles => 1);
|
||||||
|
|
||||||
$stow = new_Stow(dir => '../stow', dotfiles => 1);
|
make_path('../stow/dotfiles');
|
||||||
|
make_file('../stow/dotfiles/dot-');
|
||||||
|
|
||||||
make_path('../stow/dotfiles');
|
make_path('../stow/dotfiles/dot-.');
|
||||||
make_file('../stow/dotfiles/dot-bar');
|
make_file('../stow/dotfiles/dot-./foo');
|
||||||
make_link('.bar', '../stow/dotfiles/dot-bar');
|
|
||||||
|
|
||||||
$stow->plan_unstow('dotfiles');
|
$stow->plan_stow('dotfiles');
|
||||||
$stow->process_tasks();
|
$stow->process_tasks();
|
||||||
ok(
|
is(
|
||||||
$stow->get_conflict_count == 0 &&
|
readlink('dot-'),
|
||||||
-f '../stow/dotfiles/dot-bar' && ! -e '.bar'
|
'../stow/dotfiles/dot-',
|
||||||
=> 'unstow a simple dotfile'
|
=> 'processed dotfile'
|
||||||
);
|
);
|
||||||
|
is(
|
||||||
|
readlink('dot-.'),
|
||||||
|
'../stow/dotfiles/dot-.',
|
||||||
|
=> 'unprocessed dotfile'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
subtest("simple unstow scenario", 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');
|
||||||
|
ok(! -e '.bar' => 'unstow a simple dotfile');
|
||||||
|
});
|
||||||
|
|
||||||
|
subtest("unstow process folder marked with 'dot' prefix when directory exists is 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');
|
||||||
|
ok(-d '.emacs.d/' => 'unstow dotfile folder when folder already exists');
|
||||||
|
});
|
||||||
|
|
|
@ -16,65 +16,133 @@
|
||||||
# along with this program. If not, see https://www.gnu.org/licenses/.
|
# along with this program. If not, see https://www.gnu.org/licenses/.
|
||||||
|
|
||||||
#
|
#
|
||||||
# Testing find_stowed_path()
|
# Testing Stow:: find_stowed_path()
|
||||||
#
|
#
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Test::More tests => 18;
|
use Test::More tests => 10;
|
||||||
|
|
||||||
use testutil;
|
use testutil;
|
||||||
use Stow::Util qw(set_debug_level);
|
use Stow::Util qw(set_debug_level);
|
||||||
|
|
||||||
init_test_dirs();
|
init_test_dirs();
|
||||||
|
|
||||||
my $stow = new_Stow(dir => "$TEST_DIR/stow");
|
subtest("find link to a stowed path with relative target" => sub {
|
||||||
#set_debug_level(4);
|
plan tests => 3;
|
||||||
|
|
||||||
my ($path, $stow_path, $package) =
|
# This is a relative path, unlike $ABS_TEST_DIR below.
|
||||||
$stow->find_stowed_path("$TEST_DIR/target/a/b/c", "../../../stow/a/b/c");
|
my $target = "$TEST_DIR/target";
|
||||||
is($path, "$TEST_DIR/stow/a/b/c", "path");
|
|
||||||
is($stow_path, "$TEST_DIR/stow", "stow path");
|
|
||||||
is($package, "a", "package");
|
|
||||||
|
|
||||||
cd("$TEST_DIR/target");
|
my $stow = new_Stow(dir => "$TEST_DIR/stow", target => $target);
|
||||||
$stow->set_stow_dir("../stow");
|
my ($path, $stow_path, $package) =
|
||||||
($path, $stow_path, $package) =
|
$stow->find_stowed_path("a/b/c", "../../../stow/a/b/c");
|
||||||
$stow->find_stowed_path("a/b/c", "../../../stow/a/b/c");
|
is($path, "../stow/a/b/c", "path");
|
||||||
is($path, "../stow/a/b/c", "path from target directory");
|
is($stow_path, "../stow", "stow path");
|
||||||
is($stow_path, "../stow", "stow path from target directory");
|
is($package, "a", "package");
|
||||||
is($package, "a", "from target directory");
|
});
|
||||||
|
|
||||||
make_path("stow");
|
my $stow = new_Stow(dir => "$ABS_TEST_DIR/stow", target => "$ABS_TEST_DIR/target");
|
||||||
cd("../..");
|
|
||||||
$stow->set_stow_dir("$TEST_DIR/target/stow");
|
|
||||||
|
|
||||||
($path, $stow_path, $package) =
|
# Required by creation of stow2 and stow2/.stow below
|
||||||
$stow->find_stowed_path("$TEST_DIR/target/a/b/c", "../../stow/a/b/c");
|
cd("$ABS_TEST_DIR/target");
|
||||||
is($path, "$TEST_DIR/target/stow/a/b/c", "path");
|
|
||||||
is($stow_path, "$TEST_DIR/target/stow", "stow path");
|
|
||||||
is($package, "a", "stow is subdir of target directory");
|
|
||||||
|
|
||||||
($path, $stow_path, $package) =
|
subtest("find link to a stowed path" => sub {
|
||||||
$stow->find_stowed_path("$TEST_DIR/target/a/b/c", "../../empty");
|
plan tests => 3;
|
||||||
is($path, "", "empty path");
|
my ($path, $stow_path, $package) =
|
||||||
is($stow_path, "", "empty stow path");
|
$stow->find_stowed_path("a/b/c", "../../../stow/a/b/c");
|
||||||
is($package, "", "target is not stowed");
|
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");
|
||||||
|
});
|
||||||
|
|
||||||
make_path("$TEST_DIR/target/stow2");
|
subtest("find link to alien path not owned by Stow" => sub {
|
||||||
make_file("$TEST_DIR/target/stow2/.stow");
|
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");
|
||||||
|
});
|
||||||
|
|
||||||
($path, $stow_path, $package) =
|
# Make a second stow directory within the target directory, so that we
|
||||||
$stow->find_stowed_path("$TEST_DIR/target/a/b/c","../../stow2/a/b/c");
|
# can check that links to package files within that stow directory are
|
||||||
is($path, "$TEST_DIR/target/stow2/a/b/c", "path");
|
# detected correctly.
|
||||||
is($stow_path, "$TEST_DIR/target/stow2", "stow path");
|
make_path("stow2");
|
||||||
is($package, "a", "detect alternate stow directory");
|
|
||||||
|
|
||||||
# Possible corner case with rogue symlink pointing to ancestor of
|
# However this second stow directory is still "alien" to stow until we
|
||||||
# stow dir.
|
# put a .stow file in it. So first test a symlink pointing to a path
|
||||||
($path, $stow_path, $package) =
|
# within this second stow directory
|
||||||
$stow->find_stowed_path("$TEST_DIR/target/a/b/c","../../..");
|
subtest("second stow dir still alien without .stow" => sub {
|
||||||
is($path, "", "path");
|
plan tests => 3;
|
||||||
is($stow_path, "", "stow path");
|
my ($path, $stow_path, $package) =
|
||||||
is($package, "", "corner case - link points to ancestor of stow dir");
|
$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");
|
||||||
|
});
|
||||||
|
|
117
t/join_paths.t
117
t/join_paths.t
|
@ -22,91 +22,40 @@
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Stow::Util qw(join_paths);
|
use Stow::Util qw(join_paths set_debug_level);
|
||||||
|
|
||||||
use Test::More tests => 14;
|
#set_debug_level(4);
|
||||||
|
|
||||||
is(
|
use Test::More tests => 22;
|
||||||
join_paths('a/b/c', 'd/e/f'),
|
|
||||||
'a/b/c/d/e/f'
|
my @TESTS = (
|
||||||
=> 'simple'
|
[['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(
|
for my $test (@TESTS) {
|
||||||
join_paths('/a/b/c', '/d/e/f'),
|
my ($inputs, $expected, $scenario) = @$test;
|
||||||
'/a/b/c/d/e/f'
|
my $got = join_paths(@$inputs);
|
||||||
=> 'leading /'
|
my $descr = "$scenario: in=[" . join(', ', map "'$_'", @$inputs) . "] exp=[$expected] got=[$got]";
|
||||||
);
|
is($got, $expected, $descr);
|
||||||
|
}
|
||||||
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 "./"'
|
|
||||||
);
|
|
||||||
|
|
||||||
is(
|
|
||||||
join_paths('a/b/c', '.'),
|
|
||||||
'a/b/c'
|
|
||||||
=> '. on RHS'
|
|
||||||
);
|
|
||||||
|
|
88
t/link_dest_within_stow_dir.t
Executable file
88
t/link_dest_within_stow_dir.t
Executable 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");
|
||||||
|
});
|
887
t/stow.t
887
t/stow.t
|
@ -22,7 +22,7 @@
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Test::More tests => 118;
|
use Test::More tests => 21;
|
||||||
use Test::Output;
|
use Test::Output;
|
||||||
use English qw(-no_match_vars);
|
use English qw(-no_match_vars);
|
||||||
|
|
||||||
|
@ -37,520 +37,507 @@ my %conflicts;
|
||||||
|
|
||||||
# Note that each of the following tests use a distinct set of files
|
# Note that each of the following tests use a distinct set of files
|
||||||
|
|
||||||
#
|
subtest('stow a simple tree minimally', sub {
|
||||||
# stow a simple tree minimally
|
plan tests => 2;
|
||||||
#
|
my $stow = new_Stow(dir => '../stow');
|
||||||
$stow = new_Stow(dir => '../stow');
|
|
||||||
|
|
||||||
make_path('../stow/pkg1/bin1');
|
make_path('../stow/pkg1/bin1');
|
||||||
make_file('../stow/pkg1/bin1/file1');
|
make_file('../stow/pkg1/bin1/file1');
|
||||||
|
|
||||||
$stow->plan_stow('pkg1');
|
$stow->plan_stow('pkg1');
|
||||||
$stow->process_tasks();
|
$stow->process_tasks();
|
||||||
is_deeply([ $stow->get_conflicts ], [], 'no conflicts with minimal stow');
|
is_deeply([ $stow->get_conflicts ], [], 'no conflicts with minimal stow');
|
||||||
is(
|
|
||||||
readlink('bin1'),
|
|
||||||
'../stow/pkg1/bin1',
|
|
||||||
=> 'minimal stow of a simple tree'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
|
||||||
# stow a simple tree into an existing directory
|
|
||||||
#
|
|
||||||
$stow = new_Stow();
|
|
||||||
|
|
||||||
make_path('../stow/pkg2/lib2');
|
|
||||||
make_file('../stow/pkg2/lib2/file2');
|
|
||||||
make_path('lib2');
|
|
||||||
|
|
||||||
$stow->plan_stow('pkg2');
|
|
||||||
$stow->process_tasks();
|
|
||||||
is(
|
|
||||||
readlink('lib2/file2'),
|
|
||||||
'../../stow/pkg2/lib2/file2',
|
|
||||||
=> 'stow simple tree to existing directory'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
|
||||||
# unfold existing tree
|
|
||||||
#
|
|
||||||
$stow = new_Stow();
|
|
||||||
|
|
||||||
make_path('../stow/pkg3a/bin3');
|
|
||||||
make_file('../stow/pkg3a/bin3/file3a');
|
|
||||||
make_link('bin3' => '../stow/pkg3a/bin3'); # emulate stow
|
|
||||||
|
|
||||||
make_path('../stow/pkg3b/bin3');
|
|
||||||
make_file('../stow/pkg3b/bin3/file3b');
|
|
||||||
|
|
||||||
$stow->plan_stow('pkg3b');
|
|
||||||
$stow->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 'bin4' conflicts with existing non-dir so can't
|
|
||||||
# unfold
|
|
||||||
#
|
|
||||||
$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();
|
|
||||||
ok(
|
|
||||||
$stow->get_conflict_count == 1 &&
|
|
||||||
$conflicts{stow}{pkg4}[0] =~
|
|
||||||
qr/existing target is neither a link nor a directory/
|
|
||||||
=> 'link to new dir bin4 conflicts with existing non-directory'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
|
||||||
# Link to a new dir 'bin4a' conflicts with existing non-dir so can't
|
|
||||||
# unfold even with --adopt
|
|
||||||
#
|
|
||||||
#$stow = new_Stow(adopt => 1);
|
|
||||||
$stow = new_Stow();
|
|
||||||
|
|
||||||
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();
|
|
||||||
ok(
|
|
||||||
$stow->get_conflict_count == 1 &&
|
|
||||||
$conflicts{stow}{pkg4a}[0] =~
|
|
||||||
qr/existing target is neither a link nor a directory/
|
|
||||||
=> 'link to new dir bin4a conflicts with existing non-directory'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
|
||||||
# Link to files 'file4b' and 'bin4b' conflict with existing files
|
|
||||||
# without --adopt
|
|
||||||
#
|
|
||||||
$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
|
|
||||||
make_path ('../stow/pkg4b/bin4b');
|
|
||||||
make_file('../stow/pkg4b/file4b', 'file4b - version originally in stow package');
|
|
||||||
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) {
|
|
||||||
like(
|
|
||||||
$conflicts{stow}{pkg4b}[$i],
|
|
||||||
qr/existing target is neither a link nor a directory/
|
|
||||||
=> 'link to file4b conflicts with existing non-directory'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#
|
|
||||||
# Link to files 'file4b' and 'bin4b' do not conflict with existing
|
|
||||||
# files when --adopt is given
|
|
||||||
#
|
|
||||||
$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
|
|
||||||
make_path ('../stow/pkg4c/bin4c');
|
|
||||||
make_file('../stow/pkg4c/file4c', "file4c - version originally in stow package\n");
|
|
||||||
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(
|
is(
|
||||||
readlink $file,
|
readlink('bin1'),
|
||||||
(index($file, '/') == -1 ? '' : '../' )
|
'../stow/pkg1/bin1',
|
||||||
. "../stow/pkg4c/$file" => "$file points to right place"
|
=> 'minimal stow of a simple tree'
|
||||||
);
|
);
|
||||||
is(cat_file($file), "$file - version originally in target\n" => "$file has right contents");
|
});
|
||||||
}
|
|
||||||
|
|
||||||
|
subtest('stow a simple tree into an existing directory', sub {
|
||||||
|
plan tests => 1;
|
||||||
|
my $stow = new_Stow();
|
||||||
|
|
||||||
#
|
make_path('../stow/pkg2/lib2');
|
||||||
# Target already exists but is not owned by stow
|
make_file('../stow/pkg2/lib2/file2');
|
||||||
#
|
make_path('lib2');
|
||||||
$stow = new_Stow();
|
|
||||||
|
|
||||||
make_path('bin5');
|
$stow->plan_stow('pkg2');
|
||||||
make_invalid_link('bin5/file5','../../empty');
|
$stow->process_tasks();
|
||||||
make_path('../stow/pkg5/bin5/file5');
|
is(
|
||||||
|
readlink('lib2/file2'),
|
||||||
|
'../../stow/pkg2/lib2/file2',
|
||||||
|
=> 'stow simple tree to existing directory'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
$stow->plan_stow('pkg5');
|
subtest('unfold existing tree', sub {
|
||||||
%conflicts = $stow->get_conflicts();
|
plan tests => 3;
|
||||||
like(
|
my $stow = new_Stow();
|
||||||
$conflicts{stow}{pkg5}[-1],
|
|
||||||
qr/not owned by stow/
|
|
||||||
=> 'target already exists but is not owned by stow'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
make_path('../stow/pkg3a/bin3');
|
||||||
# Replace existing but invalid target
|
make_file('../stow/pkg3a/bin3/file3a');
|
||||||
#
|
make_link('bin3' => '../stow/pkg3a/bin3'); # emulate stow
|
||||||
$stow = new_Stow();
|
|
||||||
|
|
||||||
make_invalid_link('file6','../stow/path-does-not-exist');
|
make_path('../stow/pkg3b/bin3');
|
||||||
make_path('../stow/pkg6');
|
make_file('../stow/pkg3b/bin3/file3b');
|
||||||
make_file('../stow/pkg6/file6');
|
|
||||||
|
|
||||||
$stow->plan_stow('pkg6');
|
$stow->plan_stow('pkg3b');
|
||||||
$stow->process_tasks();
|
$stow->process_tasks();
|
||||||
is(
|
ok(-d 'bin3');
|
||||||
readlink('file6'),
|
is(readlink('bin3/file3a'), '../../stow/pkg3a/bin3/file3a');
|
||||||
'../stow/pkg6/file6'
|
is(readlink('bin3/file3b'), '../../stow/pkg3b/bin3/file3b'
|
||||||
=> 'replace existing but invalid target'
|
=> 'target already has 1 stowed package');
|
||||||
);
|
});
|
||||||
|
|
||||||
#
|
subtest("Package dir 'bin4' conflicts with existing non-dir so can't unfold", sub {
|
||||||
# Target already exists, is owned by stow, but points to a non-directory
|
plan tests => 2;
|
||||||
# (can't unfold)
|
my $stow = new_Stow();
|
||||||
#
|
|
||||||
$stow = new_Stow();
|
|
||||||
#set_debug_level(4);
|
|
||||||
|
|
||||||
make_path('bin7');
|
make_file('bin4'); # this is a file but named like a directory
|
||||||
make_path('../stow/pkg7a/bin7');
|
make_path('../stow/pkg4/bin4');
|
||||||
make_file('../stow/pkg7a/bin7/node7');
|
make_file('../stow/pkg4/bin4/file4');
|
||||||
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');
|
$stow->plan_stow('pkg4');
|
||||||
%conflicts = $stow->get_conflicts();
|
%conflicts = $stow->get_conflicts();
|
||||||
like(
|
is($stow->get_conflict_count, 1);
|
||||||
$conflicts{stow}{pkg7b}[-1],
|
like(
|
||||||
qr/existing target is stowed to a different package/
|
$conflicts{stow}{pkg4}[0],
|
||||||
=> 'link to new dir conflicts with existing stowed non-directory'
|
qr/existing target is neither a link nor a directory/
|
||||||
);
|
=> 'link to new dir bin4 conflicts with existing non-directory'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
#
|
subtest("Package dir 'bin4a' conflicts with existing non-dir " .
|
||||||
# stowing directories named 0
|
"so can't unfold even with --adopt", sub {
|
||||||
#
|
plan tests => 2;
|
||||||
$stow = new_Stow();
|
#my $stow = new_Stow(adopt => 1);
|
||||||
|
my $stow = new_Stow();
|
||||||
|
|
||||||
make_path('../stow/pkg8a/0');
|
make_file('bin4a'); # this is a file but named like a directory
|
||||||
make_file('../stow/pkg8a/0/file8a');
|
make_path('../stow/pkg4a/bin4a');
|
||||||
make_link('0' => '../stow/pkg8a/0'); # emulate stow
|
make_file('../stow/pkg4a/bin4a/file4a');
|
||||||
|
|
||||||
make_path('../stow/pkg8b/0');
|
$stow->plan_stow('pkg4a');
|
||||||
make_file('../stow/pkg8b/0/file8b');
|
%conflicts = $stow->get_conflicts();
|
||||||
|
is($stow->get_conflict_count, 1);
|
||||||
|
like($conflicts{stow}{pkg4a}[0],
|
||||||
|
qr/existing target is neither a link nor a directory/
|
||||||
|
=> 'link to new dir bin4a conflicts with existing non-directory'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
$stow->plan_stow('pkg8b');
|
subtest("Package files 'file4b' and 'bin4b' conflict with existing files", sub {
|
||||||
$stow->process_tasks();
|
plan tests => 3;
|
||||||
ok(
|
my $stow = new_Stow();
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
-d '0' &&
|
|
||||||
readlink('0/file8a') eq '../../stow/pkg8a/0/file8a' &&
|
|
||||||
readlink('0/file8b') eq '../../stow/pkg8b/0/file8b'
|
|
||||||
=> 'stowing directories named 0'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
# Populate target
|
||||||
# overriding already stowed documentation
|
make_file('file4b', 'file4b - version originally in target');
|
||||||
#
|
make_path('bin4b');
|
||||||
$stow = new_Stow(override => ['man9', 'info9']);
|
make_file('bin4b/file4b', 'bin4b/file4b - version originally in target');
|
||||||
|
|
||||||
make_path('../stow/pkg9a/man9/man1');
|
# Populate stow package
|
||||||
make_file('../stow/pkg9a/man9/man1/file9.1');
|
make_path('../stow/pkg4b');
|
||||||
make_path('man9/man1');
|
make_file('../stow/pkg4b/file4b', 'file4b - version originally in stow package');
|
||||||
make_link('man9/man1/file9.1' => '../../../stow/pkg9a/man9/man1/file9.1'); # emulate stow
|
make_path('../stow/pkg4b/bin4b');
|
||||||
|
make_file('../stow/pkg4b/bin4b/file4b', 'bin4b/file4b - version originally in stow package');
|
||||||
|
|
||||||
make_path('../stow/pkg9b/man9/man1');
|
$stow->plan_stow('pkg4b');
|
||||||
make_file('../stow/pkg9b/man9/man1/file9.1');
|
%conflicts = $stow->get_conflicts();
|
||||||
|
is($stow->get_conflict_count, 2 => 'conflict per file');
|
||||||
|
for my $i (0, 1) {
|
||||||
|
like(
|
||||||
|
$conflicts{stow}{pkg4b}[$i],
|
||||||
|
qr/existing target is neither a link nor a directory/
|
||||||
|
=> 'link to file4b conflicts with existing non-directory'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$stow->plan_stow('pkg9b');
|
subtest("Package files 'file4c' and 'bin4c' can adopt existing versions", sub {
|
||||||
$stow->process_tasks();
|
plan tests => 8;
|
||||||
ok(
|
my $stow = new_Stow(adopt => 1);
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
readlink('man9/man1/file9.1') eq '../../../stow/pkg9b/man9/man1/file9.1'
|
|
||||||
=> 'overriding existing documentation files'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
# Populate target
|
||||||
# deferring to already stowed documentation
|
make_file('file4c', "file4c - version originally in target\n");
|
||||||
#
|
make_path ('bin4c');
|
||||||
$stow = new_Stow(defer => ['man10', 'info10']);
|
make_file('bin4c/file4c', "bin4c/file4c - version originally in target\n");
|
||||||
|
|
||||||
make_path('../stow/pkg10a/man10/man1');
|
# Populate stow package
|
||||||
make_file('../stow/pkg10a/man10/man1/file10.1');
|
make_path('../stow/pkg4c');
|
||||||
make_path('man10/man1');
|
make_file('../stow/pkg4c/file4c', "file4c - version originally in stow package\n");
|
||||||
make_link('man10/man1/file10.1' => '../../../stow/pkg10a/man10/man1/file10.1'); # emulate stow
|
make_path ('../stow/pkg4c/bin4c');
|
||||||
|
make_file('../stow/pkg4c/bin4c/file4c', "bin4c/file4c - version originally in stow package\n");
|
||||||
|
|
||||||
make_path('../stow/pkg10b/man10/man1');
|
$stow->plan_stow('pkg4c');
|
||||||
make_file('../stow/pkg10b/man10/man1/file10.1');
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
$stow->plan_stow('pkg10b');
|
});
|
||||||
is($stow->get_tasks, 0, 'no tasks to process');
|
|
||||||
ok(
|
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
readlink('man10/man1/file10.1') eq '../../../stow/pkg10a/man10/man1/file10.1'
|
|
||||||
=> 'defer to existing documentation files'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
subtest("Target already exists but is not owned by stow", sub {
|
||||||
# Ignore temp files
|
plan tests => 1;
|
||||||
#
|
my $stow = new_Stow();
|
||||||
$stow = new_Stow(ignore => ['~', '\.#.*']);
|
|
||||||
|
|
||||||
make_path('../stow/pkg11/man11/man1');
|
make_path('bin5');
|
||||||
make_file('../stow/pkg11/man11/man1/file11.1');
|
make_invalid_link('bin5/file5','../../empty');
|
||||||
make_file('../stow/pkg11/man11/man1/file11.1~');
|
make_path('../stow/pkg5/bin5/file5');
|
||||||
make_file('../stow/pkg11/man11/man1/.#file11.1');
|
|
||||||
make_path('man11/man1');
|
|
||||||
|
|
||||||
$stow->plan_stow('pkg11');
|
$stow->plan_stow('pkg5');
|
||||||
$stow->process_tasks();
|
%conflicts = $stow->get_conflicts();
|
||||||
ok(
|
like(
|
||||||
$stow->get_conflict_count == 0 &&
|
$conflicts{stow}{pkg5}[-1],
|
||||||
readlink('man11/man1/file11.1') eq '../../../stow/pkg11/man11/man1/file11.1' &&
|
qr/not owned by stow/
|
||||||
!-e 'man11/man1/file11.1~' &&
|
=> 'target already exists but is not owned by stow'
|
||||||
!-e 'man11/man1/.#file11.1'
|
);
|
||||||
=> 'ignore temp files'
|
});
|
||||||
);
|
|
||||||
|
|
||||||
#
|
subtest("Replace existing but invalid target", sub {
|
||||||
# stowing links library files
|
plan tests => 1;
|
||||||
#
|
my $stow = new_Stow();
|
||||||
$stow = new_Stow();
|
|
||||||
|
|
||||||
make_path('../stow/pkg12/lib12/');
|
make_invalid_link('file6','../stow/path-does-not-exist');
|
||||||
make_file('../stow/pkg12/lib12/lib.so.1');
|
make_path('../stow/pkg6');
|
||||||
make_link('../stow/pkg12/lib12/lib.so', 'lib.so.1');
|
make_file('../stow/pkg6/file6');
|
||||||
|
|
||||||
make_path('lib12/');
|
$stow->plan_stow('pkg6');
|
||||||
|
$stow->process_tasks();
|
||||||
|
is(
|
||||||
|
readlink('file6'),
|
||||||
|
'../stow/pkg6/file6'
|
||||||
|
=> 'replace existing but invalid target'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
$stow->plan_stow('pkg12');
|
subtest("Target already exists, is owned by stow, but points to a non-directory", sub {
|
||||||
$stow->process_tasks();
|
plan tests => 1;
|
||||||
ok(
|
my $stow = new_Stow();
|
||||||
$stow->get_conflict_count == 0 &&
|
#set_debug_level(4);
|
||||||
readlink('lib12/lib.so.1') eq '../../stow/pkg12/lib12/lib.so.1' &&
|
|
||||||
readlink('lib12/lib.so' ) eq '../../stow/pkg12/lib12/lib.so'
|
|
||||||
=> 'stow links to libraries'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
make_path('bin7');
|
||||||
# unfolding to stow links to library files
|
make_path('../stow/pkg7a/bin7');
|
||||||
#
|
make_file('../stow/pkg7a/bin7/node7');
|
||||||
$stow = new_Stow();
|
make_link('bin7/node7','../../stow/pkg7a/bin7/node7');
|
||||||
|
make_path('../stow/pkg7b/bin7/node7');
|
||||||
|
make_file('../stow/pkg7b/bin7/node7/file7');
|
||||||
|
|
||||||
make_path('../stow/pkg13a/lib13/');
|
$stow->plan_stow('pkg7b');
|
||||||
make_file('../stow/pkg13a/lib13/liba.so.1');
|
%conflicts = $stow->get_conflicts();
|
||||||
make_link('../stow/pkg13a/lib13/liba.so', 'liba.so.1');
|
like(
|
||||||
make_link('lib13','../stow/pkg13a/lib13');
|
$conflicts{stow}{pkg7b}[-1],
|
||||||
|
qr/existing target is stowed to a different package/
|
||||||
|
=> 'link to new dir conflicts with existing stowed non-directory'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
make_path('../stow/pkg13b/lib13/');
|
subtest("stowing directories named 0", sub {
|
||||||
make_file('../stow/pkg13b/lib13/libb.so.1');
|
plan tests => 4;
|
||||||
make_link('../stow/pkg13b/lib13/libb.so', 'libb.so.1');
|
my $stow = new_Stow();
|
||||||
|
|
||||||
$stow->plan_stow('pkg13b');
|
make_path('../stow/pkg8a/0');
|
||||||
$stow->process_tasks();
|
make_file('../stow/pkg8a/0/file8a');
|
||||||
ok(
|
make_link('0' => '../stow/pkg8a/0'); # emulate stow
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
readlink('lib13/liba.so.1') eq '../../stow/pkg13a/lib13/liba.so.1' &&
|
|
||||||
readlink('lib13/liba.so' ) eq '../../stow/pkg13a/lib13/liba.so' &&
|
|
||||||
readlink('lib13/libb.so.1') eq '../../stow/pkg13b/lib13/libb.so.1' &&
|
|
||||||
readlink('lib13/libb.so' ) eq '../../stow/pkg13b/lib13/libb.so'
|
|
||||||
=> 'unfolding to stow links to libraries'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
make_path('../stow/pkg8b/0');
|
||||||
# stowing to stow dir should fail
|
make_file('../stow/pkg8b/0/file8b');
|
||||||
#
|
|
||||||
make_path('stow');
|
|
||||||
$stow = new_Stow(dir => 'stow');
|
|
||||||
|
|
||||||
make_path('stow/pkg14/stow/pkg15');
|
$stow->plan_stow('pkg8b');
|
||||||
make_file('stow/pkg14/stow/pkg15/node15');
|
$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'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
capture_stderr();
|
subtest("overriding already stowed documentation", sub {
|
||||||
$stow->plan_stow('pkg14');
|
plan tests => 2;
|
||||||
is($stow->get_tasks, 0, 'no tasks to process');
|
my $stow = new_Stow(override => ['man9', 'info9']);
|
||||||
ok(
|
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
! -l 'stow/pkg15'
|
|
||||||
=> "stowing to stow dir should fail"
|
|
||||||
);
|
|
||||||
like($stderr,
|
|
||||||
qr/WARNING: skipping target which was current stow directory stow/
|
|
||||||
=> "stowing to stow dir should give warning");
|
|
||||||
uncapture_stderr();
|
|
||||||
|
|
||||||
#
|
make_path('../stow/pkg9a/man9/man1');
|
||||||
# stow a simple tree minimally when cwd isn't target
|
make_file('../stow/pkg9a/man9/man1/file9.1');
|
||||||
#
|
make_path('man9/man1');
|
||||||
cd('../..');
|
make_link('man9/man1/file9.1' => '../../../stow/pkg9a/man9/man1/file9.1'); # emulate stow
|
||||||
$stow = new_Stow(dir => "$TEST_DIR/stow", target => "$TEST_DIR/target");
|
|
||||||
|
|
||||||
make_path("$TEST_DIR/stow/pkg16/bin16");
|
make_path('../stow/pkg9b/man9/man1');
|
||||||
make_file("$TEST_DIR/stow/pkg16/bin16/file16");
|
make_file('../stow/pkg9b/man9/man1/file9.1');
|
||||||
|
|
||||||
$stow->plan_stow('pkg16');
|
$stow->plan_stow('pkg9b');
|
||||||
$stow->process_tasks();
|
$stow->process_tasks();
|
||||||
is_deeply([ $stow->get_conflicts ], [], 'no conflicts with minimal stow');
|
is($stow->get_conflict_count, 0);
|
||||||
is(
|
is(readlink('man9/man1/file9.1'), '../../../stow/pkg9b/man9/man1/file9.1'
|
||||||
readlink("$TEST_DIR/target/bin16"),
|
=> 'overriding existing documentation files'
|
||||||
'../stow/pkg16/bin16',
|
);
|
||||||
=> "minimal stow of a simple tree when cwd isn't target"
|
});
|
||||||
);
|
|
||||||
|
|
||||||
#
|
subtest("deferring to already stowed documentation", sub {
|
||||||
# stow a simple tree minimally to absolute stow dir when cwd isn't
|
plan tests => 3;
|
||||||
# target
|
my $stow = new_Stow(defer => ['man10', 'info10']);
|
||||||
#
|
|
||||||
$stow = new_Stow(dir => canon_path("$TEST_DIR/stow"),
|
|
||||||
target => "$TEST_DIR/target");
|
|
||||||
|
|
||||||
make_path("$TEST_DIR/stow/pkg17/bin17");
|
make_path('../stow/pkg10a/man10/man1');
|
||||||
make_file("$TEST_DIR/stow/pkg17/bin17/file17");
|
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
|
||||||
|
|
||||||
$stow->plan_stow('pkg17');
|
make_path('../stow/pkg10b/man10/man1');
|
||||||
$stow->process_tasks();
|
make_file('../stow/pkg10b/man10/man1/file10.1');
|
||||||
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"
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
$stow->plan_stow('pkg10b');
|
||||||
# stow a simple tree minimally with absolute stow AND target dirs when
|
is($stow->get_tasks, 0, 'no tasks to process');
|
||||||
# cwd isn't target
|
is($stow->get_conflict_count, 0);
|
||||||
#
|
is(readlink('man10/man1/file10.1'), '../../../stow/pkg10a/man10/man1/file10.1'
|
||||||
$stow = new_Stow(dir => canon_path("$TEST_DIR/stow"),
|
=> 'defer to existing documentation files'
|
||||||
target => canon_path("$TEST_DIR/target"));
|
);
|
||||||
|
});
|
||||||
|
|
||||||
make_path("$TEST_DIR/stow/pkg18/bin18");
|
subtest("Ignore temp files", sub {
|
||||||
make_file("$TEST_DIR/stow/pkg18/bin18/file18");
|
plan tests => 4;
|
||||||
|
my $stow = new_Stow(ignore => ['~', '\.#.*']);
|
||||||
|
|
||||||
$stow->plan_stow('pkg18');
|
make_path('../stow/pkg11/man11/man1');
|
||||||
$stow->process_tasks();
|
make_file('../stow/pkg11/man11/man1/file11.1');
|
||||||
is_deeply([ $stow->get_conflicts ], [], 'no conflicts with minimal stow');
|
make_file('../stow/pkg11/man11/man1/file11.1~');
|
||||||
is(
|
make_file('../stow/pkg11/man11/man1/.#file11.1');
|
||||||
readlink("$TEST_DIR/target/bin18"),
|
make_path('man11/man1');
|
||||||
'../stow/pkg18/bin18',
|
|
||||||
=> "minimal stow of a simple tree with absolute stow and target dirs"
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
$stow->plan_stow('pkg11');
|
||||||
# stow a tree with no-folding enabled -
|
$stow->process_tasks();
|
||||||
# no new folded directories should be created, and existing
|
is($stow->get_conflict_count, 0);
|
||||||
# folded directories should be split open (unfolded) where
|
is(readlink('man11/man1/file11.1'), '../../../stow/pkg11/man11/man1/file11.1');
|
||||||
# (and only where) necessary
|
ok(!-e 'man11/man1/file11.1~');
|
||||||
#
|
ok(!-e 'man11/man1/.#file11.1'
|
||||||
cd("$TEST_DIR/target");
|
=> 'ignore temp files'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
sub create_pkg {
|
subtest("stowing links library files", sub {
|
||||||
my ($id, $pkg) = @_;
|
plan tests => 3;
|
||||||
|
my $stow = new_Stow();
|
||||||
|
|
||||||
my $stow_pkg = "../stow/$id-$pkg";
|
make_path('../stow/pkg12/lib12/');
|
||||||
make_path ($stow_pkg);
|
make_file('../stow/pkg12/lib12/lib.so.1');
|
||||||
make_file("$stow_pkg/$id-file-$pkg");
|
make_link('../stow/pkg12/lib12/lib.so', 'lib.so.1');
|
||||||
|
|
||||||
# create a shallow hierarchy specific to this package which isn't
|
make_path('lib12/');
|
||||||
# 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
|
$stow->plan_stow('pkg12');
|
||||||
# yet stowed
|
$stow->process_tasks();
|
||||||
make_path ("$stow_pkg/$id-$pkg-only-new2/subdir");
|
is($stow->get_conflict_count, 0);
|
||||||
make_file("$stow_pkg/$id-$pkg-only-new2/subdir/$id-file-$pkg");
|
is(readlink('lib12/lib.so.1'), '../../stow/pkg12/lib12/lib.so.1');
|
||||||
make_link("$stow_pkg/$id-$pkg-only-new2/current", "subdir");
|
is(readlink('lib12/lib.so'), '../../stow/pkg12/lib12/lib.so'
|
||||||
|
=> 'stow links to libraries'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
# create a hierarchy specific to this package which is already
|
subtest("unfolding to stow links to library files", sub {
|
||||||
# stowed via a folded tree
|
plan tests => 5;
|
||||||
make_path ("$stow_pkg/$id-$pkg-only-old");
|
my $stow = new_Stow();
|
||||||
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/pkg13a/lib13/');
|
||||||
make_path ("$stow_pkg/$id-shared");
|
make_file('../stow/pkg13a/lib13/liba.so.1');
|
||||||
make_file("$stow_pkg/$id-shared/$id-file-$pkg");
|
make_link('../stow/pkg13a/lib13/liba.so', 'liba.so.1');
|
||||||
|
make_link('lib13','../stow/pkg13a/lib13');
|
||||||
|
|
||||||
# create a partially shared hierarchy which this package uses
|
make_path('../stow/pkg13b/lib13/');
|
||||||
make_path ("$stow_pkg/$id-shared2/subdir-$pkg");
|
make_file('../stow/pkg13b/lib13/libb.so.1');
|
||||||
make_file("$stow_pkg/$id-shared2/$id-file-$pkg");
|
make_link('../stow/pkg13b/lib13/libb.so', 'libb.so.1');
|
||||||
make_file("$stow_pkg/$id-shared2/subdir-$pkg/$id-file-$pkg");
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach my $pkg (qw{a b}) {
|
$stow->plan_stow('pkg13b');
|
||||||
create_pkg('no-folding', $pkg);
|
$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'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
$stow = new_Stow('no-folding' => 1);
|
subtest("stowing to stow dir should fail", sub {
|
||||||
$stow->plan_stow('no-folding-a');
|
plan tests => 4;
|
||||||
is_deeply([ $stow->get_conflicts ], [] => 'no conflicts with --no-folding');
|
make_path('stow');
|
||||||
my @tasks = $stow->get_tasks;
|
$stow = new_Stow(dir => 'stow');
|
||||||
use Data::Dumper;
|
|
||||||
is(scalar(@tasks), 13 => "6 dirs, 7 links") || warn Dumper(\@tasks);
|
|
||||||
$stow->process_tasks();
|
|
||||||
|
|
||||||
sub check_no_folding {
|
make_path('stow/pkg14/stow/pkg15');
|
||||||
my ($pkg) = @_;
|
make_file('stow/pkg14/stow/pkg15/node15');
|
||||||
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
|
stderr_like(
|
||||||
is_link("no-folding-$pkg-only-old", "$stow_pkg/no-folding-$pkg-only-old");
|
sub { $stow->plan_stow('pkg14'); },
|
||||||
|
qr/WARNING: skipping target which was current stow directory stow/,
|
||||||
|
"stowing to stow dir should give warning"
|
||||||
|
);
|
||||||
|
|
||||||
# check newly stowed shallow tree is not folded
|
is($stow->get_tasks, 0, 'no tasks to process');
|
||||||
is_dir_not_symlink("no-folding-$pkg-only-new");
|
is($stow->get_conflict_count, 0);
|
||||||
is_link("no-folding-$pkg-only-new/no-folding-file-$pkg",
|
ok(
|
||||||
"../$stow_pkg/no-folding-$pkg-only-new/no-folding-file-$pkg");
|
! -l 'stow/pkg15'
|
||||||
|
=> "stowing to stow dir should fail"
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
# check newly stowed deeper tree is not folded
|
subtest("stow a simple tree minimally when cwd isn't target", sub {
|
||||||
is_dir_not_symlink("no-folding-$pkg-only-new2");
|
plan tests => 2;
|
||||||
is_dir_not_symlink("no-folding-$pkg-only-new2/subdir");
|
cd('../..');
|
||||||
is_link("no-folding-$pkg-only-new2/subdir/no-folding-file-$pkg",
|
$stow = new_Stow(dir => "$TEST_DIR/stow", target => "$TEST_DIR/target");
|
||||||
"../../$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
|
make_path("$TEST_DIR/stow/pkg16/bin16");
|
||||||
# newly stowed.
|
make_file("$TEST_DIR/stow/pkg16/bin16/file16");
|
||||||
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
|
$stow->plan_stow('pkg16');
|
||||||
# will be newly stowed.
|
$stow->process_tasks();
|
||||||
is_dir_not_symlink('no-folding-shared2');
|
is_deeply([ $stow->get_conflicts ], [], 'no conflicts with minimal stow');
|
||||||
is_link("no-folding-shared2/no-folding-file-$pkg",
|
is(
|
||||||
"../$stow_pkg/no-folding-shared2/no-folding-file-$pkg");
|
readlink("$TEST_DIR/target/bin16"),
|
||||||
is_link("no-folding-shared2/no-folding-file-$pkg",
|
'../stow/pkg16/bin16',
|
||||||
"../$stow_pkg/no-folding-shared2/no-folding-file-$pkg");
|
=> "minimal stow of a simple tree when cwd isn't target"
|
||||||
}
|
);
|
||||||
|
});
|
||||||
|
|
||||||
check_no_folding('a');
|
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");
|
||||||
|
|
||||||
$stow = new_Stow('no-folding' => 1);
|
make_path("$TEST_DIR/stow/pkg17/bin17");
|
||||||
$stow->plan_stow('no-folding-b');
|
make_file("$TEST_DIR/stow/pkg17/bin17/file17");
|
||||||
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');
|
$stow->plan_stow('pkg17');
|
||||||
check_no_folding('b');
|
$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');
|
||||||
|
});
|
||||||
|
|
|
@ -28,7 +28,6 @@ use Carp qw(croak);
|
||||||
use File::Basename;
|
use File::Basename;
|
||||||
use File::Path qw(make_path remove_tree);
|
use File::Path qw(make_path remove_tree);
|
||||||
use File::Spec;
|
use File::Spec;
|
||||||
use IO::Scalar;
|
|
||||||
use Test::More;
|
use Test::More;
|
||||||
|
|
||||||
use Stow;
|
use Stow;
|
||||||
|
@ -38,7 +37,6 @@ use base qw(Exporter);
|
||||||
our @EXPORT = qw(
|
our @EXPORT = qw(
|
||||||
$ABS_TEST_DIR
|
$ABS_TEST_DIR
|
||||||
$TEST_DIR
|
$TEST_DIR
|
||||||
$stderr
|
|
||||||
init_test_dirs
|
init_test_dirs
|
||||||
cd
|
cd
|
||||||
new_Stow new_compat_Stow
|
new_Stow new_compat_Stow
|
||||||
|
@ -46,25 +44,11 @@ our @EXPORT = qw(
|
||||||
remove_dir remove_file remove_link
|
remove_dir remove_file remove_link
|
||||||
cat_file
|
cat_file
|
||||||
is_link is_dir_not_symlink is_nonexistent_path
|
is_link is_dir_not_symlink is_nonexistent_path
|
||||||
capture_stderr uncapture_stderr
|
|
||||||
);
|
);
|
||||||
|
|
||||||
our $TEST_DIR = 'tmp-testing-trees';
|
our $TEST_DIR = 'tmp-testing-trees';
|
||||||
our $ABS_TEST_DIR = File::Spec->rel2abs('tmp-testing-trees');
|
our $ABS_TEST_DIR = File::Spec->rel2abs('tmp-testing-trees');
|
||||||
|
|
||||||
our $stderr;
|
|
||||||
my $tied_err;
|
|
||||||
|
|
||||||
sub capture_stderr {
|
|
||||||
undef $stderr;
|
|
||||||
$tied_err = tie *STDERR, 'IO::Scalar', \$stderr;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub uncapture_stderr {
|
|
||||||
undef $tied_err;
|
|
||||||
untie *STDERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub init_test_dirs {
|
sub init_test_dirs {
|
||||||
# Create a run_from/ subdirectory for tests which want to run
|
# Create a run_from/ subdirectory for tests which want to run
|
||||||
# from a separate directory outside the Stow directory or
|
# from a separate directory outside the Stow directory or
|
||||||
|
@ -81,6 +65,8 @@ sub init_test_dirs {
|
||||||
|
|
||||||
sub new_Stow {
|
sub new_Stow {
|
||||||
my %opts = @_;
|
my %opts = @_;
|
||||||
|
# These default paths assume that execution will be triggered from
|
||||||
|
# within the target directory.
|
||||||
$opts{dir} ||= '../stow';
|
$opts{dir} ||= '../stow';
|
||||||
$opts{target} ||= '.';
|
$opts{target} ||= '.';
|
||||||
$opts{test_mode} = 1;
|
$opts{test_mode} = 1;
|
||||||
|
@ -96,28 +82,28 @@ sub new_compat_Stow {
|
||||||
#===== SUBROUTINE ===========================================================
|
#===== SUBROUTINE ===========================================================
|
||||||
# Name : make_link()
|
# Name : make_link()
|
||||||
# Purpose : safely create a link
|
# Purpose : safely create a link
|
||||||
# Parameters: $target => path to the link
|
# Parameters: $link_src => path to the link
|
||||||
# : $source => where the new link should point
|
# : $link_dest => where the new link should point
|
||||||
# : $invalid => true iff $source refers to non-existent file
|
# : $invalid => true iff $link_dest refers to non-existent file
|
||||||
# Returns : n/a
|
# Returns : n/a
|
||||||
# Throws : fatal error if the link can not be safely created
|
# Throws : fatal error if the link can not be safely created
|
||||||
# Comments : checks for existing nodes
|
# Comments : checks for existing nodes
|
||||||
#============================================================================
|
#============================================================================
|
||||||
sub make_link {
|
sub make_link {
|
||||||
my ($target, $source, $invalid) = @_;
|
my ($link_src, $link_dest, $invalid) = @_;
|
||||||
|
|
||||||
if (-l $target) {
|
if (-l $link_src) {
|
||||||
my $old_source = readlink join('/', parent($target), $source)
|
my $old_source = readlink join('/', parent($link_src), $link_dest)
|
||||||
or die "$target is already a link but could not read link $target/$source";
|
or croak "$link_src is already a link but could not read link $link_src/$link_dest";
|
||||||
if ($old_source ne $source) {
|
if ($old_source ne $link_dest) {
|
||||||
die "$target already exists but points elsewhere\n";
|
croak "$link_src already exists but points elsewhere\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
die "$target already exists and is not a link\n" if -e $target;
|
croak "$link_src already exists and is not a link\n" if -e $link_src;
|
||||||
my $abs_target = File::Spec->rel2abs($target);
|
my $abs_target = File::Spec->rel2abs($link_src);
|
||||||
my $target_container = dirname($abs_target);
|
my $link_src_container = dirname($abs_target);
|
||||||
my $abs_source = File::Spec->rel2abs($source, $target_container);
|
my $abs_source = File::Spec->rel2abs($link_dest, $link_src_container);
|
||||||
#warn "t $target c $target_container as $abs_source";
|
#warn "t $link_src c $link_src_container as $abs_source";
|
||||||
if (-e $abs_source) {
|
if (-e $abs_source) {
|
||||||
croak "Won't make invalid link pointing to existing $abs_target"
|
croak "Won't make invalid link pointing to existing $abs_target"
|
||||||
if $invalid;
|
if $invalid;
|
||||||
|
@ -126,8 +112,8 @@ sub make_link {
|
||||||
croak "Won't make link pointing to non-existent $abs_target"
|
croak "Won't make link pointing to non-existent $abs_target"
|
||||||
unless $invalid;
|
unless $invalid;
|
||||||
}
|
}
|
||||||
symlink $source, $target
|
symlink $link_dest, $link_src
|
||||||
or die "could not create link $target => $source ($!)\n";
|
or croak "could not create link $link_src => $link_dest ($!)\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
#===== SUBROUTINE ===========================================================
|
#===== SUBROUTINE ===========================================================
|
||||||
|
@ -157,11 +143,11 @@ sub make_file {
|
||||||
my ($path, $contents) = @_;
|
my ($path, $contents) = @_;
|
||||||
|
|
||||||
if (-e $path and ! -f $path) {
|
if (-e $path and ! -f $path) {
|
||||||
die "a non-file already exists at $path\n";
|
croak "a non-file already exists at $path\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
open my $FILE ,'>', $path
|
open my $FILE ,'>', $path
|
||||||
or die "could not create file: $path ($!)\n";
|
or croak "could not create file: $path ($!)\n";
|
||||||
print $FILE $contents if defined $contents;
|
print $FILE $contents if defined $contents;
|
||||||
close $FILE;
|
close $FILE;
|
||||||
}
|
}
|
||||||
|
@ -178,9 +164,9 @@ sub make_file {
|
||||||
sub remove_link {
|
sub remove_link {
|
||||||
my ($path) = @_;
|
my ($path) = @_;
|
||||||
if (not -l $path) {
|
if (not -l $path) {
|
||||||
die qq(remove_link() called with a non-link: $path);
|
croak qq(remove_link() called with a non-link: $path);
|
||||||
}
|
}
|
||||||
unlink $path or die "could not remove link: $path ($!)\n";
|
unlink $path or croak "could not remove link: $path ($!)\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,9 +181,9 @@ sub remove_link {
|
||||||
sub remove_file {
|
sub remove_file {
|
||||||
my ($path) = @_;
|
my ($path) = @_;
|
||||||
if (-z $path) {
|
if (-z $path) {
|
||||||
die "file at $path is non-empty\n";
|
croak "file at $path is non-empty\n";
|
||||||
}
|
}
|
||||||
unlink $path or die "could not remove empty file: $path ($!)\n";
|
unlink $path or croak "could not remove empty file: $path ($!)\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,10 +199,10 @@ sub remove_dir {
|
||||||
my ($dir) = @_;
|
my ($dir) = @_;
|
||||||
|
|
||||||
if (not -d $dir) {
|
if (not -d $dir) {
|
||||||
die "$dir is not a directory";
|
croak "$dir is not a directory";
|
||||||
}
|
}
|
||||||
|
|
||||||
opendir my $DIR, $dir or die "cannot read directory: $dir ($!)\n";
|
opendir my $DIR, $dir or croak "cannot read directory: $dir ($!)\n";
|
||||||
my @listing = readdir $DIR;
|
my @listing = readdir $DIR;
|
||||||
closedir $DIR;
|
closedir $DIR;
|
||||||
|
|
||||||
|
@ -227,16 +213,16 @@ sub remove_dir {
|
||||||
|
|
||||||
my $path = "$dir/$node";
|
my $path = "$dir/$node";
|
||||||
if (-l $path or (-f $path and -z $path) or $node eq $Stow::LOCAL_IGNORE_FILE) {
|
if (-l $path or (-f $path and -z $path) or $node eq $Stow::LOCAL_IGNORE_FILE) {
|
||||||
unlink $path or die "cannot unlink $path ($!)\n";
|
unlink $path or croak "cannot unlink $path ($!)\n";
|
||||||
}
|
}
|
||||||
elsif (-d "$path") {
|
elsif (-d "$path") {
|
||||||
remove_dir($path);
|
remove_dir($path);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
die "$path is not a link, directory, or empty file\n";
|
croak "$path is not a link, directory, or empty file\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rmdir $dir or die "cannot rmdir $dir ($!)\n";
|
rmdir $dir or croak "cannot rmdir $dir ($!)\n";
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -251,7 +237,7 @@ sub remove_dir {
|
||||||
#============================================================================
|
#============================================================================
|
||||||
sub cd {
|
sub cd {
|
||||||
my ($dir) = @_;
|
my ($dir) = @_;
|
||||||
chdir $dir or die "Failed to chdir($dir): $!\n";
|
chdir $dir or croak "Failed to chdir($dir): $!\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
#===== SUBROUTINE ===========================================================
|
#===== SUBROUTINE ===========================================================
|
||||||
|
@ -264,7 +250,7 @@ sub cd {
|
||||||
#============================================================================
|
#============================================================================
|
||||||
sub cat_file {
|
sub cat_file {
|
||||||
my ($file) = @_;
|
my ($file) = @_;
|
||||||
open F, $file or die "Failed to open($file): $!\n";
|
open F, $file or croak "Failed to open($file): $!\n";
|
||||||
my $contents = join '', <F>;
|
my $contents = join '', <F>;
|
||||||
close(F);
|
close(F);
|
||||||
return $contents;
|
return $contents;
|
||||||
|
@ -309,6 +295,5 @@ sub is_nonexistent_path {
|
||||||
|
|
||||||
# Local variables:
|
# Local variables:
|
||||||
# mode: perl
|
# mode: perl
|
||||||
# cperl-indent-level: 4
|
|
||||||
# end:
|
# end:
|
||||||
# vim: ft=perl
|
# vim: ft=perl
|
||||||
|
|
562
t/unstow.t
562
t/unstow.t
|
@ -22,7 +22,7 @@
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use Test::More tests => 39;
|
use Test::More tests => 32;
|
||||||
use Test::Output;
|
use Test::Output;
|
||||||
use English qw(-no_match_vars);
|
use English qw(-no_match_vars);
|
||||||
|
|
||||||
|
@ -34,333 +34,321 @@ cd("$TEST_DIR/target");
|
||||||
|
|
||||||
# Note that each of the following tests use a distinct set of files
|
# Note that each of the following tests use a distinct set of files
|
||||||
|
|
||||||
my $stow;
|
subtest("unstow a simple tree minimally", sub {
|
||||||
my %conflicts;
|
plan tests => 3;
|
||||||
|
my $stow = new_Stow();
|
||||||
|
|
||||||
#
|
make_path('../stow/pkg1/bin1');
|
||||||
# unstow a simple tree minimally
|
make_file('../stow/pkg1/bin1/file1');
|
||||||
#
|
make_link('bin1', '../stow/pkg1/bin1');
|
||||||
$stow = new_Stow();
|
|
||||||
|
|
||||||
make_path('../stow/pkg1/bin1');
|
$stow->plan_unstow('pkg1');
|
||||||
make_file('../stow/pkg1/bin1/file1');
|
$stow->process_tasks();
|
||||||
make_link('bin1', '../stow/pkg1/bin1');
|
is($stow->get_conflict_count, 0);
|
||||||
|
ok(-f '../stow/pkg1/bin1/file1');
|
||||||
|
ok(! -e 'bin1' => 'unstow a simple tree');
|
||||||
|
});
|
||||||
|
|
||||||
$stow->plan_unstow('pkg1');
|
subtest("unstow a simple tree from an existing directory", sub {
|
||||||
$stow->process_tasks();
|
plan tests => 3;
|
||||||
ok(
|
my $stow = new_Stow();
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
-f '../stow/pkg1/bin1/file1' && ! -e 'bin1'
|
|
||||||
=> 'unstow a simple tree'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
make_path('lib2');
|
||||||
# unstow a simple tree from an existing directory
|
make_path('../stow/pkg2/lib2');
|
||||||
#
|
make_file('../stow/pkg2/lib2/file2');
|
||||||
$stow = new_Stow();
|
make_link('lib2/file2', '../../stow/pkg2/lib2/file2');
|
||||||
|
$stow->plan_unstow('pkg2');
|
||||||
|
$stow->process_tasks();
|
||||||
|
is($stow->get_conflict_count, 0);
|
||||||
|
ok(-f '../stow/pkg2/lib2/file2');
|
||||||
|
ok(-d 'lib2'
|
||||||
|
=> 'unstow simple tree from a pre-existing directory'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
make_path('lib2');
|
subtest("fold tree after unstowing", sub {
|
||||||
make_path('../stow/pkg2/lib2');
|
plan tests => 3;
|
||||||
make_file('../stow/pkg2/lib2/file2');
|
my $stow = new_Stow();
|
||||||
make_link('lib2/file2', '../../stow/pkg2/lib2/file2');
|
|
||||||
$stow->plan_unstow('pkg2');
|
|
||||||
$stow->process_tasks();
|
|
||||||
ok(
|
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
-f '../stow/pkg2/lib2/file2' && -d 'lib2'
|
|
||||||
=> 'unstow simple tree from a pre-existing directory'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
make_path('bin3');
|
||||||
# fold tree after unstowing
|
|
||||||
#
|
|
||||||
$stow = new_Stow();
|
|
||||||
|
|
||||||
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/pkg3a/bin3');
|
make_path('../stow/pkg3b/bin3');
|
||||||
make_file('../stow/pkg3a/bin3/file3a');
|
make_file('../stow/pkg3b/bin3/file3b');
|
||||||
make_link('bin3/file3a' => '../../stow/pkg3a/bin3/file3a'); # emulate stow
|
make_link('bin3/file3b' => '../../stow/pkg3b/bin3/file3b'); # emulate stow
|
||||||
|
$stow->plan_unstow('pkg3b');
|
||||||
|
$stow->process_tasks();
|
||||||
|
is($stow->get_conflict_count, 0);
|
||||||
|
ok(-l 'bin3');
|
||||||
|
is(readlink('bin3'), '../stow/pkg3a/bin3'
|
||||||
|
=> 'fold tree after unstowing'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
make_path('../stow/pkg3b/bin3');
|
subtest("existing link is owned by stow but is invalid so it gets removed anyway", sub {
|
||||||
make_file('../stow/pkg3b/bin3/file3b');
|
plan tests => 2;
|
||||||
make_link('bin3/file3b' => '../../stow/pkg3b/bin3/file3b'); # emulate stow
|
my $stow = new_Stow();
|
||||||
$stow->plan_unstow('pkg3b');
|
|
||||||
$stow->process_tasks();
|
|
||||||
ok(
|
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
-l 'bin3' &&
|
|
||||||
readlink('bin3') eq '../stow/pkg3a/bin3'
|
|
||||||
=> 'fold tree after unstowing'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
make_path('bin4');
|
||||||
# existing link is owned by stow but is invalid so it gets removed anyway
|
make_path('../stow/pkg4/bin4');
|
||||||
#
|
make_file('../stow/pkg4/bin4/file4');
|
||||||
$stow = new_Stow();
|
make_invalid_link('bin4/file4', '../../stow/pkg4/bin4/does-not-exist');
|
||||||
|
|
||||||
make_path('bin4');
|
$stow->plan_unstow('pkg4');
|
||||||
make_path('../stow/pkg4/bin4');
|
$stow->process_tasks();
|
||||||
make_file('../stow/pkg4/bin4/file4');
|
is($stow->get_conflict_count, 0);
|
||||||
make_invalid_link('bin4/file4', '../../stow/pkg4/bin4/does-not-exist');
|
ok(! -e 'bin4/file4'
|
||||||
|
=> q(remove invalid link owned by stow)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
$stow->plan_unstow('pkg4');
|
subtest("Existing link is not owned by stow", sub {
|
||||||
$stow->process_tasks();
|
plan tests => 1;
|
||||||
ok(
|
my $stow = new_Stow();
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
! -e 'bin4/file4'
|
|
||||||
=> q(remove invalid link owned by stow)
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
make_path('../stow/pkg5/bin5');
|
||||||
# Existing link is not owned by stow
|
make_invalid_link('bin5', '../not-stow');
|
||||||
#
|
|
||||||
$stow = new_Stow();
|
|
||||||
|
|
||||||
make_path('../stow/pkg5/bin5');
|
$stow->plan_unstow('pkg5');
|
||||||
make_invalid_link('bin5', '../not-stow');
|
my %conflicts = $stow->get_conflicts;
|
||||||
|
like(
|
||||||
|
$conflicts{unstow}{pkg5}[-1],
|
||||||
|
qr(existing target is not owned by stow)
|
||||||
|
=> q(existing link not owned by stow)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
$stow->plan_unstow('pkg5');
|
subtest("Target already exists, is owned by stow, but points to a different package", sub {
|
||||||
%conflicts = $stow->get_conflicts;
|
plan tests => 3;
|
||||||
like(
|
my $stow = new_Stow();
|
||||||
$conflicts{unstow}{pkg5}[-1],
|
|
||||||
qr(existing target is not owned by stow)
|
|
||||||
=> q(existing link not owned by stow)
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
make_path('bin6');
|
||||||
# Target already exists, is owned by stow, but points to a different package
|
make_path('../stow/pkg6a/bin6');
|
||||||
#
|
make_file('../stow/pkg6a/bin6/file6');
|
||||||
$stow = new_Stow();
|
make_link('bin6/file6', '../../stow/pkg6a/bin6/file6');
|
||||||
|
|
||||||
make_path('bin6');
|
make_path('../stow/pkg6b/bin6');
|
||||||
make_path('../stow/pkg6a/bin6');
|
make_file('../stow/pkg6b/bin6/file6');
|
||||||
make_file('../stow/pkg6a/bin6/file6');
|
|
||||||
make_link('bin6/file6', '../../stow/pkg6a/bin6/file6');
|
|
||||||
|
|
||||||
make_path('../stow/pkg6b/bin6');
|
$stow->plan_unstow('pkg6b');
|
||||||
make_file('../stow/pkg6b/bin6/file6');
|
is($stow->get_conflict_count, 0);
|
||||||
|
ok(-l 'bin6/file6');
|
||||||
|
is(
|
||||||
|
readlink('bin6/file6'),
|
||||||
|
'../../stow/pkg6a/bin6/file6'
|
||||||
|
=> q(ignore existing link that points to a different package)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
$stow->plan_unstow('pkg6b');
|
subtest("Don't unlink anything under the stow directory", sub {
|
||||||
ok(
|
plan tests => 4;
|
||||||
$stow->get_conflict_count == 0 &&
|
make_path('stow'); # make out stow dir a subdir of target
|
||||||
-l 'bin6/file6' &&
|
my $stow = new_Stow(dir => 'stow');
|
||||||
readlink('bin6/file6') eq '../../stow/pkg6a/bin6/file6'
|
|
||||||
=> q(ignore existing link that points to a different package)
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
# emulate stowing into ourself (bizarre corner case or accident)
|
||||||
# Don't unlink anything under the stow directory
|
make_path('stow/pkg7a/stow/pkg7b');
|
||||||
#
|
make_file('stow/pkg7a/stow/pkg7b/file7b');
|
||||||
make_path('stow'); # make out stow dir a subdir of target
|
make_link('stow/pkg7b', '../stow/pkg7a/stow/pkg7b');
|
||||||
$stow = new_Stow(dir => 'stow');
|
|
||||||
|
|
||||||
# emulate stowing into ourself (bizarre corner case or accident)
|
$stow->plan_unstow('pkg7b');
|
||||||
make_path('stow/pkg7a/stow/pkg7b');
|
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg7b');
|
||||||
make_file('stow/pkg7a/stow/pkg7b/file7b');
|
is($stow->get_conflict_count, 0);
|
||||||
make_link('stow/pkg7b', '../stow/pkg7a/stow/pkg7b');
|
ok(-l 'stow/pkg7b');
|
||||||
|
is(
|
||||||
|
readlink('stow/pkg7b'),
|
||||||
|
'../stow/pkg7a/stow/pkg7b'
|
||||||
|
=> q(don't unlink any nodes under the stow directory)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
$stow->plan_unstow('pkg7b');
|
subtest("Don't unlink any nodes under another stow directory", sub {
|
||||||
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg7b');
|
plan tests => 5;
|
||||||
ok(
|
my $stow = new_Stow(dir => 'stow');
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
-l 'stow/pkg7b' &&
|
make_path('stow2'); # make our alternate stow dir a subdir of target
|
||||||
readlink('stow/pkg7b') eq '../stow/pkg7a/stow/pkg7b'
|
make_file('stow2/.stow');
|
||||||
=> q(don't unlink any nodes under the stow directory)
|
|
||||||
);
|
# 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/
|
||||||
|
=> "unstowing from ourself should skip stow"
|
||||||
|
);
|
||||||
|
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg8a');
|
||||||
|
is($stow->get_conflict_count, 0);
|
||||||
|
ok(-l 'stow2/pkg8b');
|
||||||
|
is(
|
||||||
|
readlink('stow2/pkg8b'),
|
||||||
|
'../stow/pkg8a/stow2/pkg8b'
|
||||||
|
=> q(don't unlink any nodes under another stow directory)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
subtest("overriding already stowed documentation", sub {
|
||||||
|
plan tests => 2;
|
||||||
|
my $stow = new_Stow(override => ['man9', 'info9']);
|
||||||
|
make_file('stow/.stow');
|
||||||
|
|
||||||
|
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_unstow('pkg9b');
|
||||||
|
$stow->process_tasks();
|
||||||
|
is($stow->get_conflict_count, 0);
|
||||||
|
ok(!-l '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/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');
|
||||||
# Don't unlink any nodes under another stow directory
|
make_file('../stow/pkg10c/man10/man1/file10a.1');
|
||||||
#
|
$stow->plan_unstow('pkg10c');
|
||||||
$stow = new_Stow(dir => 'stow');
|
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg10c');
|
||||||
|
is($stow->get_conflict_count, 0);
|
||||||
|
is(
|
||||||
|
readlink('man10/man1/file10a.1'),
|
||||||
|
'../../../stow/pkg10a/man10/man1/file10a.1'
|
||||||
|
=> 'defer to existing documentation files'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
make_path('stow2'); # make our alternate stow dir a subdir of target
|
subtest("Ignore temp files", sub {
|
||||||
make_file('stow2/.stow');
|
plan tests => 2;
|
||||||
|
my $stow = new_Stow(ignore => ['~', '\.#.*']);
|
||||||
|
|
||||||
# emulate stowing into ourself (bizarre corner case or accident)
|
make_path('../stow/pkg12/man12/man1');
|
||||||
make_path('stow/pkg8a/stow2/pkg8b');
|
make_file('../stow/pkg12/man12/man1/file12.1');
|
||||||
make_file('stow/pkg8a/stow2/pkg8b/file8b');
|
make_file('../stow/pkg12/man12/man1/file12.1~');
|
||||||
make_link('stow2/pkg8b', '../stow/pkg8a/stow2/pkg8b');
|
make_file('../stow/pkg12/man12/man1/.#file12.1');
|
||||||
|
make_path('man12/man1');
|
||||||
|
make_link('man12/man1/file12.1' => '../../../stow/pkg12/man12/man1/file12.1');
|
||||||
|
|
||||||
capture_stderr();
|
$stow->plan_unstow('pkg12');
|
||||||
$stow->plan_unstow('pkg8a');
|
$stow->process_tasks();
|
||||||
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg8a');
|
is($stow->get_conflict_count, 0);
|
||||||
ok(
|
ok(!-e 'man12/man1/file12.1' => 'ignore temp files');
|
||||||
$stow->get_conflict_count == 0 &&
|
});
|
||||||
-l 'stow2/pkg8b' &&
|
|
||||||
readlink('stow2/pkg8b') eq '../stow/pkg8a/stow2/pkg8b'
|
|
||||||
=> q(don't unlink any nodes under another stow directory)
|
|
||||||
);
|
|
||||||
like($stderr,
|
|
||||||
qr/WARNING: skipping protected directory stow2/
|
|
||||||
=> "unstowing from ourself should skip stow");
|
|
||||||
uncapture_stderr();
|
|
||||||
|
|
||||||
#
|
subtest("Unstow an already unstowed package", sub {
|
||||||
# overriding already stowed documentation
|
plan tests => 2;
|
||||||
#
|
my $stow = new_Stow();
|
||||||
$stow = new_Stow(override => ['man9', 'info9']);
|
$stow->plan_unstow('pkg12');
|
||||||
make_file('stow/.stow');
|
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg12');
|
||||||
|
is(
|
||||||
|
$stow->get_conflict_count, 0
|
||||||
|
=> 'unstow already unstowed package pkg12'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
make_path('../stow/pkg9a/man9/man1');
|
subtest("Unstow a never stowed package", sub {
|
||||||
make_file('../stow/pkg9a/man9/man1/file9.1');
|
plan tests => 2;
|
||||||
make_path('man9/man1');
|
|
||||||
make_link('man9/man1/file9.1' => '../../../stow/pkg9a/man9/man1/file9.1'); # emulate stow
|
|
||||||
|
|
||||||
make_path('../stow/pkg9b/man9/man1');
|
eval { remove_dir("$TEST_DIR/target"); };
|
||||||
make_file('../stow/pkg9b/man9/man1/file9.1');
|
mkdir("$TEST_DIR/target");
|
||||||
$stow->plan_unstow('pkg9b');
|
|
||||||
$stow->process_tasks();
|
|
||||||
ok(
|
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
!-l 'man9/man1/file9.1'
|
|
||||||
=> 'overriding existing documentation files'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
my $stow = new_Stow();
|
||||||
# deferring to already stowed documentation
|
$stow->plan_unstow('pkg12');
|
||||||
#
|
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg12 which was never stowed');
|
||||||
$stow = new_Stow(defer => ['man10', 'info10']);
|
is(
|
||||||
|
$stow->get_conflict_count,
|
||||||
|
0
|
||||||
|
=> 'unstow never stowed package pkg12'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
make_path('../stow/pkg10a/man10/man1');
|
subtest("Unstowing when target contains a real file shouldn't be an issue", sub {
|
||||||
make_file('../stow/pkg10a/man10/man1/file10a.1');
|
plan tests => 3;
|
||||||
make_path('man10/man1');
|
make_file('man12/man1/file12.1');
|
||||||
make_link('man10/man1/file10a.1' => '../../../stow/pkg10a/man10/man1/file10a.1');
|
|
||||||
|
|
||||||
# need this to block folding
|
my $stow = new_Stow();
|
||||||
make_path('../stow/pkg10b/man10/man1');
|
$stow->plan_unstow('pkg12');
|
||||||
make_file('../stow/pkg10b/man10/man1/file10b.1');
|
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg12 for third time');
|
||||||
make_link('man10/man1/file10b.1' => '../../../stow/pkg10b/man10/man1/file10b.1');
|
my %conflicts = $stow->get_conflicts;
|
||||||
|
is($stow->get_conflict_count, 1);
|
||||||
|
like(
|
||||||
|
$conflicts{unstow}{pkg12}[0],
|
||||||
|
qr!existing target is neither a link nor a directory: man12/man1/file12\.1!
|
||||||
|
=> 'unstow pkg12 for third time'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
subtest("unstow a simple tree minimally when cwd isn't target", sub {
|
||||||
|
plan tests => 3;
|
||||||
|
cd('../..');
|
||||||
|
my $stow = new_Stow(dir => "$TEST_DIR/stow", target => "$TEST_DIR/target");
|
||||||
|
|
||||||
make_path('../stow/pkg10c/man10/man1');
|
make_path("$TEST_DIR/stow/pkg13/bin13");
|
||||||
make_file('../stow/pkg10c/man10/man1/file10a.1');
|
make_file("$TEST_DIR/stow/pkg13/bin13/file13");
|
||||||
$stow->plan_unstow('pkg10c');
|
make_link("$TEST_DIR/target/bin13", '../stow/pkg13/bin13');
|
||||||
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg10c');
|
|
||||||
ok(
|
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
readlink('man10/man1/file10a.1') eq '../../../stow/pkg10a/man10/man1/file10a.1'
|
|
||||||
=> 'defer to existing documentation files'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
$stow->plan_unstow('pkg13');
|
||||||
# Ignore temp files
|
$stow->process_tasks();
|
||||||
#
|
is($stow->get_conflict_count, 0);
|
||||||
$stow = new_Stow(ignore => ['~', '\.#.*']);
|
ok(-f "$TEST_DIR/stow/pkg13/bin13/file13");
|
||||||
|
ok(! -e "$TEST_DIR/target/bin13" => 'unstow a simple tree');
|
||||||
|
});
|
||||||
|
|
||||||
make_path('../stow/pkg12/man12/man1');
|
subtest("unstow a simple tree minimally with absolute stow dir when cwd isn't target", sub {
|
||||||
make_file('../stow/pkg12/man12/man1/file12.1');
|
plan tests => 3;
|
||||||
make_file('../stow/pkg12/man12/man1/file12.1~');
|
my $stow = new_Stow(dir => canon_path("$TEST_DIR/stow"),
|
||||||
make_file('../stow/pkg12/man12/man1/.#file12.1');
|
target => "$TEST_DIR/target");
|
||||||
make_path('man12/man1');
|
|
||||||
make_link('man12/man1/file12.1' => '../../../stow/pkg12/man12/man1/file12.1');
|
|
||||||
|
|
||||||
$stow->plan_unstow('pkg12');
|
make_path("$TEST_DIR/stow/pkg14/bin14");
|
||||||
$stow->process_tasks();
|
make_file("$TEST_DIR/stow/pkg14/bin14/file14");
|
||||||
ok(
|
make_link("$TEST_DIR/target/bin14", '../stow/pkg14/bin14');
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
!-e 'man12/man1/file12.1'
|
|
||||||
=> 'ignore temp files'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
$stow->plan_unstow('pkg14');
|
||||||
# Unstow an already unstowed package
|
$stow->process_tasks();
|
||||||
#
|
is($stow->get_conflict_count, 0);
|
||||||
$stow = new_Stow();
|
ok(-f "$TEST_DIR/stow/pkg14/bin14/file14");
|
||||||
$stow->plan_unstow('pkg12');
|
ok(! -e "$TEST_DIR/target/bin14"
|
||||||
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg12');
|
=> 'unstow a simple tree with absolute stow dir'
|
||||||
ok(
|
);
|
||||||
$stow->get_conflict_count == 0
|
});
|
||||||
=> 'unstow already unstowed package pkg12'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
subtest("unstow a simple tree minimally with absolute stow AND target dirs when cwd isn't target", sub {
|
||||||
# Unstow a never stowed package
|
plan tests => 3;
|
||||||
#
|
my $stow = new_Stow(dir => canon_path("$TEST_DIR/stow"),
|
||||||
|
target => canon_path("$TEST_DIR/target"));
|
||||||
|
|
||||||
eval { remove_dir("$TEST_DIR/target"); };
|
make_path("$TEST_DIR/stow/pkg15/bin15");
|
||||||
mkdir("$TEST_DIR/target");
|
make_file("$TEST_DIR/stow/pkg15/bin15/file15");
|
||||||
|
make_link("$TEST_DIR/target/bin15", '../stow/pkg15/bin15');
|
||||||
|
|
||||||
$stow = new_Stow();
|
$stow->plan_unstow('pkg15');
|
||||||
$stow->plan_unstow('pkg12');
|
$stow->process_tasks();
|
||||||
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg12 which was never stowed');
|
is($stow->get_conflict_count, 0);
|
||||||
ok(
|
ok(-f "$TEST_DIR/stow/pkg15/bin15/file15");
|
||||||
$stow->get_conflict_count == 0
|
ok(! -e "$TEST_DIR/target/bin15"
|
||||||
=> 'unstow never stowed package pkg12'
|
=> 'unstow a simple tree with absolute stow and target dirs'
|
||||||
);
|
);
|
||||||
|
});
|
||||||
#
|
|
||||||
# Unstowing when target contains a real file shouldn't be an issue.
|
|
||||||
#
|
|
||||||
make_file('man12/man1/file12.1');
|
|
||||||
|
|
||||||
$stow = new_Stow();
|
|
||||||
$stow->plan_unstow('pkg12');
|
|
||||||
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg12 for third time');
|
|
||||||
%conflicts = $stow->get_conflicts;
|
|
||||||
ok(
|
|
||||||
$stow->get_conflict_count == 1 &&
|
|
||||||
$conflicts{unstow}{pkg12}[0]
|
|
||||||
=~ m!existing target is neither a link nor a directory: man12/man1/file12\.1!
|
|
||||||
=> 'unstow pkg12 for third time'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
|
||||||
# unstow a simple tree minimally when cwd isn't target
|
|
||||||
#
|
|
||||||
cd('../..');
|
|
||||||
$stow = new_Stow(dir => "$TEST_DIR/stow", target => "$TEST_DIR/target");
|
|
||||||
|
|
||||||
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();
|
|
||||||
ok(
|
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
-f "$TEST_DIR/stow/pkg13/bin13/file13" && ! -e "$TEST_DIR/target/bin13"
|
|
||||||
=> 'unstow a simple tree'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
|
||||||
# unstow a simple tree minimally with absolute stow dir when cwd isn't
|
|
||||||
# target
|
|
||||||
#
|
|
||||||
$stow = new_Stow(dir => canon_path("$TEST_DIR/stow"),
|
|
||||||
target => "$TEST_DIR/target");
|
|
||||||
|
|
||||||
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();
|
|
||||||
ok(
|
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
-f "$TEST_DIR/stow/pkg14/bin14/file14" && ! -e "$TEST_DIR/target/bin14"
|
|
||||||
=> 'unstow a simple tree with absolute stow dir'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
|
||||||
# unstow a simple tree minimally with absolute stow AND target dirs
|
|
||||||
# when cwd isn't target
|
|
||||||
#
|
|
||||||
$stow = new_Stow(dir => canon_path("$TEST_DIR/stow"),
|
|
||||||
target => canon_path("$TEST_DIR/target"));
|
|
||||||
|
|
||||||
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();
|
|
||||||
ok(
|
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
-f "$TEST_DIR/stow/pkg15/bin15/file15" && ! -e "$TEST_DIR/target/bin15"
|
|
||||||
=> 'unstow a simple tree with absolute stow and target dirs'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# unstow a tree with no-folding enabled -
|
# unstow a tree with no-folding enabled -
|
||||||
|
@ -428,7 +416,7 @@ foreach my $pkg (qw{a b}) {
|
||||||
create_and_stow_pkg('no-folding', $pkg);
|
create_and_stow_pkg('no-folding', $pkg);
|
||||||
}
|
}
|
||||||
|
|
||||||
$stow = new_Stow('no-folding' => 1);
|
my $stow = new_Stow('no-folding' => 1);
|
||||||
$stow->plan_unstow('no-folding-b');
|
$stow->plan_unstow('no-folding-b');
|
||||||
is_deeply([ $stow->get_conflicts ], [] => 'no conflicts with --no-folding');
|
is_deeply([ $stow->get_conflicts ], [] => 'no conflicts with --no-folding');
|
||||||
use Data::Dumper;
|
use Data::Dumper;
|
||||||
|
|
604
t/unstow_orig.t
604
t/unstow_orig.t
|
@ -23,7 +23,7 @@ use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use File::Spec qw(make_path);
|
use File::Spec qw(make_path);
|
||||||
use Test::More tests => 37;
|
use Test::More tests => 17;
|
||||||
use Test::Output;
|
use Test::Output;
|
||||||
use English qw(-no_match_vars);
|
use English qw(-no_match_vars);
|
||||||
|
|
||||||
|
@ -38,366 +38,356 @@ cd("$TEST_DIR/target");
|
||||||
my $stow;
|
my $stow;
|
||||||
my %conflicts;
|
my %conflicts;
|
||||||
|
|
||||||
#
|
subtest("unstow a simple tree minimally", sub {
|
||||||
# unstow a simple tree minimally
|
plan tests => 3;
|
||||||
#
|
my $stow = new_compat_Stow();
|
||||||
|
|
||||||
$stow = new_compat_Stow();
|
make_path('../stow/pkg1/bin1');
|
||||||
|
make_file('../stow/pkg1/bin1/file1');
|
||||||
|
make_link('bin1', '../stow/pkg1/bin1');
|
||||||
|
|
||||||
make_path('../stow/pkg1/bin1');
|
$stow->plan_unstow('pkg1');
|
||||||
make_file('../stow/pkg1/bin1/file1');
|
$stow->process_tasks();
|
||||||
make_link('bin1', '../stow/pkg1/bin1');
|
is($stow->get_conflict_count, 0);
|
||||||
|
ok(-f '../stow/pkg1/bin1/file1');
|
||||||
|
ok(! -e 'bin1' => 'unstow a simple tree');
|
||||||
|
});
|
||||||
|
|
||||||
$stow->plan_unstow('pkg1');
|
subtest("unstow a simple tree from an existing directory", sub {
|
||||||
$stow->process_tasks();
|
plan tests => 3;
|
||||||
ok(
|
my $stow = new_compat_Stow();
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
-f '../stow/pkg1/bin1/file1' && ! -e 'bin1'
|
|
||||||
=> 'unstow a simple tree'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
make_path('lib2');
|
||||||
# unstow a simple tree from an existing directory
|
make_path('../stow/pkg2/lib2');
|
||||||
#
|
make_file('../stow/pkg2/lib2/file2');
|
||||||
$stow = new_compat_Stow();
|
make_link('lib2/file2', '../../stow/pkg2/lib2/file2');
|
||||||
|
$stow->plan_unstow('pkg2');
|
||||||
|
$stow->process_tasks();
|
||||||
|
is($stow->get_conflict_count, 0);
|
||||||
|
ok(-f '../stow/pkg2/lib2/file2');
|
||||||
|
ok(-d 'lib2'
|
||||||
|
=> 'unstow simple tree from a pre-existing directory'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
make_path('lib2');
|
subtest("fold tree after unstowing", sub {
|
||||||
make_path('../stow/pkg2/lib2');
|
plan tests => 3;
|
||||||
make_file('../stow/pkg2/lib2/file2');
|
my $stow = new_compat_Stow();
|
||||||
make_link('lib2/file2', '../../stow/pkg2/lib2/file2');
|
|
||||||
$stow->plan_unstow('pkg2');
|
|
||||||
$stow->process_tasks();
|
|
||||||
ok(
|
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
-f '../stow/pkg2/lib2/file2' && -d 'lib2'
|
|
||||||
=> 'unstow simple tree from a pre-existing directory'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
make_path('bin3');
|
||||||
# fold tree after unstowing
|
|
||||||
#
|
|
||||||
$stow = new_compat_Stow();
|
|
||||||
|
|
||||||
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/pkg3a/bin3');
|
make_path('../stow/pkg3b/bin3');
|
||||||
make_file('../stow/pkg3a/bin3/file3a');
|
make_file('../stow/pkg3b/bin3/file3b');
|
||||||
make_link('bin3/file3a' => '../../stow/pkg3a/bin3/file3a'); # emulate stow
|
make_link('bin3/file3b' => '../../stow/pkg3b/bin3/file3b'); # emulate stow
|
||||||
|
$stow->plan_unstow('pkg3b');
|
||||||
|
$stow->process_tasks();
|
||||||
|
is($stow->get_conflict_count, 0);
|
||||||
|
ok(-l 'bin3');
|
||||||
|
is(readlink('bin3'), '../stow/pkg3a/bin3'
|
||||||
|
=> 'fold tree after unstowing'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
make_path('../stow/pkg3b/bin3');
|
subtest("existing link is owned by stow but is invalid so it gets removed anyway", sub {
|
||||||
make_file('../stow/pkg3b/bin3/file3b');
|
plan tests => 2;
|
||||||
make_link('bin3/file3b' => '../../stow/pkg3b/bin3/file3b'); # emulate stow
|
my $stow = new_compat_Stow();
|
||||||
$stow->plan_unstow('pkg3b');
|
|
||||||
$stow->process_tasks();
|
|
||||||
ok(
|
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
-l 'bin3' &&
|
|
||||||
readlink('bin3') eq '../stow/pkg3a/bin3'
|
|
||||||
=> 'fold tree after unstowing'
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
make_path('bin4');
|
||||||
# existing link is owned by stow but is invalid so it gets removed anyway
|
make_path('../stow/pkg4/bin4');
|
||||||
#
|
make_file('../stow/pkg4/bin4/file4');
|
||||||
$stow = new_compat_Stow();
|
make_invalid_link('bin4/file4', '../../stow/pkg4/bin4/does-not-exist');
|
||||||
|
|
||||||
make_path('bin4');
|
$stow->plan_unstow('pkg4');
|
||||||
make_path('../stow/pkg4/bin4');
|
$stow->process_tasks();
|
||||||
make_file('../stow/pkg4/bin4/file4');
|
is($stow->get_conflict_count, 0);
|
||||||
make_invalid_link('bin4/file4', '../../stow/pkg4/bin4/does-not-exist');
|
ok(! -e 'bin4/file4'
|
||||||
|
=> q(remove invalid link owned by stow)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
$stow->plan_unstow('pkg4');
|
subtest("Existing link is not owned by stow", sub {
|
||||||
$stow->process_tasks();
|
plan tests => 2;
|
||||||
ok(
|
my $stow = new_compat_Stow();
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
! -e 'bin4/file4'
|
|
||||||
=> q(remove invalid link owned by stow)
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
make_path('../stow/pkg5/bin5');
|
||||||
# Existing link is not owned by stow
|
make_invalid_link('bin5', '../not-stow');
|
||||||
#
|
|
||||||
$stow = new_compat_Stow();
|
|
||||||
|
|
||||||
make_path('../stow/pkg5/bin5');
|
$stow->plan_unstow('pkg5');
|
||||||
make_invalid_link('bin5', '../not-stow');
|
# Unlike the corresponding stow_contents.t test, this doesn't
|
||||||
|
# cause any conflicts.
|
||||||
|
#
|
||||||
|
#like(
|
||||||
|
# $Conflicts[-1], qr(can't unlink.*not owned by stow)
|
||||||
|
# => q(existing link not owned by stow)
|
||||||
|
#);
|
||||||
|
ok(-l 'bin5');
|
||||||
|
is(
|
||||||
|
readlink('bin5'),
|
||||||
|
'../not-stow'
|
||||||
|
=> q(existing link not owned by stow)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
$stow->plan_unstow('pkg5');
|
subtest("Target already exists, is owned by stow, but points to a different package", sub {
|
||||||
# Unlike the corresponding stow_contents.t test, this doesn't
|
plan tests => 3;
|
||||||
# cause any conflicts.
|
my $stow = new_compat_Stow();
|
||||||
#
|
|
||||||
#like(
|
|
||||||
# $Conflicts[-1], qr(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)
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
make_path('bin6');
|
||||||
# Target already exists, is owned by stow, but points to a different package
|
make_path('../stow/pkg6a/bin6');
|
||||||
#
|
make_file('../stow/pkg6a/bin6/file6');
|
||||||
$stow = new_compat_Stow();
|
make_link('bin6/file6', '../../stow/pkg6a/bin6/file6');
|
||||||
|
|
||||||
make_path('bin6');
|
make_path('../stow/pkg6b/bin6');
|
||||||
make_path('../stow/pkg6a/bin6');
|
make_file('../stow/pkg6b/bin6/file6');
|
||||||
make_file('../stow/pkg6a/bin6/file6');
|
|
||||||
make_link('bin6/file6', '../../stow/pkg6a/bin6/file6');
|
|
||||||
|
|
||||||
make_path('../stow/pkg6b/bin6');
|
$stow->plan_unstow('pkg6b');
|
||||||
make_file('../stow/pkg6b/bin6/file6');
|
is($stow->get_conflict_count, 0);
|
||||||
|
ok(-l 'bin6/file6');
|
||||||
|
is(
|
||||||
|
readlink('bin6/file6'),
|
||||||
|
'../../stow/pkg6a/bin6/file6'
|
||||||
|
=> q(ignore existing link that points to a different package)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
$stow->plan_unstow('pkg6b');
|
subtest("Don't unlink anything under the stow directory", sub {
|
||||||
ok(
|
plan tests => 5;
|
||||||
$stow->get_conflict_count == 0 &&
|
make_path('stow'); # make stow dir a subdir of target
|
||||||
-l 'bin6/file6' &&
|
my $stow = new_compat_Stow(dir => 'stow');
|
||||||
readlink('bin6/file6') eq '../../stow/pkg6a/bin6/file6'
|
|
||||||
=> q(ignore existing link that points to a different package)
|
|
||||||
);
|
|
||||||
|
|
||||||
#
|
# emulate stowing into ourself (bizarre corner case or accident)
|
||||||
# Don't unlink anything under the stow directory
|
make_path('stow/pkg7a/stow/pkg7b');
|
||||||
#
|
make_file('stow/pkg7a/stow/pkg7b/file7b');
|
||||||
make_path('stow'); # make out stow dir a subdir of target
|
make_link('stow/pkg7b', '../stow/pkg7a/stow/pkg7b');
|
||||||
$stow = new_compat_Stow(dir => 'stow');
|
|
||||||
|
|
||||||
# emulate stowing into ourself (bizarre corner case or accident)
|
stderr_like(
|
||||||
make_path('stow/pkg7a/stow/pkg7b');
|
sub { $stow->plan_unstow('pkg7b'); },
|
||||||
make_file('stow/pkg7a/stow/pkg7b/file7b');
|
qr/WARNING: skipping target which was current stow directory stow/
|
||||||
make_link('stow/pkg7b', '../stow/pkg7a/stow/pkg7b');
|
=> "warn when unstowing from ourself"
|
||||||
|
);
|
||||||
|
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg7b');
|
||||||
|
is($stow->get_conflict_count, 0);
|
||||||
|
ok(-l 'stow/pkg7b');
|
||||||
|
is(
|
||||||
|
readlink('stow/pkg7b'),
|
||||||
|
'../stow/pkg7a/stow/pkg7b'
|
||||||
|
=> q(don't unlink any nodes under the stow directory)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
capture_stderr();
|
subtest("Don't unlink any nodes under another stow directory", sub {
|
||||||
$stow->plan_unstow('pkg7b');
|
plan tests => 5;
|
||||||
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg7b');
|
my $stow = new_compat_Stow(dir => 'stow');
|
||||||
ok(
|
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
-l 'stow/pkg7b' &&
|
|
||||||
readlink('stow/pkg7b') eq '../stow/pkg7a/stow/pkg7b'
|
|
||||||
=> q(don't unlink any nodes under the stow directory)
|
|
||||||
);
|
|
||||||
like($stderr,
|
|
||||||
qr/WARNING: skipping target which was current stow directory stow/
|
|
||||||
=> "warn when unstowing from ourself");
|
|
||||||
uncapture_stderr();
|
|
||||||
|
|
||||||
#
|
make_path('stow2'); # make our alternate stow dir a subdir of target
|
||||||
# Don't unlink any nodes under another stow directory
|
make_file('stow2/.stow');
|
||||||
#
|
|
||||||
$stow = new_compat_Stow(dir => 'stow');
|
|
||||||
|
|
||||||
make_path('stow2'); # make our alternate stow dir a subdir of target
|
# emulate stowing into ourself (bizarre corner case or accident)
|
||||||
make_file('stow2/.stow');
|
make_path('stow/pkg8a/stow2/pkg8b');
|
||||||
|
make_file('stow/pkg8a/stow2/pkg8b/file8b');
|
||||||
|
make_link('stow2/pkg8b', '../stow/pkg8a/stow2/pkg8b');
|
||||||
|
|
||||||
# emulate stowing into ourself (bizarre corner case or accident)
|
stderr_like(
|
||||||
make_path('stow/pkg8a/stow2/pkg8b');
|
sub { $stow->plan_unstow('pkg8a'); },
|
||||||
make_file('stow/pkg8a/stow2/pkg8b/file8b');
|
qr/WARNING: skipping target which was current stow directory stow/
|
||||||
make_link('stow2/pkg8b', '../stow/pkg8a/stow2/pkg8b');
|
=> "warn when skipping unstowing"
|
||||||
|
);
|
||||||
|
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg8a');
|
||||||
|
is($stow->get_conflict_count, 0);
|
||||||
|
ok(-l 'stow2/pkg8b');
|
||||||
|
is(
|
||||||
|
readlink('stow2/pkg8b'),
|
||||||
|
'../stow/pkg8a/stow2/pkg8b'
|
||||||
|
=> q(don't unlink any nodes under another stow directory)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
capture_stderr();
|
# This will be used by subsequent tests
|
||||||
$stow->plan_unstow('pkg8a');
|
|
||||||
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg8a');
|
|
||||||
ok(
|
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
-l 'stow2/pkg8b' &&
|
|
||||||
readlink('stow2/pkg8b') eq '../stow/pkg8a/stow2/pkg8b'
|
|
||||||
=> q(don't unlink any nodes under another stow directory)
|
|
||||||
);
|
|
||||||
like($stderr,
|
|
||||||
qr/WARNING: skipping target which was current stow directory stow/
|
|
||||||
=> "warn when skipping unstowing");
|
|
||||||
uncapture_stderr();
|
|
||||||
|
|
||||||
#
|
|
||||||
# overriding already stowed documentation
|
|
||||||
#
|
|
||||||
|
|
||||||
# This will be used by this and subsequent tests
|
|
||||||
sub check_protected_dirs_skipped {
|
sub check_protected_dirs_skipped {
|
||||||
|
my $coderef = shift;
|
||||||
|
my $stderr = stderr_from { $coderef->(); };
|
||||||
for my $dir (qw{stow stow2}) {
|
for my $dir (qw{stow stow2}) {
|
||||||
like($stderr,
|
like($stderr,
|
||||||
qr/WARNING: skipping protected directory $dir/
|
qr/WARNING: skipping marked Stow directory $dir/
|
||||||
=> "warn when skipping protected directory $dir");
|
=> "warn when skipping marked directory $dir");
|
||||||
}
|
}
|
||||||
uncapture_stderr();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$stow = new_compat_Stow(override => ['man9', 'info9']);
|
subtest("overriding already stowed documentation", sub {
|
||||||
make_file('stow/.stow');
|
plan tests => 4;
|
||||||
|
|
||||||
make_path('../stow/pkg9a/man9/man1');
|
my $stow = new_compat_Stow(override => ['man9', 'info9']);
|
||||||
make_file('../stow/pkg9a/man9/man1/file9.1');
|
make_file('stow/.stow');
|
||||||
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_path('../stow/pkg9a/man9/man1');
|
||||||
make_file('../stow/pkg9b/man9/man1/file9.1');
|
make_file('../stow/pkg9a/man9/man1/file9.1');
|
||||||
capture_stderr();
|
make_path('man9/man1');
|
||||||
$stow->plan_unstow('pkg9b');
|
make_link('man9/man1/file9.1' => '../../../stow/pkg9a/man9/man1/file9.1'); # emulate stow
|
||||||
$stow->process_tasks();
|
|
||||||
ok(
|
|
||||||
$stow->get_conflict_count == 0 &&
|
|
||||||
!-l 'man9/man1/file9.1'
|
|
||||||
=> 'overriding existing documentation files'
|
|
||||||
);
|
|
||||||
check_protected_dirs_skipped();
|
|
||||||
|
|
||||||
#
|
make_path('../stow/pkg9b/man9/man1');
|
||||||
# deferring to already stowed documentation
|
make_file('../stow/pkg9b/man9/man1/file9.1');
|
||||||
#
|
check_protected_dirs_skipped(
|
||||||
$stow = new_compat_Stow(defer => ['man10', 'info10']);
|
sub { $stow->plan_unstow('pkg9b'); }
|
||||||
|
);
|
||||||
|
$stow->process_tasks();
|
||||||
|
is($stow->get_conflict_count, 0);
|
||||||
|
ok(!-l 'man9/man1/file9.1'
|
||||||
|
=> 'overriding existing documentation files'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
make_path('../stow/pkg10a/man10/man1');
|
subtest("deferring to already stowed documentation", sub {
|
||||||
make_file('../stow/pkg10a/man10/man1/file10a.1');
|
plan tests => 5;
|
||||||
make_path('man10/man1');
|
my $stow = new_compat_Stow(defer => ['man10', 'info10']);
|
||||||
make_link('man10/man1/file10a.1' => '../../../stow/pkg10a/man10/man1/file10a.1');
|
|
||||||
|
|
||||||
# need this to block folding
|
make_path('../stow/pkg10a/man10/man1');
|
||||||
make_path('../stow/pkg10b/man10/man1');
|
make_file('../stow/pkg10a/man10/man1/file10a.1');
|
||||||
make_file('../stow/pkg10b/man10/man1/file10b.1');
|
make_path('man10/man1');
|
||||||
make_link('man10/man1/file10b.1' => '../../../stow/pkg10b/man10/man1/file10b.1');
|
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_path('../stow/pkg10c/man10/man1');
|
||||||
make_file('../stow/pkg10c/man10/man1/file10a.1');
|
make_file('../stow/pkg10c/man10/man1/file10a.1');
|
||||||
capture_stderr();
|
check_protected_dirs_skipped(
|
||||||
$stow->plan_unstow('pkg10c');
|
sub { $stow->plan_unstow('pkg10c'); }
|
||||||
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg10c');
|
);
|
||||||
ok(
|
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg10c');
|
||||||
$stow->get_conflict_count == 0 &&
|
is($stow->get_conflict_count, 0);
|
||||||
readlink('man10/man1/file10a.1') eq '../../../stow/pkg10a/man10/man1/file10a.1'
|
is(
|
||||||
=> 'defer to existing documentation files'
|
readlink('man10/man1/file10a.1'),
|
||||||
);
|
'../../../stow/pkg10a/man10/man1/file10a.1'
|
||||||
check_protected_dirs_skipped();
|
=> 'defer to existing documentation files'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
#
|
subtest("Ignore temp files", sub {
|
||||||
# Ignore temp files
|
plan tests => 4;
|
||||||
#
|
my $stow = new_compat_Stow(ignore => ['~', '\.#.*']);
|
||||||
$stow = new_compat_Stow(ignore => ['~', '\.#.*']);
|
|
||||||
|
|
||||||
make_path('../stow/pkg12/man12/man1');
|
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_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_path('man12/man1');
|
||||||
make_link('man12/man1/file12.1' => '../../../stow/pkg12/man12/man1/file12.1');
|
make_link('man12/man1/file12.1' => '../../../stow/pkg12/man12/man1/file12.1');
|
||||||
|
|
||||||
capture_stderr();
|
check_protected_dirs_skipped(
|
||||||
$stow->plan_unstow('pkg12');
|
sub { $stow->plan_unstow('pkg12'); }
|
||||||
$stow->process_tasks();
|
);
|
||||||
ok(
|
$stow->process_tasks();
|
||||||
$stow->get_conflict_count == 0 &&
|
is($stow->get_conflict_count, 0);
|
||||||
!-e 'man12/man1/file12.1'
|
ok(!-e 'man12/man1/file12.1' => 'ignore temp files');
|
||||||
=> 'ignore temp files'
|
});
|
||||||
);
|
|
||||||
check_protected_dirs_skipped();
|
|
||||||
|
|
||||||
#
|
subtest("Unstow an already unstowed package", sub {
|
||||||
# Unstow an already unstowed package
|
plan tests => 4;
|
||||||
#
|
my $stow = new_compat_Stow();
|
||||||
$stow = new_compat_Stow();
|
check_protected_dirs_skipped(
|
||||||
capture_stderr();
|
sub { $stow->plan_unstow('pkg12'); }
|
||||||
$stow->plan_unstow('pkg12');
|
);
|
||||||
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg12');
|
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg12');
|
||||||
ok(
|
is(
|
||||||
$stow->get_conflict_count == 0
|
$stow->get_conflict_count,
|
||||||
=> 'unstow already unstowed package pkg12'
|
0
|
||||||
);
|
=> 'unstow already unstowed package pkg12'
|
||||||
check_protected_dirs_skipped();
|
);
|
||||||
|
});
|
||||||
|
|
||||||
#
|
subtest("Unstow a never stowed package", sub {
|
||||||
# Unstow a never stowed package
|
plan tests => 4;
|
||||||
#
|
|
||||||
|
|
||||||
eval { remove_dir("$TEST_DIR/target"); };
|
eval { remove_dir("$TEST_DIR/target"); };
|
||||||
mkdir("$TEST_DIR/target");
|
mkdir("$TEST_DIR/target");
|
||||||
|
|
||||||
$stow = new_compat_Stow();
|
my $stow = new_compat_Stow();
|
||||||
capture_stderr();
|
check_protected_dirs_skipped(
|
||||||
$stow->plan_unstow('pkg12');
|
sub { $stow->plan_unstow('pkg12'); }
|
||||||
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg12 which was never stowed');
|
);
|
||||||
ok(
|
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg12 which was never stowed');
|
||||||
$stow->get_conflict_count == 0
|
is(
|
||||||
=> 'unstow never stowed package pkg12'
|
$stow->get_conflict_count,
|
||||||
);
|
0
|
||||||
check_protected_dirs_skipped();
|
=> 'unstow never stowed package pkg12'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
#
|
subtest("Unstowing when target contains a real file shouldn't be an issue", sub {
|
||||||
# Unstowing when target contains a real file shouldn't be an issue.
|
plan tests => 5;
|
||||||
#
|
make_file('man12/man1/file12.1');
|
||||||
make_file('man12/man1/file12.1');
|
|
||||||
|
|
||||||
$stow = new_compat_Stow();
|
my $stow = new_compat_Stow();
|
||||||
capture_stderr();
|
check_protected_dirs_skipped(
|
||||||
$stow->plan_unstow('pkg12');
|
sub { $stow->plan_unstow('pkg12'); }
|
||||||
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg12 for third time');
|
);
|
||||||
%conflicts = $stow->get_conflicts;
|
is($stow->get_tasks, 0, 'no tasks to process when unstowing pkg12 for third time');
|
||||||
ok(
|
%conflicts = $stow->get_conflicts;
|
||||||
$stow->get_conflict_count == 1 &&
|
is($stow->get_conflict_count, 1);
|
||||||
$conflicts{unstow}{pkg12}[0]
|
like(
|
||||||
=~ m!existing target is neither a link nor a directory: man12/man1/file12\.1!
|
$conflicts{unstow}{pkg12}[0],
|
||||||
=> 'unstow pkg12 for third time'
|
qr!existing target is neither a link nor a directory: man12/man1/file12\.1!
|
||||||
);
|
=> 'unstow pkg12 for third time'
|
||||||
check_protected_dirs_skipped();
|
);
|
||||||
|
});
|
||||||
|
|
||||||
#
|
subtest("unstow a simple tree minimally when cwd isn't target", sub {
|
||||||
# unstow a simple tree minimally when cwd isn't target
|
plan tests => 3;
|
||||||
#
|
cd('../..');
|
||||||
cd('../..');
|
my $stow = new_Stow(dir => "$TEST_DIR/stow", target => "$TEST_DIR/target");
|
||||||
$stow = new_Stow(dir => "$TEST_DIR/stow", target => "$TEST_DIR/target");
|
|
||||||
|
|
||||||
make_path("$TEST_DIR/stow/pkg13/bin13");
|
make_path("$TEST_DIR/stow/pkg13/bin13");
|
||||||
make_file("$TEST_DIR/stow/pkg13/bin13/file13");
|
make_file("$TEST_DIR/stow/pkg13/bin13/file13");
|
||||||
make_link("$TEST_DIR/target/bin13", '../stow/pkg13/bin13');
|
make_link("$TEST_DIR/target/bin13", '../stow/pkg13/bin13');
|
||||||
|
|
||||||
$stow->plan_unstow('pkg13');
|
$stow->plan_unstow('pkg13');
|
||||||
$stow->process_tasks();
|
$stow->process_tasks();
|
||||||
ok(
|
is($stow->get_conflict_count, 0);
|
||||||
$stow->get_conflict_count == 0 &&
|
ok(-f "$TEST_DIR/stow/pkg13/bin13/file13");
|
||||||
-f "$TEST_DIR/stow/pkg13/bin13/file13" && ! -e "$TEST_DIR/target/bin13"
|
ok(! -e "$TEST_DIR/target/bin13" => 'unstow a simple tree');
|
||||||
=> 'unstow a simple tree'
|
});
|
||||||
);
|
|
||||||
|
|
||||||
#
|
subtest("unstow a simple tree minimally with absolute stow dir when cwd isn't target", sub {
|
||||||
# unstow a simple tree minimally with absolute stow dir when cwd isn't
|
plan tests => 3;
|
||||||
# target
|
my $stow = new_Stow(dir => canon_path("$TEST_DIR/stow"),
|
||||||
#
|
target => "$TEST_DIR/target");
|
||||||
$stow = new_Stow(dir => canon_path("$TEST_DIR/stow"),
|
|
||||||
target => "$TEST_DIR/target");
|
|
||||||
|
|
||||||
make_path("$TEST_DIR/stow/pkg14/bin14");
|
make_path("$TEST_DIR/stow/pkg14/bin14");
|
||||||
make_file("$TEST_DIR/stow/pkg14/bin14/file14");
|
make_file("$TEST_DIR/stow/pkg14/bin14/file14");
|
||||||
make_link("$TEST_DIR/target/bin14", '../stow/pkg14/bin14');
|
make_link("$TEST_DIR/target/bin14", '../stow/pkg14/bin14');
|
||||||
|
|
||||||
$stow->plan_unstow('pkg14');
|
$stow->plan_unstow('pkg14');
|
||||||
$stow->process_tasks();
|
$stow->process_tasks();
|
||||||
ok(
|
is($stow->get_conflict_count, 0);
|
||||||
$stow->get_conflict_count == 0 &&
|
ok(-f "$TEST_DIR/stow/pkg14/bin14/file14");
|
||||||
-f "$TEST_DIR/stow/pkg14/bin14/file14" && ! -e "$TEST_DIR/target/bin14"
|
ok(! -e "$TEST_DIR/target/bin14"
|
||||||
=> 'unstow a simple tree with absolute stow dir'
|
=> 'unstow a simple tree with absolute stow dir'
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
|
||||||
#
|
subtest("unstow a simple tree minimally with absolute stow AND target dirs when cwd isn't target", sub {
|
||||||
# unstow a simple tree minimally with absolute stow AND target dirs
|
plan tests => 3;
|
||||||
# when cwd isn't target
|
my $stow = new_Stow(dir => canon_path("$TEST_DIR/stow"),
|
||||||
#
|
target => canon_path("$TEST_DIR/target"));
|
||||||
$stow = new_Stow(dir => canon_path("$TEST_DIR/stow"),
|
make_path("$TEST_DIR/stow/pkg15/bin15");
|
||||||
target => canon_path("$TEST_DIR/target"));
|
make_file("$TEST_DIR/stow/pkg15/bin15/file15");
|
||||||
|
make_link("$TEST_DIR/target/bin15", '../stow/pkg15/bin15');
|
||||||
|
|
||||||
make_path("$TEST_DIR/stow/pkg15/bin15");
|
$stow->plan_unstow('pkg15');
|
||||||
make_file("$TEST_DIR/stow/pkg15/bin15/file15");
|
$stow->process_tasks();
|
||||||
make_link("$TEST_DIR/target/bin15", '../stow/pkg15/bin15');
|
is($stow->get_conflict_count, 0);
|
||||||
|
ok(-f "$TEST_DIR/stow/pkg15/bin15/file15");
|
||||||
$stow->plan_unstow('pkg15');
|
ok(! -e "$TEST_DIR/target/bin15"
|
||||||
$stow->process_tasks();
|
=> 'unstow a simple tree with absolute stow and target dirs'
|
||||||
ok(
|
);
|
||||||
$stow->get_conflict_count == 0 &&
|
});
|
||||||
-f "$TEST_DIR/stow/pkg15/bin15/file15" && ! -e "$TEST_DIR/target/bin15"
|
|
||||||
=> 'unstow a simple tree with absolute stow and target dirs'
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
# Todo
|
|
||||||
#
|
|
||||||
# Test cleaning up subdirs with --paranoid option
|
|
||||||
|
|
||||||
|
# subtest("Test cleaning up subdirs with --paranoid option", sub {
|
||||||
|
# TODO
|
||||||
|
# });
|
||||||
|
|
Loading…
Reference in a new issue