line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Pb::Command::Context; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
our $VERSION = '0.01_04'; # TRIAL VERSION |
4
|
|
|
|
|
|
|
|
5
|
1
|
|
|
1
|
|
8
|
use Moo; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
8
|
|
6
|
1
|
|
|
1
|
|
433
|
use 5.14.0; |
|
1
|
|
|
|
|
3
|
|
7
|
1
|
|
|
1
|
|
7
|
use autodie ':all'; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
9
|
|
8
|
1
|
|
|
1
|
|
6334
|
use MooX::HandlesVia; |
|
1
|
|
|
|
|
745
|
|
|
1
|
|
|
|
|
8
|
|
9
|
1
|
|
|
1
|
|
553
|
use namespace::autoclean; |
|
1
|
|
|
|
|
11752
|
|
|
1
|
|
|
|
|
4
|
|
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
extends 'Clone'; # so we have our own `clone` method |
12
|
|
|
|
|
|
|
|
13
|
1
|
|
|
1
|
|
96
|
use Fcntl qw< :flock >; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
134
|
|
14
|
1
|
|
|
1
|
|
7
|
use File::Path qw< make_path >; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
52
|
|
15
|
1
|
|
|
1
|
|
463
|
use Const::Fast; |
|
1
|
|
|
|
|
1099
|
|
|
1
|
|
|
|
|
6
|
|
16
|
1
|
|
|
1
|
|
571
|
use Time::Piece; |
|
1
|
|
|
|
|
8763
|
|
|
1
|
|
|
|
|
4
|
|
17
|
1
|
|
|
1
|
|
98
|
use File::Basename; |
|
1
|
|
|
|
|
13
|
|
|
1
|
|
|
|
|
277
|
|
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
|
|
8
|
use overload '%{}' => sub { (grep { caller =~ /^$_\b/ } @RAW_ACCESS) ? $_[0] : $_[0]->_vars }, fallback => 1; |
|
1
|
|
|
3
|
|
2
|
|
|
1
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
46
|
|
|
6
|
|
|
|
|
87
|
|
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
|
0
|
|
|
|
|
return 'ASKACTION' if $self->_opts->{interactive}; |
98
|
0
|
|
|
|
|
|
return 'ACTION'; |
99
|
|
|
|
|
|
|
} |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
sub _safe_file_rw |
102
|
|
|
|
|
|
|
{ |
103
|
0
|
|
|
0
|
|
|
my ($self, $file, $line) = @_; |
104
|
0
|
0
|
|
|
|
|
my ($open_mode, $lock_mode) = defined $line ? ('>', LOCK_EX) : ('<', LOCK_SH); |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
# This is essentially the same amount of paranoia that Proc::Pidfile undergoes. I just don't |
107
|
|
|
|
|
|
|
# have to catch all the errors because I have `autodie` turned on. |
108
|
|
|
|
|
|
|
eval |
109
|
0
|
|
|
|
|
|
{ |
110
|
0
|
|
|
|
|
|
local *FILE; |
111
|
0
|
|
|
|
|
|
open FILE, $open_mode, $file; |
112
|
0
|
|
|
|
|
|
flock FILE, $lock_mode; |
113
|
0
|
0
|
|
|
|
|
if ($open_mode eq '<') |
114
|
|
|
|
|
|
|
{ |
115
|
0
|
|
|
|
|
|
$line = ; |
116
|
0
|
|
|
|
|
|
chomp $line; |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
else |
119
|
|
|
|
|
|
|
{ |
120
|
0
|
|
|
|
|
|
say FILE $line; |
121
|
|
|
|
|
|
|
} |
122
|
0
|
|
|
|
|
|
flock FILE, LOCK_UN; |
123
|
0
|
|
|
|
|
|
close(FILE); |
124
|
|
|
|
|
|
|
}; |
125
|
0
|
0
|
|
|
|
|
if ($@) |
126
|
|
|
|
|
|
|
{ |
127
|
0
|
0
|
|
|
|
|
$self->raise_error("file read/write failure [" . $@ =~ s/ at .*? line \d+.*\n//sr . "]") |
128
|
|
|
|
|
|
|
unless $@ =~ /^Can't open '$file' for reading:/; |
129
|
|
|
|
|
|
|
} |
130
|
0
|
|
|
|
|
|
return $line; |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
################## |
136
|
|
|
|
|
|
|
# PUBLIC METHODS # |
137
|
|
|
|
|
|
|
################## |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
|
140
|
0
|
|
|
0
|
1
|
|
sub set_debug { my ($self, $level) = @_; $self->_vars->{DEBUG} = $level } |
|
0
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
|
142
|
0
|
|
|
0
|
1
|
|
sub set_var { my ($self, $var, $val) = @_; $self->_vars->{$var} = $val } |
|
0
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
# Currently, this just sets the `ERR` context var, but in the future it may do more. |
147
|
|
|
|
|
|
|
sub raise_error |
148
|
|
|
|
|
|
|
{ |
149
|
0
|
|
|
0
|
1
|
|
my ($self, $err) = @_; |
150
|
0
|
|
|
|
|
|
$self->_vars->{ERR} = $err; |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
# These are more specialized versions of `raise_error`; again, very simple to start with, but |
154
|
|
|
|
|
|
|
# there's room for expansion. |
155
|
|
|
|
|
|
|
sub syntax_error |
156
|
|
|
|
|
|
|
{ |
157
|
0
|
|
|
0
|
1
|
|
my ($self, $err) = @_; |
158
|
0
|
|
|
|
|
|
$self->_dont_update_statfile; # syntax errors shouldn't fire the `unless_clean_exit` condition |
159
|
0
|
|
|
|
|
|
$self->raise_error($err); |
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
sub usage_error |
162
|
|
|
|
|
|
|
{ |
163
|
0
|
|
|
0
|
1
|
|
my ($self, $err) = @_; |
164
|
0
|
|
|
|
|
|
$self->_dont_update_statfile; # usage errors shouldn't fire the `unless_clean_exit` condition |
165
|
0
|
|
|
|
|
|
$self->raise_error($err); |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
sub start_conditions_not_met |
168
|
|
|
|
|
|
|
{ |
169
|
0
|
|
|
0
|
1
|
|
my ($self, $err) = @_; |
170
|
|
|
|
|
|
|
# Again, since the command is not going to get run, these errors can't fire off the |
171
|
|
|
|
|
|
|
# `unless_clean_exit` condition. |
172
|
0
|
|
|
|
|
|
$self->_dont_update_statfile; |
173
|
0
|
|
|
|
|
|
$self->raise_error($err); |
174
|
|
|
|
|
|
|
} |
175
|
|
|
|
|
|
|
|
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
###################### |
178
|
|
|
|
|
|
|
# STRUCTURE BUILDERS # |
179
|
|
|
|
|
|
|
###################### |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
sub setup_context |
183
|
|
|
|
|
|
|
{ |
184
|
0
|
|
|
0
|
1
|
|
my ($inv, $vars, $optdefs, $control) = @_; |
185
|
0
|
0
|
|
|
|
|
my $self = ref $inv ? $inv->clone : $inv->new; |
186
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
# set whatever vars weren't already set |
188
|
0
|
|
|
|
|
|
$self->set_var($_ => $vars->{$_}) foreach keys %$vars; |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
# validate opts (this might also set some vars) |
191
|
0
|
|
|
|
|
|
$self->validate_opts($optdefs); |
192
|
0
|
0
|
|
|
|
|
return $self if $self->error; # no point in continuing if an opt was bobbled |
193
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
# have to do this at runtime so that we only create a logfile for the running command |
195
|
0
|
|
|
|
|
|
$self->prep_logfile; |
196
|
|
|
|
|
|
|
# have to this at run time so we have parsed options to work with |
197
|
0
|
|
|
|
|
|
$self->_set_runmode( $self->_extrapolate_run_mode ); |
198
|
|
|
|
|
|
|
|
199
|
|
|
|
|
|
|
# process control stuff; some of this might mean we have to bail out |
200
|
0
|
0
|
|
|
|
|
unless ( $self->_process_control_structure($control) ) |
201
|
|
|
|
|
|
|
{ |
202
|
|
|
|
|
|
|
# this should never be necessary; `error` should always be set by `_process_control_structure` |
203
|
0
|
0
|
|
|
|
|
$self->syntax_error('Unknown error processing control structure') unless $self->error; |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
0
|
|
|
|
|
|
return $self; |
207
|
|
|
|
|
|
|
} |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
# This deals with all the stuff you can put in the "control structure (i.e. the hashref that follows |
210
|
|
|
|
|
|
|
# the `control_via` keyword). |
211
|
|
|
|
|
|
|
sub _process_control_structure |
212
|
|
|
|
|
|
|
{ |
213
|
0
|
|
|
0
|
|
|
my ($self, $control) = @_; |
214
|
|
|
|
|
|
|
|
215
|
0
|
|
|
|
|
|
foreach (grep { exists $control->{$_} } qw< pidfile statusfile unless_clean_exit >) |
|
0
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
{ |
217
|
0
|
|
|
|
|
|
my $value = delete $control->{$_}; |
218
|
0
|
0
|
|
|
|
|
if ($_ eq 'pidfile') |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
219
|
|
|
|
|
|
|
{ |
220
|
0
|
0
|
|
|
|
|
return undef unless $self->prep_pidfile($value); |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
elsif ($_ eq 'statusfile') |
223
|
|
|
|
|
|
|
{ |
224
|
0
|
|
|
|
|
|
$self->_set_statfile($self->_prep_filename($value)); |
225
|
|
|
|
|
|
|
my $statfile = sub |
226
|
|
|
|
|
|
|
{ |
227
|
0
|
0
|
|
0
|
|
|
if ($self->update_statfile) |
228
|
|
|
|
|
|
|
{ |
229
|
0
|
|
0
|
|
|
|
my $exit_status = $self->error // $CLEAN_EXIT; |
230
|
0
|
|
|
|
|
|
$self->_safe_file_rw($self->statfile, "last run: $exit_status at " . scalar localtime); |
231
|
|
|
|
|
|
|
} |
232
|
0
|
|
|
|
|
|
}; |
233
|
|
|
|
|
|
|
# have to use string `eval` here, otherwise the `END` will always fire |
234
|
0
|
|
|
|
|
|
eval 'END { $statfile->() }'; |
235
|
|
|
|
|
|
|
} |
236
|
|
|
|
|
|
|
elsif ($_ eq 'unless_clean_exit') |
237
|
|
|
|
|
|
|
{ |
238
|
0
|
0
|
|
|
|
|
unless (defined $self->statfile) |
239
|
|
|
|
|
|
|
{ |
240
|
0
|
|
|
|
|
|
$self->syntax_error("cannot specify `unless_clean_exit' without `statusfile'"); |
241
|
0
|
|
|
|
|
|
return undef; |
242
|
|
|
|
|
|
|
} |
243
|
0
|
|
|
|
|
|
my $lastrun = $self->_safe_file_rw($self->statfile); |
244
|
0
|
0
|
|
|
|
|
return undef if $self->error; |
245
|
0
|
0
|
|
|
|
|
if ($lastrun) # if not, probably means this is the first run |
246
|
|
|
|
|
|
|
{ |
247
|
0
|
|
|
|
|
|
my ($last_exit) = $lastrun =~ /: (.*?) at /; |
248
|
0
|
0
|
|
|
|
|
unless ($last_exit eq $CLEAN_EXIT) |
249
|
|
|
|
|
|
|
{ |
250
|
0
|
|
|
|
|
|
$self->raise_error($last_exit); # in case our message wants to access %ERR |
251
|
0
|
|
|
|
|
|
my $msg = $self->_expand_vars($value); |
252
|
0
|
|
|
|
|
|
$self->start_conditions_not_met($msg); # this is the real (user-supplied) error message |
253
|
0
|
|
|
|
|
|
return undef; |
254
|
|
|
|
|
|
|
} |
255
|
|
|
|
|
|
|
} |
256
|
|
|
|
|
|
|
} |
257
|
|
|
|
|
|
|
} |
258
|
0
|
0
|
|
|
|
|
if ( %$control ) |
259
|
|
|
|
|
|
|
{ |
260
|
0
|
|
|
|
|
|
$self->syntax_error("unknown parameter(s) in control structure [" . join(',', sort keys %$control) . "]"); |
261
|
0
|
|
|
|
|
|
return undef; |
262
|
|
|
|
|
|
|
} |
263
|
|
|
|
|
|
|
else |
264
|
|
|
|
|
|
|
{ |
265
|
0
|
|
|
|
|
|
return 1; |
266
|
|
|
|
|
|
|
} |
267
|
|
|
|
|
|
|
} |
268
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
|
271
|
|
|
|
|
|
|
sub connect_to |
272
|
|
|
|
|
|
|
{ |
273
|
0
|
|
|
0
|
1
|
|
my ($self, $command) = @_; |
274
|
|
|
|
|
|
|
|
275
|
|
|
|
|
|
|
# This little dance is to find the ultimate parent command in case we end up with an inline |
276
|
|
|
|
|
|
|
# subcommand or somesuch (viz. CLI::Osprey::InlineSubcommand). |
277
|
0
|
|
|
|
|
|
my $top_level = $command; |
278
|
0
|
|
0
|
|
|
|
$top_level = $top_level->parent_command while $top_level->can('parent_command') and $top_level->parent_command; |
279
|
|
|
|
|
|
|
|
280
|
0
|
|
|
|
|
|
$self->_set_toplevel_command($top_level); |
281
|
0
|
|
|
|
|
|
$self->_vars->{ME} = $top_level->invoked_as; |
282
|
0
|
|
|
|
|
|
$self->_parse_opts($command); |
283
|
|
|
|
|
|
|
} |
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
# Build the options hash. Merges both local and global opts. |
286
|
|
|
|
|
|
|
sub _parse_opts |
287
|
|
|
|
|
|
|
{ |
288
|
0
|
|
|
0
|
|
|
my ($self, $command) = @_; |
289
|
0
|
|
|
|
|
|
my $optobj_method = '_osprey_options'; |
290
|
0
|
0
|
|
|
|
|
my %opt_objects = $command->can($optobj_method) ? $command->$optobj_method : (); |
291
|
0
|
|
|
|
|
|
$self->_opts->{$_} = $command->$_ foreach keys %opt_objects; |
292
|
|
|
|
|
|
|
# get options from top-level command as well (these are the global opts) |
293
|
|
|
|
|
|
|
{ |
294
|
|
|
|
|
|
|
# I'm pretty sure the top-level command will always have an options method. |
295
|
0
|
|
|
|
|
|
my %opt_objects = $self->toplevel_command->$optobj_method; |
|
0
|
|
|
|
|
|
|
296
|
0
|
|
0
|
|
|
|
$self->_opts->{$_} //= $self->toplevel_command->$_ foreach keys %opt_objects; |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
sub validate_args |
303
|
|
|
|
|
|
|
{ |
304
|
0
|
|
|
0
|
1
|
|
my $defs = pop; |
305
|
0
|
|
|
|
|
|
my ($self, @args) = @_; |
306
|
|
|
|
|
|
|
|
307
|
0
|
|
|
|
|
|
foreach my $def (@$defs) |
308
|
|
|
|
|
|
|
{ |
309
|
0
|
|
|
|
|
|
my $arg = shift @args; |
310
|
0
|
0
|
|
|
|
|
return undef unless $self->_validate_value(arg => $def->{type}, $def->{name} => $arg); |
311
|
0
|
|
|
|
|
|
$self->set_var($def->{name}, $arg); |
312
|
|
|
|
|
|
|
} |
313
|
0
|
|
|
|
|
|
return 1; |
314
|
|
|
|
|
|
|
} |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
sub validate_opts |
318
|
|
|
|
|
|
|
{ |
319
|
0
|
|
|
0
|
1
|
|
my ($self, $defs) = @_; |
320
|
|
|
|
|
|
|
|
321
|
0
|
|
|
|
|
|
foreach my $def (@$defs) |
322
|
|
|
|
|
|
|
{ |
323
|
0
|
|
|
|
|
|
my $opt = $self->_opts->{ $def->{name} }; |
324
|
0
|
0
|
|
|
|
|
return undef unless $self->_validate_value(opt => $def->{type}, $def->{name} => $opt); |
325
|
|
|
|
|
|
|
# unlike args, opts only get saved as context vars upon request |
326
|
0
|
0
|
|
|
|
|
$self->set_var($def->{name}, $opt) if $def->{access_as_var}; |
327
|
|
|
|
|
|
|
} |
328
|
0
|
|
|
|
|
|
return 1; |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
# Consolidate error message into a private method for consistency. |
332
|
|
|
|
|
|
|
sub _validate_value |
333
|
|
|
|
|
|
|
{ |
334
|
0
|
|
|
0
|
|
|
my ($self, $thing, $type, $name, $value) = @_; |
335
|
|
|
|
|
|
|
|
336
|
0
|
0
|
|
|
|
|
if ($type->check($value)) |
337
|
|
|
|
|
|
|
{ |
338
|
0
|
|
|
|
|
|
return 1; |
339
|
|
|
|
|
|
|
} |
340
|
|
|
|
|
|
|
else |
341
|
|
|
|
|
|
|
{ |
342
|
0
|
|
|
|
|
|
$self->usage_error("$thing $name fails validation [" . $type->validate($value) . "]"); |
343
|
0
|
|
|
|
|
|
return undef; |
344
|
|
|
|
|
|
|
} |
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
|
349
|
|
|
|
|
|
|
sub prep_logfile |
350
|
|
|
|
|
|
|
{ |
351
|
0
|
|
|
0
|
1
|
|
my $self = shift; |
352
|
0
|
0
|
|
|
|
|
return unless $self->has_var('LOGFILE'); |
353
|
0
|
|
|
|
|
|
$self->_set_logfile( $self->_prep_filename($self->_vars->{LOGFILE}) ); |
354
|
0
|
|
|
|
|
|
return 1; |
355
|
|
|
|
|
|
|
} |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
sub prep_pidfile |
360
|
|
|
|
|
|
|
{ |
361
|
0
|
|
|
0
|
1
|
|
my ($self, $filename) = @_; |
362
|
0
|
|
|
|
|
|
require Proc::Pidfile; |
363
|
0
|
|
|
|
|
|
my $pidfile = eval { Proc::Pidfile->new( pidfile => $self->_prep_filename($filename) ) }; |
|
0
|
|
|
|
|
|
|
364
|
0
|
0
|
|
|
|
|
if ($pidfile) |
365
|
|
|
|
|
|
|
{ |
366
|
0
|
|
|
|
|
|
$self->_set_proc_pidfile($pidfile); |
367
|
|
|
|
|
|
|
} |
368
|
|
|
|
|
|
|
else |
369
|
|
|
|
|
|
|
{ |
370
|
0
|
0
|
|
|
|
|
if ( $@ =~ /already running: (\d+)/ ) |
371
|
|
|
|
|
|
|
{ |
372
|
0
|
|
|
|
|
|
$self->start_conditions_not_met("previous instance already running [$1]"); |
373
|
0
|
|
|
|
|
|
return undef; |
374
|
|
|
|
|
|
|
} |
375
|
|
|
|
|
|
|
else |
376
|
|
|
|
|
|
|
{ |
377
|
0
|
|
|
|
|
|
die; # rethrow |
378
|
|
|
|
|
|
|
} |
379
|
|
|
|
|
|
|
} |
380
|
0
|
|
|
|
|
|
return 1; |
381
|
|
|
|
|
|
|
} |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
1; |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
# ABSTRACT: context object for a Pb command |
389
|
|
|
|
|
|
|
# COPYRIGHT |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
__END__ |