Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use shellwords for .stowrc parsing #111

Merged
merged 2 commits into from
Jun 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions bin/stow.in
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,7 @@ require 5.006_001;
use POSIX qw(getcwd);
use Getopt::Long qw(GetOptionsFromArray);
use Scalar::Util qw(reftype);
use Text::ParseWords qw(shellwords);

@USE_LIB_PMDIR@
use Stow;
Expand Down Expand Up @@ -581,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:
Expand Down Expand Up @@ -683,7 +684,7 @@ sub get_config_file_options {
or die "Could not open $file for reading\n";
while (my $line = <$FILE>){
chomp $line;
push @defaults, split " ", $line;
push @defaults, shellwords($line);
}
close $FILE or die "Could not close open file: $file\n";
}
Expand Down
6 changes: 5 additions & 1 deletion doc/stow.texi
Original file line number Diff line number Diff line change
Expand Up @@ -1016,7 +1016,11 @@ For options that take a file path, environment variables and the tilde
character (@command{~}) are expanded. An environment variable can be
given in either the @command{$VAR} or @command{$@{VAR@}} form. To
prevent expansion, escape the @command{$} or @command{~} with a
backslash.
backslash. Since these values are first subject to standard shell
quoting rules, if you want special characters such as @command{\b} or
@command{$} to be treated as regular expression assertions then they
will need extra escaping, i.e. @command{\\b} and @command{\\\$}
respectively.

The options @command{-D}, @command{-S}, and @command{-R} are ignored in
resource files. This is also true of any package names given in the
Expand Down
6 changes: 3 additions & 3 deletions t/cli_options.t
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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.
Expand Down
64 changes: 41 additions & 23 deletions t/rc_options.t
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
use strict;
use warnings;

use Test::More tests => 34;
use Test::More tests => 35;

use testutil;

Expand Down Expand Up @@ -102,7 +102,7 @@ HERE

($options, $pkgs_to_delete, $pkgs_to_stow) = process_options();
is($options->{target}, "../target", "--target from \$HOME/.stowrc");
is($options->{dir}, "../stow", "-d from \$HOME/.stowrc");
is($options->{dir}, "../stow", "-d ../stow from \$HOME/.stowrc");

#
# Test ~/.stowrc file with one absolute option per line.
Expand All @@ -117,7 +117,20 @@ HERE
is($options->{target}, "$ABS_TEST_DIR/target"
=> "--target from \$HOME/.stowrc");
is($options->{dir}, "$ABS_TEST_DIR/stow"
=> "-d from \$HOME/.stowrc");
=> "-d $ABS_TEST_DIR/stow from \$HOME/.stowrc");

#
# Test ~/.stowrc file with with options with paths containing spaces.
#
local @ARGV = ('dummy');
make_file($HOME_RC_FILE, <<HERE);
-d "$ABS_TEST_DIR/stow directory"
--target "$ABS_TEST_DIR/target"
HERE

($options, $pkgs_to_delete, $pkgs_to_stow) = process_options();
is($options->{dir}, "$ABS_TEST_DIR/stow directory",
=> "-d from \$HOME/.stowrc with spaces");

#
# Test that some but not all options ~/.stowrc file are overridden by
Expand All @@ -140,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";

Expand All @@ -166,7 +179,7 @@ make_file($HOME_RC_FILE, <<HERE);
--defer=info
HERE
($options, $pkgs_to_delete, $pkgs_to_stow) = process_options();
is_deeply($options->{defer}, [qr(\Ainfo), qr(\Aman)],
is_deeply($options->{defer}, [qr{\A(info)}, qr{\A(man)}],
'defer man and info');

# ======== Filepath Expansion Tests ========
Expand Down Expand Up @@ -215,26 +228,32 @@ is(expand_tilde('/path/~/here'), '/path/~/here', 'middle ~ not expanded');
is(expand_tilde('\~/path'), '~/path', 'escaped tilde');

#
# Test that environment variable expansion is applied.
# 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/stow
--ignore=\$HOME
--defer=\$HOME
--override=\$HOME
--target="$HOME/dir with space in/file with space in"
--ignore=\\$FOO\\$
--defer="foo\\b.*bar"
--defer="\\.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 \$HOME/.stowrc --dir");
is($options->{target}, "$ABS_TEST_DIR/stow",
"apply environment expansion on \$HOME/.stowrc --target");
is_deeply($options->{ignore}, [qr(\$HOME\z)],
"environment expansion not applied on --ignore");
is_deeply($options->{defer}, [qr(\A\$HOME)],
"environment expansion not applied on --defer");
is_deeply($options->{override}, [qr(\A\$HOME)],
"environment expansion not applied on --override");
"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}, 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(foo\b.*bar)}, qr{\A(\.jpg$)}],
'environment expansion not applied on --defer but backslash removed');
is_deeply($options->{override}, [qr{\A(\.png$)}, qr{\A(bin|man)}],
'environment expansion not applied on --override but backslash removed');

#
# Test that tilde expansion is applied in correct places.
Expand All @@ -251,16 +270,15 @@ 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");

#
# Clean up files used for testing.
#
unlink $HOME_RC_FILE or die "Unable to clean up $HOME_RC_FILE.\n";
remove_dir($ABS_TEST_DIR);

2 changes: 1 addition & 1 deletion t/testutil.pm
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ sub init_test_dirs {
# Create a run_from/ subdirectory for tests which want to run
# from a separate directory outside the Stow directory or
# target directory.
for my $dir ("target", "stow", "run_from") {
for my $dir ("target", "stow", "run_from", "stow directory") {
my $path = "$test_dir/$dir";
-d $path and remove_tree($path);
make_path($path);
Expand Down
Loading