From f0ec80f3a4fc588944a6ad070241d4aa4bbf188d Mon Sep 17 00:00:00 2001 From: Adam Spiers Date: Sat, 15 Jun 2024 13:03:07 +0100 Subject: [PATCH] Fix parsing of regexp options like --override=bin|man Previously the \A and \z anchoring for --ignore / --override / --defer was being applied without wrapping the user-specified regexp in parentheses, so if it was something like bin|man then the anchor would only apply to one half of those two paths. So add parentheses, and also change from qr() to qr{} syntax to visually differentiate between regexp boundaries and parentheses inside the regexp. --- bin/stow.in | 6 +++--- t/cli_options.t | 6 +++--- t/rc_options.t | 24 +++++++++++++++--------- 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/bin/stow.in b/bin/stow.in index c4654d0..5e4da93 100755 --- a/bin/stow.in +++ b/bin/stow.in @@ -582,19 +582,19 @@ sub parse_options { 'ignore=s' => sub { my $regex = $_[1]; - push @{$options{ignore}}, qr($regex\z); + push @{$options{ignore}}, qr{($regex)\z}; }, 'override=s' => sub { my $regex = $_[1]; - push @{$options{override}}, qr(\A$regex); + push @{$options{override}}, qr{\A($regex)}; }, 'defer=s' => sub { my $regex = $_[1]; - push @{$options{defer}}, qr(\A$regex); + push @{$options{defer}}, qr{\A($regex)}; }, # a little craziness so we can do different actions on the same line: diff --git a/t/cli_options.t b/t/cli_options.t index 8b73bf5..7c8a253 100755 --- a/t/cli_options.t +++ b/t/cli_options.t @@ -73,7 +73,7 @@ local @ARGV = ( 'dummy' ); ($options, $pkgs_to_delete, $pkgs_to_stow) = process_options(); -is_deeply($options->{defer}, [ qr(\Aman), qr(\Ainfo) ] => 'defer man and info'); +is_deeply($options->{defer}, [ qr{\A(man)}, qr{\A(info)} ] => 'defer man and info'); # # Check setting override paths @@ -84,7 +84,7 @@ local @ARGV = ( 'dummy' ); ($options, $pkgs_to_delete, $pkgs_to_stow) = process_options(); -is_deeply($options->{override}, [qr(\Aman), qr(\Ainfo)] => 'override man and info'); +is_deeply($options->{override}, [qr{\A(man)}, qr{\A(info)}] => 'override man and info'); # # Check setting ignored paths @@ -95,7 +95,7 @@ local @ARGV = ( 'dummy' ); ($options, $pkgs_to_delete, $pkgs_to_stow) = process_options(); -is_deeply($options->{ignore}, [ qr(~\z), qr(\.#.*\z) ] => 'ignore temp files'); +is_deeply($options->{ignore}, [ qr{(~)\z}, qr{(\.#.*)\z} ] => 'ignore temp files'); # # Check that expansion not applied. diff --git a/t/rc_options.t b/t/rc_options.t index 5e1a2d7..ef00ead 100755 --- a/t/rc_options.t +++ b/t/rc_options.t @@ -153,7 +153,7 @@ is($options->{target}, "$ABS_TEST_DIR/target" => "--target overridden by \$PWD/.stowrc"); is($options->{dir}, "$ABS_TEST_DIR/stow" => "-d overridden \$PWD/.stowrc"); -is_deeply($options->{defer}, [qr(\Ainfo), qr(\Aman)], +is_deeply($options->{defer}, [qr{\A(info)}, qr{\A(man)}], 'defer man and info'); unlink($CWD_RC_FILE) or die "Failed to unlink $CWD_RC_FILE"; @@ -179,7 +179,7 @@ make_file($HOME_RC_FILE, <{defer}, [qr(\Ainfo), qr(\Aman)], +is_deeply($options->{defer}, [qr{\A(info)}, qr{\A(man)}], 'defer man and info'); # ======== Filepath Expansion Tests ======== @@ -229,24 +229,30 @@ is(expand_tilde('\~/path'), '~/path', 'escaped tilde'); # # Test that environment variable expansion is applied unless quoted. +# Include examples from the manual # make_file($HOME_RC_FILE, <<'HERE'); --dir=$HOME/stow --target="$HOME/dir with space in/file with space in" --ignore=\\$FOO\\$ +--defer="foo\\b.*bar" --defer="\\.jpg\$" ---override=\\.jpg\$ +--override=\\.png\$ +--override=bin|man +--ignore='perllocal\.pod' +--ignore='\.packlist' +--ignore='\.bs' HERE ($options, $pkgs_to_delete, $pkgs_to_stow) = get_config_file_options(); is($options->{dir}, "$ABS_TEST_DIR/stow", "apply environment expansion on --dir"); is($options->{target}, "$ABS_TEST_DIR/dir with space in/file with space in", "apply environment expansion on --target"); -is_deeply($options->{ignore}, [qr(\$FOO\$\z)], +is_deeply($options->{ignore}, [qr{(\$FOO\$)\z}, qr{(perllocal\.pod)\z}, qr{(\.packlist)\z}, qr{(\.bs)\z}], 'environment expansion not applied on --ignore but backslash removed'); -is_deeply($options->{defer}, [qr(\A\.jpg$)], +is_deeply($options->{defer}, [qr{\A(foo\b.*bar)}, qr{\A(\.jpg$)}], 'environment expansion not applied on --defer but backslash removed'); -is_deeply($options->{override}, [qr(\A\.jpg$)], +is_deeply($options->{override}, [qr{\A(\.png$)}, qr{\A(bin|man)}], 'environment expansion not applied on --override but backslash removed'); # @@ -264,11 +270,11 @@ is($options->{dir}, "$ABS_TEST_DIR/stow", "apply tilde expansion on \$HOME/.stowrc --dir"); is($options->{target}, "$ABS_TEST_DIR/stow", "apply tilde expansion on \$HOME/.stowrc --target"); -is_deeply($options->{ignore}, [qr(~/stow\z)], +is_deeply($options->{ignore}, [qr{(~/stow)\z}], "tilde expansion not applied on --ignore"); -is_deeply($options->{defer}, [qr(\A~/stow)], +is_deeply($options->{defer}, [qr{\A(~/stow)}], "tilde expansion not applied on --defer"); -is_deeply($options->{override}, [qr(\A~/stow)], +is_deeply($options->{override}, [qr{\A(~/stow)}], "tilde expansion not applied on --override"); #