diff --git a/NEWS b/NEWS index 3cc5562..3b676da 100644 --- a/NEWS +++ b/NEWS @@ -22,6 +22,16 @@ News file for Stow. Thanks to Joris Vankerschaver for this feature! +*** Shell-like expansion in .stowrc files + + For options within .stowrc files which describe file paths, "~" can + be included to expand to the current value of $HOME, and + environment variables can be referenced e.g. via "$FOO" or + "${FOO}". To prevent expansion, escape with a backslash. + + Thanks a lot to Charles LeDoux for his diligent work on this + feature! + *** chkstow now honours the $STOW_DIR environment variable The stow script already honoured the $STOW_DIR environment diff --git a/bin/stow.in b/bin/stow.in index dd6fb8e..9afe2a1 100755 --- a/bin/stow.in +++ b/bin/stow.in @@ -343,6 +343,28 @@ Stow will re-fold the tree by removing the symlinks to the surviving package, removing the directory, then linking the directory back to the surviving package. +=head1 RESOURCE FILES + +F searches for default command line options at F<.stowrc> (current +directory) and F<~/.stowrc> (home directory) in that order. If both +locations are present, the files are effectively appended together. + +The effect of options in the resource file is similar to simply prepending +the options to the command line. For options that provide a single value, +such as F<--target> or F<--dir>, the command line option will overwrite any +options in the resource file. For options that can be given more than once, +F<--ignore> for example, command line options and resource options are +appended together. + +Environment variables and the tilde character (F<~>) will be expanded for +options that take a file path. + +The options F<-D>, F<-R>, F<-S>, and any packages listed in the resource +file are ignored. + +See the info manual for more information on how stow handles resource +file. + =head1 SEE ALSO The full documentation for F is maintained as a Texinfo manual. @@ -633,7 +655,8 @@ sub check_packages { # Throws : a fatal error if a bad option is given # Comments : Parses the contents of '~/.stowrc' and '.stowrc' with the same # parser as the command line options. Additionally expands any -# environment variables in --target or --dir options. +# environment variables or ~ character in --target or --dir +# options. #============================================================================= sub get_config_file_options { my @defaults = (); @@ -655,16 +678,36 @@ sub get_config_file_options { # Expand environment variables and glob characters. if (exists $rc_options->{target}) { $rc_options->{target} = - expand_environment($rc_options->{target}, '--target option'); + expand_filepath($rc_options->{target}, '--target option'); } if (exists $rc_options->{dir}) { $rc_options->{dir} = - expand_environment($rc_options->{dir}, '--dir option'); + expand_filepath($rc_options->{dir}, '--dir option'); } return ($rc_options, $rc_pkgs_to_unstow, $rc_pkgs_to_stow); } +#===== SUBROUTINE ============================================================ +# Name : expand_filepath() +# Purpose : Handles expansions that need to be applied to +# : file paths. Currently expands environment +# : variables and the tilde. +# Parameters: $path => string to perform expansion on. +# : $source => where the string came from +# Returns : String with replacements performed. +# Throws : n/a +# Comments : n/a +#============================================================================= +sub expand_filepath { + my ($path, $source) = @_; + + $path = expand_environment($path, $source); + $path = expand_tilde($path); + + return $path; +} + #===== SUBROUTINE ============================================================ # Name : expand_environment() # Purpose : Expands evironment variables. @@ -700,6 +743,30 @@ sub _safe_expand_env_var { return $ENV{$var}; } +#===== SUBROUTINE ============================================================ +# Name : expand_tilde() +# Purpose : Expands tilde to user's home directory path. +# Parameters: $path => string to perform expansion on. +# Returns : String with replacements performed. +# Throws : n/a +# Comments : http://docstore.mik.ua/orelly/perl4/cook/ch07_04.htm +#============================================================================= +sub expand_tilde { + my ($path) = @_; + # Replace tilde with home path. + $path =~ s{ ^ ~ ( [^/]* ) } + { $1 + ? (getpwnam($1))[7] + : ( $ENV{HOME} || $ENV{LOGDIR} + || (getpwuid($<))[7] + ) + }ex; + # Replace espaced tilde with regular tilde. + $path =~ s/\\~/~/g; + return $path +} + + #===== SUBROUTINE =========================================================== # Name : usage() # Purpose : print program usage message and exit diff --git a/doc/stow.texi b/doc/stow.texi index 1042ad4..d4e4087 100644 --- a/doc/stow.texi +++ b/doc/stow.texi @@ -881,9 +881,10 @@ directory. Default command line options may be set in @file{.stowrc} (current directory) or @file{~/.stowrc} (home directory). These are parsed in -that order, and effectively prepended to the command line arguments -(with the notable difference that they won't be processed by the shell). -This feature can be used for some interesting effects. +that order, and are appended together if they both exist. The effect of +the options in the resource file is similar to simply prepending the +options to the command line. This feature can be used for some +interesting effects. For example, suppose your site uses more than one stow directory, perhaps in order to share around responsibilities with a number of systems @@ -922,6 +923,22 @@ immediate parent directory @file{/usr/local/stow}), overriding any pre-existing links to bin files or man pages, and ignoring some cruft that gets installed by default. +If an option is provided both on the command line and in a resource file, +the command line option takes precedence. For options that provide a single +value, such as @command{--target} or @command{--dir}, the command line +option will overwrite any options in the resource file. For options that can +be given more than once, @command{--ignore} for example, command line +options and resource options are appended together. + +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. + +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 +resource file. @c =========================================================================== @node Compile-time vs Install-time, Bootstrapping, Resource Files, Top diff --git a/t/rc_options.t b/t/rc_options.t index c6c2061..6905df5 100755 --- a/t/rc_options.t +++ b/t/rc_options.t @@ -7,7 +7,7 @@ use strict; use warnings; -use Test::More tests => 15; +use Test::More tests => 23; use testutil; @@ -107,6 +107,16 @@ delete $ENV{'WITH_UNDERSCORE'}; # Expansion with escaped $ is(expand_environment('\$HOME/stow'), '$HOME/stow', 'expand \$HOME'); +# +# Test tilde (~) expansion +# +# Basic expansion +is(expand_tilde('~/path'), "$ENV{HOME}/path", 'tilde expansion to $HOME'); +# Should not expand if middle of path +is(expand_tilde('/path/~/here'), '/path/~/here', 'middle ~ not expanded'); +# Test escaped ~ +is(expand_tilde('\~/path'), '~/path', 'escaped tilde'); + # # Test that environment variable expansion is applied. # @@ -130,6 +140,29 @@ is_deeply($options->{defer}, [qr(\A\$HOME)], is_deeply($options->{override}, [qr(\A\$HOME)], "environment expansion not applied on --override"); +# +# Test that tilde expansion is applied in correct places. +# +$rc_contents = <<'HERE'; +--dir=~/stow +--target=~/stow +--ignore=~/stow +--defer=~/stow +--override=~/stow +HERE +make_file($RC_FILE, $rc_contents); +($options, $pkgs_to_delete, $pkgs_to_stow) = get_config_file_options(); +is($options->{dir}, "$OUT_DIR/stow", + "apply environment expansion on stowrc --dir"); +is($options->{target}, "$OUT_DIR/stow", + "apply environment expansion on stowrc --target"); +is_deeply($options->{ignore}, [qr(~/stow\z)], + "environment expansion not applied on --ignore"); +is_deeply($options->{defer}, [qr(\A~/stow)], + "environment expansion not applied on --defer"); +is_deeply($options->{override}, [qr(\A~/stow)], + "environment expansion not applied on --override"); + # Clean up files used for testing. # unlink $RC_FILE or die "Unable to clean up $RC_FILE.\n";