File Coverage

blib/lib/Stow.pm
Criterion Covered Total %
statement 653 738 88.4
branch 272 368 73.9
condition 28 38 73.6
subroutine 59 61 96.7
pod 40 51 78.4
total 1052 1256 83.7


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2             #
3             # This file is part of GNU Stow.
4             #
5             # GNU Stow is free software: you can redistribute it and/or modify it
6             # under the terms of the GNU General Public License as published by
7             # the Free Software Foundation, either version 3 of the License, or
8             # (at your option) any later version.
9             #
10             # GNU Stow is distributed in the hope that it will be useful, but
11             # WITHOUT ANY WARRANTY; without even the implied warranty of
12             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13             # General Public License for more details.
14             #
15             # You should have received a copy of the GNU General Public License
16             # along with this program. If not, see https://www.gnu.org/licenses/.
17              
18             package Stow;
19              
20             =head1 NAME
21              
22             Stow - manage farms of symbolic links
23              
24             =head1 SYNOPSIS
25              
26             my $stow = new Stow(%$options);
27              
28             $stow->plan_unstow(@pkgs_to_unstow);
29             $stow->plan_stow (@pkgs_to_stow);
30              
31             my %conflicts = $stow->get_conflicts;
32             $stow->process_tasks() unless %conflicts;
33              
34             =head1 DESCRIPTION
35              
36             This is the backend Perl module for GNU Stow, a program for managing
37             the installation of software packages, keeping them separate
38             (C vs. C, for example)
39             while making them appear to be installed in the same place
40             (C).
41              
42             Stow doesn't store an extra state between runs, so there's no danger
43             of mangling directories when file hierarchies don't match the
44             database. Also, stow will never delete any files, directories, or
45             links that appear in a stow directory, so it is always possible to
46             rebuild the target tree.
47              
48             =cut
49              
50 16     16   1525535 use strict;
  16         31  
  16         701  
51 16     16   77 use warnings;
  16         30  
  16         1071  
52              
53 16     16   99 use Carp qw(carp cluck croak confess longmess);
  16         25  
  16         1316  
54 16     16   8989 use File::Copy qw(move);
  16         91812  
  16         1173  
55 16     16   112 use File::Spec;
  16         28  
  16         428  
56 16     16   5839 use POSIX qw(getcwd);
  16         105963  
  16         132  
57              
58 16         193408 use Stow::Util qw(set_debug_level debug error set_test_mode
59             join_paths restore_cwd canon_path parent
60 16     16   26426 adjust_dotfile unadjust_dotfile);
  16         45  
61              
62             our $ProgramName = 'stow';
63             our $VERSION = '2.4.1';
64              
65             our $LOCAL_IGNORE_FILE = '.stow-local-ignore';
66             our $GLOBAL_IGNORE_FILE = '.stow-global-ignore';
67              
68             our @default_global_ignore_regexps =
69             __PACKAGE__->get_default_global_ignore_regexps();
70              
71             # These are the default options for each Stow instance.
72             our %DEFAULT_OPTIONS = (
73             conflicts => 0,
74             simulate => 0,
75             verbose => 0,
76             paranoid => 0,
77             compat => 0,
78             test_mode => 0,
79             dotfiles => 0,
80             adopt => 0,
81             'no-folding' => 0,
82             ignore => [],
83             override => [],
84             defer => [],
85             );
86              
87             =head1 CONSTRUCTORS
88              
89             =head2 new(%options)
90              
91             =head3 Required options
92              
93             =over 4
94              
95             =item * dir - the stow directory
96              
97             =item * target - the target directory
98              
99             =back
100              
101             =head3 Non-mandatory options
102              
103             See the documentation for the F CLI front-end for information on these.
104              
105             =over 4
106              
107             =item * conflicts
108              
109             =item * simulate
110              
111             =item * verbose
112              
113             =item * paranoid
114              
115             =item * compat
116              
117             =item * test_mode
118              
119             =item * adopt
120              
121             =item * no-folding
122              
123             =item * ignore
124              
125             =item * override
126              
127             =item * defer
128              
129             =back
130              
131             N.B. This sets the current working directory to the target directory.
132              
133             =cut
134              
135             sub new {
136 90     90 1 2608925 my $self = shift;
137 90   33     594 my $class = ref($self) || $self;
138 90         449 my %opts = @_;
139              
140 90         305 my $new = bless { }, $class;
141              
142 90         353 $new->{action_count} = 0;
143              
144 90         275 for my $required_arg (qw(dir target)) {
145             croak "$class->new() called without '$required_arg' parameter\n"
146 180 50       548 unless exists $opts{$required_arg};
147 180         449 $new->{$required_arg} = delete $opts{$required_arg};
148             }
149              
150 90         630 for my $opt (keys %DEFAULT_OPTIONS) {
151             $new->{$opt} = exists $opts{$opt} ? delete $opts{$opt}
152 1080 100       2350 : $DEFAULT_OPTIONS{$opt};
153             }
154              
155 90 50       332 if (%opts) {
156 0         0 croak "$class->new() called with unrecognised parameter(s): ",
157             join(", ", keys %opts), "\n";
158             }
159              
160 90         336 set_debug_level($new->get_verbosity());
161 90         367 set_test_mode($new->{test_mode});
162 90         329 $new->set_stow_dir();
163 90         380 $new->init_state();
164              
165 90         370 return $new;
166             }
167              
168             sub get_verbosity {
169 90     90 0 150 my $self = shift;
170              
171 90 50       299 return $self->{verbose} unless $self->{test_mode};
172              
173 90 50       777 return 0 unless exists $ENV{TEST_VERBOSE};
174 0 0       0 return 0 unless length $ENV{TEST_VERBOSE};
175              
176             # Convert TEST_VERBOSE=y into numeric value
177 0 0       0 $ENV{TEST_VERBOSE} = 3 if $ENV{TEST_VERBOSE} !~ /^\d+$/;
178              
179 0         0 return $ENV{TEST_VERBOSE};
180             }
181              
182             =head2 set_stow_dir([$dir])
183              
184             Sets a new stow directory. This allows the use of multiple stow
185             directories within one Stow instance, e.g.
186              
187             $stow->plan_stow('foo');
188             $stow->set_stow_dir('/different/stow/dir');
189             $stow->plan_stow('bar');
190             $stow->process_tasks;
191              
192             If C<$dir> is omitted, uses the value of the C parameter passed
193             to the L constructor.
194              
195             =cut
196              
197             sub set_stow_dir {
198 92     92 1 5030 my $self = shift;
199 92         256 my ($dir) = @_;
200 92 100       299 if (defined $dir) {
201 2         9 $self->{dir} = $dir;
202             }
203              
204 92         329 my $stow_dir = canon_path($self->{dir});
205 92         259 my $target = canon_path($self->{target});
206              
207             # Calculate relative path from target directory to stow directory.
208             # This will be commonly used as a prefix for constructing and
209             # recognising symlinks "installed" in the target directory which
210             # point to package files under the stow directory.
211 92         9872 $self->{stow_path} = File::Spec->abs2rel($stow_dir, $target);
212              
213 92         522 debug(2, 0, "stow dir is $stow_dir");
214 92         410 debug(2, 0, "stow dir path relative to target $target is $self->{stow_path}");
215             }
216              
217             sub init_state {
218 90     90 0 152 my $self = shift;
219              
220             # Store conflicts during pre-processing
221 90         193 $self->{conflicts} = {};
222 90         196 $self->{conflict_count} = 0;
223              
224             # Store command line packages to stow (-S and -R)
225 90         187 $self->{pkgs_to_stow} = [];
226              
227             # Store command line packages to unstow (-D and -R)
228 90         209 $self->{pkgs_to_delete} = [];
229              
230             # The following structures are used by the abstractions that allow us to
231             # defer operating on the filesystem until after all potential conflicts have
232             # been assessed.
233              
234             # $self->{tasks}: list of operations to be performed (in order)
235             # each element is a hash ref of the form
236             # {
237             # action => ... ('create' or 'remove' or 'move')
238             # type => ... ('link' or 'dir' or 'file')
239             # path => ... (unique)
240             # source => ... (only for links)
241             # dest => ... (only for moving files)
242             # }
243 90         189 $self->{tasks} = [];
244              
245             # $self->{dir_task_for}: map a path to the corresponding directory task reference
246             # This structure allows us to quickly determine if a path has an existing
247             # directory task associated with it.
248 90         266 $self->{dir_task_for} = {};
249              
250             # $self->{link_task_for}: map a path to the corresponding directory task reference
251             # This structure allows us to quickly determine if a path has an existing
252             # directory task associated with it.
253 90         316 $self->{link_task_for} = {};
254              
255             # N.B.: directory tasks and link tasks are NOT mutually exclusive due
256             # to tree splitting (which involves a remove link task followed by
257             # a create directory task).
258             }
259              
260             =head1 METHODS
261              
262             =head2 plan_unstow(@packages)
263              
264             Plan which symlink/directory creation/removal tasks need to be executed
265             in order to unstow the given packages. Any potential conflicts are then
266             accessible via L.
267              
268             =cut
269              
270             sub plan_unstow {
271 40     40 1 104818 my $self = shift;
272 40         163 my @packages = @_;
273              
274 40 50       155 return unless @packages;
275              
276 40         265 debug(2, 0, "Planning unstow of: @packages ...");
277              
278             $self->within_target_do(sub {
279 40     40   87 for my $package (@packages) {
280 40         143 my $pkg_path = join_paths($self->{stow_path}, $package);
281 40 50       760 if (not -d $pkg_path) {
282 0         0 error("The stow directory $self->{stow_path} does not contain package $package");
283             }
284 40         181 debug(2, 0, "Planning unstow of package $package...");
285 40         186 $self->unstow_contents(
286             $package,
287             '.',
288             '.',
289             );
290 40         184 debug(2, 0, "Planning unstow of package $package... done");
291 40         146 $self->{action_count}++;
292             }
293 40         368 });
294             }
295              
296             =head2 plan_stow(@packages)
297              
298             Plan which symlink/directory creation/removal tasks need to be executed
299             in order to stow the given packages. Any potential conflicts are then
300             accessible via L.
301              
302             =cut
303              
304             sub plan_stow {
305 44     44 1 32094 my $self = shift;
306 44         244 my @packages = @_;
307              
308 44 50       190 return unless @packages;
309              
310 44         300 debug(2, 0, "Planning stow of: @packages ...");
311              
312             $self->within_target_do(sub {
313 44     44   146 for my $package (@packages) {
314 46         194 my $pkg_path = join_paths($self->{stow_path}, $package);
315 46 50       906 if (not -d $pkg_path) {
316 0         0 error("The stow directory $self->{stow_path} does not contain package $package");
317             }
318 46         211 debug(2, 0, "Planning stow of package $package...");
319             $self->stow_contents(
320             $self->{stow_path},
321 46         256 $package,
322             '.',
323             '.',
324             );
325 46         171 debug(2, 0, "Planning stow of package $package... done");
326 46         193 $self->{action_count}++;
327             }
328 44         416 });
329             }
330              
331             =head2 within_target_do($code)
332              
333             Execute code within target directory, preserving cwd.
334              
335             =over 4
336              
337             =item $code
338              
339             Anonymous subroutine to execute within target dir.
340              
341             =back
342              
343             This is done to ensure that the consumer of the Stow interface doesn't
344             have to worry about (a) what their cwd is, and (b) that their cwd
345             might change.
346              
347             =cut
348              
349             sub within_target_do {
350 136     136 1 263 my $self = shift;
351 136         279 my ($code) = @_;
352              
353 136         1185 my $cwd = getcwd();
354             chdir($self->{target})
355 136 50       1339 or error("Cannot chdir to target tree: $self->{target} ($!)");
356 136         593 debug(3, 0, "cwd now $self->{target}");
357              
358 136         414 $self->$code();
359              
360 136         538 restore_cwd($cwd);
361 136         466 debug(3, 0, "cwd restored to $cwd");
362             }
363              
364             =head2 stow_contents($stow_path, $package, $pkg_subdir, $target_subdir)
365              
366             Stow the contents of the given directory.
367              
368             =over 4
369              
370             =item $stow_path
371              
372             Relative path from current (i.e. target) directory to the stow dir
373             containing the package to be stowed. This can differ from
374             C<$self->{stow_path}> when unfolding a (sub)tree which is already
375             stowed from a package in a different stow directory (see the "Multiple
376             Stow Directories" section of the manual).
377              
378             =item $package
379              
380             The package whose contents are being stowed.
381              
382             =item $pkg_subdir
383              
384             Subdirectory of the installation image in the package directory which
385             needs stowing as a symlink which points to it. This is relative to
386             the top-level package directory.
387              
388             =item $target_subdir
389              
390             Subdirectory of the target directory which either needs a symlink to the
391             corresponding package subdirectory in the installation image, or if
392             it's an existing directory, it's an unfolded tree which may need to
393             be folded or recursed into.
394              
395             =back
396              
397             C and C are mutually recursive.
398              
399             =cut
400              
401             sub stow_contents {
402 111     111 1 211 my $self = shift;
403 111         348 my ($stow_path, $package, $pkg_subdir, $target_subdir) = @_;
404              
405 111 100       310 return if $self->should_skip_target($pkg_subdir);
406              
407 110         834 my $cwd = getcwd();
408 110         337 my $msg = "Stowing contents of $stow_path / $package / $pkg_subdir (cwd=$cwd)";
409 110         1827 $msg =~ s!$ENV{HOME}(/|$)!~$1!g;
410 110         354 debug(3, 0, $msg);
411 110         317 debug(4, 1, "target subdir is $target_subdir");
412              
413             # Calculate the path to the package directory or sub-directory
414             # whose contents need to be stowed, relative to the current
415             # (target directory). This is needed so that we can check it's a
416             # valid directory, and can read its contents to iterate over them.
417 110         264 my $pkg_path_from_cwd = join_paths($stow_path, $package, $pkg_subdir);
418              
419 110 50       386 error("stow_contents() called with non-directory target: $target_subdir")
420             unless $self->is_a_node($target_subdir);
421              
422 110 50       5099 opendir my $DIR, $pkg_path_from_cwd
423             or error("cannot read directory: $pkg_path_from_cwd ($!)");
424 110         3256 my @listing = readdir $DIR;
425 110         1317 closedir $DIR;
426              
427             NODE:
428 110         610 for my $node (sort @listing) {
429 397 100       875 next NODE if $node eq '.';
430 287 100       582 next NODE if $node eq '..';
431              
432 177         550 my $package_node_path = join_paths($pkg_subdir, $node);
433 177         286 my $target_node = $node;
434 177         320 my $target_node_path = join_paths($target_subdir, $target_node);
435 177 100       572 next NODE if $self->ignore($stow_path, $package, $target_node_path);
436              
437 161 100       469 if ($self->{dotfiles}) {
438 41         99 my $adjusted = adjust_dotfile($node);
439 41 100       88 if ($adjusted ne $node) {
440 29         71 debug(4, 1, "Adjusting: $node => $adjusted");
441 29         32 $target_node = $adjusted;
442 29         47 $target_node_path = join_paths($target_subdir, $target_node);
443             }
444             }
445              
446             $self->stow_node(
447 161         579 $stow_path,
448             $package,
449             $package_node_path,
450             $target_node_path
451             );
452             }
453             }
454              
455             =head2 stow_node($stow_path, $package, $pkg_subpath, $target_subpath)
456              
457             Stow the given node
458              
459             =over 4
460              
461             =item $stow_path
462              
463             Relative path from current (i.e. target) directory to the stow dir
464             containing the node to be stowed. This can differ from
465             C<$self->{stow_path}> when unfolding a (sub)tree which is already
466             stowed from a package in a different stow directory (see the "Multiple
467             Stow Directories" section of the manual).
468              
469             =item $package
470              
471             The package containing the node being stowed.
472              
473             =item $pkg_subpath
474              
475             Subpath of the installation image in the package directory which needs
476             stowing as a symlink which points to it. This is relative to the
477             top-level package directory.
478              
479             =item $target_subpath
480              
481             Subpath of the target directory which either needs a symlink to the
482             corresponding package subpathectory in the installation image, or if
483             it's an existing directory, it's an unfolded tree which may need to
484             be folded or recursed into.
485              
486             =back
487              
488             C and C are mutually recursive.
489              
490             =cut
491              
492             sub stow_node {
493 161     161 1 223 my $self = shift;
494 161         387 my ($stow_path, $package, $pkg_subpath, $target_subpath) = @_;
495              
496 161         504 debug(3, 0, "Stowing entry $stow_path / $package / $pkg_subpath");
497             # Calculate the path to the package directory or sub-directory
498             # whose contents need to be stowed, relative to the current
499             # (target directory). This is needed so that we can check it's a
500             # valid directory, and can read its contents to iterate over them.
501 161         408 my $pkg_path_from_cwd = join_paths($stow_path, $package, $pkg_subpath);
502              
503             # Don't try to stow absolute symlinks (they can't be unstowed)
504 161 100       3215 if (-l $pkg_path_from_cwd) {
505 5         24 my $link_dest = $self->read_a_link($pkg_path_from_cwd);
506 5 50       25 if ($link_dest =~ m{\A/}) {
507 0         0 $self->conflict(
508             'stow',
509             $package,
510             "source is an absolute symlink $pkg_path_from_cwd => $link_dest"
511             );
512 0         0 debug(3, 0, "Absolute symlinks cannot be unstowed");
513 0         0 return;
514             }
515             }
516              
517             # How many directories deep are we?
518 161         443 my $level = ($pkg_subpath =~ tr,/,,);
519 161         632 debug(2, 1, "level of $pkg_subpath is $level");
520              
521             # Calculate the destination of the symlink which would need to be
522             # installed within this directory in the absence of folding. This
523             # is relative to the target (sub-)directory where the symlink will
524             # be installed when the plans are executed, so as we descend down
525             # into the package hierarchy, it will have extra "../" segments
526             # prefixed to it.
527 161         466 my $link_dest = join_paths('../' x $level, $pkg_path_from_cwd);
528 161         511 debug(4, 1, "link destination $link_dest");
529              
530             # Does the target already exist?
531 161 100 100     485 if ($self->is_a_link($target_subpath)) {
    100 100        
    100          
532             # Where is the link pointing?
533 38         125 my $existing_link_dest = $self->read_a_link($target_subpath);
534 38 50       121 if (not $existing_link_dest) {
535 0         0 error("Could not read link: $target_subpath");
536             }
537 38         163 debug(4, 1, "Evaluate existing link: $target_subpath => $existing_link_dest");
538              
539             # Does it point to a node under any stow directory?
540 38         159 my ($existing_pkg_path_from_cwd, $existing_stow_path, $existing_package) =
541             $self->find_stowed_path($target_subpath, $existing_link_dest);
542 38 100       85 if (not $existing_pkg_path_from_cwd) {
543 1         10 $self->conflict(
544             'stow',
545             $package,
546             "existing target is not owned by stow: $target_subpath"
547             );
548 1         12 return;
549             }
550              
551             # Does the existing $target_subpath actually point to anything?
552 37 100       80 if ($self->is_a_node($existing_pkg_path_from_cwd)) {
553 36 100 66     121 if ($existing_link_dest eq $link_dest) {
    100          
    100          
    100          
554 24         60 debug(2, 0, "--- Skipping $target_subpath as it already points to $link_dest");
555             }
556             elsif ($self->defer($target_subpath)) {
557 1         4 debug(2, 0, "--- Deferring installation of: $target_subpath");
558             }
559             elsif ($self->override($target_subpath)) {
560 1         4 debug(2, 0, "--- Overriding installation of: $target_subpath");
561 1         7 $self->do_unlink($target_subpath);
562 1         5 $self->do_link($link_dest, $target_subpath);
563             }
564             elsif ($self->is_a_dir(join_paths(parent($target_subpath), $existing_link_dest)) &&
565             $self->is_a_dir(join_paths(parent($target_subpath), $link_dest)))
566             {
567              
568             # If the existing link points to a directory,
569             # and the proposed new link points to a directory,
570             # then we can unfold (split open) the tree at that point
571              
572 9         42 debug(2, 0, "--- Unfolding $target_subpath which was already owned by $existing_package");
573 9         45 $self->do_unlink($target_subpath);
574 9         50 $self->do_mkdir($target_subpath);
575 9         36 $self->stow_contents(
576             $existing_stow_path,
577             $existing_package,
578             $pkg_subpath,
579             $target_subpath,
580             );
581             $self->stow_contents(
582             $self->{stow_path},
583 9         33 $package,
584             $pkg_subpath,
585             $target_subpath,
586             );
587             }
588             else {
589 1         9 $self->conflict(
590             'stow',
591             $package,
592             "existing target is stowed to a different package: "
593             . "$target_subpath => $existing_link_dest"
594             );
595             }
596             }
597             else {
598             # The existing link is invalid, so replace it with a good link
599 1         16 debug(2, 0, "--- replacing invalid link: $target_subpath");
600 1         6 $self->do_unlink($target_subpath);
601 1         3 $self->do_link($link_dest, $target_subpath);
602             }
603             }
604             elsif ($self->is_a_node($target_subpath)) {
605 45         149 debug(4, 1, "Evaluate existing node: $target_subpath");
606 45 100       162 if ($self->is_a_dir($target_subpath)) {
607 39 100       427 if (! -d $pkg_path_from_cwd) {
608             # FIXME: why wasn't this ever needed before?
609 2         14 $self->conflict(
610             'stow',
611             $package,
612             "cannot stow non-directory $pkg_path_from_cwd over existing directory target $target_subpath"
613             );
614             }
615             else {
616             $self->stow_contents(
617             $self->{stow_path},
618 37         226 $package,
619             $pkg_subpath,
620             $target_subpath,
621             );
622             }
623             }
624             else {
625             # If we're here, $target_subpath is not a current or
626             # planned directory.
627              
628 6 100       15 if ($self->{adopt}) {
629 3 100       33 if (-d $pkg_path_from_cwd) {
630 1         7 $self->conflict(
631             'stow',
632             $package,
633             "cannot stow directory $pkg_path_from_cwd over existing non-directory target $target_subpath"
634             );
635             }
636             else {
637 2         8 $self->do_mv($target_subpath, $pkg_path_from_cwd);
638 2         6 $self->do_link($link_dest, $target_subpath);
639             }
640             }
641             else {
642 3         14 $self->conflict(
643             'stow',
644             $package,
645             "cannot stow $pkg_path_from_cwd over existing target $target_subpath since neither a link nor a directory and --adopt not specified"
646             );
647             }
648             }
649             }
650             elsif ($self->{'no-folding'} && -d $pkg_path_from_cwd && ! -l $pkg_path_from_cwd) {
651 10         50 $self->do_mkdir($target_subpath);
652             $self->stow_contents(
653             $self->{stow_path},
654 10         37 $package,
655             $pkg_subpath,
656             $target_subpath,
657             );
658             }
659             else {
660 68         241 $self->do_link($link_dest, $target_subpath);
661             }
662 160         853 return;
663             }
664              
665             =head2 should_skip_target($target_subdir)
666              
667             Determine whether C<$target_subdir> is a stow directory which should
668             not be stowed to or unstowed from. This mechanism protects stow
669             directories from being altered by stow, and is a necessary safety
670             check because the stow directory could live beneath the target
671             directory.
672              
673             =over 4
674              
675             =item $target_subdir => relative path to symlink target from the current directory
676              
677             =back
678              
679             Returns true iff target is a stow directory
680              
681             cwd must be the top-level target directory, otherwise
682             C won't work.
683              
684             =cut
685              
686             sub should_skip_target {
687 432     432 1 562 my $self = shift;
688 432         712 my ($target) = @_;
689              
690             # Don't try to remove anything under a stow directory
691 432 100       1030 if ($target eq $self->{stow_path}) {
692 3         193 warn "WARNING: skipping target which was current stow directory $target\n";
693 3         19 return 1;
694             }
695              
696 429 100       899 if ($self->marked_stow_dir($target)) {
697 10         523 warn "WARNING: skipping marked Stow directory $target\n";
698 10         41 return 1;
699             }
700              
701 419 50       1004 if (-e join_paths($target, ".nonstow")) {
702 0         0 warn "WARNING: skipping protected directory $target\n";
703 0         0 return 1;
704             }
705              
706 419         1460 debug(4, 1, "$target not protected; shouldn't skip");
707 419         990 return 0;
708             }
709              
710             # cwd must be the top-level target directory, otherwise
711             # marked_stow_dir() won't work.
712             sub marked_stow_dir {
713 503     503 0 624 my $self = shift;
714 503         756 my ($dir) = @_;
715 503 100       1029 if (-e join_paths($dir, ".stow")) {
716 12         44 debug(5, 5, "> $dir contained .stow");
717 12         33 return 1;
718             }
719 491         1449 return 0;
720             }
721              
722             =head2 unstow_contents($package, $pkg_subdir, $target_subdir)
723              
724             Unstow the contents of the given directory
725              
726             =over 4
727              
728             =item $package
729              
730             The package whose contents are being unstowed.
731              
732             =item $pkg_subdir
733              
734             Subdirectory of the installation image in the package directory which
735             may need a symlink pointing to it to be unstowed. This is relative to
736             the top-level package directory.
737              
738             =item $target_subdir
739              
740             Subdirectory of the target directory which either needs unstowing of a
741             symlink to the corresponding package subdirectory in the installation
742             image, or if it's an existing directory, it's an unfolded tree which
743             may need to be recursed into.
744              
745             =back
746              
747             C and C are mutually recursive.
748             Here we traverse the package tree, rather than the target tree.
749              
750             =cut
751              
752             sub unstow_contents {
753 321     321 1 374 my $self = shift;
754 321         528 my ($package, $pkg_subdir, $target_subdir) = @_;
755              
756 321 100       759 return if $self->should_skip_target($target_subdir);
757              
758 309         1973 my $cwd = getcwd();
759 309 100       1404 my $msg = "Unstowing contents of $self->{stow_path} / $package / $pkg_subdir (cwd=$cwd" . ($self->{compat} ? ', compat' : '') . ")";
760 309         3954 $msg =~ s!$ENV{HOME}/!~/!g;
761 309         747 debug(3, 0, $msg);
762 309         716 debug(4, 1, "target subdir is $target_subdir");
763              
764             # Calculate the path to the package directory or sub-directory
765             # whose contents need to be unstowed, relative to the current
766             # (target directory). This is needed so that we can check it's a
767             # valid directory, and can read its contents to iterate over them.
768 309         670 my $pkg_path_from_cwd = join_paths($self->{stow_path}, $package, $pkg_subdir);
769              
770 309 100       589 if ($self->{compat}) {
771             # In compat mode we traverse the target tree not the source tree,
772             # so we're unstowing the contents of /target/foo, there's no
773             # guarantee that the corresponding /stow/mypkg/foo exists.
774 258 50       3203 error("unstow_contents() in compat mode called with non-directory target: $target_subdir")
775             unless -d $target_subdir;
776             }
777             else {
778             # We traverse the package installation image tree not the
779             # target tree, so $pkg_path_from_cwd must exist.
780 51 50       928 error("unstow_contents() called with non-directory path: $pkg_path_from_cwd")
781             unless -d $pkg_path_from_cwd;
782              
783             # When called at the top level, $target_subdir should exist. And
784             # unstow_node() should only call this via mutual recursion if
785             # $target_subdir exists.
786 51 50       215 error("unstow_contents() called with invalid target: $target_subdir")
787             unless $self->is_a_node($target_subdir);
788             }
789              
790 309 100       767 my $dir = $self->{compat} ? $target_subdir : $pkg_path_from_cwd;
791 309 50       9033 opendir my $DIR, $dir
792             or error("cannot read directory: $dir ($!)");
793 309         7490 my @listing = readdir $DIR;
794 309         2726 closedir $DIR;
795              
796             NODE:
797 309         1350 for my $node (sort @listing) {
798 1634 100       2772 next NODE if $node eq '.';
799 1325 100       1916 next NODE if $node eq '..';
800              
801 1016         1264 my $package_node = $node;
802 1016         1029 my $target_node = $node;
803 1016         1803 my $target_node_path = join_paths($target_subdir, $target_node);
804              
805 1016 100       2820 next NODE if $self->ignore($self->{stow_path}, $package, $target_node_path);
806              
807 1010 100       1985 if ($self->{dotfiles}) {
808 41 100       66 if ($self->{compat}) {
809             # $node is in the target tree, so we need to reverse
810             # adjust any .* files in case they came from a dot-*
811             # file.
812 5         12 my $adjusted = unadjust_dotfile($node);
813 5 100       13 if ($adjusted ne $node) {
814 3         10 debug(4, 1, "Reverse adjusting: $node => $adjusted");
815 3         6 $package_node = $adjusted;
816             }
817             }
818             else {
819             # $node is in the package tree, so adjust any dot-*
820             # files for the target.
821 36         62 my $adjusted = adjust_dotfile($node);
822 36 100       69 if ($adjusted ne $node) {
823 24         54 debug(4, 1, "Adjusting: $node => $adjusted");
824 24         28 $target_node = $adjusted;
825 24         35 $target_node_path = join_paths($target_subdir, $target_node);
826             }
827             }
828             }
829 1010         1492 my $package_node_path = join_paths($pkg_subdir, $package_node);
830              
831 1010         2347 $self->unstow_node(
832             $package,
833             $package_node_path,
834             $target_node_path
835             );
836             }
837              
838 309 100 66     2225 if (! $self->{compat} && -d $target_subdir) {
839 51         181 $self->cleanup_invalid_links($target_subdir);
840             }
841             }
842              
843             =head2 unstow_node($package, $pkg_subpath, $target_subpath)
844              
845             Unstow the given node.
846              
847             =over 4
848              
849             =item $package
850              
851             The package containing the node being unstowed.
852              
853             =item $pkg_subpath
854              
855             Subpath of the installation image in the package directory which needs
856             stowing as a symlink which points to it. This is relative to the
857             top-level package directory.
858              
859             =item $target_subpath
860              
861             Subpath of the target directory which either needs a symlink to the
862             corresponding package subpathectory in the installation image, or if
863             it's an existing directory, it's an unfolded tree which may need to
864             be folded or recursed into.
865              
866             =back
867              
868             C and C are mutually recursive.
869              
870             =cut
871              
872             sub unstow_node {
873 1010     1010 1 1045 my $self = shift;
874 1010         1576 my ($package, $pkg_subpath, $target_subpath) = @_;
875              
876 1010         2136 debug(3, 0, "Unstowing entry from target: $target_subpath");
877 1010         2591 debug(4, 1, "Package entry: $self->{stow_path} / $package / $pkg_subpath");
878             # Calculate the path to the package directory or sub-directory
879             # whose contents need to be unstowed, relative to the current
880             # (target directory).
881             # Does the target exist?
882 1010 100       1900 if ($self->is_a_link($target_subpath)) {
    100          
    100          
883 75         261 $self->unstow_link_node($package, $pkg_subpath, $target_subpath);
884             }
885             elsif (-d $target_subpath) {
886 281         849 $self->unstow_contents($package, $pkg_subpath, $target_subpath);
887              
888             # This action may have made the parent directory foldable
889 281 100       690 if (my $parent_in_pkg = $self->foldable($target_subpath)) {
890 9         27 $self->fold_tree($target_subpath, $parent_in_pkg);
891             }
892             }
893             elsif (-e $target_subpath) {
894 633         1455 debug(2, 1, "$target_subpath doesn't need to be unstowed");
895             }
896             else {
897 21         61 debug(2, 1, "$target_subpath did not exist to be unstowed");
898             }
899             }
900              
901             sub unstow_link_node {
902 75     75 0 97 my $self = shift;
903 75         184 my ($package, $pkg_subpath, $target_subpath) = @_;
904 75         242 debug(4, 2, "Evaluate existing link: $target_subpath");
905              
906             # Where is the link pointing?
907 75         218 my $link_dest = $self->read_a_link($target_subpath);
908 75 50       156 if (not $link_dest) {
909 0         0 error("Could not read link: $target_subpath");
910             }
911              
912 75 50       219 if ($link_dest =~ m{\A/}) {
913 0         0 warn "Ignoring an absolute symlink: $target_subpath => $link_dest\n";
914 0         0 return;
915             }
916              
917             # Does it point to a node under any stow directory?
918 75         223 my ($existing_pkg_path_from_cwd, $existing_stow_path, $existing_package) =
919             $self->find_stowed_path($target_subpath, $link_dest);
920 75 100       183 if (not $existing_pkg_path_from_cwd) {
921             # The user is unstowing the package, so they don't want links to it.
922             # Therefore we should allow them to have a link pointing elsewhere
923             # which would conflict with the package if they were stowing it.
924 13         47 debug(5, 3, "Ignoring unowned link $target_subpath => $link_dest");
925 13         51 return;
926             }
927              
928 62         152 my $pkg_path_from_cwd = join_paths($self->{stow_path}, $package, $pkg_subpath);
929              
930             # Does the existing $target_subpath actually point to anything?
931 62 100       1228 if (-e $existing_pkg_path_from_cwd) {
932 60 100       178 if ($existing_pkg_path_from_cwd eq $pkg_path_from_cwd) {
933             # It points to the package we're unstowing, so unstow the link.
934 34         178 $self->do_unlink($target_subpath);
935             }
936             else {
937 26         68 debug(5, 3, "Ignoring link $target_subpath => $link_dest");
938             }
939             }
940             else {
941 2         11 debug(2, 0, "--- removing invalid link into a stow directory: $pkg_path_from_cwd");
942 2         15 $self->do_unlink($target_subpath);
943             }
944             }
945              
946             =head2 link_owned_by_package($target_subpath, $link_dest)
947              
948             Determine whether the given link points to a member of a stowed
949             package.
950              
951             =over 4
952              
953             =item $target_subpath
954              
955             Path to a symbolic link under current directory.
956              
957             =item $link_dest
958              
959             Where that link points to.
960              
961             =back
962              
963             Lossy wrapper around find_stowed_path().
964              
965             Returns the package iff link is owned by stow, otherwise ''.
966              
967             =cut
968              
969             sub link_owned_by_package {
970 22     22 1 34 my $self = shift;
971 22         45 my ($target_subpath, $link_dest) = @_;
972              
973 22         79 my ($pkg_path_from_cwd, $stow_path, $package) =
974             $self->find_stowed_path($target_subpath, $link_dest);
975 22         55 return $package;
976             }
977              
978             =head2 find_stowed_path($target_subpath, $link_dest)
979              
980             Determine whether the given symlink within the target directory is a
981             stowed path pointing to a member of a package under the stow dir, and
982             if so, obtain a breakdown of information about this stowed path.
983              
984             =over 4
985              
986             =item $target_subpath
987              
988             Path to a symbolic link somewhere under the target directory, relative
989             to the top-level target directory (which is also expected to be the
990             current directory).
991              
992             =item $link_dest
993              
994             Where that link points to (needed because link might not exist yet due
995             to two-phase approach, so we can't just call C). If this
996             is owned by Stow, it will be expressed relative to (the directory
997             containing) C<$target_subpath>. However if it's not, it could of course be
998             relative or absolute, point absolutely anywhere, and could even be
999             dangling.
1000              
1001             =back
1002              
1003             Returns C<($pkg_path_from_cwd, $stow_path, $package)> where
1004             C<$pkg_path_from_cwd> and C<$stow_path> are relative from the
1005             top-level target directory. C<$pkg_path_from_cwd> is the full
1006             relative path to the member of the package pointed to by
1007             C<$link_dest>; C<$stow_path> is the relative path to the stow
1008             directory; and C<$package> is the name of the package; or C<('', '',
1009             '')> if link is not owned by stow.
1010              
1011             cwd must be the top-level target directory, otherwise
1012             C won't work. Allow for stow dir
1013             not being under target dir.
1014              
1015             =cut
1016              
1017             sub find_stowed_path {
1018 145     145 1 57338 my $self = shift;
1019 145         330 my ($target_subpath, $link_dest) = @_;
1020              
1021 145 100       405 if (substr($link_dest, 0, 1) eq '/') {
1022             # Symlink points to an absolute path, therefore it cannot be
1023             # owned by Stow.
1024 2         12 return ('', '', '');
1025             }
1026              
1027             # Evaluate softlink relative to its target, without relying on
1028             # what's actually on the filesystem, since the link might not
1029             # exist yet.
1030 143         514 debug(4, 2, "find_stowed_path(target=$target_subpath; source=$link_dest)");
1031 143         448 my $pkg_path_from_cwd = join_paths(parent($target_subpath), $link_dest);
1032 143         411 debug(4, 3, "is symlink destination $pkg_path_from_cwd owned by stow?");
1033              
1034             # First check whether the link is owned by the current stow
1035             # directory, in which case $pkg_path_from_cwd will be a prefix of
1036             # $self->{stow_path}.
1037 143         400 my ($package, $pkg_subpath) = $self->link_dest_within_stow_dir($pkg_path_from_cwd);
1038 143 100       385 if (length $package) {
1039 112         336 debug(4, 3, "yes - package $package in $self->{stow_path} may contain $pkg_subpath");
1040 112         444 return ($pkg_path_from_cwd, $self->{stow_path}, $package);
1041             }
1042              
1043             # If no .stow file was found, we need to find out whether it's
1044             # owned by the current stow directory, in which case
1045             # $pkg_path_from_cwd will be a prefix of $self->{stow_path}.
1046 31         106 my ($stow_path, $ext_package) = $self->find_containing_marked_stow_dir($pkg_path_from_cwd);
1047 31 100       88 if (length $stow_path) {
1048 2         10 debug(5, 5, "yes - $stow_path in $pkg_path_from_cwd was marked as a stow dir; package=$ext_package");
1049 2         12 return ($pkg_path_from_cwd, $stow_path, $ext_package);
1050             }
1051              
1052 29         109 return ('', '', '');
1053             }
1054              
1055             =head2 link_dest_within_stow_dir($link_dest)
1056              
1057             Detect whether symlink destination is within current stow dir
1058              
1059             =over 4
1060              
1061             =item $link_dest - destination of the symlink relative
1062              
1063             =back
1064              
1065             Returns C<($package, $pkg_subpath)> - package within the current stow
1066             dir and subpath within that package which the symlink points to.
1067              
1068             =cut
1069              
1070             sub link_dest_within_stow_dir {
1071 149     149 1 31176 my $self = shift;
1072 149         337 my ($link_dest) = @_;
1073              
1074 149         595 debug(4, 4, "common prefix? link_dest=$link_dest; stow_path=$self->{stow_path}");
1075              
1076 149         1314 my $removed = $link_dest =~ s,^\Q$self->{stow_path}/,,;
1077 149 100       360 if (! $removed) {
1078 33         114 debug(4, 3, "no - $link_dest not under $self->{stow_path}");
1079 33         141 return ('', '');
1080             }
1081              
1082 116         447 debug(4, 4, "remaining after removing $self->{stow_path}: $link_dest");
1083 116         710 my @dirs = File::Spec->splitdir($link_dest);
1084 116         239 my $package = shift @dirs;
1085 116         751 my $pkg_subpath = File::Spec->catdir(@dirs);
1086 116         394 return ($package, $pkg_subpath);
1087             }
1088              
1089             =head2 find_containing_marked_stow_dir($pkg_path_from_cwd)
1090              
1091             Detect whether path is within a marked stow directory
1092              
1093             =over 4
1094              
1095             =item $pkg_path_from_cwd => path to directory to check
1096              
1097             =back
1098              
1099             Returns C<($stow_path, $package)> where C<$stow_path> is the highest
1100             directory (relative from the top-level target directory) which is
1101             marked as a Stow directory, and C<$package> is the containing package;
1102             or C<('', '')> if no containing directory is marked as a stow
1103             directory.
1104              
1105             cwd must be the top-level target directory, otherwise
1106             C won't work.
1107              
1108             =cut
1109              
1110             sub find_containing_marked_stow_dir {
1111 31     31 1 50 my $self = shift;
1112 31         66 my ($pkg_path_from_cwd) = @_;
1113              
1114             # Search for .stow files - this allows us to detect links
1115             # owned by stow directories other than the current one.
1116 31         192 my @segments = File::Spec->splitdir($pkg_path_from_cwd);
1117 31         105 for my $last_segment (0 .. $#segments) {
1118 74         256 my $pkg_path_from_cwd = join_paths(@segments[0 .. $last_segment]);
1119 74         222 debug(5, 5, "is $pkg_path_from_cwd marked stow dir?");
1120 74 100       175 if ($self->marked_stow_dir($pkg_path_from_cwd)) {
1121 2 50       11 if ($last_segment == $#segments) {
1122             # This should probably never happen. Even if it did,
1123             # there would be no way of calculating $package.
1124 0         0 internal_error("find_stowed_path() called directly on stow dir");
1125             }
1126              
1127 2         38 my $package = $segments[$last_segment + 1];
1128 2         16 return ($pkg_path_from_cwd, $package);
1129             }
1130             }
1131 29         113 return ('', '');
1132             }
1133              
1134             =head2 cleanup_invalid_links($dir)
1135              
1136             Clean up orphaned links that may block folding
1137              
1138             =over 4
1139              
1140             =item $dir
1141              
1142             Path to directory to check
1143              
1144             =back
1145              
1146             This is invoked by C. We only clean up links which
1147             are both orphaned and owned by Stow, i.e. they point to a non-existent
1148             location within a Stow package. These can block tree folding, and
1149             they can easily occur when a file in Stow package is renamed or
1150             removed, so the benefit should outweigh the low risk of actually
1151             someone wanting to keep an orphaned link to within a Stow package.
1152              
1153             =cut
1154              
1155             sub cleanup_invalid_links {
1156 55     55 1 121 my $self = shift;
1157 55         120 my ($dir) = @_;
1158              
1159 55         354 my $cwd = getcwd();
1160 55         236 debug(2, 0, "Cleaning up any invalid links in $dir (pwd=$cwd)");
1161              
1162 55 50       490 if (not -d $dir) {
1163 0         0 internal_error("cleanup_invalid_links() called with a non-directory: $dir");
1164             }
1165              
1166 55 50       1454 opendir my $DIR, $dir
1167             or error("cannot read directory: $dir ($!)");
1168 55         1457 my @listing = readdir $DIR;
1169 55         515 closedir $DIR;
1170              
1171             NODE:
1172 55         271 for my $node (sort @listing) {
1173 357 100       644 next NODE if $node eq '.';
1174 302 100       529 next NODE if $node eq '..';
1175              
1176 247         524 my $node_path = join_paths($dir, $node);
1177              
1178 247 100       2922 next unless -l $node_path;
1179              
1180 67         283 debug(4, 1, "Checking validity of link $node_path");
1181              
1182 67 100       232 if (exists $self->{link_task_for}{$node_path}) {
1183 26         63 my $action = $self->{link_task_for}{$node_path}{action};
1184 26 50       59 if ($action ne 'remove') {
1185 0         0 warn "Unexpected action $action scheduled for $node_path; skipping clean-up\n";
1186             }
1187             else {
1188 26         69 debug(4, 2, "$node_path scheduled for removal; skipping clean-up");
1189             }
1190 26         61 next;
1191             }
1192              
1193             # Where is the link pointing?
1194             # (don't use read_a_link() here)
1195 41         761 my $link_dest = readlink($node_path);
1196 41 50       114 if (not $link_dest) {
1197 0         0 error("Could not read link $node_path");
1198             }
1199              
1200 41         128 my $target_subpath = join_paths($dir, $link_dest);
1201 41         138 debug(4, 2, "join $dir $link_dest");
1202 41 100       576 if (-e $target_subpath) {
1203 31         131 debug(4, 2, "Link target $link_dest exists at $target_subpath; skipping clean up");
1204 31         78 next;
1205             }
1206             else {
1207 10         29 debug(4, 2, "Link target $link_dest doesn't exist at $target_subpath");
1208             }
1209              
1210 10         35 debug(3, 1,
1211             "Checking whether valid link $node_path -> $link_dest is " .
1212             "owned by stow");
1213              
1214 10         57 my $owner = $self->link_owned_by_package($node_path, $link_dest);
1215 10 100       30 if ($owner) {
1216             # owned by stow
1217 1         21 debug(2, 0, "--- removing link owned by $owner: $node_path => " .
1218             join_paths($dir, $link_dest));
1219 1         5 $self->do_unlink($node_path);
1220             }
1221             }
1222 55         408 return;
1223             }
1224              
1225              
1226             =head2 foldable($target_subdir)
1227              
1228             Determine whether a tree can be folded
1229              
1230             =over 4
1231              
1232             =item $target_subdir
1233              
1234             Path to the target sub-directory to check for foldability, relative to
1235             the current directory (the top-level target directory).
1236              
1237             =back
1238              
1239             Returns path to the parent dir iff the tree can be safely folded. The
1240             path returned is relative to the parent of C<$target_subdir>, i.e. it
1241             can be used as the source for a replacement symlink.
1242              
1243             =cut
1244              
1245             sub foldable {
1246 285     285 1 1038 my $self = shift;
1247 285         462 my ($target_subdir) = @_;
1248              
1249 285         735 debug(3, 2, "Is $target_subdir foldable?");
1250 285 100       732 if ($self->{'no-folding'}) {
1251 6         24 debug(3, 3, "Not foldable because --no-folding enabled");
1252 6         36 return '';
1253             }
1254              
1255 279 50       6998 opendir my $DIR, $target_subdir
1256             or error(qq{Cannot read directory "$target_subdir" ($!)\n});
1257 279         5507 my @listing = readdir $DIR;
1258 279         1985 closedir $DIR;
1259              
1260             # We want to see if all the symlinks in $target_subdir point to
1261             # files under the same parent subdirectory in the package
1262             # (e.g. ../../stow/pkg1/common_dir/file1). So remember which
1263             # parent subdirectory we've already seen, and if we come across a
1264             # second one which is different,
1265             # (e.g. ../../stow/pkg2/common_dir/file2), then $target_subdir
1266             # common_dir which contains file{1,2} cannot be folded to be
1267             # a symlink to (say) ../../stow/pkg1/common_dir.
1268 279         434 my $parent_in_pkg = '';
1269              
1270             NODE:
1271 279         1022 for my $node (sort @listing) {
1272 821 100       1383 next NODE if $node eq '.';
1273 542 100       815 next NODE if $node eq '..';
1274              
1275 263         638 my $target_node_path = join_paths($target_subdir, $node);
1276              
1277             # Skip nodes scheduled for removal
1278 263 100       669 next NODE if not $self->is_a_node($target_node_path);
1279              
1280             # If it's not a link then we can't fold its parent
1281 250 100       535 if (not $self->is_a_link($target_node_path)) {
1282 227         556 debug(3, 3, "Not foldable because $target_node_path not a link");
1283 227         1538 return '';
1284             }
1285              
1286             # Where is the link pointing?
1287 23         62 my $link_dest = $self->read_a_link($target_node_path);
1288 23 50       50 if (not $link_dest) {
1289 0         0 error("Could not read link $target_node_path");
1290             }
1291 23         49 my $new_parent = parent($link_dest);
1292 23 100       63 if ($parent_in_pkg eq '') {
    50          
1293 18         39 $parent_in_pkg = $new_parent;
1294             }
1295             elsif ($parent_in_pkg ne $new_parent) {
1296 5         20 debug(3, 3, "Not foldable because $target_subdir contains links to entries in both $parent_in_pkg and $new_parent");
1297 5         33 return '';
1298             }
1299             }
1300 47 100       115 if (not $parent_in_pkg) {
1301 35         122 debug(3, 3, "Not foldable because $target_subdir contains no links");
1302 35         232 return '';
1303             }
1304              
1305             # If we get here then all nodes inside $target_subdir are links,
1306             # and those links point to nodes inside the same directory.
1307              
1308             # chop of leading '..' to get the path to the common parent directory
1309             # relative to the parent of our $target_subdir
1310 12         42 $parent_in_pkg =~ s{\A\.\./}{};
1311              
1312             # If the resulting path is owned by stow, we can fold it
1313 12 100       40 if ($self->link_owned_by_package($target_subdir, $parent_in_pkg)) {
1314 10         28 debug(3, 3, "$target_subdir is foldable");
1315 10         54 return $parent_in_pkg;
1316             }
1317             else {
1318 2         8 debug(3, 3, "$target_subdir is not foldable");
1319 2         16 return '';
1320             }
1321             }
1322              
1323             =head2 fold_tree($target_subdir, $pkg_subpath)
1324              
1325             Fold the given tree
1326              
1327             =over 4
1328              
1329             =item $target_subdir
1330              
1331             Directory that we will replace with a link to $pkg_subpath.
1332              
1333             =item $pkg_subpath
1334              
1335             link to the folded tree source
1336              
1337             =back
1338              
1339             Only called iff foldable() is true so we can remove some checks.
1340              
1341             =cut
1342              
1343             sub fold_tree {
1344 9     9 1 13 my $self = shift;
1345 9         23 my ($target_subdir, $pkg_subpath) = @_;
1346              
1347 9         28 debug(3, 0, "--- Folding tree: $target_subdir => $pkg_subpath");
1348              
1349 9 50       237 opendir my $DIR, $target_subdir
1350             or error(qq{Cannot read directory "$target_subdir" ($!)\n});
1351 9         182 my @listing = readdir $DIR;
1352 9         63 closedir $DIR;
1353              
1354             NODE:
1355 9         33 for my $node (sort @listing) {
1356 29 100       59 next NODE if $node eq '.';
1357 20 100       35 next NODE if $node eq '..';
1358 11 100       26 next NODE if not $self->is_a_node(join_paths($target_subdir, $node));
1359 9         23 $self->do_unlink(join_paths($target_subdir, $node));
1360             }
1361 9         32 $self->do_rmdir($target_subdir);
1362 9         30 $self->do_link($pkg_subpath, $target_subdir);
1363 9         39 return;
1364             }
1365              
1366              
1367             =head2 conflict($package, $message)
1368              
1369             Handle conflicts in stow operations
1370              
1371             =over 4
1372              
1373             =item $package
1374              
1375             the package involved with the conflicting operation
1376              
1377             =item $message
1378              
1379             a description of the conflict
1380              
1381             =back
1382              
1383             =cut
1384              
1385             sub conflict {
1386 8     8 1 16 my $self = shift;
1387 8         23 my ($action, $package, $message) = @_;
1388              
1389 8         44 debug(2, 0, "CONFLICT when ${action}ing $package: $message");
1390 8   100     59 $self->{conflicts}{$action}{$package} ||= [];
1391 8         15 push @{ $self->{conflicts}{$action}{$package} }, $message;
  8         28  
1392 8         20 $self->{conflict_count}++;
1393              
1394 8         20 return;
1395             }
1396              
1397             =head2 get_conflicts()
1398              
1399             Returns a nested hash of all potential conflicts discovered: the keys
1400             are actions ('stow' or 'unstow'), and the values are hashrefs whose
1401             keys are stow package names and whose values are conflict
1402             descriptions, e.g.:
1403              
1404             (
1405             stow => {
1406             perl => [
1407             "existing target is not owned by stow: bin/a2p"
1408             "existing target is neither a link nor a directory: bin/perl"
1409             ]
1410             }
1411             )
1412              
1413             =cut
1414              
1415             sub get_conflicts {
1416 20     20 1 192 my $self = shift;
1417 20         72 return %{ $self->{conflicts} };
  20         153  
1418             }
1419              
1420             =head2 get_conflict_count()
1421              
1422             Returns the number of conflicts found.
1423              
1424             =cut
1425              
1426             sub get_conflict_count {
1427 57     57 1 327 my $self = shift;
1428 57         433 return $self->{conflict_count};
1429             }
1430              
1431             =head2 get_tasks()
1432              
1433             Returns a list of all symlink/directory creation/removal tasks.
1434              
1435             =cut
1436              
1437             sub get_tasks {
1438 27     27 1 10449 my $self = shift;
1439 27         44 return @{ $self->{tasks} };
  27         205  
1440             }
1441              
1442             =head2 get_action_count()
1443              
1444             Returns the number of actions planned for this Stow instance.
1445              
1446             =cut
1447              
1448             sub get_action_count {
1449 0     0 1 0 my $self = shift;
1450 0         0 return $self->{action_count};
1451             }
1452              
1453             =head2 ignore($stow_path, $package, $target)
1454              
1455             Determine if the given path matches a regex in our ignore list.
1456              
1457             =over 4
1458              
1459             =item $stow_path
1460              
1461             the stow directory containing the package
1462              
1463             =item $package
1464              
1465             the package containing the path
1466              
1467             =item $target
1468              
1469             the path to check against the ignore list relative to its package
1470             directory
1471              
1472             =back
1473              
1474             Returns true iff the path should be ignored.
1475              
1476             =cut
1477              
1478             sub ignore {
1479 1464     1464 1 281036 my $self = shift;
1480 1464         3179 my ($stow_path, $package, $target) = @_;
1481              
1482 1464 50       2841 internal_error(__PACKAGE__ . "::ignore() called with empty target")
1483             unless length $target;
1484              
1485 1464         1928 for my $suffix (@{ $self->{ignore} }) {
  1464         3304  
1486 150 100       1550 if ($target =~ m/$suffix/) {
1487 4         13 debug(4, 1, "Ignoring path $target due to --ignore=$suffix");
1488 4         19 return 1;
1489             }
1490             }
1491              
1492 1460         3359 my $package_dir = join_paths($stow_path, $package);
1493 1460         3517 my ($path_regexp, $segment_regexp) =
1494             $self->get_ignore_regexps($package_dir);
1495 1458 50       6089 debug(5, 2, "Ignore list regexp for paths: " .
1496             (defined $path_regexp ? "/$path_regexp/" : "none"));
1497 1458 100       4663 debug(5, 2, "Ignore list regexp for segments: " .
1498             (defined $segment_regexp ? "/$segment_regexp/" : "none"));
1499              
1500 1458 100 66     17371 if (defined $path_regexp and "/$target" =~ $path_regexp) {
1501 25         96 debug(4, 1, "Ignoring path /$target");
1502 25         156 return 1;
1503             }
1504              
1505 1433         6171 (my $basename = $target) =~ s!.+/!!;
1506 1433 100 100     8349 if (defined $segment_regexp and $basename =~ $segment_regexp) {
1507 26         105 debug(4, 1, "Ignoring path segment $basename");
1508 26         120 return 1;
1509             }
1510              
1511 1407         3662 debug(5, 1, "Not ignoring $target");
1512 1407         3877 return 0;
1513             }
1514              
1515             sub get_ignore_regexps {
1516 1460     1460 0 1809 my $self = shift;
1517 1460         2253 my ($dir) = @_;
1518              
1519             # N.B. the local and global stow ignore files have to have different
1520             # names so that:
1521             # 1. the global one can be a symlink to within a stow
1522             # package, managed by stow itself, and
1523             # 2. the local ones can be ignored via hardcoded logic in
1524             # GlobsToRegexp(), so that they always stay within their stow packages.
1525              
1526 1460         2990 my $local_stow_ignore = join_paths($dir, $LOCAL_IGNORE_FILE);
1527 1460         3643 my $global_stow_ignore = join_paths($ENV{HOME}, $GLOBAL_IGNORE_FILE);
1528              
1529 1460         2470 for my $file ($local_stow_ignore, $global_stow_ignore) {
1530 2696 100       32506 if (-e $file) {
1531 266         1414 debug(5, 1, "Using ignore file: $file");
1532 266         1172 return $self->get_ignore_regexps_from_file($file);
1533             }
1534             else {
1535 2430         5475 debug(5, 1, "$file didn't exist");
1536             }
1537             }
1538              
1539 1194         2326 debug(4, 1, "Using built-in ignore list");
1540 1194         3150 return @default_global_ignore_regexps;
1541             }
1542              
1543             my %ignore_file_regexps;
1544              
1545             sub get_ignore_regexps_from_file {
1546 266     266 0 494 my $self = shift;
1547 266         750 my ($file) = @_;
1548              
1549 266 100       974 if (exists $ignore_file_regexps{$file}) {
1550 244         745 debug(4, 2, "Using memoized regexps from $file");
1551 244         386 return @{ $ignore_file_regexps{$file} };
  244         1480  
1552             }
1553              
1554 22 50       940 if (! open(REGEXPS, $file)) {
1555 0         0 debug(4, 2, "Failed to open $file: $!");
1556 0         0 return undef;
1557             }
1558              
1559 22         116 my @regexps = $self->get_ignore_regexps_from_fh(\*REGEXPS);
1560 20         366 close(REGEXPS);
1561              
1562 20         115 $ignore_file_regexps{$file} = [ @regexps ];
1563 20         107 return @regexps;
1564             }
1565              
1566             =head2 invalidate_memoized_regexp($file)
1567              
1568             For efficiency of performance, regular expressions are compiled from
1569             each ignore list file the first time it is used by the Stow process,
1570             and then memoized for future use. If you expect the contents of these
1571             files to change during a single run, you will need to invalidate the
1572             memoized value from this cache. This method allows you to do that.
1573              
1574             =cut
1575              
1576             sub invalidate_memoized_regexp {
1577 21     21 1 5909 my $self = shift;
1578 21         74 my ($file) = @_;
1579 21 100       103 if (exists $ignore_file_regexps{$file}) {
1580 18         112 debug(4, 2, "Invalidated memoized regexp for $file");
1581 18         117 delete $ignore_file_regexps{$file};
1582             }
1583             else {
1584 3         17 debug(2, 1, "WARNING: no memoized regexp for $file to invalidate");
1585             }
1586             }
1587              
1588             sub get_ignore_regexps_from_fh {
1589 38     38 0 79 my $self = shift;
1590 38         99 my ($fh) = @_;
1591 38         115 my %regexps;
1592 38         685 while (<$fh>) {
1593 398         581 chomp;
1594 398         719 s/^\s+//;
1595 398         749 s/\s+$//;
1596 398 100 100     1526 next if /^#/ or length($_) == 0;
1597 286         1658 s/\s+#.+//; # strip comments to right of pattern
1598 286         560 s/\\#/#/g;
1599 286         1198 $regexps{$_}++;
1600             }
1601              
1602             # Local ignore lists should *always* stay within the stow directory,
1603             # because this is the only place stow looks for them.
1604 38         217 $regexps{"^/\Q$LOCAL_IGNORE_FILE\E\$"}++;
1605              
1606 38         290 return $self->compile_ignore_regexps(%regexps);
1607             }
1608              
1609             sub compile_ignore_regexps {
1610 38     38 0 89 my $self = shift;
1611 38         291 my (%regexps) = @_;
1612              
1613 38         88 my @segment_regexps;
1614             my @path_regexps;
1615 38         259 for my $regexp (keys %regexps) {
1616 324 100       627 if (index($regexp, '/') < 0) {
1617             # No / found in regexp, so use it for matching against basename
1618 227         500 push @segment_regexps, $regexp;
1619             }
1620             else {
1621             # / found in regexp, so use it for matching against full path
1622 97         299 push @path_regexps, $regexp;
1623             }
1624             }
1625              
1626 38         172 my $segment_regexp = join '|', @segment_regexps;
1627 38         106 my $path_regexp = join '|', @path_regexps;
1628 38 100       183 $segment_regexp = @segment_regexps ?
1629             $self->compile_regexp("^($segment_regexp)\$") : undef;
1630 37 50       226 $path_regexp = @path_regexps ?
1631             $self->compile_regexp("(^|/)($path_regexp)(/|\$)") : undef;
1632              
1633 36         356 return ($path_regexp, $segment_regexp);
1634             }
1635              
1636             sub compile_regexp {
1637 66     66 0 117 my $self = shift;
1638 66         163 my ($regexp) = @_;
1639 66         132 my $compiled = eval { qr/$regexp/ };
  66         3731  
1640 66 100       295 die "Failed to compile regexp: $@\n" if $@;
1641 64         174 return $compiled;
1642             }
1643              
1644             sub get_default_global_ignore_regexps {
1645 16     16 0 55 my $class = shift;
1646             # Bootstrap issue - first time we stow, we will be stowing
1647             # .cvsignore so it might not exist in ~ yet, or if it does, it could
1648             # be an old version missing the entries we need. So we make sure
1649             # they are there by hardcoding some crucial entries.
1650 16         71 return $class->get_ignore_regexps_from_fh(\*DATA);
1651             }
1652              
1653             =head2 defer($path)
1654              
1655             Determine if the given path matches a regex in our C list
1656              
1657             =over 4
1658              
1659             =item $path
1660              
1661             =back
1662              
1663             Returns boolean.
1664              
1665             =cut
1666              
1667             sub defer {
1668 16     16 1 81 my $self = shift;
1669 16         40 my ($path) = @_;
1670              
1671 16         29 for my $prefix (@{ $self->{defer} }) {
  16         72  
1672 8 100       146 return 1 if $path =~ m/$prefix/;
1673             }
1674 13         65 return 0;
1675             }
1676              
1677             =head2 override($path)
1678              
1679             Determine if the given path matches a regex in our C list
1680              
1681             =over 4
1682              
1683             =item $path
1684              
1685             =back
1686              
1687             Returns boolean
1688              
1689             =cut
1690              
1691             sub override {
1692 11     11 1 17 my $self = shift;
1693 11         28 my ($path) = @_;
1694              
1695 11         36 for my $regex (@{ $self->{override} }) {
  11         27  
1696 1 50       28 return 1 if $path =~ m/$regex/;
1697             }
1698 10         38 return 0;
1699             }
1700              
1701             ##############################################################################
1702             #
1703             # The following code provides the abstractions that allow us to defer operating
1704             # on the filesystem until after all potential conflcits have been assessed.
1705             #
1706             ##############################################################################
1707              
1708             =head2 process_tasks()
1709              
1710             Process each task in the tasks list
1711              
1712             =over 4
1713              
1714             =item none
1715              
1716             =back
1717              
1718             Returns : n/a
1719             Throws : fatal error if tasks list is corrupted or a task fails
1720              
1721             =cut
1722              
1723             sub process_tasks {
1724 52     52 1 8169 my $self = shift;
1725              
1726 52         194 debug(2, 0, "Processing tasks...");
1727              
1728             # Strip out all tasks with a skip action
1729 52         94 $self->{tasks} = [ grep { $_->{action} ne 'skip' } @{ $self->{tasks} } ];
  153         442  
  52         167  
1730              
1731 52 50       168 if (not @{ $self->{tasks} }) {
  52         180  
1732 0         0 return;
1733             }
1734              
1735             $self->within_target_do(sub {
1736 52     52   91 for my $task (@{ $self->{tasks} }) {
  52         135  
1737 145         378 $self->process_task($task);
1738             }
1739 52         417 });
1740              
1741 52         336 debug(2, 0, "Processing tasks... done");
1742             }
1743              
1744             =head2 process_task($task)
1745              
1746             Process a single task.
1747              
1748             =over 4
1749              
1750             =item $task => the task to process
1751              
1752             =back
1753              
1754             Returns : n/a
1755             Throws : fatal error if task fails
1756             # #
1757             Must run from within target directory. Task involve either creating
1758             or deleting dirs and symlinks an action is set to 'skip' if it is
1759             found to be redundant
1760              
1761             =cut
1762              
1763             sub process_task {
1764 145     145 1 221 my $self = shift;
1765 145         259 my ($task) = @_;
1766              
1767 145 100       461 if ($task->{action} eq 'create') {
    100          
    50          
1768 90 100       368 if ($task->{type} eq 'dir') {
    50          
1769 19 50       2165 mkdir($task->{path}, 0777)
1770             or error("Could not create directory: $task->{path} ($!)");
1771 19         81 return;
1772             }
1773             elsif ($task->{type} eq 'link') {
1774             symlink $task->{source}, $task->{path}
1775             or error(
1776             "Could not create symlink: %s => %s ($!)",
1777             $task->{path},
1778             $task->{source}
1779 71 50       8468 );
1780 71         319 return;
1781             }
1782             }
1783             elsif ($task->{action} eq 'remove') {
1784 53 100       228 if ($task->{type} eq 'dir') {
    50          
1785             rmdir $task->{path}
1786 7 50       416 or error("Could not remove directory: $task->{path} ($!)");
1787 7         40 return;
1788             }
1789             elsif ($task->{type} eq 'link') {
1790             unlink $task->{path}
1791 46 50       7049 or error("Could not remove link: $task->{path} ($!)");
1792 46         220 return;
1793             }
1794             }
1795             elsif ($task->{action} eq 'move') {
1796 2 50       6 if ($task->{type} eq 'file') {
1797             # rename() not good enough, since the stow directory
1798             # might be on a different filesystem to the target.
1799             move $task->{path}, $task->{dest}
1800 2 50       10 or error("Could not move $task->{path} -> $task->{dest} ($!)");
1801 2         566 return;
1802             }
1803             }
1804              
1805             # Should never happen.
1806 0         0 internal_error("bad task action: $task->{action}");
1807             }
1808              
1809             =head2 link_task_action($path)
1810              
1811             Finds the link task action for the given path, if there is one
1812              
1813             =over 4
1814              
1815             =item $path
1816              
1817             =back
1818              
1819             Returns C<'remove'>, C<'create'>, or C<''> if there is no action.
1820             Throws a fatal exception if an invalid action is found.
1821              
1822             =cut
1823              
1824             sub link_task_action {
1825 2158     2158 1 2416 my $self = shift;
1826 2158         2663 my ($path) = @_;
1827              
1828 2158 100       4472 if (! exists $self->{link_task_for}{$path}) {
1829 2116         4518 debug(4, 4, "| link_task_action($path): no task");
1830 2116         6303 return '';
1831             }
1832              
1833 42         91 my $action = $self->{link_task_for}{$path}->{action};
1834 42 50 66     155 internal_error("bad task action: $action")
1835             unless $action eq 'remove' or $action eq 'create';
1836              
1837 42         135 debug(4, 1, "link_task_action($path): link task exists with action $action");
1838 42         101 return $action;
1839             }
1840              
1841             =head2 dir_task_action($path)
1842              
1843             Finds the dir task action for the given path, if there is one.
1844              
1845             =over 4
1846              
1847             =item $path
1848              
1849             =back
1850              
1851             Returns C<'remove'>, C<'create'>, or C<''> if there is no action.
1852             Throws a fatal exception if an invalid action is found.
1853              
1854             =cut
1855              
1856             sub dir_task_action {
1857 659     659 1 797 my $self = shift;
1858 659         1023 my ($path) = @_;
1859              
1860 659 100       1365 if (! exists $self->{dir_task_for}{$path}) {
1861 627         1500 debug(4, 4, "| dir_task_action($path): no task");
1862 627         1131 return '';
1863             }
1864              
1865 32         68 my $action = $self->{dir_task_for}{$path}->{action};
1866 32 50 66     135 internal_error("bad task action: $action")
1867             unless $action eq 'remove' or $action eq 'create';
1868              
1869 32         106 debug(4, 4, "| dir_task_action($path): dir task exists with action $action");
1870 32         58 return $action;
1871             }
1872              
1873             =head2 parent_link_scheduled_for_removal($target_path)
1874              
1875             Determine whether the given path or any parent thereof is a link
1876             scheduled for removal
1877              
1878             =over 4
1879              
1880             =item $target_path
1881              
1882             =back
1883              
1884             Returns boolean
1885              
1886             =cut
1887              
1888             sub parent_link_scheduled_for_removal {
1889 741     741 1 914 my $self = shift;
1890 741         1024 my ($target_path) = @_;
1891              
1892 741         984 my $prefix = '';
1893 741         3097 for my $part (split m{/+}, $target_path) {
1894 1507         2641 $prefix = join_paths($prefix, $part);
1895 1507         3664 debug(5, 4, "| parent_link_scheduled_for_removal($target_path): prefix $prefix");
1896 1507 100 66     3494 if (exists $self->{link_task_for}{$prefix} and
1897             $self->{link_task_for}{$prefix}->{action} eq 'remove') {
1898 9         28 debug(4, 4, "| parent_link_scheduled_for_removal($target_path): link scheduled for removal");
1899 9         63 return 1;
1900             }
1901             }
1902              
1903 732         1894 debug(4, 4, "| parent_link_scheduled_for_removal($target_path): returning false");
1904 732         1763 return 0;
1905             }
1906              
1907             =head2 is_a_link($target_path)
1908              
1909             Determine if the given path is a current or planned link.
1910              
1911             =over 4
1912              
1913             =item $target_path
1914              
1915             =back
1916              
1917             Returns false if an existing link is scheduled for removal and true if
1918             a non-existent link is scheduled for creation.
1919              
1920             =cut
1921              
1922             sub is_a_link {
1923 1421     1421 1 1575 my $self = shift;
1924 1421         1880 my ($target_path) = @_;
1925 1421         3053 debug(4, 2, "is_a_link($target_path)");
1926              
1927 1421 100       2681 if (my $action = $self->link_task_action($target_path)) {
1928 8 50       36 if ($action eq 'remove') {
    50          
1929 0         0 debug(4, 2, "is_a_link($target_path): returning 0 (remove action found)");
1930 0         0 return 0;
1931             }
1932             elsif ($action eq 'create') {
1933 8         46 debug(4, 2, "is_a_link($target_path): returning 1 (create action found)");
1934 8         25 return 1;
1935             }
1936             }
1937              
1938 1413 100       21156 if (-l $target_path) {
1939             # Check if any of its parent are links scheduled for removal
1940             # (need this for edge case during unfolding)
1941 129         451 debug(4, 2, "is_a_link($target_path): is a real link");
1942 129 100       326 return $self->parent_link_scheduled_for_removal($target_path) ? 0 : 1;
1943             }
1944              
1945 1284         4212 debug(4, 2, "is_a_link($target_path): returning 0");
1946 1284         12714 return 0;
1947             }
1948              
1949             =head2 is_a_dir($target_path)
1950              
1951             Determine if the given path is a current or planned directory
1952              
1953             =over 4
1954              
1955             =item $target_path
1956              
1957             =back
1958              
1959             Returns false if an existing directory is scheduled for removal and
1960             true if a non-existent directory is scheduled for creation. We also
1961             need to be sure we are not just following a link.
1962              
1963             =cut
1964              
1965             sub is_a_dir {
1966 64     64 1 96 my $self = shift;
1967 64         132 my ($target_path) = @_;
1968 64         191 debug(4, 1, "is_a_dir($target_path)");
1969              
1970 64 50       163 if (my $action = $self->dir_task_action($target_path)) {
1971 0 0       0 if ($action eq 'remove') {
    0          
1972 0         0 return 0;
1973             }
1974             elsif ($action eq 'create') {
1975 0         0 return 1;
1976             }
1977             }
1978              
1979 64 50       166 return 0 if $self->parent_link_scheduled_for_removal($target_path);
1980              
1981 64 100       1042 if (-d $target_path) {
1982 57         245 debug(4, 1, "is_a_dir($target_path): real dir");
1983 57         224 return 1;
1984             }
1985              
1986 7         26 debug(4, 1, "is_a_dir($target_path): returning false");
1987 7         17 return 0;
1988             }
1989              
1990             =head2 is_a_node($target_path)
1991              
1992             Determine whether the given path is a current or planned node.
1993              
1994             =over 4
1995              
1996             =item $target_path
1997              
1998             =back
1999              
2000             Returns false if an existing node is scheduled for removal, or true if
2001             a non-existent node is scheduled for creation. We also need to be
2002             sure we are not just following a link.
2003              
2004             =cut
2005              
2006             sub is_a_node {
2007 595     595 1 785 my $self = shift;
2008 595         956 my ($target_path) = @_;
2009 595         1433 debug(4, 4, "| Checking whether $target_path is a current/planned node");
2010              
2011 595         1259 my $laction = $self->link_task_action($target_path);
2012 595         1405 my $daction = $self->dir_task_action($target_path);
2013              
2014 595 100       1385 if ($laction eq 'remove') {
    100          
2015 21 50       74 if ($daction eq 'remove') {
    100          
2016 0         0 internal_error("removing link and dir: $target_path");
2017 0         0 return 0;
2018             }
2019             elsif ($daction eq 'create') {
2020             # Assume that we're unfolding $target_path, and that the link
2021             # removal action is earlier than the dir creation action
2022             # in the task queue. FIXME: is this a safe assumption?
2023 6         33 return 1;
2024             }
2025             else { # no dir action
2026 15         56 return 0;
2027             }
2028             }
2029             elsif ($laction eq 'create') {
2030 4 50       9 if ($daction eq 'remove') {
    0          
2031             # Assume that we're folding $target_path, and that the dir
2032             # removal action is earlier than the link creation action
2033             # in the task queue. FIXME: is this a safe assumption?
2034 4         10 return 1;
2035             }
2036             elsif ($daction eq 'create') {
2037 0         0 internal_error("creating link and dir: $target_path");
2038 0         0 return 1;
2039             }
2040             else { # no dir action
2041 0         0 return 1;
2042             }
2043             }
2044             else {
2045             # No link action
2046 570 50       1314 if ($daction eq 'remove') {
    100          
2047 0         0 return 0;
2048             }
2049             elsif ($daction eq 'create') {
2050 22         98 return 1;
2051             }
2052             else { # no dir action
2053             # fall through to below
2054             }
2055             }
2056              
2057 548 100       1225 return 0 if $self->parent_link_scheduled_for_removal($target_path);
2058              
2059 540 100       8895 if (-e $target_path) {
2060 469         1620 debug(4, 3, "| is_a_node($target_path): really exists");
2061 469         1346 return 1;
2062             }
2063              
2064 71         240 debug(4, 3, "| is_a_node($target_path): returning false");
2065 71         722 return 0;
2066             }
2067              
2068             =head2 read_a_link($link)
2069              
2070             Return the destination of a current or planned link.
2071              
2072             =over 4
2073              
2074             =item $link
2075              
2076             Path to the link target.
2077              
2078             =back
2079              
2080             Returns the destination of the given link. Throws a fatal exception
2081             if the given path is not a current or planned link.
2082              
2083             =cut
2084              
2085             sub read_a_link {
2086 141     141 1 203 my $self = shift;
2087 141         245 my ($link) = @_;
2088              
2089 141 100       259 if (my $action = $self->link_task_action($link)) {
    50          
2090 8         34 debug(4, 2, "read_a_link($link): task exists with action $action");
2091              
2092 8 50       22 if ($action eq 'create') {
    0          
2093 8         24 return $self->{link_task_for}{$link}->{source};
2094             }
2095             elsif ($action eq 'remove') {
2096 0         0 internal_error(
2097             "read_a_link() passed a path that is scheduled for removal: $link"
2098             );
2099             }
2100             }
2101             elsif (-l $link) {
2102 133         451 debug(4, 2, "read_a_link($link): is a real link");
2103 133 50       3456 my $link_dest = readlink $link or error("Could not read link: $link ($!)");
2104 133         432 return $link_dest;
2105             }
2106 0         0 internal_error("read_a_link() passed a non-link path: $link\n");
2107             }
2108              
2109             =head2 do_link($link_dest, $link_src)
2110              
2111             Wrap 'link' operation for later processing
2112              
2113             =over 4
2114              
2115             =item $link_dest
2116              
2117             the existing file to link to
2118              
2119             =item $link_src
2120              
2121             the file to link
2122              
2123             =back
2124              
2125             Throws an error if this clashes with an existing planned operation.
2126             Cleans up operations that undo previous operations.
2127              
2128             =cut
2129              
2130             sub do_link {
2131 81     81 1 133 my $self = shift;
2132 81         200 my ($link_dest, $link_src) = @_;
2133              
2134 81 100       218 if (exists $self->{dir_task_for}{$link_src}) {
2135 9         47 my $task_ref = $self->{dir_task_for}{$link_src};
2136              
2137 9 50       40 if ($task_ref->{action} eq 'create') {
    50          
2138 0 0       0 if ($task_ref->{type} eq 'dir') {
2139 0         0 internal_error(
2140             "new link (%s => %s) clashes with planned new directory",
2141             $link_src,
2142             $link_dest,
2143             );
2144             }
2145             }
2146             elsif ($task_ref->{action} eq 'remove') {
2147             # We may need to remove a directory before creating a link so continue.
2148             }
2149             else {
2150 0         0 internal_error("bad task action: $task_ref->{action}");
2151             }
2152             }
2153              
2154 81 100       205 if (exists $self->{link_task_for}{$link_src}) {
2155 2         6 my $task_ref = $self->{link_task_for}{$link_src};
2156              
2157 2 50       14 if ($task_ref->{action} eq 'create') {
    50          
2158 0 0       0 if ($task_ref->{source} ne $link_dest) {
2159             internal_error(
2160             "new link clashes with planned new link: %s => %s",
2161             $task_ref->{path},
2162             $task_ref->{source},
2163             )
2164 0         0 }
2165             else {
2166 0         0 debug(1, 0, "LINK: $link_src => $link_dest (duplicates previous action)");
2167 0         0 return;
2168             }
2169             }
2170             elsif ($task_ref->{action} eq 'remove') {
2171 2 50       10 if ($task_ref->{source} eq $link_dest) {
2172             # No need to remove a link we are going to recreate
2173 0         0 debug(1, 0, "LINK: $link_src => $link_dest (reverts previous action)");
2174 0         0 $self->{link_task_for}{$link_src}->{action} = 'skip';
2175 0         0 delete $self->{link_task_for}{$link_src};
2176 0         0 return;
2177             }
2178             # We may need to remove a link to replace it so continue
2179             }
2180             else {
2181 0         0 internal_error("bad task action: $task_ref->{action}");
2182             }
2183             }
2184              
2185             # Creating a new link
2186 81         280 debug(1, 0, "LINK: $link_src => $link_dest");
2187 81         498 my $task = {
2188             action => 'create',
2189             type => 'link',
2190             path => $link_src,
2191             source => $link_dest,
2192             };
2193 81         129 push @{ $self->{tasks} }, $task;
  81         211  
2194 81         208 $self->{link_task_for}{$link_src} = $task;
2195              
2196 81         154 return;
2197             }
2198              
2199             =head2 do_unlink($file)
2200              
2201             Wrap 'unlink' operation for later processing
2202              
2203             =over 4
2204              
2205             =item $file
2206              
2207             the file to unlink
2208              
2209             =back
2210              
2211             Throws an error if this clashes with an existing planned operation.
2212             Will remove an existing planned link.
2213              
2214             =cut
2215              
2216             sub do_unlink {
2217 57     57 1 87 my $self = shift;
2218 57         157 my ($file) = @_;
2219              
2220 57 100       188 if (exists $self->{link_task_for}{$file}) {
2221 8         21 my $task_ref = $self->{link_task_for}{$file};
2222 8 50       38 if ($task_ref->{action} eq 'remove') {
    50          
2223 0         0 debug(1, 0, "UNLINK: $file (duplicates previous action)");
2224 0         0 return;
2225             }
2226             elsif ($task_ref->{action} eq 'create') {
2227             # Do need to create a link then remove it
2228 8         33 debug(1, 0, "UNLINK: $file (reverts previous action)");
2229 8         21 $self->{link_task_for}{$file}->{action} = 'skip';
2230 8         22 delete $self->{link_task_for}{$file};
2231 8         16 return;
2232             }
2233             else {
2234 0         0 internal_error("bad task action: $task_ref->{action}");
2235             }
2236             }
2237              
2238 49 50 33     158 if (exists $self->{dir_task_for}{$file} and $self->{dir_task_for}{$file} eq 'create') {
2239             internal_error(
2240             "new unlink operation clashes with planned operation: %s dir %s",
2241             $self->{dir_task_for}{$file}->{action},
2242 0         0 $file
2243             );
2244             }
2245              
2246             # Remove the link
2247 49         167 debug(1, 0, "UNLINK: $file");
2248              
2249 49 50       528 my $source = readlink $file or error("could not readlink $file ($!)");
2250              
2251 49         379 my $task = {
2252             action => 'remove',
2253             type => 'link',
2254             path => $file,
2255             source => $source,
2256             };
2257 49         81 push @{ $self->{tasks} }, $task;
  49         150  
2258 49         165 $self->{link_task_for}{$file} = $task;
2259              
2260 49         174 return;
2261             }
2262              
2263             =head2 do_mkdir($dir)
2264              
2265             Wrap 'mkdir' operation
2266              
2267             =over 4
2268              
2269             =item $dir
2270              
2271             the directory to remove
2272              
2273             =back
2274              
2275             Throws a fatal exception if operation fails. Outputs a message if
2276             'verbose' option is set. Does not perform operation if 'simulate'
2277             option is set. Cleans up operations that undo previous operations.
2278              
2279             =cut
2280              
2281             sub do_mkdir {
2282 19     19 1 32 my $self = shift;
2283 19         38 my ($dir) = @_;
2284              
2285 19 100       67 if (exists $self->{link_task_for}{$dir}) {
2286 3         8 my $task_ref = $self->{link_task_for}{$dir};
2287              
2288 3 50       17 if ($task_ref->{action} eq 'create') {
    50          
2289             internal_error(
2290             "new dir clashes with planned new link (%s => %s)",
2291             $task_ref->{path},
2292             $task_ref->{source},
2293 0         0 );
2294             }
2295             elsif ($task_ref->{action} eq 'remove') {
2296             # May need to remove a link before creating a directory so continue
2297             }
2298             else {
2299 0         0 internal_error("bad task action: $task_ref->{action}");
2300             }
2301             }
2302              
2303 19 50       52 if (exists $self->{dir_task_for}{$dir}) {
2304 0         0 my $task_ref = $self->{dir_task_for}{$dir};
2305              
2306 0 0       0 if ($task_ref->{action} eq 'create') {
    0          
2307 0         0 debug(1, 0, "MKDIR: $dir (duplicates previous action)");
2308 0         0 return;
2309             }
2310             elsif ($task_ref->{action} eq 'remove') {
2311 0         0 debug(1, 0, "MKDIR: $dir (reverts previous action)");
2312 0         0 $self->{dir_task_for}{$dir}->{action} = 'skip';
2313 0         0 delete $self->{dir_task_for}{$dir};
2314 0         0 return;
2315             }
2316             else {
2317 0         0 internal_error("bad task action: $task_ref->{action}");
2318             }
2319             }
2320              
2321 19         64 debug(1, 0, "MKDIR: $dir");
2322 19         110 my $task = {
2323             action => 'create',
2324             type => 'dir',
2325             path => $dir,
2326             source => undef,
2327             };
2328 19         30 push @{ $self->{tasks} }, $task;
  19         57  
2329 19         48 $self->{dir_task_for}{$dir} = $task;
2330              
2331 19         32 return;
2332             }
2333              
2334             =head2 do_rmdir($dir)
2335              
2336             Wrap 'rmdir' operation
2337              
2338             =over 4
2339              
2340             =item $dir
2341              
2342             the directory to remove
2343              
2344             =back
2345              
2346             Throws a fatal exception if operation fails. Outputs a message if
2347             'verbose' option is set. Does not perform operation if 'simulate'
2348             option is set.
2349              
2350             =cut
2351              
2352             sub do_rmdir {
2353 9     9 1 13 my $self = shift;
2354 9         17 my ($dir) = @_;
2355              
2356 9 50       20 if (exists $self->{link_task_for}{$dir}) {
2357 0         0 my $task_ref = $self->{link_task_for}{$dir};
2358             internal_error(
2359             "rmdir clashes with planned operation: %s link %s => %s",
2360             $task_ref->{action},
2361             $task_ref->{path},
2362             $task_ref->{source}
2363 0         0 );
2364             }
2365              
2366 9 50       54 if (exists $self->{dir_task_for}{$dir}) {
2367 0         0 my $task_ref = $self->{link_task_for}{$dir};
2368              
2369 0 0       0 if ($task_ref->{action} eq 'remove') {
    0          
2370 0         0 debug(1, 0, "RMDIR $dir (duplicates previous action)");
2371 0         0 return;
2372             }
2373             elsif ($task_ref->{action} eq 'create') {
2374 0         0 debug(1, 0, "MKDIR $dir (reverts previous action)");
2375 0         0 $self->{link_task_for}{$dir}->{action} = 'skip';
2376 0         0 delete $self->{link_task_for}{$dir};
2377 0         0 return;
2378             }
2379             else {
2380 0         0 internal_error("bad task action: $task_ref->{action}");
2381             }
2382             }
2383              
2384 9         23 debug(1, 0, "RMDIR $dir");
2385 9         35 my $task = {
2386             action => 'remove',
2387             type => 'dir',
2388             path => $dir,
2389             source => '',
2390             };
2391 9         13 push @{ $self->{tasks} }, $task;
  9         20  
2392 9         25 $self->{dir_task_for}{$dir} = $task;
2393              
2394 9         14 return;
2395             }
2396              
2397             =head2 do_mv($src, $dst)
2398              
2399             Wrap 'move' operation for later processing.
2400              
2401             =over 4
2402              
2403             =item $src
2404              
2405             the file to move
2406              
2407             =item $dst
2408              
2409             the path to move it to
2410              
2411             =back
2412              
2413             Throws an error if this clashes with an existing planned operation.
2414             Alters contents of package installation image in stow dir.
2415              
2416             =cut
2417              
2418             sub do_mv {
2419 2     2 1 3 my $self = shift;
2420 2         6 my ($src, $dst) = @_;
2421              
2422 2 50       10 if (exists $self->{link_task_for}{$src}) {
    50          
2423             # I don't *think* this should ever happen, but I'm not
2424             # 100% sure.
2425 0         0 my $task_ref = $self->{link_task_for}{$src};
2426             internal_error(
2427             "do_mv: pre-existing link task for $src; action: %s, source: %s",
2428             $task_ref->{action}, $task_ref->{source}
2429 0         0 );
2430             }
2431             elsif (exists $self->{dir_task_for}{$src}) {
2432 0         0 my $task_ref = $self->{dir_task_for}{$src};
2433             internal_error(
2434             "do_mv: pre-existing dir task for %s?! action: %s",
2435             $src, $task_ref->{action}
2436 0         0 );
2437             }
2438              
2439             # Remove the link
2440 2         7 debug(1, 0, "MV: $src -> $dst");
2441              
2442 2         12 my $task = {
2443             action => 'move',
2444             type => 'file',
2445             path => $src,
2446             dest => $dst,
2447             };
2448 2         4 push @{ $self->{tasks} }, $task;
  2         5  
2449              
2450             # FIXME: do we need this for anything?
2451             #$self->{mv_task_for}{$file} = $task;
2452              
2453 2         4 return;
2454             }
2455              
2456              
2457             #############################################################################
2458             #
2459             # End of methods; subroutines follow.
2460             # FIXME: Ideally these should be in a separate module.
2461              
2462              
2463             # ===== PRIVATE SUBROUTINE ===================================================
2464             # Name : internal_error()
2465             # Purpose : output internal error message in a consistent form and die
2466             =over 4
2467              
2468             =item $message => error message to output
2469              
2470             =back
2471              
2472             Returns : n/a
2473             Throws : n/a
2474              
2475             =cut
2476              
2477             sub internal_error {
2478 0     0 0   my ($format, @args) = @_;
2479 0           my $error = sprintf($format, @args);
2480 0           my $stacktrace = Carp::longmess();
2481 0           die <
2482              
2483             $ProgramName: INTERNAL ERROR: $error$stacktrace
2484              
2485             This _is_ a bug. Please submit a bug report so we can fix it! :-)
2486             See http://www.gnu.org/software/stow/ for how to do this.
2487             EOF
2488             }
2489              
2490             =head1 BUGS
2491              
2492             =head1 SEE ALSO
2493              
2494             =cut
2495              
2496             1;
2497              
2498             # Local variables:
2499             # mode: perl
2500             # end:
2501             # vim: ft=perl
2502              
2503             #############################################################################
2504             # Default global list of ignore regexps follows
2505             # (automatically appended by the Makefile)
2506              
2507             __DATA__