Skip to content

Commit

Permalink
Special processing for dotfiles
Browse files Browse the repository at this point in the history
  • Loading branch information
Joris Vankerschaver committed Oct 4, 2016
1 parent c171ca8 commit 182acbb
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 3 deletions.
1 change: 1 addition & 0 deletions MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ t/chkstow.t
t/cleanup_invalid_links.t
t/cli_options.t
t/defer.t
t/dotfiles.t
t/examples.t
t/find_stowed_path.t
t/foldable.t
Expand Down
18 changes: 17 additions & 1 deletion bin/stow.in
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,22 @@ stowed to another package.
Force stowing files beginning with this Perl regex if the file is
already stowed to another package.
=item --dotfiles
Enable special handling for "dotfiles" (files or folders whose name
begins with a period) in the package directory. If this option is
enabled, Stow will add a preprocessing step for each file or folder
whose name begins with "dot-", and replace the "dot-" prefix in the
name by a period (.). This is useful when Stow is used to manage
collections of dotfiles, to avoid having a package directory full of
hidden files.
For example, suppose we have a package containing two files,
F<stow/dot-bashrc> and F<stow/dot-emacs.d/init.el>. With this option,
Stow will create symlinks from F<.bashrc> to F<stow/dot-bashrc> and
from F<.emacs.d/init.el> to F<stow/dot-emacs.d/init.el>. Any other
files, whose name does not begin with "dot-", will be processed as usual.
=item -V
=item --version
Expand Down Expand Up @@ -481,7 +497,7 @@ sub process_options {
\%options,
'verbose|v:+', 'help|h', 'simulate|n|no',
'version|V', 'compat|p', 'dir|d=s', 'target|t=s',
'adopt', 'no-folding',
'adopt', 'no-folding', 'dotfiles',

# clean and pre-compile any regex's at parse time
'ignore=s' =>
Expand Down
23 changes: 22 additions & 1 deletion lib/Stow.pm.in
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ use File::Spec;
use POSIX qw(getcwd);

use Stow::Util qw(set_debug_level debug error set_test_mode
join_paths restore_cwd canon_path parent);
join_paths restore_cwd canon_path parent adjust_dotfile);

our $ProgramName = 'stow';
our $VERSION = '@VERSION@';
Expand All @@ -60,6 +60,7 @@ our %DEFAULT_OPTIONS = (
paranoid => 0,
compat => 0,
test_mode => 0,
dotfiles => 0,
adopt => 0,
'no-folding' => 0,
ignore => [],
Expand Down Expand Up @@ -377,6 +378,13 @@ sub stow_contents {
next NODE if $node eq '..';
my $node_target = join_paths($target, $node);
next NODE if $self->ignore($stow_path, $package, $node_target);

if ($self->{dotfiles}) {
my $adj_node_target = adjust_dotfile($node_target);
debug(4, " Adjusting: $node_target => $adj_node_target");
$node_target = $adj_node_target;
}

$self->stow_node(
$stow_path,
$package,
Expand Down Expand Up @@ -744,6 +752,13 @@ sub unstow_contents {
next NODE if $node eq '..';
my $node_target = join_paths($target, $node);
next NODE if $self->ignore($stow_path, $package, $node_target);

if ($self->{dotfiles}) {
my $adj_node_target = adjust_dotfile($node_target);
debug(4, " Adjusting: $node_target => $adj_node_target");
$node_target = $adj_node_target;
}

$self->unstow_node($stow_path, $package, $node_target);
}
if (-d $target) {
Expand Down Expand Up @@ -801,6 +816,12 @@ sub unstow_node {
# Does the existing $target actually point to anything?
if (-e $existing_path) {
# Does link points to the right place?

# Adjust for dotfile if necessary.
if ($self->{dotfiles}) {
$existing_path = adjust_dotfile($existing_path);
}

if ($existing_path eq $path) {
$self->do_unlink($target);
}
Expand Down
16 changes: 15 additions & 1 deletion lib/Stow/Util.pm.in
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use POSIX qw(getcwd);
use base qw(Exporter);
our @EXPORT_OK = qw(
error debug set_debug_level set_test_mode
join_paths parent canon_path restore_cwd
join_paths parent canon_path restore_cwd adjust_dotfile
);

our $ProgramName = 'stow';
Expand Down Expand Up @@ -193,6 +193,20 @@ sub restore_cwd {
chdir($prev) or error("Your current directory $prev seems to have vanished");
}

sub adjust_dotfile {
my ($target) = @_;

my @result = ();
for my $part (split m{/+}, $target) {
if (($part ne "dot-") && ($part ne "dot-.")) {
$part =~ s/^dot-/./;
}
push @result, $part;
}

return join '/', @result;
}

=head1 BUGS
=head1 SEE ALSO
Expand Down
116 changes: 116 additions & 0 deletions t/dotfiles.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#!/usr/local/bin/perl

#
# Test case for dotfiles special processing
#

use strict;
use warnings;

use testutil;

use Test::More tests => 6;
use English qw(-no_match_vars);

use testutil;

init_test_dirs();
cd("$OUT_DIR/target");

my $stow;

#
# process a dotfile marked with 'dot' prefix
#

$stow = new_Stow(dir => '../stow', dotfiles => 1);

make_dir('../stow/dotfiles');
make_file('../stow/dotfiles/dot-foo');

$stow->plan_stow('dotfiles');
$stow->process_tasks();
is(
readlink('.foo'),
'../stow/dotfiles/dot-foo',
=> 'processed dotfile'
);

#
# ensure that turning off dotfile processing links files as usual
#

$stow = new_Stow(dir => '../stow', dotfiles => 0);

make_dir('../stow/dotfiles');
make_file('../stow/dotfiles/dot-foo');

$stow->plan_stow('dotfiles');
$stow->process_tasks();
is(
readlink('dot-foo'),
'../stow/dotfiles/dot-foo',
=> 'unprocessed dotfile'
);


#
# process folder marked with 'dot' prefix
#

$stow = new_Stow(dir => '../stow', dotfiles => 1);

make_dir('../stow/dotfiles/dot-emacs');
make_file('../stow/dotfiles/dot-emacs/init.el');

$stow->plan_stow('dotfiles');
$stow->process_tasks();
is(
readlink('.emacs'),
'../stow/dotfiles/dot-emacs',
=> 'processed dotfile folder'
);

#
# corner case: paths that have a part in them that's just "$DOT_PREFIX" or
# "$DOT_PREFIX." should not have that part expanded.
#

$stow = new_Stow(dir => '../stow', dotfiles => 1);

make_dir('../stow/dotfiles');
make_file('../stow/dotfiles/dot-');

make_dir('../stow/dotfiles/dot-.');
make_file('../stow/dotfiles/dot-./foo');

$stow->plan_stow('dotfiles');
$stow->process_tasks();
is(
readlink('dot-'),
'../stow/dotfiles/dot-',
=> 'processed dotfile'
);
is(
readlink('dot-.'),
'../stow/dotfiles/dot-.',
=> 'unprocessed dotfile'
);

#
# simple unstow scenario
#

$stow = new_Stow(dir => '../stow', dotfiles => 1);

make_dir('../stow/dotfiles');
make_file('../stow/dotfiles/dot-bar');
make_link('.bar', '../stow/dotfiles/dot-bar');

$stow->plan_unstow('dotfiles');
$stow->process_tasks();
ok(
$stow->get_conflict_count == 0 &&
-f '../stow/dotfiles/dot-bar' && ! -e '.bar'
=> 'unstow a simple dotfile'
);

0 comments on commit 182acbb

Please sign in to comment.