App-perlmv-u
view release on metacpan or search on metacpan
lib/App/perlmv/u.pm view on Meta::CPAN
return [];
}
}
sub _write_undo_file {
require Sereal::Encoder;
my $path = _undo_file_path();
open my $fh, ">", $path
or die "perlmv-u: Can't open undo file '$path' for writing: $!\n";
print $fh Sereal::Encoder::encode_sereal($_[0]);
close $fh or die "perlmv-u: Can't write undo file '$path': $!\n";
}
$SPEC{move_multiple} = {
v => 1.1,
args => {
file_pairs => {
summary => 'Pairs of [source, target]',
schema => ['array*', {
of=>['array*', elems=>['pathname*', 'pathname*']],
}],
req => 1,
pos => 0,
greedy => 1,
description => <<'_',
Both `source` and `target` must be absolute paths.
_
},
},
features => {
tx => {v=>2},
idempotent => 1,
dry_run => 1,
},
};
sub move_multiple {
require File::Util::Test;
my %args = @_;
my $tx_action = $args{-tx_action};
if ($tx_action eq 'check_state') {
my (%src, %dest, %exists);
for my $pair (@{ $args{pairs} }) {
my ($src, $dest) = @$pair;
$src {$src}++;
$dest{$dest}++;
for my $k ($src, $dest) {
unless (exists $exists{$k}) {
$exists{$k} = File::Util::Test::file_exists($k);
}
}
}
my $all_dest_exist = 1;
for (keys %dest) {
unless ($exists{$_}) { $all_dest_exist = 0; last }
}
my $all_src_not_in_dest_not_exist = 1;
for (keys %src) {
next if $dest{$_};
if ($exists{$_}) { $all_src_not_in_dest_not_exist = 0; last }
}
if ($all_dest_exist && $all_src_not_in_dest_not_exist) {
# fixed
return [304, "All sources do not exist and ".
"all targets already exist"];
}
my $all_src_exist = 1;
for (keys %src) {
unless ($exists{$_}) { $all_src_exist = 0; last }
}
my $all_dest_not_in_src_not_exist = 1;
for (keys %dest) {
next if $src{$_};
if ($exists{$_}) { $all_dest_not_in_src_not_exist = 0; last }
}
if ($all_src_exist && $all_dest_not_in_src_not_exist) {
# fixable
my @do_actions;
my @undo_actions;
my @pairs;
for my $pair (reverse @{ $args{pairs} }) {
push @pairs, [$pair->[1] => $pair->[0]];
}
push @do_actions , ['move_multiple', {pairs => $args{pairs}}];
push @undo_actions, ['move_multiple', {pairs => \@pairs}];
return [200, "OK", undef, {
do_actions =>\@do_actions,
undo_actions=>\@undo_actions}];
} else {
# not fixable
return [412, "Either some sources do not exist or ".
"some targets exist already"];
}
} elsif ($tx_action eq 'fix_state') {
for my $pair (@{ $args{pairs} }) {
my ($src, $dest) = @$pair;
log_info("Renaming %s -> %s ...", $src, $dest);
unless (rename $src, $dest) {
if ($args{_ignore_errors}) {
warn "Can't rename '$src' -> '$dest': $!, skipped\n" if $!;
} else {
return [500, "Can't rename '$src' -> '$dest': $!"] if $!;
}
}
}
[200, "OK"];
} else {
return [400, "Invalid -tx_action"];
}
}
$SPEC{perlmv} = {
v => 1.1,
summary => 'Rename files using Perl code, with undo/redo',
args => {
eval => {
summary => 'Perl code to rename file',
schema => 'str*',
cmdline_aliases => {e=>{}},
description => <<'_',
Your Perl code will receive the original filename in `$_` and is expected to
modify it. If it is unmodified, the last expression is used as the new filename.
If it is also the same as the original filename, the file is not renamed.
_
req => 1,
},
files => {
'x.name.is_plural' => 1,
'x.name.singular' => 'file',
schema => ['array*', of=>'pathname*'],
req => 1,
pos => 0,
greedy => 1,
},
( run in 1.578 second using v1.01-cache-2.11-cpan-39bf76dae61 )