Browse Source

add --dry-run and basename collision-checking to mark-mv & mark-cp

Adds App::MarkFile::check_collisions().  Right now this just bails if
something would be weird.  An option to solve interactively is probably
a good idea, but for now this will at least prevent the obvious
foot-shooting case.

Of course it should probably also list the overlapping source paths...
master
Brennen Bearnes 2 years ago
parent
commit
bf21b27d24
3 changed files with 76 additions and 25 deletions
  1. +23
    -1
      bin/mark-cp
  2. +28
    -23
      bin/mark-mv
  3. +25
    -1
      lib/App/MarkFiles.pm

+ 23
- 1
bin/mark-cp View File

@ -4,12 +4,29 @@ use warnings;
use strict;
use 5.10.0;
use App::MarkFiles qw(each_path);
use App::MarkFiles qw(each_path check_collisions);
use File::Basename;
use File::Copy;
use File::Spec;
use Getopt::Long;
my $dry_run;
GetOptions(
'no-action|dry-run|n' => \$dry_run,
help => sub { pod2usage(0) },
) or pod2usage(2);
my (@collisions) = check_collisions();
if (scalar @collisions) {
# We got something. Alert the user and bail.
say "Multiple marked paths would be copied to the following filenames:";
say join "\n", @collisions;
say "";
say "No action taken, since this probably isn't what you want.";
exit(1);
}
each_path(sub {
my ($path) = @_;
@ -26,6 +43,11 @@ each_path(sub {
# See mark-mv for some discussion of what happens if target exists.
}
if ($dry_run) {
say "Would copy: $path";
return;
}
if (copy($path, './')) {
say "Copied: $path";
} else {

+ 28
- 23
bin/mark-mv View File

@ -4,14 +4,30 @@ use warnings;
use strict;
use 5.10.0;
use App::MarkFiles qw(each_path remove);
use App::MarkFiles qw(each_path remove check_collisions);
use File::Basename;
use File::Copy;
use File::Spec;
use Getopt::Long;
use Pod::Usage;
my @unmark;
my $dry_run;
GetOptions(
'no-action|dry-run|n' => \$dry_run,
help => sub { pod2usage(0) },
) or pod2usage(2);
my (@collisions) = check_collisions();
if (scalar @collisions) {
# We got something. Alert the user and bail.
say "Multiple marked paths would move to the following filenames:";
say join "\n", @collisions;
say "";
say "No action taken, since this probably isn't what you want.";
exit(1);
}
my @unmark;
each_path(sub {
my ($path) = @_;
@ -25,27 +41,12 @@ each_path(sub {
if (-e $target) {
say "Warning: $path will overwrite $target";
}
# So here's the question. What do we do if the target exists?
#
# There are a couple of cases here:
#
# 1. Our mark list contains a file of the same name as something already in
# the destination directory.
#
# 2. Our mark list contains the same filename more than once.
#
# These seem like distinct problems, to a degree. #1 is effectively
# standard unix behavior, and I'm not sure we need to protect the user from
# it unless they ask us to with a -i option or something. #2 is more
# problematic. No matter what you do, you're likely to wind up with
# unexpected outcomes.
#
# We could refuse to operate unless a "rename duplicates" option is
# invoked, or just interactively solve each collision. This seems most
# pressing for mark-mv, since it could easily result in data loss by
# cascading a set of moves where you wind up with just one source file
# left anywhere.
if ($dry_run) {
say "Would move: $path";
push @unmark, $path;
return;
}
if (move($path, $target)) {
@ -56,4 +57,8 @@ each_path(sub {
}
});
remove(@unmark);
if ($dry_run) {
say "Would remove marks from: " . join ', ', @unmark;
} else {
remove(@unmark);
}

+ 25
- 1
lib/App/MarkFiles.pm View File

@ -62,11 +62,12 @@ use strict;
use warnings;
use base qw(Exporter);
our @EXPORT_OK = qw(get_dbh each_path add remove);
our @EXPORT_OK = qw(get_dbh each_path add remove check_collisions);
our ($VERSION) = '0.0.1';
use DBI;
use File::Basename;
use File::HomeDir;
use File::Spec;
@ -181,6 +182,29 @@ sub each_path {
}
}
=item check_collisions()
Return a list of basenames which would collide from the current list.
=cut
sub check_collisions {
# Accumulate a list of basenames:
my %basenames;
each_path(sub {
my ($path) = @_;
my ($source_basename, $source_path) = fileparse($path);
$basenames{ $source_basename }++;
});
my @collisions;
while(my($basename, $count) = each %basenames) {
push @collisions, $basename if 1 < $count;
}
return @collisions;
}
=back
=head1 AUTHOR

Loading…
Cancel
Save