-
Notifications
You must be signed in to change notification settings - Fork 0
/
dcdb-upgrade.perl
executable file
·282 lines (211 loc) · 7.22 KB
/
dcdb-upgrade.perl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
#!/usr/bin/perl -w
use lib qw(. dclib);
use version;
use DiaColloDB;
use DiaColloDB::Upgrade;
use File::Basename qw(basename);
use Getopt::Long qw(:config no_ignore_case);
use Pod::Usage;
use utf8;
use strict;
BEGIN {
select(STDERR); $|=1; select(STDOUT); $|=1;
binmode(STDOUT,':utf8');
}
##======================================================================
## Globals
##-- program vars
our $prog = basename($0);
##-- upgrade options
our %uopts = (
backup=>1,
keep=>0,
);
##======================================================================
## command-line
my $act = 'upgrade'; ##-- one of: help list which check upgrade apply revert
my @upgrades = qw();
GetOptions(
'help|h' => sub { $act='help' },
'list-available|list-all|list|all|available' => sub { $act='list' },
'which|w|list-applied|applied|la' => sub { $act='which' },
'check|c' => => sub { $act='check' },
'upgrade|u' => sub { $act='upgrade' },
'force-apply|fa|apply|a=s' => sub { $act='apply'; @upgrades = grep {($_//'') ne ''} split(/[\s\,]+/,$_[1]) },
'revert|reverse|rollback|r' => sub { $act='revert' },
##
'backup|b!' => \$uopts{backup},
'keep|k!' => \$uopts{keep},
);
pod2usage({-exitval=>0,-verbose=>0}) if ($act eq 'help');
pod2usage({-exitval=>1,-verbose=>0,-msg=>"$prog: ERROR: no DBDIR specified!"}) if ($act ne 'list' && @ARGV < 1);
warn("$prog: WARNING: too many arguments for -list mode") if ($act eq 'list' && @ARGV);
##======================================================================
## MAIN
DiaColloDB->ensureLog();
my $up = 'DiaColloDB::Upgrade';
if ($act eq 'list') {
##-- list available upgrades
print map {"$_\n"} $up->available();
exit 0;
}
my $timer = DiaColloDB::Timer->start();
my $dbdir = shift;
$dbdir =~ s{/+$}{};
my (@needed,@which);
if ($act =~ /^(?:check|upgrade)$/) {
##-- find applicable upgrades
$up->info("checking applicable upgrades for $dbdir");
@needed = $up->needed($dbdir, \%uopts, $up->available);
if ($act eq 'check') {
##-- check: ostentatiously list applicable upgrades
print "\n", (map {"$_\n"} @needed), "\n" if (@needed);
} else {
##-- upgrade: log applicable upgrades (they'll be applied below)
$up->info("found applicable upgrade package: $_") foreach (@needed);
}
if (!@needed) {
$up->info("no applicable upgrades found for $dbdir");
}
}
elsif ($act =~ /^which|revert$/) {
$up->info("checking auto-applied upgrades for $dbdir");
@which = $up->which($dbdir, \%uopts);
if ($act eq 'which') {
##-- which: ostentatiously list applied upgrades
my $fmt = "%-42s %-16s %-21s %-8s -> %-8s\n";
print
("\n",
sprintf($fmt, map {"#".uc($_)} qw(package by timestamp v_from v_to)),
(map {
(my $by = ($_->{by}//'?')) =~ s/^DiaColloDB::Upgrade:://;
sprintf($fmt, ref($_), $by, map {($_//'?')} @$_{qw(timestamp version_from version_to)});
} @which),
"\n");
}
if (!@which) {
$up->info("no auto-applied upgrades found for $dbdir");
}
}
if ($act eq 'upgrade') {
##-- upgrade: apply available upgrades
$up->upgrade($dbdir, \%uopts, @needed)
or die("$0: upgrade failed for $dbdir");
}
elsif ($act eq 'apply') {
##-- apply: force-apply selected upgrades
$up->upgrade($dbdir,\%uopts, @upgrades)
or die("$0: force-apply upgrade(s) failed");
}
elsif ($act eq 'revert') {
##-- revert: un-apply most recent upgrade
my $rb = $which[0];
die("$0: no auto-upgrades to roll back!")
if (!defined($rb));
die("$0: no revert() method for class ", ref($rb))
if (!UNIVERSAL::can($rb,'revert'));
$rb->revert()
or die("$0: revert failed for class ", ref($rb));
}
##-- all done
$up->info("operation '$act' completed in ", $timer->timestr);
__END__
###############################################################
## pods
###############################################################
=pod
=head1 NAME
dcdb-upgrade.perl - upgrade a DiaColloDB directory in-place
=head1 SYNOPSIS
dcdb-upgrade.perl -list
dcdb-upgrade.perl [OPTIONS] DBDIR
Options:
-h, -help # this help message
-l, -list # list all available upgrade packages
-w, -which # list previous auto-upgrades to DBDIR
-c, -check # check applicability of available upgrades for DBDIR
-u, -upgrade # apply any applicable upgrades to DBDIR (default)
-r, -revert # revert the most recent upgrade to DBDIR
-a, -apply PKGS # force-apply comma-separated upgrade package(s) to DBDIR
-[no]backup # do/don't create auto-backups (default=do)
-[no]keep # do/don't keep temporary files created by upgrade (default=don't)
=cut
###############################################################
## DESCRIPTION
###############################################################
=pod
=head1 DESCRIPTION
dcdb-upgrade.perl
checks for & applies automatic upgrades to a L<DiaColloDB|DiaColloDB>
database directory, using the L<DiaColloDB::Upgrade|DiaColloDB::Upgrade> API.
The DBDIR database is altered in-place, so it is safest
to make a backup of DBDIR before upgrading.
=cut
###############################################################
## OPTIONS AND ARGUMENTS
###############################################################
=pod
=head1 OPTIONS AND ARGUMENTS
=cut
###############################################################
# Arguments
###############################################################
=pod
=head2 Arguments
=over 4
=item DBDIR
L<DiaColloDB|DiaColloDB> database directory to be checked and/or upgraded.
=back
=cut
###############################################################
# Options
###############################################################
=pod
=head2 Options
=over 4
=item -h, -help
Display a brief help message and exit.
=item -l, -list
List all known L<DiaColloDB::Upgrade|DiaColloDB::Upgrade> packages.
=item -w, -which
List upgrades previously applied to C<DBDIR>.
=item -c, -check
Check applicability of available upgrades to C<DBDIR>.
=item -u, -upgrade
Apply any applicable upgrades to F<DBDIR>;
this is the default mode of operation.
It is safest to make a manual backup of F<DBDIR> before upgrading,
although the L<DiaColloDB::Upgrade::Base|DiaColloDB::Upgrade::Base>
hierarchy should provide backup functionality for changed files.
=item -r, -revert
Revert the most recently applied upgrade to F<DBDIR>;
requires that a backup was auto-created by the L<DiaColloDB::Upgrade::Base|DiaColloDB::Upgrade::Base>
subclass implementing the most recent upgrade.
=item -a, -apply PKGS
Force-apply the comma- or space-separated list of
L<DiaColloDB::Upgrade|DiaColloDB::Upgrade>-compliant packages
C<PKGS> to F<DBDIR>.
Use with caution, no applicability checking is performed in this mode.
=back
=cut
###############################################################
# Bugs and Limitations
###############################################################
=pod
=head1 BUGS AND LIMITATIONS
Probably many.
=cut
###############################################################
# Footer
###############################################################
=pod
=head1 ACKNOWLEDGEMENTS
Perl by Larry Wall.
=head1 AUTHOR
Bryan Jurish E<lt>[email protected]<gt>
=head1 SEE ALSO
L<DiaColloDB::Upgrade(3pm)|DiaColloDB::Upgrade>,
L<DiaColloDB(3pm)|DiaColloDB>,
L<dcdb-info.perl(1)|dcdb-info.perl>,
perl(1).
=cut