| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
#!/usr/bin/env perl |
|
2
|
10
|
|
|
10
|
|
5151
|
use 5.010001; |
|
|
10
|
|
|
|
|
23
|
|
|
3
|
10
|
|
|
10
|
|
34
|
use warnings; |
|
|
10
|
|
|
|
|
12
|
|
|
|
10
|
|
|
|
|
284
|
|
|
4
|
10
|
|
|
10
|
|
34
|
use strict; |
|
|
10
|
|
|
|
|
8
|
|
|
|
10
|
|
|
|
|
201
|
|
|
5
|
10
|
|
|
10
|
|
5436
|
use utf8; |
|
|
10
|
|
|
|
|
82
|
|
|
|
10
|
|
|
|
|
54
|
|
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
our $VERSION = 'v2.3.7'; |
|
8
|
|
|
|
|
|
|
|
|
9
|
10
|
|
|
10
|
|
353
|
use FindBin; |
|
|
10
|
|
|
|
|
12
|
|
|
|
10
|
|
|
|
|
469
|
|
|
10
|
10
|
|
|
10
|
|
4006
|
use lib "$FindBin::Bin/../lib/perl5"; |
|
|
10
|
|
|
|
|
5000
|
|
|
|
10
|
|
|
|
|
60
|
|
|
11
|
10
|
|
|
10
|
|
1000
|
use Path::Tiny; |
|
|
10
|
|
|
|
|
12
|
|
|
|
10
|
|
|
|
|
393
|
|
|
12
|
10
|
|
|
10
|
|
2925
|
use Narada; |
|
|
10
|
|
|
|
|
15
|
|
|
|
10
|
|
|
|
|
265
|
|
|
13
|
10
|
|
|
10
|
|
3033
|
use Narada::Lock qw( exclusive_lock unlock_new shared_lock unlock ); |
|
|
10
|
|
|
|
|
21
|
|
|
|
10
|
|
|
|
|
56
|
|
|
14
|
10
|
|
|
10
|
|
23367
|
use App::migrate; |
|
|
10
|
|
|
|
|
31887
|
|
|
|
10
|
|
|
|
|
315
|
|
|
15
|
10
|
|
|
10
|
|
6180
|
use Getopt::Long qw( GetOptionsFromArray ); |
|
|
10
|
|
|
|
|
71867
|
|
|
|
10
|
|
|
|
|
36
|
|
|
16
|
|
|
|
|
|
|
|
|
17
|
10
|
|
|
10
|
|
1408
|
use constant INITIAL_VERSION => '0.0.0'; |
|
|
10
|
|
|
|
|
13
|
|
|
|
10
|
|
|
|
|
554
|
|
|
18
|
10
|
|
|
10
|
|
34
|
use constant FULL_BACKUP => path('.backup/full.tar'); |
|
|
10
|
|
|
|
|
12
|
|
|
|
10
|
|
|
|
|
55
|
|
|
19
|
10
|
|
|
10
|
|
870
|
use constant USAGE => <<'EOUSAGE'; |
|
|
10
|
|
|
|
|
13
|
|
|
|
10
|
|
|
|
|
11359
|
|
|
20
|
|
|
|
|
|
|
Usage: |
|
21
|
|
|
|
|
|
|
narada-install [--allow-downgrade|-D] [--allow-restore|-R] [-f ] |
|
22
|
|
|
|
|
|
|
narada-install [-f ] --path|-p ... |
|
23
|
|
|
|
|
|
|
narada-install --check|-c |
|
24
|
|
|
|
|
|
|
narada-install --help|-h |
|
25
|
|
|
|
|
|
|
EOUSAGE |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
my $Last_backup; # OPTIMIZATION delay copying last backup to drop exclusive_lock faster |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
main(@ARGV) if !caller; |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
|
|
33
|
9
|
|
|
9
|
|
233
|
sub err { die "narada-install: @_\n" }; |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
sub main { |
|
36
|
|
|
|
|
|
|
## no critic (RequireCarping) |
|
37
|
62
|
|
|
62
|
|
291858
|
my ($allow_downgrade, $allow_restore, @files) = (0, 0); |
|
38
|
62
|
|
|
|
|
83
|
my ($is_path, $check, $is_help); |
|
39
|
0
|
|
|
|
|
0
|
my ($prev_version, $next_version, $path); |
|
40
|
62
|
100
|
|
|
|
334
|
GetOptionsFromArray(\@_, |
|
41
|
|
|
|
|
|
|
'D|allow-downgrade' => \$allow_downgrade, |
|
42
|
|
|
|
|
|
|
'R|allow-restore' => \$allow_restore, |
|
43
|
|
|
|
|
|
|
'f=s@' => \@files, |
|
44
|
|
|
|
|
|
|
'p|path' => \$is_path, |
|
45
|
|
|
|
|
|
|
'c|check=s' => \$check, |
|
46
|
|
|
|
|
|
|
'h|help' => \$is_help, |
|
47
|
|
|
|
|
|
|
) or die USAGE; |
|
48
|
61
|
100
|
|
|
|
24428
|
if ($is_help) { |
|
49
|
4
|
|
|
|
|
87
|
print USAGE; |
|
50
|
4
|
|
|
|
|
15
|
return; |
|
51
|
|
|
|
|
|
|
} |
|
52
|
57
|
100
|
|
|
|
125
|
if (defined $check) { |
|
53
|
12
|
100
|
100
|
|
|
109
|
die USAGE if @_ || $is_path || $allow_downgrade || $allow_restore || @files; |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
54
|
7
|
|
|
|
|
190
|
say "Checking $check"; |
|
55
|
7
|
|
|
|
|
30
|
App::migrate->new->load($check); |
|
56
|
2
|
|
|
|
|
9415
|
return; |
|
57
|
|
|
|
|
|
|
} |
|
58
|
45
|
100
|
|
|
|
120
|
if ($is_path) { |
|
59
|
7
|
100
|
|
|
|
32
|
die USAGE if @_ <= 2; |
|
60
|
3
|
|
|
|
|
5
|
$path = [@_]; |
|
61
|
3
|
|
|
|
|
4
|
$prev_version = $path->[0]; |
|
62
|
3
|
|
|
|
|
3
|
$next_version = $path->[-1]; |
|
63
|
3
|
|
|
|
|
2
|
$allow_downgrade= 1; |
|
64
|
3
|
|
|
|
|
4
|
$allow_restore = 1; |
|
65
|
|
|
|
|
|
|
} |
|
66
|
|
|
|
|
|
|
else { |
|
67
|
38
|
100
|
|
|
|
129
|
die USAGE if @_ != 1; |
|
68
|
34
|
|
|
|
|
48
|
$next_version = $_[0]; |
|
69
|
34
|
|
|
|
|
44
|
$prev_version = INITIAL_VERSION; |
|
70
|
34
|
100
|
|
|
|
98
|
if (path(q{.})->children(qr/\A(?![.]release\z|[.]backup\z|[.]lock)/ms)) { |
|
71
|
23
|
|
|
|
|
4157
|
Narada::detect('narada'); |
|
72
|
23
|
|
|
|
|
59
|
($prev_version) = path('VERSION')->lines({chomp=>1}); |
|
73
|
|
|
|
|
|
|
} |
|
74
|
|
|
|
|
|
|
} |
|
75
|
37
|
100
|
|
|
|
4902
|
if ($next_version eq $prev_version) { |
|
76
|
5
|
|
|
|
|
19
|
return; |
|
77
|
|
|
|
|
|
|
} |
|
78
|
|
|
|
|
|
|
|
|
79
|
32
|
|
|
|
|
115
|
my $migrate = load($prev_version, $next_version, @files); |
|
80
|
32
|
|
66
|
|
|
242
|
$path ||= get_path($migrate, $prev_version, $next_version); |
|
81
|
32
|
|
|
|
|
111
|
check_path($migrate, $path, $allow_downgrade, $allow_restore); |
|
82
|
31
|
|
|
|
|
87
|
migrate($migrate, $path); |
|
83
|
|
|
|
|
|
|
|
|
84
|
25
|
|
|
|
|
4114
|
return; |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub load { |
|
88
|
29
|
|
|
29
|
|
80
|
my ($prev_version, $next_version, @files) = @_; |
|
89
|
29
|
|
|
|
|
250
|
my $migrate = App::migrate->new; |
|
90
|
29
|
100
|
|
|
|
450
|
if ($next_version ne INITIAL_VERSION) { |
|
91
|
14
|
|
|
|
|
52
|
push @files, ".release/$next_version.migrate"; |
|
92
|
|
|
|
|
|
|
} |
|
93
|
29
|
100
|
|
|
|
385
|
if (-f ".release/$prev_version.migrate") { |
|
94
|
20
|
|
|
|
|
62
|
push @files, ".release/$prev_version.migrate"; |
|
95
|
|
|
|
|
|
|
} |
|
96
|
29
|
|
|
|
|
68
|
for (@files) { |
|
97
|
51
|
|
|
|
|
174460
|
say "Loading $_"; |
|
98
|
51
|
|
|
|
|
219
|
$migrate->load($_); |
|
99
|
|
|
|
|
|
|
} |
|
100
|
29
|
|
|
|
|
136131
|
return $migrate; |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
sub get_path { |
|
104
|
33
|
|
|
33
|
|
1324
|
my ($migrate, $prev_version, $next_version) = @_; |
|
105
|
33
|
|
|
|
|
143
|
my @paths = $migrate->find_paths($prev_version, $next_version); |
|
106
|
33
|
100
|
|
|
|
1685
|
if (0 == @paths) { |
|
|
|
100
|
|
|
|
|
|
|
107
|
1
|
|
|
|
|
4
|
err "Unable to find migration path from $prev_version to $next_version"; |
|
108
|
|
|
|
|
|
|
} |
|
109
|
|
|
|
|
|
|
elsif (1 != @paths) { |
|
110
|
|
|
|
|
|
|
err join "\n", |
|
111
|
|
|
|
|
|
|
'Found more than one upgrade path, run one of these commands to choose a path:', |
|
112
|
1
|
|
|
|
|
3
|
map {"\tnarada-install --path @{$_}"} @paths; |
|
|
2
|
|
|
|
|
2
|
|
|
|
2
|
|
|
|
|
9
|
|
|
113
|
|
|
|
|
|
|
} |
|
114
|
31
|
|
|
|
|
120
|
return $paths[0]; |
|
115
|
|
|
|
|
|
|
} |
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
sub check_path { |
|
118
|
39
|
|
|
39
|
|
456
|
my ($migrate, $path, $allow_downgrade, $allow_restore) = @_; |
|
119
|
39
|
100
|
|
|
|
96
|
if ($allow_restore) { |
|
120
|
15
|
|
|
|
|
24
|
$allow_downgrade = 1; |
|
121
|
|
|
|
|
|
|
} |
|
122
|
39
|
|
|
|
|
135
|
for my $step ($migrate->get_steps($path)) { |
|
123
|
759
|
|
|
|
|
1646
|
my $t = $step->{type}; |
|
124
|
759
|
|
100
|
|
|
1332
|
my $is_down = $t eq 'downgrade' || $t eq 'after_downgrade'; |
|
125
|
759
|
100
|
100
|
|
|
1470
|
err 'Downgrade required, use --allow-downgrade to continue' |
|
126
|
|
|
|
|
|
|
if $is_down && !$allow_downgrade; |
|
127
|
757
|
100
|
100
|
|
|
1091
|
err 'Restore from backup required, use --allow-restore to continue' |
|
128
|
|
|
|
|
|
|
if $t eq 'RESTORE' && !$allow_restore; |
|
129
|
754
|
100
|
|
|
|
941
|
if ($t eq 'RESTORE') { |
|
130
|
7
|
|
|
|
|
48
|
my $f = path(".backup/full-$step->{next_version}.tar"); |
|
131
|
7
|
100
|
|
|
|
242
|
err "Required backup not found: $f" if !$f->is_file; |
|
132
|
|
|
|
|
|
|
} |
|
133
|
|
|
|
|
|
|
} |
|
134
|
31
|
|
|
|
|
73
|
return; |
|
135
|
|
|
|
|
|
|
} |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
sub migrate { |
|
138
|
28
|
|
|
28
|
|
59
|
my ($migrate, $path) = @_; |
|
139
|
|
|
|
|
|
|
|
|
140
|
28
|
|
|
|
|
401
|
say 'Acquire exclusive lock ...'; |
|
141
|
28
|
|
|
|
|
170
|
exclusive_lock(); |
|
142
|
|
|
|
|
|
|
{ |
|
143
|
28
|
|
|
|
|
112
|
local $ENV{NARADA_SKIP_LOCK} = 1; |
|
|
28
|
|
|
|
|
565
|
|
|
144
|
28
|
|
|
|
|
105
|
$Last_backup = undef; # tests may call main() many times |
|
145
|
28
|
|
|
|
|
330
|
$migrate->on(BACKUP => \&_backup) |
|
146
|
|
|
|
|
|
|
->on(RESTORE => \&_restore) |
|
147
|
|
|
|
|
|
|
->on(VERSION => \&_version) |
|
148
|
|
|
|
|
|
|
->on(error => \&_error) |
|
149
|
|
|
|
|
|
|
->run($path); |
|
150
|
|
|
|
|
|
|
} |
|
151
|
22
|
|
|
|
|
859
|
unlock_new(); |
|
152
|
|
|
|
|
|
|
|
|
153
|
22
|
|
|
|
|
175
|
shared_lock(); |
|
154
|
22
|
50
|
33
|
|
|
293
|
if ($Last_backup && !FULL_BACKUP->exists) { |
|
155
|
22
|
|
|
|
|
548
|
path($Last_backup)->copy(FULL_BACKUP); |
|
156
|
|
|
|
|
|
|
} |
|
157
|
22
|
|
|
|
|
13173
|
unlock(); |
|
158
|
|
|
|
|
|
|
|
|
159
|
22
|
|
|
|
|
52
|
return; |
|
160
|
|
|
|
|
|
|
} |
|
161
|
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
sub ask { |
|
163
|
0
|
|
|
0
|
|
|
my ($msg, $match) = @_; |
|
164
|
0
|
|
|
|
|
|
print $msg; |
|
165
|
|
|
|
|
|
|
# TODO try IO::Prompter |
|
166
|
|
|
|
|
|
|
## no critic (ProhibitExplicitStdin) |
|
167
|
0
|
|
|
|
|
|
while () { |
|
168
|
0
|
|
|
|
|
|
chomp; |
|
169
|
0
|
0
|
|
|
|
|
return $_ if /$match/ms; |
|
170
|
0
|
|
|
|
|
|
print $msg; |
|
171
|
|
|
|
|
|
|
} |
|
172
|
0
|
|
|
|
|
|
die "Interrupted by EOF\n"; |
|
173
|
|
|
|
|
|
|
} |
|
174
|
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
sub _backup { |
|
176
|
76
|
|
|
76
|
|
5237
|
my ($step) = @_; |
|
177
|
76
|
100
|
|
|
|
356
|
if ($step->{version} ne INITIAL_VERSION) { |
|
178
|
66
|
100
|
|
|
|
263
|
if ($Last_backup) { |
|
179
|
37
|
|
|
|
|
179
|
path($Last_backup)->copy(FULL_BACKUP); |
|
180
|
|
|
|
|
|
|
} |
|
181
|
66
|
|
|
|
|
21445
|
my $file = ".backup/full-$step->{version}.tar"; |
|
182
|
66
|
|
|
|
|
933
|
say "Backuping to $file"; |
|
183
|
66
|
100
|
|
|
|
54109964
|
system('narada-backup') == 0 or die "BACKUP failed\n"; |
|
184
|
62
|
|
|
|
|
638
|
$Last_backup = $file; |
|
185
|
62
|
|
|
|
|
2608
|
FULL_BACKUP->move($Last_backup); |
|
186
|
|
|
|
|
|
|
} |
|
187
|
72
|
|
|
|
|
64644
|
return; |
|
188
|
|
|
|
|
|
|
} |
|
189
|
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
sub _restore { |
|
191
|
9
|
|
|
9
|
|
780
|
my ($step) = @_; |
|
192
|
9
|
|
|
|
|
53
|
my $file = ".backup/full-$step->{version}.tar"; |
|
193
|
9
|
|
|
|
|
194
|
say "Restoring from $file"; |
|
194
|
9
|
100
|
|
|
|
2437159
|
system('narada-restore', $file) == 0 or die "RESTORE failed\n"; |
|
195
|
6
|
|
|
|
|
170
|
return; |
|
196
|
|
|
|
|
|
|
} |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
sub _version { |
|
199
|
72
|
|
|
72
|
|
3678107
|
my ($step) = @_; |
|
200
|
72
|
|
|
|
|
1672
|
say "Migration to $step->{version} completed"; |
|
201
|
72
|
100
|
|
|
|
495
|
if ($step->{version} eq INITIAL_VERSION) { |
|
202
|
13
|
|
|
|
|
571
|
path('VERSION')->remove; |
|
203
|
|
|
|
|
|
|
} |
|
204
|
|
|
|
|
|
|
else { |
|
205
|
59
|
|
|
|
|
664
|
path('VERSION')->spew_utf8("$step->{version}\n"); |
|
206
|
|
|
|
|
|
|
} |
|
207
|
72
|
|
|
|
|
69855
|
return; |
|
208
|
|
|
|
|
|
|
} |
|
209
|
|
|
|
|
|
|
|
|
210
|
|
|
|
|
|
|
sub _error { |
|
211
|
10
|
|
|
10
|
|
17580
|
say q{}; |
|
212
|
10
|
|
|
|
|
98
|
say 'YOU NEED TO MANUALLY FIX THIS ISSUE RIGHT NOW'; |
|
213
|
10
|
|
|
|
|
410
|
my $prompt |
|
214
|
|
|
|
|
|
|
= "Please choose what to do:\n" |
|
215
|
|
|
|
|
|
|
. " shell - run $ENV{SHELL} (exit from it to return to this menu)\n" |
|
216
|
|
|
|
|
|
|
. " continue - continue migration (use if you have fixed this issue)\n" |
|
217
|
|
|
|
|
|
|
. " restore - interrupt migration and RESTORE previous version from backup\n" |
|
218
|
|
|
|
|
|
|
. 'Enter action [shell]: ' |
|
219
|
|
|
|
|
|
|
; |
|
220
|
10
|
|
|
|
|
37
|
while (1) { |
|
221
|
10
|
|
|
|
|
208
|
my $ans = lc ask($prompt, qr/\A(?:shell|continue|restore|\s*)\z/msi); |
|
222
|
10
|
100
|
|
|
|
229
|
if ($ans eq 'restore') { |
|
|
|
50
|
|
|
|
|
|
|
223
|
6
|
|
|
|
|
138
|
die "Migration failed\n"; |
|
224
|
|
|
|
|
|
|
} |
|
225
|
|
|
|
|
|
|
elsif ($ans eq 'continue') { |
|
226
|
4
|
|
|
|
|
27
|
last; |
|
227
|
|
|
|
|
|
|
} |
|
228
|
|
|
|
|
|
|
else { |
|
229
|
0
|
|
|
|
|
0
|
system $ENV{SHELL}; |
|
230
|
|
|
|
|
|
|
} |
|
231
|
|
|
|
|
|
|
} |
|
232
|
4
|
|
|
|
|
24
|
return; |
|
233
|
|
|
|
|
|
|
} |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
1; # Magic true value required at end of module |
|
237
|
|
|
|
|
|
|
__END__ |