Last active
April 20, 2023 17:12
-
-
Save Mons/14e6995f2df67b8855243a31ab7d17a6 to your computer and use it in GitHub Desktop.
Script for changing stored UUID of Tarantool backup files (.snap, .xlog, .vy*)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env perl | |
use 5.010; | |
use strict; | |
use File::Find; | |
use Getopt::Long; | |
sub usage { | |
return <<EOF | |
=============================================================== | |
= Usage = | |
$0 [ -f <from-uuid> ] -t <to-uuid> [ -r ] [ -i <include> ] [ -e <exclude> ] path-to-folders | |
-f set from which uuid to change to avoid errors | |
-t which uuid to write into files | |
-r do real job (by default works in dry run) | |
-i include files by regexp mask. match full path from entry point. ex: -i '\.bak$' | |
-e exclude files by regexp mask. match full path from entry point. ex: -e '\.tmp/' | |
-v be verbose | |
EOF | |
} | |
sub examples { | |
return <<EOF | |
=============================================================== | |
= Examples = | |
$0 -t 00000000-0000-1111-1111-111111111111 -i '\.bak$' | |
About to replace 94873272-47e4-4915-922f-c911c7079bdc to 00000000-0000-1111-1111-111111111111 in 5 files: | |
SNAP: 2, XLOG: 3 | |
Run with -r to change files | |
--------------------------------------------------------------- | |
$0 -t 00000000-0000-1111-1111-111111111111 -i '\.bak$' -v | |
About to replace 94873272-47e4-4915-922f-c911c7079bdc to 00000000-0000-1111-1111-111111111111 in 5 files: | |
./00000000000000000000.xlog | |
./00000000000000000000.snap | |
./xxx/00000000000000000000.xlog | |
./xxx/00000000000000000000.snap | |
./xxx/00000000000000000002.xlog | |
Run with -r to change files | |
--------------------------------------------------------------- | |
$0 -t 00000000-0000-1111-1111-111111111111 -i '\.bak$' -r | |
Replaced 94873272-47e4-4915-922f-c911c7079bdc to 00000000-0000-1111-1111-111111111111 in 5 files: | |
SNAP: 2, XLOG: 3 | |
--------------------------------------------------------------- | |
$0 -t 00000000-0000-1111-1111-111111111111 -i '\.bak$' -r | |
No files to change | |
EOF | |
} | |
unless (@ARGV) { print usage(),examples(); exit; }; | |
my $from; | |
my $to; | |
my $real; | |
my @include; | |
my @exclude; | |
my $verbose; | |
GetOptions( | |
'f|from=s' => \$from, | |
't|to=s' => \$to, | |
'r|run' => \$real, | |
'i|include=s' => \@include, | |
'e|exclude=s' => \@exclude, | |
'v|verbose' => \$verbose, | |
) or die usage(); | |
unshift @include, qr/\.(?:snap|xlog|vylog)$/; | |
$to or die "Replacement UUID required\n\n".usage(); | |
$to = lc $to; | |
for ($from?($from):(),$to) { | |
$_ = lc $_; | |
m{\A | |
[0-9a-f]{8}- | |
(?:[0-9a-f]{4}-){3} | |
[0-9a-f]{12} | |
\z}x or die "Malformed uuid `$_'\n\n".usage(); | |
} | |
@ARGV or @ARGV = ("."); | |
# use DDP; | |
my %changes; | |
my %files; | |
my $changed = 0; | |
File::Find::finddepth sub { | |
return unless -f; | |
if (@exclude) { | |
for (@exclude) { | |
return if $File::Find::name =~ /$_/; | |
} | |
} | |
CHECK: { | |
for (@include) { | |
last CHECK if $File::Find::name =~ /$_/; | |
} | |
return; | |
} | |
open my $fd, "+<", $_ or die "Cant open $File::Find::name: $!"; | |
my $rd = sysread $fd, my $buf, 100; | |
if ($rd > 0) { | |
if($buf =~ m{ | |
^ | |
(?<prefix> | |
(?<type>\N+) \n | |
(?<version>\N+) \n | |
(\N+\n)*? | |
Instance: \s )(?<uuid>\S+) \n | |
}gcsx) { | |
if ($to eq $+{uuid}) { | |
say "Skip $File::Find::name: no change required" if $verbose; | |
return; | |
} | |
if ($from) { | |
if ($from eq $+{uuid}) { | |
$changes{$from}{ $+{type} }++; | |
} | |
else { | |
say "Skip $File::Find::name: other uuid ($+{uuid})"; | |
return; | |
} | |
} else { | |
$changes{$+{uuid}}{ $+{type} }++; | |
} | |
push @{ $files{$+{uuid}}//=[] }, $File::Find::name; | |
if ($real) { | |
sysseek $fd, length($+{prefix}), 0 or die "$File::Find::name: Failed to seek: $!\n"; | |
syswrite($fd, $to) == length $to or die "$File::Find::name: Failed to write UUID: $!\n"; | |
close $fd; | |
if ($verbose) { | |
say "$File::Find::name: $+{uuid} -> $to"; | |
} | |
} | |
} else { | |
say "Skip $File::Find::name: file format mismatch"; | |
}; | |
} else { | |
say "Skip $File::Find::name: failed to read file: $!"; | |
} | |
}, @ARGV; | |
print "\n"; | |
my $uuids = keys %changes; | |
my $total = 0; | |
for my $uuid (keys %changes) { | |
for my $type (keys %{ $changes{ $uuid } }) { | |
$total += $changes{ $uuid }{$type}; | |
} | |
} | |
if ($total == 0) { | |
say "No files to change"; | |
exit; | |
} | |
if ($uuids == 1) { | |
my ($uuid,$count) = %changes; | |
print + ($real ? "Replaced" : "About to replace")." $uuid to $to in $total files:\n"; | |
if ($verbose and not $real) { | |
for (@{ $files{ $uuid }} ) { | |
say "\t$_"; | |
} | |
} else { | |
print "\t".join (", ", map { "$_: $changes{$uuid}{$_}" } sort keys %{ $changes{ $uuid } })."\n"; | |
} | |
say "\nRun with -r to change files" unless $real; | |
} | |
else { | |
say + ($real ? "Replaced" : "Found")." $uuids different uuids in $total files"; | |
for my $uuid (keys %changes) { | |
print "$uuid:"; | |
if ($verbose and not $real) { | |
print "\n"; | |
for (@{ $files{ $uuid }} ) { | |
say "\t$_"; | |
} | |
} else { | |
print "\t".join (", ", map { "$_: $changes{$uuid}{$_}" } sort keys %{ $changes{ $uuid } })."\n"; | |
} | |
} | |
say "\nPlease, specify uuid for replacement with -f" unless $real; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment