3 # This file is part of GNU Stow.
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.
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.
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/.
19 # Test stowing packages.
25 use Test
::More tests
=> 21;
27 use English
qw(-no_match_vars);
29 use Stow
::Util
qw(canon_path set_debug_level);
33 cd
("$TEST_DIR/target");
38 # Note that each of the following tests use a distinct set of files
40 subtest
('stow a simple tree minimally', sub {
42 my $stow = new_Stow
(dir
=> '../stow');
44 make_path
('../stow/pkg1/bin1');
45 make_file
('../stow/pkg1/bin1/file1');
47 $stow->plan_stow('pkg1');
48 $stow->process_tasks();
49 is_deeply
([ $stow->get_conflicts ], [], 'no conflicts with minimal stow');
53 => 'minimal stow of a simple tree'
57 subtest
('stow a simple tree into an existing directory', sub {
59 my $stow = new_Stow
();
61 make_path
('../stow/pkg2/lib2');
62 make_file
('../stow/pkg2/lib2/file2');
65 $stow->plan_stow('pkg2');
66 $stow->process_tasks();
68 readlink('lib2/file2'),
69 '../../stow/pkg2/lib2/file2',
70 => 'stow simple tree to existing directory'
74 subtest
('unfold existing tree', sub {
76 my $stow = new_Stow
();
78 make_path
('../stow/pkg3a/bin3');
79 make_file
('../stow/pkg3a/bin3/file3a');
80 make_link
('bin3' => '../stow/pkg3a/bin3'); # emulate stow
82 make_path
('../stow/pkg3b/bin3');
83 make_file
('../stow/pkg3b/bin3/file3b');
85 $stow->plan_stow('pkg3b');
86 $stow->process_tasks();
88 is
(readlink('bin3/file3a'), '../../stow/pkg3a/bin3/file3a');
89 is
(readlink('bin3/file3b'), '../../stow/pkg3b/bin3/file3b'
90 => 'target already has 1 stowed package');
93 subtest
("Link to a new dir 'bin4' conflicts with existing non-dir so can't unfold", sub {
95 my $stow = new_Stow
();
97 make_file
('bin4'); # this is a file but named like a directory
98 make_path
('../stow/pkg4/bin4');
99 make_file
('../stow/pkg4/bin4/file4');
101 $stow->plan_stow('pkg4');
102 %conflicts = $stow->get_conflicts();
103 is
($stow->get_conflict_count, 1);
104 ok
($conflicts{stow
}{pkg4
}[0] =~
105 qr/existing target is neither a link nor a directory/
106 => 'link to new dir bin4 conflicts with existing non-directory'
110 subtest
("Link to a new dir 'bin4a' conflicts with existing non-dir " .
111 "so can't unfold even with --adopt", sub {
113 #my $stow = new_Stow(adopt => 1);
114 my $stow = new_Stow
();
116 make_file
('bin4a'); # this is a file but named like a directory
117 make_path
('../stow/pkg4a/bin4a');
118 make_file
('../stow/pkg4a/bin4a/file4a');
120 $stow->plan_stow('pkg4a');
121 %conflicts = $stow->get_conflicts();
122 is
($stow->get_conflict_count, 1);
123 like
($conflicts{stow
}{pkg4a
}[0],
124 qr/existing target is neither a link nor a directory/
125 => 'link to new dir bin4a conflicts with existing non-directory'
129 subtest
("Link to files 'file4b' and 'bin4b' conflict with existing files", sub {
131 my $stow = new_Stow
();
134 make_file
('file4b', 'file4b - version originally in target');
136 make_file
('bin4b/file4b', 'bin4b/file4b - version originally in target');
139 make_path
('../stow/pkg4b/bin4b');
140 make_file
('../stow/pkg4b/file4b', 'file4b - version originally in stow package');
141 make_file
('../stow/pkg4b/bin4b/file4b', 'bin4b/file4b - version originally in stow package');
143 $stow->plan_stow('pkg4b');
144 %conflicts = $stow->get_conflicts();
145 is
($stow->get_conflict_count, 2 => 'conflict per file');
148 $conflicts{stow
}{pkg4b
}[$i],
149 qr/existing target is neither a link nor a directory/
150 => 'link to file4b conflicts with existing non-directory'
155 subtest
("Link to files 'file4b' and 'bin4b' do not conflict with existing", sub {
157 my $stow = new_Stow
(adopt
=> 1);
160 make_file
('file4c', "file4c - version originally in target\n");
162 make_file
('bin4c/file4c', "bin4c/file4c - version originally in target\n");
165 make_path
('../stow/pkg4c/bin4c');
166 make_file
('../stow/pkg4c/file4c', "file4c - version originally in stow package\n");
167 make_file
('../stow/pkg4c/bin4c/file4c', "bin4c/file4c - version originally in stow package\n");
169 $stow->plan_stow('pkg4c');
170 is
($stow->get_conflict_count, 0 => 'no conflicts with --adopt');
171 is
($stow->get_tasks, 4 => 'two tasks per file');
172 $stow->process_tasks();
173 for my $file ('file4c', 'bin4c/file4c') {
174 ok
(-l
$file, "$file turned into a symlink");
177 (index($file, '/') == -1 ?
'' : '../' )
178 . "../stow/pkg4c/$file" => "$file points to right place"
180 is
(cat_file
($file), "$file - version originally in target\n" => "$file has right contents");
185 subtest
("Target already exists but is not owned by stow", sub {
187 my $stow = new_Stow
();
190 make_invalid_link
('bin5/file5','../../empty');
191 make_path
('../stow/pkg5/bin5/file5');
193 $stow->plan_stow('pkg5');
194 %conflicts = $stow->get_conflicts();
196 $conflicts{stow
}{pkg5
}[-1],
197 qr/not owned by stow/
198 => 'target already exists but is not owned by stow'
202 subtest
("Replace existing but invalid target", sub {
204 my $stow = new_Stow
();
206 make_invalid_link
('file6','../stow/path-does-not-exist');
207 make_path
('../stow/pkg6');
208 make_file
('../stow/pkg6/file6');
210 $stow->plan_stow('pkg6');
211 $stow->process_tasks();
215 => 'replace existing but invalid target'
219 subtest
("Target already exists, is owned by stow, but points to a non-directory", sub {
221 my $stow = new_Stow
();
225 make_path
('../stow/pkg7a/bin7');
226 make_file
('../stow/pkg7a/bin7/node7');
227 make_link
('bin7/node7','../../stow/pkg7a/bin7/node7');
228 make_path
('../stow/pkg7b/bin7/node7');
229 make_file
('../stow/pkg7b/bin7/node7/file7');
231 $stow->plan_stow('pkg7b');
232 %conflicts = $stow->get_conflicts();
234 $conflicts{stow
}{pkg7b
}[-1],
235 qr/existing target is stowed to a different package/
236 => 'link to new dir conflicts with existing stowed non-directory'
240 subtest
("stowing directories named 0", sub {
242 my $stow = new_Stow
();
244 make_path
('../stow/pkg8a/0');
245 make_file
('../stow/pkg8a/0/file8a');
246 make_link
('0' => '../stow/pkg8a/0'); # emulate stow
248 make_path
('../stow/pkg8b/0');
249 make_file
('../stow/pkg8b/0/file8b');
251 $stow->plan_stow('pkg8b');
252 $stow->process_tasks();
253 is
($stow->get_conflict_count, 0);
255 is
(readlink('0/file8a'), '../../stow/pkg8a/0/file8a');
256 is
(readlink('0/file8b'), '../../stow/pkg8b/0/file8b'
257 => 'stowing directories named 0'
261 subtest
("overriding already stowed documentation", sub {
263 my $stow = new_Stow
(override
=> ['man9', 'info9']);
265 make_path
('../stow/pkg9a/man9/man1');
266 make_file
('../stow/pkg9a/man9/man1/file9.1');
267 make_path
('man9/man1');
268 make_link
('man9/man1/file9.1' => '../../../stow/pkg9a/man9/man1/file9.1'); # emulate stow
270 make_path
('../stow/pkg9b/man9/man1');
271 make_file
('../stow/pkg9b/man9/man1/file9.1');
273 $stow->plan_stow('pkg9b');
274 $stow->process_tasks();
275 is
($stow->get_conflict_count, 0);
276 is
(readlink('man9/man1/file9.1'), '../../../stow/pkg9b/man9/man1/file9.1'
277 => 'overriding existing documentation files'
281 subtest
("deferring to already stowed documentation", sub {
283 my $stow = new_Stow
(defer
=> ['man10', 'info10']);
285 make_path
('../stow/pkg10a/man10/man1');
286 make_file
('../stow/pkg10a/man10/man1/file10.1');
287 make_path
('man10/man1');
288 make_link
('man10/man1/file10.1' => '../../../stow/pkg10a/man10/man1/file10.1'); # emulate stow
290 make_path
('../stow/pkg10b/man10/man1');
291 make_file
('../stow/pkg10b/man10/man1/file10.1');
293 $stow->plan_stow('pkg10b');
294 is
($stow->get_tasks, 0, 'no tasks to process');
295 is
($stow->get_conflict_count, 0);
296 is
(readlink('man10/man1/file10.1'), '../../../stow/pkg10a/man10/man1/file10.1'
297 => 'defer to existing documentation files'
301 subtest
("Ignore temp files", sub {
303 my $stow = new_Stow
(ignore
=> ['~', '\.#.*']);
305 make_path
('../stow/pkg11/man11/man1');
306 make_file
('../stow/pkg11/man11/man1/file11.1');
307 make_file
('../stow/pkg11/man11/man1/file11.1~');
308 make_file
('../stow/pkg11/man11/man1/.#file11.1');
309 make_path
('man11/man1');
311 $stow->plan_stow('pkg11');
312 $stow->process_tasks();
313 is
($stow->get_conflict_count, 0);
314 is
(readlink('man11/man1/file11.1'), '../../../stow/pkg11/man11/man1/file11.1');
315 ok
(!-e
'man11/man1/file11.1~');
316 ok
(!-e
'man11/man1/.#file11.1'
317 => 'ignore temp files'
321 subtest
("stowing links library files", sub {
323 my $stow = new_Stow
();
325 make_path
('../stow/pkg12/lib12/');
326 make_file
('../stow/pkg12/lib12/lib.so.1');
327 make_link
('../stow/pkg12/lib12/lib.so', 'lib.so.1');
331 $stow->plan_stow('pkg12');
332 $stow->process_tasks();
333 is
($stow->get_conflict_count, 0);
334 is
(readlink('lib12/lib.so.1'), '../../stow/pkg12/lib12/lib.so.1');
335 is
(readlink('lib12/lib.so'), '../../stow/pkg12/lib12/lib.so'
336 => 'stow links to libraries'
340 subtest
("unfolding to stow links to library files", sub {
342 my $stow = new_Stow
();
344 make_path
('../stow/pkg13a/lib13/');
345 make_file
('../stow/pkg13a/lib13/liba.so.1');
346 make_link
('../stow/pkg13a/lib13/liba.so', 'liba.so.1');
347 make_link
('lib13','../stow/pkg13a/lib13');
349 make_path
('../stow/pkg13b/lib13/');
350 make_file
('../stow/pkg13b/lib13/libb.so.1');
351 make_link
('../stow/pkg13b/lib13/libb.so', 'libb.so.1');
353 $stow->plan_stow('pkg13b');
354 $stow->process_tasks();
355 is
($stow->get_conflict_count, 0);
356 is
(readlink('lib13/liba.so.1'), '../../stow/pkg13a/lib13/liba.so.1');
357 is
(readlink('lib13/liba.so' ), '../../stow/pkg13a/lib13/liba.so');
358 is
(readlink('lib13/libb.so.1'), '../../stow/pkg13b/lib13/libb.so.1');
359 is
(readlink('lib13/libb.so' ), '../../stow/pkg13b/lib13/libb.so'
360 => 'unfolding to stow links to libraries'
364 subtest
("stowing to stow dir should fail", sub {
367 $stow = new_Stow
(dir
=> 'stow');
369 make_path
('stow/pkg14/stow/pkg15');
370 make_file
('stow/pkg14/stow/pkg15/node15');
373 $stow->plan_stow('pkg14');
374 is
($stow->get_tasks, 0, 'no tasks to process');
375 is
($stow->get_conflict_count, 0);
378 => "stowing to stow dir should fail"
381 qr/WARNING: skipping target which was current stow directory stow/
382 => "stowing to stow dir should give warning");
386 subtest
("stow a simple tree minimally when cwd isn't target", sub {
389 $stow = new_Stow
(dir
=> "$TEST_DIR/stow", target
=> "$TEST_DIR/target");
391 make_path
("$TEST_DIR/stow/pkg16/bin16");
392 make_file
("$TEST_DIR/stow/pkg16/bin16/file16");
394 $stow->plan_stow('pkg16');
395 $stow->process_tasks();
396 is_deeply
([ $stow->get_conflicts ], [], 'no conflicts with minimal stow');
398 readlink("$TEST_DIR/target/bin16"),
399 '../stow/pkg16/bin16',
400 => "minimal stow of a simple tree when cwd isn't target"
404 subtest
("stow a simple tree minimally to absolute stow dir when cwd isn't", sub {
406 my $stow = new_Stow
(dir
=> canon_path
("$TEST_DIR/stow"),
407 target
=> "$TEST_DIR/target");
409 make_path
("$TEST_DIR/stow/pkg17/bin17");
410 make_file
("$TEST_DIR/stow/pkg17/bin17/file17");
412 $stow->plan_stow('pkg17');
413 $stow->process_tasks();
414 is_deeply
([ $stow->get_conflicts ], [], 'no conflicts with minimal stow');
416 readlink("$TEST_DIR/target/bin17"),
417 '../stow/pkg17/bin17',
418 => "minimal stow of a simple tree with absolute stow dir"
422 subtest
("stow a simple tree minimally with absolute stow AND target dirs when", sub {
424 my $stow = new_Stow
(dir
=> canon_path
("$TEST_DIR/stow"),
425 target
=> canon_path
("$TEST_DIR/target"));
427 make_path
("$TEST_DIR/stow/pkg18/bin18");
428 make_file
("$TEST_DIR/stow/pkg18/bin18/file18");
430 $stow->plan_stow('pkg18');
431 $stow->process_tasks();
432 is_deeply
([ $stow->get_conflicts ], [], 'no conflicts with minimal stow');
434 readlink("$TEST_DIR/target/bin18"),
435 '../stow/pkg18/bin18',
436 => "minimal stow of a simple tree with absolute stow and target dirs"
440 subtest
("stow a tree with no-folding enabled", sub {
442 # folded directories should be split open (unfolded) where
443 # (and only where) necessary
445 cd
("$TEST_DIR/target");
450 my $stow_pkg = "../stow/$id-$pkg";
451 make_path
($stow_pkg);
452 make_file
("$stow_pkg/$id-file-$pkg");
454 # create a shallow hierarchy specific to this package which isn't
456 make_path
("$stow_pkg/$id-$pkg-only-new");
457 make_file
("$stow_pkg/$id-$pkg-only-new/$id-file-$pkg");
459 # create a deeper hierarchy specific to this package which isn't
461 make_path
("$stow_pkg/$id-$pkg-only-new2/subdir");
462 make_file
("$stow_pkg/$id-$pkg-only-new2/subdir/$id-file-$pkg");
463 make_link
("$stow_pkg/$id-$pkg-only-new2/current", "subdir");
465 # create a hierarchy specific to this package which is already
466 # stowed via a folded tree
467 make_path
("$stow_pkg/$id-$pkg-only-old");
468 make_link
("$id-$pkg-only-old", "$stow_pkg/$id-$pkg-only-old");
469 make_file
("$stow_pkg/$id-$pkg-only-old/$id-file-$pkg");
471 # create a shared hierarchy which this package uses
472 make_path
("$stow_pkg/$id-shared");
473 make_file
("$stow_pkg/$id-shared/$id-file-$pkg");
475 # create a partially shared hierarchy which this package uses
476 make_path
("$stow_pkg/$id-shared2/subdir-$pkg");
477 make_file
("$stow_pkg/$id-shared2/$id-file-$pkg");
478 make_file
("$stow_pkg/$id-shared2/subdir-$pkg/$id-file-$pkg");
481 foreach my $pkg (qw{a b
}) {
482 create_pkg
('no-folding', $pkg);
485 $stow = new_Stow
('no-folding' => 1);
486 $stow->plan_stow('no-folding-a');
487 is_deeply
([ $stow->get_conflicts ], [] => 'no conflicts with --no-folding');
488 my @tasks = $stow->get_tasks;
490 is
(scalar(@tasks), 13 => "6 dirs, 7 links") || warn Dumper
(\
@tasks);
491 $stow->process_tasks();
493 sub check_no_folding
{
495 my $stow_pkg = "../stow/no-folding-$pkg";
496 is_link
("no-folding-file-$pkg", "$stow_pkg/no-folding-file-$pkg");
498 # check existing folded tree is untouched
499 is_link
("no-folding-$pkg-only-old", "$stow_pkg/no-folding-$pkg-only-old");
501 # check newly stowed shallow tree is not folded
502 is_dir_not_symlink
("no-folding-$pkg-only-new");
503 is_link
("no-folding-$pkg-only-new/no-folding-file-$pkg",
504 "../$stow_pkg/no-folding-$pkg-only-new/no-folding-file-$pkg");
506 # check newly stowed deeper tree is not folded
507 is_dir_not_symlink
("no-folding-$pkg-only-new2");
508 is_dir_not_symlink
("no-folding-$pkg-only-new2/subdir");
509 is_link
("no-folding-$pkg-only-new2/subdir/no-folding-file-$pkg",
510 "../../$stow_pkg/no-folding-$pkg-only-new2/subdir/no-folding-file-$pkg");
511 is_link
("no-folding-$pkg-only-new2/current",
512 "../$stow_pkg/no-folding-$pkg-only-new2/current");
514 # check shared tree is not folded. first time round this will be
516 is_dir_not_symlink
('no-folding-shared');
517 is_link
("no-folding-shared/no-folding-file-$pkg",
518 "../$stow_pkg/no-folding-shared/no-folding-file-$pkg");
520 # check partially shared tree is not folded. first time round this
521 # will be newly stowed.
522 is_dir_not_symlink
('no-folding-shared2');
523 is_link
("no-folding-shared2/no-folding-file-$pkg",
524 "../$stow_pkg/no-folding-shared2/no-folding-file-$pkg");
525 is_link
("no-folding-shared2/no-folding-file-$pkg",
526 "../$stow_pkg/no-folding-shared2/no-folding-file-$pkg");
529 check_no_folding
('a');
531 $stow = new_Stow
('no-folding' => 1);
532 $stow->plan_stow('no-folding-b');
533 is_deeply
([ $stow->get_conflicts ], [] => 'no conflicts with --no-folding');
534 @tasks = $stow->get_tasks;
535 is
(scalar(@tasks), 11 => '4 dirs, 7 links') || warn Dumper
(\
@tasks);
536 $stow->process_tasks();
538 check_no_folding
('a');
539 check_no_folding
('b');