line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Pb::Command::Context; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $VERSION = '0.01_03'; # TRIAL VERSION |
4
|
|
|
|
|
|
|
|
5
|
1
|
|
|
1
|
|
8
|
use Moo; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
6
|
|
6
|
1
|
|
|
1
|
|
351
|
use 5.14.0; |
|
1
|
|
|
|
|
3
|
|
7
|
1
|
|
|
1
|
|
6
|
use autodie ':all'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
7
|
|
8
|
1
|
|
|
1
|
|
5222
|
use MooX::HandlesVia; |
|
1
|
|
|
|
|
626
|
|
|
1
|
|
|
|
|
6
|
|
9
|
1
|
|
|
1
|
|
503
|
use namespace::autoclean; |
|
1
|
|
|
|
|
9608
|
|
|
1
|
|
|
|
|
5
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
extends 'Clone'; # so we have our own `clone` method |
12
|
|
|
|
|
|
|
|
13
|
1
|
|
|
1
|
|
74
|
use Fcntl qw< :flock >; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
97
|
|
14
|
1
|
|
|
1
|
|
5
|
use File::Path qw< make_path >; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
41
|
|
15
|
1
|
|
|
1
|
|
363
|
use Const::Fast; |
|
1
|
|
|
|
|
832
|
|
|
1
|
|
|
|
|
5
|
|
16
|
1
|
|
|
1
|
|
483
|
use Time::Piece; |
|
1
|
|
|
|
|
7127
|
|
|
1
|
|
|
|
|
4
|
|
17
|
1
|
|
|
1
|
|
75
|
use File::Basename; |
|
1
|
|
|
|
|
7
|
|
|
1
|
|
|
|
|
246
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# Default values for vars here; most values are set as we go along. |
21
|
|
|
|
|
|
|
my %DEFAULT_CONTEXT = |
22
|
|
|
|
|
|
|
( |
23
|
|
|
|
|
|
|
DEBUG => 0, |
24
|
|
|
|
|
|
|
TIME => localtime($^T)->strftime("%Y%m%d%H%M%S"), |
25
|
|
|
|
|
|
|
DATE => localtime($^T)->strftime("%Y%m%d"), |
26
|
|
|
|
|
|
|
); |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
# This is how we tell if we didn't have an error on the last run. |
29
|
|
|
|
|
|
|
my $CLEAN_EXIT = 'exited cleanly'; |
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
############## |
33
|
|
|
|
|
|
|
# ATTRIBUTES # |
34
|
|
|
|
|
|
|
############## |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# These are the actual context vars that flows can access via hash deferencing. |
39
|
|
|
|
|
|
|
has _vars => ( is => 'ro', default => sub { +{%DEFAULT_CONTEXT} }, handles_via => 'Hash', |
40
|
|
|
|
|
|
|
handles => { var => 'get', has_var => 'exists', }, ); |
41
|
|
|
|
|
|
|
# These are the options (both command-specific and global) for the running command. |
42
|
|
|
|
|
|
|
has _opts => ( is => 'ro', default => sub { +{ } }, handles_via => 'Hash', |
43
|
|
|
|
|
|
|
handles => { opt => 'get', opts => 'elements', }, ); |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
# The `@RAW_ACCESS` lists packages that are allowed to access our internals directly. Everyone else |
46
|
|
|
|
|
|
|
# who treats us like a hash reference gets the hash of context vars instead. This is how we get |
47
|
|
|
|
|
|
|
# around the infinite dereferencing loop we would otherwise engender for being a blessed hash that |
48
|
|
|
|
|
|
|
# defines an overloaded hash dereference operator. See `perldoc overload` for more details. |
49
|
|
|
|
|
|
|
# (This method is a bit hacky, but effective, and fairly quick.) |
50
|
|
|
|
|
|
|
my @RAW_ACCESS = qw< Method::Generate::Accessor Pb::Command::Context >; |
51
|
1
|
50
|
|
1
|
|
7
|
use overload '%{}' => sub { (grep { caller =~ /^$_\b/ } @RAW_ACCESS) ? $_[0] : $_[0]->_vars }, fallback => 1; |
|
1
|
|
|
3
|
|
1
|
|
|
1
|
|
|
|
|
5
|
|
|
3
|
|
|
|
|
42
|
|
|
6
|
|
|
|
|
71
|
|
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
# Simple attributes; free to read, but only certain people can write to them. |
54
|
|
|
|
|
|
|
has runmode => ( is => 'rwp', ); |
55
|
|
|
|
|
|
|
has statfile => ( is => 'rwp', ); |
56
|
|
|
|
|
|
|
has proc_pidfile => ( is => 'rwp', ); |
57
|
|
|
|
|
|
|
has toplevel_command => ( is => 'rwp', ); |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
# Do we, or do we not, update the statfile (if any) when we exit? |
60
|
|
|
|
|
|
|
has update_statfile => ( is => 'rwp', default => 1, ); |
61
|
0
|
|
|
0
|
|
|
sub _dont_update_statfile { my $self = shift; $self->_set_update_statfile(0); } |
|
0
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
# pseudo-attributes |
64
|
|
|
|
|
|
|
# (Mostly context vars posing as attributes, but also some attributes' attributes.) |
65
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
|
67
|
0
|
|
|
0
|
1
|
|
sub error { my $self = shift; $self->_vars->{ERR} } |
|
0
|
|
|
|
|
|
|
68
|
0
|
|
|
0
|
1
|
|
sub logfile { my $self = shift; $self->_vars->{LOGFILE} } |
|
0
|
|
|
|
|
|
|
69
|
0
|
0
|
|
0
|
1
|
|
sub pidfile { my $self = shift; my $ppf = $self->proc_pidfile; $ppf ? $ppf->pidfile : undef } |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
|
71
|
0
|
|
|
0
|
|
|
sub _set_logfile { my ($self, $file) = @_; $self->_vars->{LOGFILE} = $file; } |
|
0
|
|
|
|
|
|
|
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
################## |
75
|
|
|
|
|
|
|
# HELPER METHODS # |
76
|
|
|
|
|
|
|
################## |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
sub _expand_vars |
79
|
|
|
|
|
|
|
{ |
80
|
0
|
|
|
0
|
|
|
my ($self, $string) = @_; |
81
|
0
|
|
0
|
|
|
|
$string =~ s{%(\w+)}{ $self->_vars->{$1} // $self->raise_error("variable $1 used in expansion but never defined") }ge; |
|
0
|
|
|
|
|
|
|
82
|
0
|
|
|
|
|
|
return $string; |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
sub _prep_filename |
86
|
|
|
|
|
|
|
{ |
87
|
0
|
|
|
0
|
|
|
my ($self, $file) = @_; |
88
|
0
|
|
|
|
|
|
$file = $self->_expand_vars($file); |
89
|
0
|
|
|
|
|
|
make_path(dirname($file)); |
90
|
0
|
|
|
|
|
|
return $file; |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
sub _extrapolate_run_mode |
94
|
|
|
|
|
|
|
{ |
95
|
0
|
|
|
0
|
|
|
my ($self) = @_; |
96
|
0
|
0
|
|
|
|
|
return 'NOACTION' if $self->_opts->{pretend}; |
97
|
0
|
|
|
|
|
|
return 'ACTION'; |
98
|
|
|
|
|
|
|
} |
99
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
sub _safe_file_rw |
101
|
|
|
|
|
|
|
{ |
102
|
0
|
|
|
0
|
|
|
my ($self, $file, $line) = @_; |
103
|
0
|
0
|
|
|
|
|
my ($open_mode, $lock_mode) = defined $line ? ('>', LOCK_EX) : ('<', LOCK_SH); |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# This is essentially the same amount of paranoia that Proc::Pidfile undergoes. I just don't |
106
|
|
|
|
|
|
|
# have to catch all the errors because I have `autodie` turned on. |
107
|
|
|
|
|
|
|
eval |
108
|
0
|
|
|
|
|
|
{ |
109
|
0
|
|
|
|
|
|
local *FILE; |
110
|
0
|
|
|
|
|
|
open FILE, $open_mode, $file; |
111
|
0
|
|
|
|
|
|
flock FILE, $lock_mode; |
112
|
0
|
0
|
|
|
|
|
if ($open_mode eq '<') |
113
|
|
|
|
|
|
|
{ |
114
|
0
|
|
|
|
|
|
$line = ; |
115
|
0
|
|
|
|
|
|
chomp $line; |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
else |
118
|
|
|
|
|
|
|
{ |
119
|
0
|
|
|
|
|
|
say FILE $line; |
120
|
|
|
|
|
|
|
} |
121
|
0
|
|
|
|
|
|
flock FILE, LOCK_UN; |
122
|
0
|
|
|
|
|
|
close(FILE); |
123
|
|
|
|
|
|
|
}; |
124
|
0
|
0
|
|
|
|
|
if ($@) |
125
|
|
|
|
|
|
|
{ |
126
|
0
|
0
|
|
|
|
|
$self->raise_error("file read/write failure [" . $@ =~ s/ at .*? line \d+.*\n//sr . "]") |
127
|
|
|
|
|
|
|
unless $@ =~ /^Can't open '$file' for reading:/; |
128
|
|
|
|
|
|
|
} |
129
|
0
|
|
|
|
|
|
return $line; |
130
|
|
|
|
|
|
|
} |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
################## |
135
|
|
|
|
|
|
|
# PUBLIC METHODS # |
136
|
|
|
|
|
|
|
################## |
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
|
139
|
0
|
|
|
0
|
1
|
|
sub set_debug { my ($self, $level) = @_; $self->_vars->{DEBUG} = $level } |
|
0
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
|
141
|
0
|
|
|
0
|
1
|
|
sub set_var { my ($self, $var, $val) = @_; $self->_vars->{$var} = $val } |
|
0
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
# Currently, this just sets the `ERR` context var, but in the future it may do more. |
146
|
|
|
|
|
|
|
sub raise_error |
147
|
|
|
|
|
|
|
{ |
148
|
0
|
|
|
0
|
1
|
|
my ($self, $err) = @_; |
149
|
0
|
|
|
|
|
|
$self->_vars->{ERR} = $err; |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
# These are more specialized versions of `raise_error`; again, very simple to start with, but |
153
|
|
|
|
|
|
|
# there's room for expansion. |
154
|
|
|
|
|
|
|
sub syntax_error |
155
|
|
|
|
|
|
|
{ |
156
|
0
|
|
|
0
|
1
|
|
my ($self, $err) = @_; |
157
|
0
|
|
|
|
|
|
$self->_dont_update_statfile; # syntax errors shouldn't fire the `unless_clean_exit` condition |
158
|
0
|
|
|
|
|
|
$self->raise_error($err); |
159
|
|
|
|
|
|
|
} |
160
|
|
|
|
|
|
|
sub usage_error |
161
|
|
|
|
|
|
|
{ |
162
|
0
|
|
|
0
|
1
|
|
my ($self, $err) = @_; |
163
|
0
|
|
|
|
|
|
$self->_dont_update_statfile; # usage errors shouldn't fire the `unless_clean_exit` condition |
164
|
0
|
|
|
|
|
|
$self->raise_error($err); |
165
|
|
|
|
|
|
|
} |
166
|
|
|
|
|
|
|
sub start_conditions_not_met |
167
|
|
|
|
|
|
|
{ |
168
|
0
|
|
|
0
|
1
|
|
my ($self, $err) = @_; |
169
|
|
|
|
|
|
|
# Again, since the command is not going to get run, these errors can't fire off the |
170
|
|
|
|
|
|
|
# `unless_clean_exit` condition. |
171
|
0
|
|
|
|
|
|
$self->_dont_update_statfile; |
172
|
0
|
|
|
|
|
|
$self->raise_error($err); |
173
|
|
|
|
|
|
|
} |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
###################### |
177
|
|
|
|
|
|
|
# STRUCTURE BUILDERS # |
178
|
|
|
|
|
|
|
###################### |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
sub setup_context |
182
|
|
|
|
|
|
|
{ |
183
|
0
|
|
|
0
|
1
|
|
my ($inv, $vars, $optdefs, $control) = @_; |
184
|
0
|
0
|
|
|
|
|
my $self = ref $inv ? $inv->clone : $inv->new; |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
# set whatever vars weren't already set |
187
|
0
|
|
|
|
|
|
$self->set_var($_ => $vars->{$_}) foreach keys %$vars; |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
# validate opts (this might also set some vars) |
190
|
0
|
|
|
|
|
|
$self->validate_opts($optdefs); |
191
|
0
|
0
|
|
|
|
|
return $self if $self->error; # no point in continuing if an opt was bobbled |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
# have to do this at runtime so that we only create a logfile for the running command |
194
|
0
|
|
|
|
|
|
$self->prep_logfile; |
195
|
|
|
|
|
|
|
# have to this at run time so we have parsed options to work with |
196
|
0
|
|
|
|
|
|
$self->_set_runmode( $self->_extrapolate_run_mode ); |
197
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
# process control stuff; some of this might mean we have to bail out |
199
|
0
|
0
|
|
|
|
|
unless ( $self->_process_control_structure($control) ) |
200
|
|
|
|
|
|
|
{ |
201
|
|
|
|
|
|
|
# this should never be necessary; `error` should always be set by `_process_control_structure` |
202
|
0
|
0
|
|
|
|
|
$self->syntax_error('Unknown error processing control structure') unless $self->error; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
0
|
|
|
|
|
|
return $self; |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# This deals with all the stuff you can put in the "control structure (i.e. the hashref that follows |
209
|
|
|
|
|
|
|
# the `control_via` keyword). |
210
|
|
|
|
|
|
|
sub _process_control_structure |
211
|
|
|
|
|
|
|
{ |
212
|
0
|
|
|
0
|
|
|
my ($self, $control) = @_; |
213
|
|
|
|
|
|
|
|
214
|
0
|
|
|
|
|
|
foreach (grep { exists $control->{$_} } qw< pidfile statusfile unless_clean_exit >) |
|
0
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
{ |
216
|
0
|
|
|
|
|
|
my $value = delete $control->{$_}; |
217
|
0
|
0
|
|
|
|
|
if ($_ eq 'pidfile') |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
218
|
|
|
|
|
|
|
{ |
219
|
0
|
0
|
|
|
|
|
return undef unless $self->prep_pidfile($value); |
220
|
|
|
|
|
|
|
} |
221
|
|
|
|
|
|
|
elsif ($_ eq 'statusfile') |
222
|
|
|
|
|
|
|
{ |
223
|
0
|
|
|
|
|
|
$self->_set_statfile($self->_prep_filename($value)); |
224
|
|
|
|
|
|
|
my $statfile = sub |
225
|
|
|
|
|
|
|
{ |
226
|
0
|
0
|
|
0
|
|
|
if ($self->update_statfile) |
227
|
|
|
|
|
|
|
{ |
228
|
0
|
|
0
|
|
|
|
my $exit_status = $self->error // $CLEAN_EXIT; |
229
|
0
|
|
|
|
|
|
$self->_safe_file_rw($self->statfile, "last run: $exit_status at " . scalar localtime); |
230
|
|
|
|
|
|
|
} |
231
|
0
|
|
|
|
|
|
}; |
232
|
|
|
|
|
|
|
# have to use string `eval` here, otherwise the `END` will always fire |
233
|
0
|
|
|
|
|
|
eval 'END { $statfile->() }'; |
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
elsif ($_ eq 'unless_clean_exit') |
236
|
|
|
|
|
|
|
{ |
237
|
0
|
0
|
|
|
|
|
unless (defined $self->statfile) |
238
|
|
|
|
|
|
|
{ |
239
|
0
|
|
|
|
|
|
$self->syntax_error("cannot specify `unless_clean_exit' without `statusfile'"); |
240
|
0
|
|
|
|
|
|
return undef; |
241
|
|
|
|
|
|
|
} |
242
|
0
|
|
|
|
|
|
my $lastrun = $self->_safe_file_rw($self->statfile); |
243
|
0
|
0
|
|
|
|
|
return undef if $self->error; |
244
|
0
|
0
|
|
|
|
|
if ($lastrun) # if not, probably means this is the first run |
245
|
|
|
|
|
|
|
{ |
246
|
0
|
|
|
|
|
|
my ($last_exit) = $lastrun =~ /: (.*?) at /; |
247
|
0
|
0
|
|
|
|
|
unless ($last_exit eq $CLEAN_EXIT) |
248
|
|
|
|
|
|
|
{ |
249
|
0
|
|
|
|
|
|
$self->raise_error($last_exit); # in case our message wants to access %ERR |
250
|
0
|
|
|
|
|
|
my $msg = $self->_expand_vars($value); |
251
|
0
|
|
|
|
|
|
$self->start_conditions_not_met($msg); # this is the real (user-supplied) error message |
252
|
0
|
|
|
|
|
|
return undef; |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
} |
257
|
0
|
0
|
|
|
|
|
if ( %$control ) |
258
|
|
|
|
|
|
|
{ |
259
|
0
|
|
|
|
|
|
$self->syntax_error("unknown parameter(s) in control structure [" . join(',', sort keys %$control) . "]"); |
260
|
0
|
|
|
|
|
|
return undef; |
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
else |
263
|
|
|
|
|
|
|
{ |
264
|
0
|
|
|
|
|
|
return 1; |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
sub connect_to |
271
|
|
|
|
|
|
|
{ |
272
|
0
|
|
|
0
|
1
|
|
my ($self, $command) = @_; |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
# This little dance is to find the ultimate parent command in case we end up with an inline |
275
|
|
|
|
|
|
|
# subcommand or somesuch (viz. CLI::Osprey::InlineSubcommand). |
276
|
0
|
|
|
|
|
|
my $top_level = $command; |
277
|
0
|
|
0
|
|
|
|
$top_level = $top_level->parent_command while $top_level->can('parent_command') and $top_level->parent_command; |
278
|
|
|
|
|
|
|
|
279
|
0
|
|
|
|
|
|
$self->_set_toplevel_command($top_level); |
280
|
0
|
|
|
|
|
|
$self->_vars->{ME} = $top_level->invoked_as; |
281
|
0
|
|
|
|
|
|
$self->_parse_opts($command); |
282
|
|
|
|
|
|
|
} |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
# Build the options hash. Merges both local and global opts. |
285
|
|
|
|
|
|
|
sub _parse_opts |
286
|
|
|
|
|
|
|
{ |
287
|
0
|
|
|
0
|
|
|
my ($self, $command) = @_; |
288
|
0
|
|
|
|
|
|
my $optobj_method = '_osprey_options'; |
289
|
0
|
0
|
|
|
|
|
my %opt_objects = $command->can($optobj_method) ? $command->$optobj_method : (); |
290
|
0
|
|
|
|
|
|
$self->_opts->{$_} = $command->$_ foreach keys %opt_objects; |
291
|
|
|
|
|
|
|
# get options from top-level command as well (these are the global opts) |
292
|
|
|
|
|
|
|
{ |
293
|
|
|
|
|
|
|
# I'm pretty sure the top-level command will always have an options method. |
294
|
0
|
|
|
|
|
|
my %opt_objects = $self->toplevel_command->$optobj_method; |
|
0
|
|
|
|
|
|
|
295
|
0
|
|
0
|
|
|
|
$self->_opts->{$_} //= $self->toplevel_command->$_ foreach keys %opt_objects; |
296
|
|
|
|
|
|
|
} |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
sub validate_args |
302
|
|
|
|
|
|
|
{ |
303
|
0
|
|
|
0
|
1
|
|
my $defs = pop; |
304
|
0
|
|
|
|
|
|
my ($self, @args) = @_; |
305
|
|
|
|
|
|
|
|
306
|
0
|
|
|
|
|
|
foreach my $def (@$defs) |
307
|
|
|
|
|
|
|
{ |
308
|
0
|
|
|
|
|
|
my $arg = shift @args; |
309
|
0
|
0
|
|
|
|
|
return undef unless $self->_validate_value(arg => $def->{type}, $def->{name} => $arg); |
310
|
0
|
|
|
|
|
|
$self->set_var($def->{name}, $arg); |
311
|
|
|
|
|
|
|
} |
312
|
0
|
|
|
|
|
|
return 1; |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
sub validate_opts |
317
|
|
|
|
|
|
|
{ |
318
|
0
|
|
|
0
|
1
|
|
my ($self, $defs) = @_; |
319
|
|
|
|
|
|
|
|
320
|
0
|
|
|
|
|
|
foreach my $def (@$defs) |
321
|
|
|
|
|
|
|
{ |
322
|
0
|
|
|
|
|
|
my $opt = $self->_opts->{ $def->{name} }; |
323
|
0
|
0
|
|
|
|
|
return undef unless $self->_validate_value(opt => $def->{type}, $def->{name} => $opt); |
324
|
|
|
|
|
|
|
# unlike args, opts only get saved as context vars upon request |
325
|
0
|
0
|
|
|
|
|
$self->set_var($def->{name}, $opt) if $def->{access_as_var}; |
326
|
|
|
|
|
|
|
} |
327
|
0
|
|
|
|
|
|
return 1; |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
# Consolidate error message into a private method for consistency. |
331
|
|
|
|
|
|
|
sub _validate_value |
332
|
|
|
|
|
|
|
{ |
333
|
0
|
|
|
0
|
|
|
my ($self, $thing, $type, $name, $value) = @_; |
334
|
|
|
|
|
|
|
|
335
|
0
|
0
|
|
|
|
|
if ($type->check($value)) |
336
|
|
|
|
|
|
|
{ |
337
|
0
|
|
|
|
|
|
return 1; |
338
|
|
|
|
|
|
|
} |
339
|
|
|
|
|
|
|
else |
340
|
|
|
|
|
|
|
{ |
341
|
0
|
|
|
|
|
|
$self->usage_error("$thing $name fails validation [" . $type->validate($value) . "]"); |
342
|
0
|
|
|
|
|
|
return undef; |
343
|
|
|
|
|
|
|
} |
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
sub prep_logfile |
349
|
|
|
|
|
|
|
{ |
350
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
351
|
0
|
0
|
|
|
|
|
return unless $self->has_var('LOGFILE'); |
352
|
0
|
|
|
|
|
|
$self->_set_logfile( $self->_prep_filename($self->_vars->{LOGFILE}) ); |
353
|
0
|
|
|
|
|
|
return 1; |
354
|
|
|
|
|
|
|
} |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
sub prep_pidfile |
359
|
|
|
|
|
|
|
{ |
360
|
0
|
|
|
0
|
1
|
|
my ($self, $filename) = @_; |
361
|
0
|
|
|
|
|
|
require Proc::Pidfile; |
362
|
0
|
|
|
|
|
|
my $pidfile = eval { Proc::Pidfile->new( pidfile => $self->_prep_filename($filename) ) }; |
|
0
|
|
|
|
|
|
|
363
|
0
|
0
|
|
|
|
|
if ($pidfile) |
364
|
|
|
|
|
|
|
{ |
365
|
0
|
|
|
|
|
|
$self->_set_proc_pidfile($pidfile); |
366
|
|
|
|
|
|
|
} |
367
|
|
|
|
|
|
|
else |
368
|
|
|
|
|
|
|
{ |
369
|
0
|
0
|
|
|
|
|
if ( $@ =~ /already running: (\d+)/ ) |
370
|
|
|
|
|
|
|
{ |
371
|
0
|
|
|
|
|
|
$self->start_conditions_not_met("previous instance already running [$1]"); |
372
|
0
|
|
|
|
|
|
return undef; |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
else |
375
|
|
|
|
|
|
|
{ |
376
|
0
|
|
|
|
|
|
die; # rethrow |
377
|
|
|
|
|
|
|
} |
378
|
|
|
|
|
|
|
} |
379
|
0
|
|
|
|
|
|
return 1; |
380
|
|
|
|
|
|
|
} |
381
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
1; |
384
|
|
|
|
|
|
|
|
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
# ABSTRACT: context object for a Pb command |
388
|
|
|
|
|
|
|
# COPYRIGHT |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
__END__ |