| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Command::V2; # additional methods to dispatch from a command-line |
|
2
|
9
|
|
|
9
|
|
195
|
use strict; |
|
|
9
|
|
|
|
|
10
|
|
|
|
9
|
|
|
|
|
230
|
|
|
3
|
9
|
|
|
9
|
|
32
|
use warnings; |
|
|
9
|
|
|
|
|
11
|
|
|
|
9
|
|
|
|
|
224
|
|
|
4
|
|
|
|
|
|
|
|
|
5
|
9
|
|
|
9
|
|
33
|
use IO::File; |
|
|
9
|
|
|
|
|
10
|
|
|
|
9
|
|
|
|
|
1316
|
|
|
6
|
9
|
|
|
9
|
|
40
|
use List::MoreUtils; |
|
|
9
|
|
|
|
|
12
|
|
|
|
9
|
|
|
|
|
121
|
|
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
# instead of tacking these methods onto general Command::V2 objects |
|
9
|
|
|
|
|
|
|
# they could be put on the Command::Shell class, which is a wrapper/adaptor Command for translating from |
|
10
|
|
|
|
|
|
|
# command-line shell to purely functional commands. |
|
11
|
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
# old entry point |
|
13
|
|
|
|
|
|
|
# new cmds will call Command::Shell->run("MyClass",@ARGV) |
|
14
|
|
|
|
|
|
|
# which goes straight into _cmdline_run for now... |
|
15
|
|
|
|
|
|
|
sub execute_with_shell_params_and_exit { |
|
16
|
0
|
|
|
0
|
0
|
0
|
my $class = shift; |
|
17
|
0
|
0
|
|
|
|
0
|
if (@_) { |
|
18
|
0
|
|
|
|
|
0
|
die "No params expected for execute_with_shell_params_and_exit()!"; |
|
19
|
|
|
|
|
|
|
} |
|
20
|
0
|
|
|
|
|
0
|
my @argv = @ARGV; |
|
21
|
0
|
|
|
|
|
0
|
@ARGV = (); |
|
22
|
0
|
|
|
|
|
0
|
my $exit_code = $class->_cmdline_run(@argv); |
|
23
|
0
|
|
|
|
|
0
|
exit $exit_code; |
|
24
|
|
|
|
|
|
|
} |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
sub _cmdline_run { |
|
27
|
|
|
|
|
|
|
# This automatically parses command-line options and "does the right thing": |
|
28
|
|
|
|
|
|
|
# TODO: abstract out all dispatchers for commands into a given API |
|
29
|
0
|
|
|
0
|
|
0
|
my $class = shift; |
|
30
|
0
|
|
|
|
|
0
|
my @argv = @_; |
|
31
|
|
|
|
|
|
|
|
|
32
|
0
|
|
0
|
|
|
0
|
$Command::entry_point_class ||= $class; |
|
33
|
0
|
|
0
|
|
|
0
|
$Command::entry_point_bin ||= File::Basename::basename($0); |
|
34
|
|
|
|
|
|
|
|
|
35
|
0
|
0
|
|
|
|
0
|
if ($ENV{COMP_CWORD}) { |
|
36
|
0
|
|
|
|
|
0
|
require Getopt::Complete; |
|
37
|
0
|
|
|
|
|
0
|
my @spec = $class->resolve_option_completion_spec(); |
|
38
|
0
|
|
|
|
|
0
|
my $options = Getopt::Complete::Options->new(@spec); |
|
39
|
0
|
|
|
|
|
0
|
$options->handle_shell_completion; |
|
40
|
0
|
|
|
|
|
0
|
die "error: failed to exit after handling shell completion!"; |
|
41
|
|
|
|
|
|
|
} |
|
42
|
|
|
|
|
|
|
|
|
43
|
0
|
|
|
|
|
0
|
my $exit_code; |
|
44
|
0
|
|
|
|
|
0
|
eval { |
|
45
|
0
|
|
|
|
|
0
|
$exit_code = $class->_execute_with_shell_params_and_return_exit_code(@argv); |
|
46
|
0
|
0
|
|
|
|
0
|
UR::Context->commit or die "Failed to commit!: " . UR::Context->error_message(); |
|
47
|
|
|
|
|
|
|
}; |
|
48
|
0
|
0
|
|
|
|
0
|
if ($@) { |
|
49
|
0
|
|
|
|
|
0
|
$class->error_message($@); |
|
50
|
0
|
0
|
|
|
|
0
|
UR::Context->rollback or die "Failed to rollback changes after failed commit!!!\n"; |
|
51
|
0
|
0
|
|
|
|
0
|
$exit_code = 255 unless ($exit_code); |
|
52
|
|
|
|
|
|
|
} |
|
53
|
0
|
|
|
|
|
0
|
return $exit_code; |
|
54
|
|
|
|
|
|
|
} |
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
sub _execute_with_shell_params_and_return_exit_code { |
|
57
|
1
|
|
|
1
|
|
1047
|
my $class = shift; |
|
58
|
1
|
|
|
|
|
3
|
my @argv = @_; |
|
59
|
|
|
|
|
|
|
|
|
60
|
1
|
|
|
|
|
3
|
my $original_cmdline = join("\0",$0,@argv); |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
# make --foo=bar equivalent to --foo bar |
|
63
|
1
|
0
|
|
|
|
3
|
@argv = map { ($_ =~ /^(--\w+?)\=(.*)/) ? ($1,$2) : ($_) } @argv; |
|
|
0
|
|
|
|
|
0
|
|
|
64
|
1
|
|
|
|
|
8
|
my ($delegate_class, $params, $errors) = $class->resolve_class_and_params_for_argv(@argv); |
|
65
|
|
|
|
|
|
|
|
|
66
|
1
|
|
|
|
|
1
|
my $exit_code; |
|
67
|
1
|
50
|
33
|
|
|
5
|
if ($errors and @$errors) { |
|
68
|
0
|
|
|
|
|
0
|
$delegate_class->dump_status_messages(1); |
|
69
|
0
|
|
|
|
|
0
|
$delegate_class->dump_warning_messages(1); |
|
70
|
0
|
|
|
|
|
0
|
$delegate_class->dump_error_messages(1); |
|
71
|
0
|
|
|
|
|
0
|
for my $error (@$errors) { |
|
72
|
0
|
|
|
|
|
0
|
$delegate_class->error_message(join(' ', $error->property_names) . ": " . $error->desc); |
|
73
|
|
|
|
|
|
|
} |
|
74
|
0
|
|
|
|
|
0
|
$exit_code = 1; |
|
75
|
|
|
|
|
|
|
} |
|
76
|
|
|
|
|
|
|
else { |
|
77
|
1
|
|
|
|
|
7
|
my $rv = $class->_execute_delegate_class_with_params($delegate_class,$params,$original_cmdline); |
|
78
|
1
|
|
|
|
|
9
|
$exit_code = $delegate_class->exit_code_for_return_value($rv); |
|
79
|
|
|
|
|
|
|
} |
|
80
|
|
|
|
|
|
|
|
|
81
|
1
|
|
|
|
|
3
|
return $exit_code; |
|
82
|
|
|
|
|
|
|
} |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
sub _execute_delegate_class_with_params { |
|
86
|
|
|
|
|
|
|
# this is called by both the shell dispatcher and http dispatcher for now |
|
87
|
3
|
|
|
3
|
|
1433
|
my ($class, $delegate_class, $params, $original_cmdline) = @_; |
|
88
|
|
|
|
|
|
|
|
|
89
|
3
|
50
|
|
|
|
10
|
unless ($delegate_class) { |
|
90
|
0
|
|
|
|
|
0
|
$class->dump_status_messages(1); |
|
91
|
0
|
|
|
|
|
0
|
$class->dump_warning_messages(1); |
|
92
|
0
|
|
|
|
|
0
|
$class->dump_error_messages(1); |
|
93
|
0
|
|
|
|
|
0
|
$class->dump_usage_messages(1); |
|
94
|
0
|
|
|
|
|
0
|
$class->dump_debug_messages(0); |
|
95
|
0
|
|
|
|
|
0
|
$class->usage_message($class->help_usage_complete_text); |
|
96
|
0
|
|
|
|
|
0
|
return; |
|
97
|
|
|
|
|
|
|
} |
|
98
|
|
|
|
|
|
|
|
|
99
|
3
|
|
|
|
|
20
|
$delegate_class->dump_status_messages(1); |
|
100
|
3
|
|
|
|
|
15
|
$delegate_class->dump_warning_messages(1); |
|
101
|
3
|
|
|
|
|
14
|
$delegate_class->dump_error_messages(1); |
|
102
|
3
|
|
|
|
|
13
|
$delegate_class->dump_usage_messages(1); |
|
103
|
3
|
|
|
|
|
15
|
$delegate_class->dump_debug_messages(0); |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
# FIXME There should be a better check for params that are there because they came from the |
|
106
|
|
|
|
|
|
|
# command line, and params that exist for infrastructural purposes. 'original_command_line' |
|
107
|
|
|
|
|
|
|
# won't ever be given on the command line and shouldn't count toward the next test. |
|
108
|
|
|
|
|
|
|
# maybe check the is_input properties... |
|
109
|
3
|
100
|
|
|
|
10
|
if ( !defined($params) ) { |
|
110
|
1
|
|
|
|
|
13
|
my $command_name = $delegate_class->command_name; |
|
111
|
1
|
|
|
|
|
7
|
$delegate_class->status_message($delegate_class->help_usage_complete_text); |
|
112
|
1
|
|
|
|
|
7
|
$delegate_class->error_message("Please specify valid params for '$command_name'."); |
|
113
|
1
|
|
|
|
|
3
|
return; |
|
114
|
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
|
|
116
|
2
|
50
|
|
|
|
5
|
if ( $params->{help} ) { |
|
117
|
0
|
|
|
|
|
0
|
$delegate_class->usage_message($delegate_class->help_usage_complete_text); |
|
118
|
0
|
|
|
|
|
0
|
return 1; |
|
119
|
|
|
|
|
|
|
} |
|
120
|
|
|
|
|
|
|
|
|
121
|
2
|
50
|
|
|
|
5
|
$params->{'original_command_line'} = $original_cmdline if (defined $original_cmdline); |
|
122
|
2
|
|
|
|
|
10
|
my $command_object = $delegate_class->create(%$params); |
|
123
|
|
|
|
|
|
|
|
|
124
|
2
|
50
|
|
|
|
7
|
unless ($command_object) { |
|
125
|
|
|
|
|
|
|
# The delegate class should have emitted an error message. |
|
126
|
|
|
|
|
|
|
# This is just in case the developer is sloppy, and the user will think the task did not fail. |
|
127
|
0
|
|
|
|
|
0
|
print STDERR "Exiting.\n"; |
|
128
|
0
|
|
|
|
|
0
|
return; |
|
129
|
|
|
|
|
|
|
} |
|
130
|
|
|
|
|
|
|
|
|
131
|
2
|
|
|
|
|
7
|
$command_object->dump_status_messages(1); |
|
132
|
2
|
|
|
|
|
8
|
$command_object->dump_warning_messages(1); |
|
133
|
2
|
|
|
|
|
4
|
$command_object->dump_error_messages(1); |
|
134
|
2
|
|
|
|
|
6
|
$command_object->dump_debug_messages($command_object->debug); |
|
135
|
2
|
100
|
|
|
|
4
|
if ($command_object->debug) { |
|
136
|
1
|
|
|
|
|
62
|
UR::ModuleBase->dump_debug_messages($command_object->debug); |
|
137
|
|
|
|
|
|
|
} |
|
138
|
|
|
|
|
|
|
|
|
139
|
2
|
|
|
|
|
45
|
my $rv = $command_object->execute($params); |
|
140
|
|
|
|
|
|
|
|
|
141
|
2
|
50
|
|
|
|
6
|
if ($command_object->__errors__) { |
|
142
|
0
|
|
|
|
|
0
|
$command_object->delete; |
|
143
|
|
|
|
|
|
|
} |
|
144
|
|
|
|
|
|
|
|
|
145
|
2
|
|
|
|
|
4
|
return $rv; |
|
146
|
|
|
|
|
|
|
} |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
sub resolve_class_and_params_for_argv { |
|
149
|
|
|
|
|
|
|
# This is used by execute_with_shell_params_and_exit, but might be used within an application. |
|
150
|
20
|
|
|
20
|
0
|
19692
|
my $self = shift; |
|
151
|
20
|
|
|
|
|
47
|
my @argv = @_; |
|
152
|
|
|
|
|
|
|
|
|
153
|
20
|
|
|
|
|
64
|
my ($params_hash,@spec) = $self->_shell_args_getopt_specification; |
|
154
|
20
|
50
|
|
|
|
31
|
unless (grep { /^help\W/ } @spec) { |
|
|
100
|
|
|
|
|
124
|
|
|
155
|
20
|
|
|
|
|
28
|
push @spec, "help!"; |
|
156
|
|
|
|
|
|
|
} |
|
157
|
|
|
|
|
|
|
|
|
158
|
20
|
|
|
|
|
18
|
my @error_tags; |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
# Thes nasty GetOptions modules insist on working on |
|
161
|
|
|
|
|
|
|
# the real @ARGV, while we like a little more flexibility. |
|
162
|
|
|
|
|
|
|
# Not a problem in Perl. :) (which is probably why it was never fixed) |
|
163
|
20
|
|
|
|
|
25
|
local @ARGV; |
|
164
|
20
|
|
|
|
|
34
|
@ARGV = @argv; |
|
165
|
|
|
|
|
|
|
|
|
166
|
20
|
|
|
|
|
17
|
do { |
|
167
|
|
|
|
|
|
|
# GetOptions also likes to emit warnings instead of return a list of errors :( |
|
168
|
20
|
|
|
|
|
17
|
my @errors; |
|
169
|
|
|
|
|
|
|
my $rv; |
|
170
|
|
|
|
|
|
|
{ |
|
171
|
20
|
|
|
0
|
|
8
|
local $SIG{__WARN__} = sub { push @errors, @_ }; |
|
|
20
|
|
|
|
|
114
|
|
|
|
0
|
|
|
|
|
0
|
|
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
## Change the pattern to be '--', '-' followed by a non-digit, or '+'. |
|
174
|
|
|
|
|
|
|
## This s the effect of treating a negative number as a value of an option. |
|
175
|
|
|
|
|
|
|
## This means that we won't be allowed to have an option named, say, -1. |
|
176
|
|
|
|
|
|
|
## But since command modules' properties have to be allowable function names, |
|
177
|
|
|
|
|
|
|
## and "1" is not a valid function name, it's not really a problem |
|
178
|
|
|
|
|
|
|
#Getopt::Long::Configure('prefix_pattern=--|-(?!\D)|\+'); |
|
179
|
20
|
|
|
|
|
65
|
$rv = GetOptions($params_hash,@spec); |
|
180
|
|
|
|
|
|
|
} |
|
181
|
20
|
50
|
|
|
|
7972
|
unless ($rv) { |
|
182
|
0
|
|
|
|
|
0
|
for my $error (@errors) { |
|
183
|
0
|
|
|
|
|
0
|
$self->error_message($error); |
|
184
|
|
|
|
|
|
|
} |
|
185
|
0
|
|
|
|
|
0
|
return($self, undef); |
|
186
|
|
|
|
|
|
|
} |
|
187
|
|
|
|
|
|
|
}; |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
# Q: Is there a standard getopt spec for capturing non-option paramters? |
|
190
|
|
|
|
|
|
|
# Perhaps that's not getting "options" :) |
|
191
|
|
|
|
|
|
|
# A: Yes. Use '<>'. But we need to process this anyway, so it won't help us. |
|
192
|
|
|
|
|
|
|
|
|
193
|
20
|
50
|
|
|
|
57
|
if (my @names = $self->_bare_shell_argument_names) { |
|
194
|
0
|
|
|
|
|
0
|
for (my $n=0; $n < @ARGV; $n++) { |
|
195
|
0
|
|
|
|
|
0
|
my $name = $names[$n]; |
|
196
|
0
|
0
|
|
|
|
0
|
unless ($name) { |
|
197
|
0
|
|
|
|
|
0
|
$self->error_message("Unexpected bare arguments: @ARGV[$n..$#ARGV]!"); |
|
198
|
0
|
|
|
|
|
0
|
return($self, undef); |
|
199
|
|
|
|
|
|
|
} |
|
200
|
0
|
|
|
|
|
0
|
my $value = $ARGV[$n]; |
|
201
|
0
|
|
|
|
|
0
|
my $meta = $self->__meta__->property_meta_for_name($name); |
|
202
|
0
|
0
|
0
|
|
|
0
|
if ($meta->is_many and $n == $#names) { |
|
203
|
|
|
|
|
|
|
# slurp the rest |
|
204
|
0
|
|
|
|
|
0
|
$params_hash->{$name} = [@ARGV[$n..$#ARGV]]; |
|
205
|
0
|
|
|
|
|
0
|
last; |
|
206
|
|
|
|
|
|
|
} |
|
207
|
|
|
|
|
|
|
else { |
|
208
|
0
|
|
|
|
|
0
|
$params_hash->{$name} = $value; |
|
209
|
|
|
|
|
|
|
} |
|
210
|
|
|
|
|
|
|
} |
|
211
|
|
|
|
|
|
|
} |
|
212
|
|
|
|
|
|
|
|
|
213
|
20
|
50
|
33
|
|
|
53
|
if (@ARGV and not $self->_bare_shell_argument_names) { |
|
214
|
|
|
|
|
|
|
## argv but no names |
|
215
|
0
|
|
|
|
|
0
|
$self->error_message("Unexpected bare arguments: @ARGV!"); |
|
216
|
0
|
|
|
|
|
0
|
return($self, undef); |
|
217
|
|
|
|
|
|
|
} |
|
218
|
|
|
|
|
|
|
|
|
219
|
20
|
|
|
|
|
57
|
for my $key (keys %$params_hash) { |
|
220
|
|
|
|
|
|
|
# handle any has-many comma-sep values |
|
221
|
29
|
|
|
|
|
33
|
my $value = $params_hash->{$key}; |
|
222
|
29
|
50
|
100
|
|
|
126
|
if (ref($value)) { |
|
|
|
100
|
|
|
|
|
|
|
223
|
0
|
|
|
|
|
0
|
my @new_value; |
|
224
|
0
|
|
|
|
|
0
|
for my $v (@$value) { |
|
225
|
0
|
|
|
|
|
0
|
my @parts = split(/,\s*/,$v); |
|
226
|
0
|
|
|
|
|
0
|
push @new_value, @parts; |
|
227
|
|
|
|
|
|
|
} |
|
228
|
0
|
|
|
|
|
0
|
@$value = @new_value; |
|
229
|
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
} elsif ($value eq q('') or $value eq q("")) { |
|
231
|
|
|
|
|
|
|
# Handle the special values '' and "" to mean undef/NULL |
|
232
|
4
|
|
|
|
|
4
|
$params_hash->{$key} = ''; |
|
233
|
|
|
|
|
|
|
} |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
# turn dashes into underscores |
|
236
|
29
|
|
|
|
|
25
|
my $new_key = $key; |
|
237
|
|
|
|
|
|
|
|
|
238
|
29
|
100
|
|
|
|
68
|
next unless ($new_key =~ tr/-/_/); |
|
239
|
28
|
0
|
33
|
|
|
47
|
if (exists $params_hash->{$new_key} && exists $params_hash->{$key}) { |
|
240
|
|
|
|
|
|
|
# this corrects a problem where is_many properties badly interact |
|
241
|
|
|
|
|
|
|
# with bare args leaving two entries in the hash like: |
|
242
|
|
|
|
|
|
|
# a-bare-opt => [], a_bare_opt => ['with','vals'] |
|
243
|
0
|
|
|
|
|
0
|
delete $params_hash->{$key}; |
|
244
|
0
|
|
|
|
|
0
|
next; |
|
245
|
|
|
|
|
|
|
} |
|
246
|
28
|
|
|
|
|
51
|
$params_hash->{$new_key} = delete $params_hash->{$key}; |
|
247
|
|
|
|
|
|
|
} |
|
248
|
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
# futher work is looking for errors, and may display them |
|
250
|
|
|
|
|
|
|
# if help is set, return now |
|
251
|
|
|
|
|
|
|
# we might have returned sooner, but having full info available |
|
252
|
|
|
|
|
|
|
# allows for dynamic help |
|
253
|
20
|
50
|
|
|
|
40
|
if ($params_hash->{help}) { |
|
254
|
0
|
|
|
|
|
0
|
return ($self, $params_hash); |
|
255
|
|
|
|
|
|
|
} |
|
256
|
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
## |
|
258
|
20
|
|
|
|
|
19
|
my $params = $params_hash; |
|
259
|
20
|
|
|
|
|
61
|
my $class = $self->class; |
|
260
|
|
|
|
|
|
|
|
|
261
|
20
|
100
|
|
|
|
48
|
if (my @errors = $self->_errors_from_missing_parameters($params)) { |
|
262
|
17
|
|
|
|
|
84
|
return ($class, $params, \@errors); |
|
263
|
|
|
|
|
|
|
} |
|
264
|
|
|
|
|
|
|
|
|
265
|
3
|
50
|
|
|
|
7
|
unless (@_) { |
|
266
|
0
|
|
|
|
|
0
|
return ($class, $params); |
|
267
|
|
|
|
|
|
|
} |
|
268
|
|
|
|
|
|
|
|
|
269
|
|
|
|
|
|
|
# should this be moved up into the methods which are only called |
|
270
|
|
|
|
|
|
|
# directly from the shell, or is it okay everywhere in this module to |
|
271
|
|
|
|
|
|
|
# presume we're a direct cmdline call? -ssmith |
|
272
|
|
|
|
|
|
|
local $ENV{UR_COMMAND_DUMP_STATUS_MESSAGES} = (!exists($ENV{UR_COMMAND_DUMP_STATUS_MESSAGES}) |
|
273
|
3
|
|
33
|
|
|
32
|
or $ENV{UR_COMMAND_DUMP_STATUS_MESSAGES}); |
|
274
|
|
|
|
|
|
|
|
|
275
|
3
|
|
|
|
|
21
|
my @params_to_resolve = $self->_params_to_resolve($params); |
|
276
|
3
|
|
|
|
|
5
|
for my $p (@params_to_resolve) { |
|
277
|
0
|
|
|
|
|
0
|
my $param_arg_str = join(',', @{$p->{value}}); |
|
|
0
|
|
|
|
|
0
|
|
|
278
|
0
|
|
|
|
|
0
|
my $pmeta = $self->__meta__->property($p->{name}); |
|
279
|
|
|
|
|
|
|
|
|
280
|
0
|
|
|
|
|
0
|
my @params; |
|
281
|
0
|
|
|
|
|
0
|
eval { |
|
282
|
0
|
|
|
|
|
0
|
@params = $self->resolve_param_value_from_cmdline_text($p); |
|
283
|
|
|
|
|
|
|
}; |
|
284
|
|
|
|
|
|
|
|
|
285
|
0
|
0
|
|
|
|
0
|
if ($@) { |
|
286
|
|
|
|
|
|
|
push @error_tags, UR::Object::Tag->create( |
|
287
|
|
|
|
|
|
|
type => 'invalid', |
|
288
|
0
|
|
|
|
|
0
|
properties => [$p->{name}], |
|
289
|
|
|
|
|
|
|
desc => "Errors while resolving from $param_arg_str: $@", |
|
290
|
|
|
|
|
|
|
); |
|
291
|
|
|
|
|
|
|
} |
|
292
|
0
|
0
|
0
|
|
|
0
|
if (@params and $params[0]) { |
|
293
|
0
|
0
|
|
|
|
0
|
if ($pmeta->{'is_many'}) { |
|
294
|
0
|
|
|
|
|
0
|
$params->{$p->{name}} = \@params; |
|
295
|
|
|
|
|
|
|
} |
|
296
|
|
|
|
|
|
|
else { |
|
297
|
0
|
|
|
|
|
0
|
$params->{$p->{name}} = $params[0]; |
|
298
|
|
|
|
|
|
|
} |
|
299
|
|
|
|
|
|
|
} |
|
300
|
|
|
|
|
|
|
else { |
|
301
|
|
|
|
|
|
|
push @error_tags, UR::Object::Tag->create( |
|
302
|
|
|
|
|
|
|
type => 'invalid', |
|
303
|
0
|
|
|
|
|
0
|
properties => [$p->{name}], |
|
304
|
|
|
|
|
|
|
desc => "Problem resolving from $param_arg_str.", |
|
305
|
|
|
|
|
|
|
); |
|
306
|
|
|
|
|
|
|
} |
|
307
|
|
|
|
|
|
|
} |
|
308
|
|
|
|
|
|
|
|
|
309
|
3
|
50
|
|
|
|
9
|
if (@error_tags) { |
|
310
|
0
|
|
|
|
|
0
|
return ($class, undef, \@error_tags); |
|
311
|
|
|
|
|
|
|
} |
|
312
|
|
|
|
|
|
|
else { |
|
313
|
3
|
|
|
|
|
29
|
return ($class, $params); |
|
314
|
|
|
|
|
|
|
} |
|
315
|
|
|
|
|
|
|
} |
|
316
|
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
sub resolve_option_completion_spec { |
|
318
|
6
|
|
|
6
|
0
|
11
|
my $class = shift; |
|
319
|
6
|
|
|
|
|
35
|
my @completion_spec = $class->_shell_args_getopt_complete_specification; |
|
320
|
9
|
|
|
9
|
|
13157
|
no warnings; |
|
|
9
|
|
|
|
|
16
|
|
|
|
9
|
|
|
|
|
8226
|
|
|
321
|
6
|
50
|
|
|
|
13
|
unless (grep { /^help\W/ } @completion_spec) { |
|
|
72
|
|
|
|
|
74
|
|
|
322
|
6
|
|
|
|
|
11
|
push @completion_spec, "help!" => undef; |
|
323
|
|
|
|
|
|
|
} |
|
324
|
|
|
|
|
|
|
return \@completion_spec |
|
325
|
6
|
|
|
|
|
14
|
} |
|
326
|
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
sub _errors_from_missing_parameters { |
|
328
|
20
|
|
|
20
|
|
17
|
my ($self, $params) = @_; |
|
329
|
|
|
|
|
|
|
|
|
330
|
20
|
|
|
|
|
63
|
my $class_meta = $self->__meta__; |
|
331
|
|
|
|
|
|
|
|
|
332
|
20
|
|
|
|
|
448
|
my @all_property_metas = $class_meta->properties(); |
|
333
|
20
|
|
|
|
|
40
|
my @specified_property_metas = grep { exists $params->{$_->property_name} } @all_property_metas; |
|
|
260
|
|
|
|
|
360
|
|
|
334
|
|
|
|
|
|
|
|
|
335
|
20
|
|
|
|
|
26
|
my %specified_property_metas = map { $_->property_name => $_ } @specified_property_metas; |
|
|
29
|
|
|
|
|
39
|
|
|
336
|
20
|
|
|
|
|
24
|
my %set_indirectly; |
|
337
|
20
|
|
|
|
|
26
|
my @todo = @specified_property_metas; |
|
338
|
20
|
|
|
|
|
46
|
while (my $property_meta = shift @todo) { |
|
339
|
29
|
50
|
|
|
|
53
|
if (my $via = $property_meta->via) { |
|
|
|
50
|
|
|
|
|
|
|
340
|
0
|
0
|
|
|
|
0
|
if (not $property_meta->is_mutable) { |
|
341
|
0
|
|
0
|
|
|
0
|
my $list = $set_indirectly{$via} ||= []; |
|
342
|
0
|
|
|
|
|
0
|
push @$list, $property_meta; |
|
343
|
|
|
|
|
|
|
} |
|
344
|
0
|
0
|
|
|
|
0
|
unless ($specified_property_metas{$via}) { |
|
345
|
0
|
|
|
|
|
0
|
my $via_meta = $specified_property_metas{$via} = $class_meta->property($via); |
|
346
|
0
|
|
|
|
|
0
|
push @specified_property_metas, $via_meta; |
|
347
|
0
|
|
|
|
|
0
|
push @todo, $via_meta; |
|
348
|
|
|
|
|
|
|
} |
|
349
|
|
|
|
|
|
|
} |
|
350
|
|
|
|
|
|
|
elsif (my $id_by = $property_meta) { |
|
351
|
29
|
|
50
|
|
|
128
|
my $list = $set_indirectly{$id_by} ||= []; |
|
352
|
29
|
|
|
|
|
40
|
push @$list, $property_meta; |
|
353
|
29
|
50
|
|
|
|
55
|
unless ($specified_property_metas{$id_by}) { |
|
354
|
29
|
|
|
|
|
71
|
my $id_by_meta = $specified_property_metas{$id_by} = $class_meta->property($id_by); |
|
355
|
29
|
|
|
|
|
29
|
push @specified_property_metas, $id_by_meta; |
|
356
|
29
|
|
|
|
|
66
|
push @todo, $id_by_meta; |
|
357
|
|
|
|
|
|
|
} |
|
358
|
|
|
|
|
|
|
} |
|
359
|
|
|
|
|
|
|
} |
|
360
|
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
# TODO: this should use @all_property_metas, and filter down to is_param and is_input |
|
362
|
|
|
|
|
|
|
# This old code just ignores things inherited from a base class. |
|
363
|
|
|
|
|
|
|
# We will need to be careful fixing this because it could add checks to tools which |
|
364
|
|
|
|
|
|
|
# work currently and lead to unexpected failures. |
|
365
|
20
|
|
|
|
|
19
|
my @property_names; |
|
366
|
20
|
50
|
|
|
|
42
|
if (my $has = $class_meta->{has}) { |
|
367
|
20
|
|
|
|
|
153
|
@property_names = List::MoreUtils::uniq(keys %$has); |
|
368
|
|
|
|
|
|
|
} |
|
369
|
20
|
|
|
|
|
47
|
my @property_metas = map { $class_meta->property_meta_for_name($_); } @property_names; |
|
|
120
|
|
|
|
|
179
|
|
|
370
|
|
|
|
|
|
|
|
|
371
|
20
|
|
|
|
|
23
|
my @error_tags; |
|
372
|
20
|
|
|
|
|
30
|
for my $property_meta (@property_metas) { |
|
373
|
120
|
|
|
|
|
191
|
my $pn = $property_meta->property_name; |
|
374
|
|
|
|
|
|
|
|
|
375
|
120
|
100
|
|
|
|
168
|
next if $property_meta->is_optional; |
|
376
|
60
|
50
|
|
|
|
86
|
next if $property_meta->implied_by; |
|
377
|
60
|
50
|
|
|
|
111
|
next if defined $property_meta->default_value; |
|
378
|
60
|
100
|
|
|
|
91
|
next if defined $params->{$pn}; |
|
379
|
50
|
50
|
|
|
|
70
|
next if $set_indirectly{$pn}; |
|
380
|
|
|
|
|
|
|
|
|
381
|
50
|
50
|
|
|
|
81
|
if (my $via = $property_meta->via) { |
|
382
|
0
|
0
|
0
|
|
|
0
|
if ($params->{$via} or $set_indirectly{$via}) { |
|
383
|
0
|
|
|
|
|
0
|
next; |
|
384
|
|
|
|
|
|
|
} |
|
385
|
|
|
|
|
|
|
} |
|
386
|
|
|
|
|
|
|
|
|
387
|
50
|
|
|
|
|
53
|
my $arg = $pn; |
|
388
|
50
|
|
|
|
|
120
|
$arg =~ s/_/-/g; |
|
389
|
50
|
|
|
|
|
63
|
$arg = "--$arg"; |
|
390
|
|
|
|
|
|
|
|
|
391
|
50
|
100
|
66
|
|
|
183
|
if ($property_meta->is_output and not $property_meta->is_input and not $property_meta->is_param) { |
|
|
|
|
66
|
|
|
|
|
|
392
|
20
|
50
|
33
|
|
|
57
|
if ($property_meta->_data_type_as_class_name->__meta__->data_source |
|
|
|
50
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
and not $property_meta->_data_type_as_class_name->isa("UR::Value") |
|
394
|
|
|
|
|
|
|
) { |
|
395
|
|
|
|
|
|
|
# outputs with a data source do not need a specification |
|
396
|
|
|
|
|
|
|
# on the cmdline to "store" them after execution |
|
397
|
0
|
|
|
|
|
0
|
next; |
|
398
|
|
|
|
|
|
|
} |
|
399
|
|
|
|
|
|
|
elsif ($property_meta->is_calculated) { |
|
400
|
|
|
|
|
|
|
# outputs that are calculated don't need to be specified on |
|
401
|
|
|
|
|
|
|
# the command line |
|
402
|
20
|
|
|
|
|
43
|
next; |
|
403
|
|
|
|
|
|
|
} |
|
404
|
|
|
|
|
|
|
else { |
|
405
|
0
|
|
|
|
|
0
|
push @error_tags, UR::Object::Tag->create( |
|
406
|
|
|
|
|
|
|
type => 'invalid', |
|
407
|
|
|
|
|
|
|
properties => [$pn], |
|
408
|
|
|
|
|
|
|
desc => "Output requires specified destination: " . $arg . "." |
|
409
|
|
|
|
|
|
|
); |
|
410
|
|
|
|
|
|
|
} |
|
411
|
|
|
|
|
|
|
} |
|
412
|
|
|
|
|
|
|
else { |
|
413
|
30
|
|
|
|
|
49
|
$DB::single = 1; |
|
414
|
30
|
|
|
|
|
136
|
push @error_tags, UR::Object::Tag->create( |
|
415
|
|
|
|
|
|
|
type => 'invalid', |
|
416
|
|
|
|
|
|
|
properties => [$pn], |
|
417
|
|
|
|
|
|
|
desc => "Missing required parameter: " . $arg . "." |
|
418
|
|
|
|
|
|
|
); |
|
419
|
|
|
|
|
|
|
} |
|
420
|
|
|
|
|
|
|
} |
|
421
|
|
|
|
|
|
|
|
|
422
|
20
|
|
|
|
|
117
|
return @error_tags; |
|
423
|
|
|
|
|
|
|
} |
|
424
|
|
|
|
|
|
|
|
|
425
|
|
|
|
|
|
|
sub _params_to_resolve { |
|
426
|
3
|
|
|
3
|
|
5
|
my ($self, $params) = @_; |
|
427
|
3
|
|
|
|
|
4
|
my @params_to_resolve; |
|
428
|
3
|
50
|
|
|
|
9
|
if ($params) { |
|
429
|
3
|
|
|
|
|
11
|
my $cmeta = $self->__meta__; |
|
430
|
3
|
|
|
|
|
5
|
my @params_will_require_verification; |
|
431
|
|
|
|
|
|
|
my @params_may_require_verification; |
|
432
|
|
|
|
|
|
|
|
|
433
|
3
|
|
|
|
|
7
|
for my $param_name (keys %$params) { |
|
434
|
6
|
|
|
|
|
20
|
my $pmeta = $cmeta->property($param_name); |
|
435
|
6
|
50
|
|
|
|
11
|
unless ($pmeta) { |
|
436
|
|
|
|
|
|
|
# This message was a die after a next, so I guess it isn't supposed to be fatal? |
|
437
|
0
|
|
|
|
|
0
|
$self->warning_message("No metadata for property '$param_name'"); |
|
438
|
0
|
|
|
|
|
0
|
next; |
|
439
|
|
|
|
|
|
|
} |
|
440
|
|
|
|
|
|
|
|
|
441
|
6
|
|
|
|
|
16
|
my $param_type = $pmeta->data_type; |
|
442
|
6
|
50
|
|
|
|
17
|
next unless($self->_can_resolve_type($param_type)); |
|
443
|
|
|
|
|
|
|
|
|
444
|
0
|
|
|
|
|
0
|
my $param_arg = $params->{$param_name}; |
|
445
|
0
|
0
|
|
|
|
0
|
if (my $arg_type = ref($param_arg)) { |
|
446
|
0
|
0
|
|
|
|
0
|
next if $arg_type eq $param_type; # param is already the right type |
|
447
|
0
|
0
|
|
|
|
0
|
if ($arg_type ne 'ARRAY') { |
|
448
|
0
|
|
|
|
|
0
|
$self->error_message("no handler for property '$param_name' with argument type " . ref($param_arg)); |
|
449
|
0
|
|
|
|
|
0
|
next; |
|
450
|
|
|
|
|
|
|
} |
|
451
|
|
|
|
|
|
|
} else { |
|
452
|
0
|
|
|
|
|
0
|
$param_arg = [$param_arg]; |
|
453
|
|
|
|
|
|
|
} |
|
454
|
0
|
0
|
|
|
|
0
|
next unless (@$param_arg); |
|
455
|
|
|
|
|
|
|
|
|
456
|
0
|
|
|
|
|
0
|
my $resolve_info = { |
|
457
|
|
|
|
|
|
|
name => $param_name, |
|
458
|
|
|
|
|
|
|
class => $param_type, |
|
459
|
|
|
|
|
|
|
value => $param_arg, |
|
460
|
|
|
|
|
|
|
}; |
|
461
|
0
|
|
|
|
|
0
|
push(@params_to_resolve, $resolve_info); |
|
462
|
|
|
|
|
|
|
|
|
463
|
0
|
|
|
|
|
0
|
my $require_user_verify = $pmeta->{'require_user_verify'}; |
|
464
|
0
|
0
|
|
|
|
0
|
if ( defined($require_user_verify) ) { |
|
465
|
0
|
0
|
|
|
|
0
|
push @params_will_require_verification, "'$param_name'" if ($require_user_verify); |
|
466
|
|
|
|
|
|
|
} else { |
|
467
|
0
|
|
|
|
|
0
|
push @params_may_require_verification, "'$param_name'"; |
|
468
|
|
|
|
|
|
|
} |
|
469
|
|
|
|
|
|
|
} |
|
470
|
|
|
|
|
|
|
|
|
471
|
3
|
|
|
|
|
8
|
my @adverbs = ('will', 'may'); |
|
472
|
3
|
|
|
|
|
8
|
my @params_adverb_require_verification = ( |
|
473
|
|
|
|
|
|
|
\@params_will_require_verification, |
|
474
|
|
|
|
|
|
|
\@params_may_require_verification, |
|
475
|
|
|
|
|
|
|
); |
|
476
|
3
|
|
|
|
|
15
|
for (my $i = 0; $i < @adverbs; $i++) { |
|
477
|
6
|
|
|
|
|
8
|
my $adverb = $adverbs[$i]; |
|
478
|
6
|
|
|
|
|
6
|
my @param_adverb_require_verification = @{$params_adverb_require_verification[$i]}; |
|
|
6
|
|
|
|
|
10
|
|
|
479
|
6
|
50
|
|
|
|
20
|
next unless (@param_adverb_require_verification); |
|
480
|
|
|
|
|
|
|
|
|
481
|
0
|
0
|
|
|
|
0
|
if (@param_adverb_require_verification > 1) { |
|
482
|
0
|
|
|
|
|
0
|
$param_adverb_require_verification[-1] = 'and ' . $param_adverb_require_verification[-1]; |
|
483
|
|
|
|
|
|
|
} |
|
484
|
0
|
|
|
|
|
0
|
my $param_str = join(', ', @param_adverb_require_verification); |
|
485
|
0
|
|
|
|
|
0
|
$self->status_message($param_str . " $adverb require verification..."); |
|
486
|
|
|
|
|
|
|
} |
|
487
|
|
|
|
|
|
|
} |
|
488
|
3
|
|
|
|
|
9
|
return @params_to_resolve; |
|
489
|
|
|
|
|
|
|
} |
|
490
|
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
sub _can_resolve_type { |
|
492
|
6
|
|
|
6
|
|
11
|
my ($self, $type) = @_; |
|
493
|
|
|
|
|
|
|
|
|
494
|
6
|
50
|
|
|
|
9
|
return 0 unless($type); |
|
495
|
|
|
|
|
|
|
|
|
496
|
6
|
|
|
|
|
9
|
my $non_classes = 0; |
|
497
|
6
|
50
|
|
|
|
12
|
if (ref($type) ne 'ARRAY') { |
|
498
|
6
|
|
|
|
|
12
|
$non_classes = $type !~ m/::/; |
|
499
|
|
|
|
|
|
|
} else { |
|
500
|
0
|
|
|
|
|
0
|
$non_classes = scalar grep { ! m/::/ } @$type; |
|
|
0
|
|
|
|
|
0
|
|
|
501
|
|
|
|
|
|
|
} |
|
502
|
6
|
|
|
|
|
20
|
return $non_classes == 0; |
|
503
|
|
|
|
|
|
|
} |
|
504
|
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
sub _shell_args_property_meta { |
|
506
|
58
|
|
|
58
|
|
59
|
my $self = shift; |
|
507
|
58
|
|
|
|
|
149
|
my $class_meta = $self->__meta__; |
|
508
|
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
# Find which property metas match the rules. We have to do it this way |
|
510
|
|
|
|
|
|
|
# because just calling 'get_all_property_metas()' will product multiple matches |
|
511
|
|
|
|
|
|
|
# if a property is overridden in a child class |
|
512
|
58
|
|
|
|
|
197
|
my ($rule, %extra) = UR::Object::Property->define_boolexpr(@_); |
|
513
|
58
|
|
|
|
|
60
|
my %seen; |
|
514
|
58
|
|
|
|
|
54
|
my (@positional,@required_input,@required_param,@optional_input,@optional_param, @output); |
|
515
|
|
|
|
|
|
|
|
|
516
|
58
|
|
|
|
|
1479
|
my @property_meta = $class_meta->properties(); |
|
517
|
|
|
|
|
|
|
PROP: |
|
518
|
58
|
|
|
|
|
111
|
foreach my $property_meta (@property_meta) { |
|
519
|
749
|
|
|
|
|
2832
|
my $property_name = $property_meta->property_name; |
|
520
|
|
|
|
|
|
|
|
|
521
|
749
|
50
|
|
|
|
1364
|
next if $seen{$property_name}++; |
|
522
|
749
|
100
|
|
|
|
1496
|
next unless $rule->evaluate($property_meta); |
|
523
|
725
|
100
|
100
|
|
|
1337
|
next unless $property_meta->can("is_param") and ($property_meta->is_param or $property_meta->is_input or $property_meta->is_output); |
|
|
|
|
66
|
|
|
|
|
|
524
|
377
|
100
|
|
|
|
709
|
if (%extra) { |
|
525
|
9
|
|
|
9
|
|
52
|
no warnings; |
|
|
9
|
|
|
|
|
12
|
|
|
|
9
|
|
|
|
|
30651
|
|
|
526
|
6
|
|
|
|
|
9
|
for my $key (keys %extra) { |
|
527
|
6
|
100
|
|
|
|
18
|
if ($property_meta->$key ne $extra{$key}) { |
|
528
|
4
|
|
|
|
|
8
|
next PROP; |
|
529
|
|
|
|
|
|
|
} |
|
530
|
|
|
|
|
|
|
} |
|
531
|
|
|
|
|
|
|
} |
|
532
|
|
|
|
|
|
|
|
|
533
|
373
|
50
|
|
|
|
557
|
next if $property_name eq 'id'; |
|
534
|
373
|
100
|
|
|
|
553
|
next if $property_name eq 'result'; |
|
535
|
320
|
50
|
|
|
|
390
|
next if $property_name eq 'is_executed'; |
|
536
|
320
|
50
|
|
|
|
383
|
next if $property_name eq 'original_command_line'; |
|
537
|
320
|
50
|
|
|
|
469
|
next if $property_name =~ /^_/; |
|
538
|
|
|
|
|
|
|
|
|
539
|
320
|
50
|
|
|
|
620
|
next if $property_meta->implied_by; |
|
540
|
320
|
100
|
|
|
|
479
|
next if $property_meta->is_calculated; |
|
541
|
|
|
|
|
|
|
# Kept commented out from UR's Command.pm, I believe is_output is a workflow property |
|
542
|
|
|
|
|
|
|
# and not something we need to exclude (counter to the old comment below). |
|
543
|
|
|
|
|
|
|
#next if $property_meta->{is_output}; # TODO: This was breaking the G::M::T::Annotate::TranscriptVariants annotator. This should probably still be here but temporarily roll back |
|
544
|
280
|
50
|
|
|
|
445
|
next if $property_meta->is_transient; |
|
545
|
280
|
100
|
|
|
|
423
|
next if $property_meta->is_constant; |
|
546
|
279
|
50
|
66
|
|
|
443
|
if (($property_meta->is_delegated) || (defined($property_meta->data_type) and $property_meta->data_type =~ /::/)) { |
|
|
|
|
33
|
|
|
|
|
|
547
|
0
|
0
|
|
|
|
0
|
next unless($self->can('resolve_param_value_from_cmdline_text')); |
|
548
|
|
|
|
|
|
|
} |
|
549
|
|
|
|
|
|
|
else { |
|
550
|
279
|
50
|
|
|
|
445
|
next unless($property_meta->is_mutable); |
|
551
|
|
|
|
|
|
|
} |
|
552
|
|
|
|
|
|
|
|
|
553
|
279
|
100
|
|
|
|
653
|
if ($property_meta->{shell_args_position}) { |
|
|
|
100
|
|
|
|
|
|
|
554
|
16
|
|
|
|
|
33
|
push @positional, $property_meta; |
|
555
|
|
|
|
|
|
|
} |
|
556
|
|
|
|
|
|
|
elsif ($property_meta->is_optional) { |
|
557
|
168
|
100
|
66
|
|
|
534
|
if ($property_meta->is_input or $property_meta->is_output) { |
|
|
|
50
|
|
|
|
|
|
|
558
|
15
|
|
|
|
|
27
|
push @optional_input, $property_meta; |
|
559
|
|
|
|
|
|
|
} |
|
560
|
|
|
|
|
|
|
elsif ($property_meta->is_param) { |
|
561
|
153
|
|
|
|
|
245
|
push @optional_param, $property_meta; |
|
562
|
|
|
|
|
|
|
} |
|
563
|
|
|
|
|
|
|
} |
|
564
|
|
|
|
|
|
|
else { |
|
565
|
95
|
100
|
66
|
|
|
303
|
if ($property_meta->is_input or $property_meta->is_output) { |
|
|
|
50
|
|
|
|
|
|
|
566
|
8
|
|
|
|
|
23
|
push @required_input, $property_meta; |
|
567
|
|
|
|
|
|
|
} |
|
568
|
|
|
|
|
|
|
elsif ($property_meta->is_param) { |
|
569
|
87
|
|
|
|
|
139
|
push @required_param, $property_meta; |
|
570
|
|
|
|
|
|
|
} |
|
571
|
|
|
|
|
|
|
} |
|
572
|
|
|
|
|
|
|
} |
|
573
|
|
|
|
|
|
|
|
|
574
|
58
|
|
|
|
|
45
|
my @result; |
|
575
|
|
|
|
|
|
|
@result = ( |
|
576
|
46
|
|
|
|
|
120
|
(sort { $a->position_in_module_header cmp $b->position_in_module_header } @required_param), |
|
577
|
145
|
|
|
|
|
235
|
(sort { $a->position_in_module_header cmp $b->position_in_module_header } @optional_param), |
|
578
|
0
|
|
|
|
|
0
|
(sort { $a->position_in_module_header cmp $b->position_in_module_header } @required_input), |
|
579
|
7
|
|
|
|
|
18
|
(sort { $a->position_in_module_header cmp $b->position_in_module_header } @optional_input), |
|
580
|
58
|
|
|
|
|
188
|
(sort { $a->shell_args_position <=> $b->shell_args_position } @positional), |
|
|
6
|
|
|
|
|
23
|
|
|
581
|
|
|
|
|
|
|
); |
|
582
|
|
|
|
|
|
|
|
|
583
|
58
|
|
|
|
|
315
|
return @result; |
|
584
|
|
|
|
|
|
|
} |
|
585
|
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
sub _shell_arg_name_from_property_meta { |
|
588
|
137
|
|
|
137
|
|
114
|
my ($self, $property_meta,$singularize) = @_; |
|
589
|
137
|
50
|
|
|
|
288
|
my $property_name = ($singularize ? $property_meta->singular_name : $property_meta->property_name); |
|
590
|
137
|
|
|
|
|
114
|
my $param_name = $property_name; |
|
591
|
137
|
|
|
|
|
220
|
$param_name =~ s/_/-/g; |
|
592
|
137
|
|
|
|
|
174
|
return $param_name; |
|
593
|
|
|
|
|
|
|
} |
|
594
|
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
sub _shell_arg_getopt_qualifier_from_property_meta { |
|
596
|
136
|
|
|
136
|
|
103
|
my ($self, $property_meta) = @_; |
|
597
|
|
|
|
|
|
|
|
|
598
|
136
|
100
|
|
|
|
206
|
my $many = ($property_meta->is_many ? '@' : ''); |
|
599
|
136
|
100
|
100
|
|
|
195
|
if (defined($property_meta->data_type) and $property_meta->data_type =~ /Boolean/) { |
|
600
|
9
|
|
|
|
|
28
|
return '!' . $many; |
|
601
|
|
|
|
|
|
|
} |
|
602
|
|
|
|
|
|
|
#elsif ($property_meta->is_optional) { |
|
603
|
|
|
|
|
|
|
# return ':s' . $many; |
|
604
|
|
|
|
|
|
|
#} |
|
605
|
|
|
|
|
|
|
else { |
|
606
|
127
|
|
|
|
|
289
|
return '=s' . $many; |
|
607
|
|
|
|
|
|
|
} |
|
608
|
|
|
|
|
|
|
} |
|
609
|
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
sub _shell_arg_usage_string_from_property_meta { |
|
611
|
0
|
|
|
0
|
|
0
|
my ($self, $property_meta) = @_; |
|
612
|
0
|
|
|
|
|
0
|
my $string = $self->_shell_arg_name_from_property_meta($property_meta); |
|
613
|
0
|
0
|
|
|
|
0
|
if ($property_meta->{shell_args_position}) { |
|
614
|
0
|
|
|
|
|
0
|
$string = uc($string); |
|
615
|
|
|
|
|
|
|
} |
|
616
|
|
|
|
|
|
|
|
|
617
|
0
|
0
|
|
|
|
0
|
if ($property_meta->{shell_args_position}) { |
|
618
|
0
|
0
|
|
|
|
0
|
if ($property_meta->is_optional) { |
|
619
|
0
|
|
|
|
|
0
|
$string = "[$string]"; |
|
620
|
|
|
|
|
|
|
} |
|
621
|
|
|
|
|
|
|
} |
|
622
|
|
|
|
|
|
|
else { |
|
623
|
0
|
|
|
|
|
0
|
$string = "--$string"; |
|
624
|
0
|
0
|
0
|
|
|
0
|
if (defined($property_meta->data_type) and $property_meta->data_type =~ /Boolean/) { |
|
625
|
0
|
|
|
|
|
0
|
$string = "[$string]"; |
|
626
|
|
|
|
|
|
|
} |
|
627
|
|
|
|
|
|
|
else { |
|
628
|
0
|
0
|
|
|
|
0
|
if ($property_meta->is_many) { |
|
629
|
0
|
|
|
|
|
0
|
$string .= "=?[,?]"; |
|
630
|
|
|
|
|
|
|
} |
|
631
|
|
|
|
|
|
|
else { |
|
632
|
0
|
|
|
|
|
0
|
$string .= '=?'; |
|
633
|
|
|
|
|
|
|
} |
|
634
|
0
|
0
|
|
|
|
0
|
if ($property_meta->is_optional) { |
|
635
|
0
|
|
|
|
|
0
|
$string = "[$string]"; |
|
636
|
|
|
|
|
|
|
} |
|
637
|
|
|
|
|
|
|
} |
|
638
|
|
|
|
|
|
|
} |
|
639
|
0
|
|
|
|
|
0
|
return $string; |
|
640
|
|
|
|
|
|
|
} |
|
641
|
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
sub _shell_arg_getopt_specification_from_property_meta { |
|
643
|
100
|
|
|
100
|
|
80
|
my ($self,$property_meta) = @_; |
|
644
|
100
|
|
|
|
|
138
|
my $arg_name = $self->_shell_arg_name_from_property_meta($property_meta); |
|
645
|
|
|
|
|
|
|
return ( |
|
646
|
100
|
|
|
|
|
140
|
$arg_name . $self->_shell_arg_getopt_qualifier_from_property_meta($property_meta), |
|
647
|
|
|
|
|
|
|
#this prevents defaults from being used for is_many properties |
|
648
|
|
|
|
|
|
|
#($property_meta->is_many ? ($arg_name => []) : ()) |
|
649
|
|
|
|
|
|
|
); |
|
650
|
|
|
|
|
|
|
} |
|
651
|
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
|
|
653
|
|
|
|
|
|
|
sub _shell_arg_getopt_complete_specification_from_property_meta { |
|
654
|
36
|
|
|
36
|
|
32
|
my ($self,$property_meta) = @_; |
|
655
|
36
|
|
|
|
|
60
|
my $arg_name = $self->_shell_arg_name_from_property_meta($property_meta); |
|
656
|
36
|
|
|
|
|
56
|
my $completions = $property_meta->valid_values; |
|
657
|
36
|
100
|
|
|
|
43
|
if ($completions) { |
|
658
|
3
|
50
|
|
|
|
8
|
if (ref($completions) eq 'ARRAY') { |
|
659
|
3
|
|
|
|
|
13
|
$completions = [ @$completions ]; |
|
660
|
|
|
|
|
|
|
} |
|
661
|
|
|
|
|
|
|
} |
|
662
|
|
|
|
|
|
|
else { |
|
663
|
33
|
|
|
|
|
44
|
my $type = $property_meta->data_type; |
|
664
|
33
|
|
|
|
|
60
|
my @complete_as_files = ( |
|
665
|
|
|
|
|
|
|
'File','FilePath','Filesystem','FileSystem','FilesystemPath','FileSystemPath', |
|
666
|
|
|
|
|
|
|
'Text','String', |
|
667
|
|
|
|
|
|
|
); |
|
668
|
33
|
|
|
|
|
38
|
my @complete_as_directories = ( |
|
669
|
|
|
|
|
|
|
'Directory','DirectoryPath','Dir','DirPath', |
|
670
|
|
|
|
|
|
|
); |
|
671
|
33
|
100
|
|
|
|
65
|
if (!defined($type)) { |
|
672
|
1
|
|
|
|
|
2
|
$completions = 'files'; |
|
673
|
|
|
|
|
|
|
} |
|
674
|
|
|
|
|
|
|
else { |
|
675
|
32
|
|
|
|
|
29
|
for my $pattern (@complete_as_files) { |
|
676
|
238
|
100
|
66
|
|
|
580
|
if (!$type || $type eq $pattern) { |
|
677
|
19
|
|
|
|
|
14
|
$completions = 'files'; |
|
678
|
19
|
|
|
|
|
16
|
last; |
|
679
|
|
|
|
|
|
|
} |
|
680
|
|
|
|
|
|
|
} |
|
681
|
32
|
|
|
|
|
26
|
for my $pattern (@complete_as_directories) { |
|
682
|
128
|
50
|
33
|
|
|
319
|
if ( $type && $type eq $pattern) { |
|
683
|
0
|
|
|
|
|
0
|
$completions = 'directories'; |
|
684
|
0
|
|
|
|
|
0
|
last; |
|
685
|
|
|
|
|
|
|
} |
|
686
|
|
|
|
|
|
|
} |
|
687
|
|
|
|
|
|
|
} |
|
688
|
|
|
|
|
|
|
} |
|
689
|
|
|
|
|
|
|
return ( |
|
690
|
36
|
|
|
|
|
72
|
$arg_name . $self->_shell_arg_getopt_qualifier_from_property_meta($property_meta), |
|
691
|
|
|
|
|
|
|
$completions, |
|
692
|
|
|
|
|
|
|
# ($property_meta->is_many ? ($arg_name => []) : ()) |
|
693
|
|
|
|
|
|
|
); |
|
694
|
|
|
|
|
|
|
} |
|
695
|
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
sub _shell_args_getopt_specification { |
|
697
|
20
|
|
|
20
|
|
23
|
my $self = shift; |
|
698
|
20
|
|
|
|
|
20
|
my @getopt; |
|
699
|
|
|
|
|
|
|
my @params; |
|
700
|
20
|
|
|
|
|
52
|
for my $meta ($self->_shell_args_property_meta) { |
|
701
|
100
|
|
|
|
|
149
|
my ($spec, @params_addition) = $self->_shell_arg_getopt_specification_from_property_meta($meta); |
|
702
|
100
|
|
|
|
|
104
|
push @getopt,$spec; |
|
703
|
100
|
|
|
|
|
95
|
push @params, @params_addition; |
|
704
|
|
|
|
|
|
|
} |
|
705
|
20
|
|
|
|
|
51
|
@getopt = sort @getopt; |
|
706
|
20
|
|
|
|
|
63
|
return { @params}, @getopt; |
|
707
|
|
|
|
|
|
|
} |
|
708
|
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
sub _shell_args_getopt_complete_specification { |
|
710
|
6
|
|
|
6
|
|
11
|
my $self = shift; |
|
711
|
6
|
|
|
|
|
9
|
my @getopt; |
|
712
|
6
|
|
|
|
|
41
|
for my $meta ($self->_shell_args_property_meta) { |
|
713
|
36
|
|
|
|
|
102
|
my ($spec, $completions) = $self->_shell_arg_getopt_complete_specification_from_property_meta($meta); |
|
714
|
36
|
|
|
|
|
55
|
push @getopt, $spec, $completions; |
|
715
|
|
|
|
|
|
|
} |
|
716
|
6
|
|
|
|
|
28
|
return @getopt; |
|
717
|
|
|
|
|
|
|
} |
|
718
|
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
|
|
720
|
|
|
|
|
|
|
sub _bare_shell_argument_names { |
|
721
|
20
|
|
|
20
|
|
24
|
my $self = shift; |
|
722
|
20
|
|
|
|
|
59
|
my $meta = $self->__meta__; |
|
723
|
|
|
|
|
|
|
my @ordered_names = |
|
724
|
0
|
|
|
|
|
0
|
map { $_->property_name } |
|
725
|
0
|
|
|
|
|
0
|
sort { $a->{shell_args_position} <=> $b->{shell_args_position} } |
|
726
|
20
|
|
|
|
|
41
|
grep { $_->{shell_args_position} } |
|
|
100
|
|
|
|
|
108
|
|
|
727
|
|
|
|
|
|
|
$self->_shell_args_property_meta(); |
|
728
|
20
|
|
|
|
|
52
|
return @ordered_names; |
|
729
|
|
|
|
|
|
|
} |
|
730
|
|
|
|
|
|
|
|
|
731
|
|
|
|
|
|
|
# |
|
732
|
|
|
|
|
|
|
# Logic to turn command-line text into objects for parameter/input values |
|
733
|
|
|
|
|
|
|
# |
|
734
|
|
|
|
|
|
|
|
|
735
|
|
|
|
|
|
|
our %ALTERNATE_FROM_CLASS = (); |
|
736
|
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
# This will prevent infinite loops during recursion. |
|
738
|
|
|
|
|
|
|
our %SEEN_FROM_CLASS = (); |
|
739
|
|
|
|
|
|
|
our $MESSAGE; |
|
740
|
|
|
|
|
|
|
|
|
741
|
|
|
|
|
|
|
sub resolve_param_value_from_cmdline_text { |
|
742
|
3
|
|
|
3
|
0
|
5
|
my ($self, $param_info) = @_; |
|
743
|
3
|
|
|
|
|
10
|
my $param_name = $param_info->{name}; |
|
744
|
3
|
|
|
|
|
5
|
my $param_class = $param_info->{class}; |
|
745
|
3
|
|
|
|
|
3
|
my @param_args = @{$param_info->{value}}; |
|
|
3
|
|
|
|
|
6
|
|
|
746
|
3
|
|
|
|
|
8
|
my $param_str = join(',', @param_args); |
|
747
|
|
|
|
|
|
|
|
|
748
|
3
|
50
|
|
|
|
8
|
if (ref($param_class) eq 'ARRAY') { |
|
749
|
0
|
|
|
|
|
0
|
my @param_class = @$param_class; |
|
750
|
0
|
0
|
|
|
|
0
|
if (@param_class > 1) { |
|
751
|
0
|
|
|
|
|
0
|
die 'Multiple data types on command arguments are not supported.'; |
|
752
|
|
|
|
|
|
|
} else { |
|
753
|
0
|
|
|
|
|
0
|
$param_class = $param_class[0]; |
|
754
|
|
|
|
|
|
|
} |
|
755
|
|
|
|
|
|
|
} |
|
756
|
|
|
|
|
|
|
|
|
757
|
3
|
|
|
|
|
6
|
my $param_resolve_message = "Resolving parameter '$param_name' from command argument '$param_str'..."; |
|
758
|
3
|
|
|
|
|
10
|
my $pmeta = $self->__meta__->property($param_name); |
|
759
|
3
|
|
|
|
|
5
|
my $require_user_verify = $pmeta->{'require_user_verify'}; |
|
760
|
|
|
|
|
|
|
|
|
761
|
3
|
|
|
|
|
6
|
my @results; |
|
762
|
3
|
|
|
|
|
4
|
my $bx = eval { UR::BoolExpr->resolve_for_string($param_class, $param_str) }; |
|
|
3
|
|
|
|
|
10
|
|
|
763
|
3
|
|
|
|
|
5
|
my $bx_error = $@; |
|
764
|
3
|
100
|
|
|
|
6
|
if ($bx) { |
|
765
|
2
|
|
|
|
|
14
|
@results = $param_class->get($bx); |
|
766
|
2
|
50
|
33
|
|
|
9
|
if (@results > 1 && !defined($require_user_verify)) { |
|
767
|
0
|
|
|
|
|
0
|
$require_user_verify = 1; |
|
768
|
|
|
|
|
|
|
} |
|
769
|
|
|
|
|
|
|
} else { |
|
770
|
1
|
|
|
|
|
2
|
for my $arg (@param_args) { |
|
771
|
2
|
|
|
|
|
5
|
%SEEN_FROM_CLASS = (); |
|
772
|
|
|
|
|
|
|
|
|
773
|
|
|
|
|
|
|
# call resolve_param_value_from_text without a via_method to "bootstrap" recursion |
|
774
|
2
|
|
|
|
|
8
|
my @arg_results = $self->resolve_param_value_from_text($arg, $param_class); |
|
775
|
|
|
|
|
|
|
|
|
776
|
2
|
50
|
33
|
|
|
6
|
if (@arg_results != 1 && !defined($require_user_verify)) { |
|
777
|
0
|
|
|
|
|
0
|
$require_user_verify = 1; |
|
778
|
|
|
|
|
|
|
} |
|
779
|
|
|
|
|
|
|
|
|
780
|
2
|
|
|
|
|
3
|
push @results, @arg_results; |
|
781
|
|
|
|
|
|
|
} |
|
782
|
|
|
|
|
|
|
} |
|
783
|
3
|
50
|
|
|
|
9
|
if (@results) { |
|
784
|
|
|
|
|
|
|
# the ALTERNATE_FROM_CLASS stuff leads to non $param_class objects in results |
|
785
|
3
|
|
|
|
|
17
|
@results = List::MoreUtils::uniq(@results); |
|
786
|
3
|
|
|
|
|
6
|
@results = grep { $_->isa($param_class) } @results; |
|
|
6
|
|
|
|
|
21
|
|
|
787
|
|
|
|
|
|
|
|
|
788
|
3
|
|
|
|
|
30
|
$self->status_message($param_resolve_message . " found " . @results); |
|
789
|
|
|
|
|
|
|
} |
|
790
|
|
|
|
|
|
|
else { |
|
791
|
0
|
0
|
|
|
|
0
|
if ($bx_error) { |
|
792
|
0
|
|
|
|
|
0
|
$self->status_message($bx_error); |
|
793
|
|
|
|
|
|
|
} |
|
794
|
0
|
|
|
|
|
0
|
$self->status_message($param_resolve_message . " none found."); |
|
795
|
|
|
|
|
|
|
} |
|
796
|
|
|
|
|
|
|
|
|
797
|
3
|
50
|
|
|
|
15
|
return unless (@results); |
|
798
|
|
|
|
|
|
|
|
|
799
|
3
|
|
|
|
|
38
|
my $limit_results_method = "_limit_results_for_$param_name"; |
|
800
|
3
|
50
|
|
|
|
9
|
if ( $self->can($limit_results_method) ) { |
|
801
|
0
|
|
|
|
|
0
|
@results = $self->$limit_results_method(@results); |
|
802
|
0
|
0
|
|
|
|
0
|
return unless (@results); |
|
803
|
|
|
|
|
|
|
} |
|
804
|
3
|
|
|
|
|
212
|
@results = List::MoreUtils::uniq(@results); |
|
805
|
3
|
50
|
|
|
|
8
|
if ($require_user_verify) { |
|
806
|
0
|
0
|
0
|
|
|
0
|
if (!$pmeta->{'is_many'} && @results > 1) { |
|
807
|
0
|
0
|
|
|
|
0
|
$MESSAGE .= "\n" if ($MESSAGE); |
|
808
|
0
|
|
|
|
|
0
|
$MESSAGE .= "'$param_name' expects only one result."; |
|
809
|
|
|
|
|
|
|
|
|
810
|
0
|
0
|
|
|
|
0
|
if ($ENV{UR_NO_REQUIRE_USER_VERIFY}) { |
|
811
|
0
|
|
|
|
|
0
|
die "$MESSAGE\n"; |
|
812
|
|
|
|
|
|
|
} |
|
813
|
|
|
|
|
|
|
} |
|
814
|
0
|
|
|
|
|
0
|
@results = $self->_get_user_verification_for_param_value($param_name, @results); |
|
815
|
|
|
|
|
|
|
} |
|
816
|
3
|
|
33
|
|
|
10
|
while (!$pmeta->{'is_many'} && @results > 1) { |
|
817
|
0
|
0
|
|
|
|
0
|
$MESSAGE .= "\n" if ($MESSAGE); |
|
818
|
0
|
|
|
|
|
0
|
$MESSAGE .= "'$param_name' expects only one result, not many!"; |
|
819
|
0
|
|
|
|
|
0
|
@results = $self->_get_user_verification_for_param_value($param_name, @results); |
|
820
|
|
|
|
|
|
|
} |
|
821
|
|
|
|
|
|
|
|
|
822
|
3
|
50
|
|
|
|
5
|
if (wantarray) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
823
|
3
|
|
|
|
|
12
|
return @results; |
|
824
|
|
|
|
|
|
|
} |
|
825
|
|
|
|
|
|
|
elsif (not defined wantarray) { |
|
826
|
0
|
|
|
|
|
0
|
return; |
|
827
|
|
|
|
|
|
|
} |
|
828
|
|
|
|
|
|
|
elsif (@results > 1) { |
|
829
|
0
|
|
|
|
|
0
|
Carp::confess("Multiple matches found!"); |
|
830
|
|
|
|
|
|
|
} |
|
831
|
|
|
|
|
|
|
else { |
|
832
|
0
|
|
|
|
|
0
|
return $results[0]; |
|
833
|
|
|
|
|
|
|
} |
|
834
|
|
|
|
|
|
|
} |
|
835
|
|
|
|
|
|
|
|
|
836
|
|
|
|
|
|
|
sub resolve_param_value_from_text { |
|
837
|
2
|
|
|
2
|
0
|
4
|
my ($self, $param_arg, $param_class, $via_method) = @_; |
|
838
|
|
|
|
|
|
|
|
|
839
|
2
|
50
|
|
|
|
4
|
unless ($param_class) { |
|
840
|
0
|
|
|
|
|
0
|
$param_class = $self->class; |
|
841
|
|
|
|
|
|
|
} |
|
842
|
|
|
|
|
|
|
|
|
843
|
2
|
|
|
|
|
3
|
$SEEN_FROM_CLASS{$param_class} = 1; |
|
844
|
2
|
|
|
|
|
3
|
my @results; |
|
845
|
|
|
|
|
|
|
# try getting BoolExpr, otherwise fallback on '_resolve_param_value_from_text_by_name_or_id' parser |
|
846
|
2
|
|
|
|
|
3
|
eval { @results = $self->_resolve_param_value_from_text_by_bool_expr($param_class, $param_arg); }; |
|
|
2
|
|
|
|
|
6
|
|
|
847
|
2
|
50
|
33
|
|
|
13
|
Carp::croak($@) if ($@ and $@ !~ m/Not a valid BoolExpr/); |
|
848
|
2
|
50
|
33
|
|
|
9
|
if (!@results && !$@) { |
|
849
|
|
|
|
|
|
|
# no result and was valid BoolExpr then we don't want to break it apart because we |
|
850
|
|
|
|
|
|
|
# could query enormous amounts of info |
|
851
|
0
|
|
|
|
|
0
|
return; |
|
852
|
|
|
|
|
|
|
} |
|
853
|
|
|
|
|
|
|
# the first param_arg is all param_args to try BoolExpr so skip if it has commas |
|
854
|
2
|
50
|
33
|
|
|
8
|
if (!@results && $param_arg !~ /,/) { |
|
855
|
2
|
|
|
|
|
3
|
my @results_by_string; |
|
856
|
2
|
50
|
|
|
|
6
|
if ($param_class->can('_resolve_param_value_from_text_by_name_or_id')) { |
|
857
|
0
|
|
|
|
|
0
|
@results_by_string = $param_class->_resolve_param_value_from_text_by_name_or_id($param_arg); |
|
858
|
|
|
|
|
|
|
} |
|
859
|
|
|
|
|
|
|
else { |
|
860
|
2
|
|
|
|
|
101
|
@results_by_string = $self->_resolve_param_value_from_text_by_name_or_id($param_class, $param_arg); |
|
861
|
|
|
|
|
|
|
} |
|
862
|
2
|
|
|
|
|
3
|
push @results, @results_by_string; |
|
863
|
|
|
|
|
|
|
} |
|
864
|
|
|
|
|
|
|
# if we still don't have any values then try via alternate class |
|
865
|
2
|
0
|
33
|
|
|
3
|
if (!@results && $param_arg !~ /,/) { |
|
866
|
0
|
|
|
|
|
0
|
@results = $self->_resolve_param_value_via_related_class_method($param_class, $param_arg, $via_method); |
|
867
|
|
|
|
|
|
|
} |
|
868
|
|
|
|
|
|
|
|
|
869
|
2
|
50
|
|
|
|
4
|
if ($via_method) { |
|
870
|
0
|
|
|
|
|
0
|
@results = map { $_->$via_method } @results; |
|
|
0
|
|
|
|
|
0
|
|
|
871
|
|
|
|
|
|
|
} |
|
872
|
|
|
|
|
|
|
|
|
873
|
2
|
50
|
|
|
|
35
|
if (wantarray) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
874
|
2
|
|
|
|
|
4
|
return @results; |
|
875
|
|
|
|
|
|
|
} |
|
876
|
|
|
|
|
|
|
elsif (not defined wantarray) { |
|
877
|
0
|
|
|
|
|
0
|
return; |
|
878
|
|
|
|
|
|
|
} |
|
879
|
|
|
|
|
|
|
elsif (@results > 1) { |
|
880
|
0
|
|
|
|
|
0
|
Carp::confess("Multiple matches found!"); |
|
881
|
|
|
|
|
|
|
} |
|
882
|
|
|
|
|
|
|
else { |
|
883
|
0
|
|
|
|
|
0
|
return $results[0]; |
|
884
|
|
|
|
|
|
|
} |
|
885
|
|
|
|
|
|
|
} |
|
886
|
|
|
|
|
|
|
|
|
887
|
|
|
|
|
|
|
sub _resolve_param_value_via_related_class_method { |
|
888
|
0
|
|
|
0
|
|
0
|
my ($self, $param_class, $param_arg, $via_method) = @_; |
|
889
|
0
|
|
|
|
|
0
|
my @results; |
|
890
|
|
|
|
|
|
|
my $via_class; |
|
891
|
0
|
0
|
|
|
|
0
|
if (exists($ALTERNATE_FROM_CLASS{$param_class})) { |
|
892
|
0
|
|
|
|
|
0
|
$via_class = $param_class; |
|
893
|
|
|
|
|
|
|
} |
|
894
|
|
|
|
|
|
|
else { |
|
895
|
0
|
|
|
|
|
0
|
for my $class (keys %ALTERNATE_FROM_CLASS) { |
|
896
|
0
|
0
|
|
|
|
0
|
if ($param_class->isa($class)) { |
|
897
|
0
|
0
|
|
|
|
0
|
if ($via_class) { |
|
898
|
0
|
|
|
|
|
0
|
$self->error_message("Found additional via_class $class but already found $via_class!"); |
|
899
|
|
|
|
|
|
|
} |
|
900
|
0
|
|
|
|
|
0
|
$via_class = $class; |
|
901
|
|
|
|
|
|
|
} |
|
902
|
|
|
|
|
|
|
} |
|
903
|
|
|
|
|
|
|
} |
|
904
|
0
|
0
|
|
|
|
0
|
if ($via_class) { |
|
905
|
0
|
|
|
|
|
0
|
my @from_classes = sort keys %{$ALTERNATE_FROM_CLASS{$via_class}}; |
|
|
0
|
|
|
|
|
0
|
|
|
906
|
0
|
|
0
|
|
|
0
|
while (@from_classes && !@results) { |
|
907
|
0
|
|
|
|
|
0
|
my $from_class = shift @from_classes; |
|
908
|
0
|
|
|
|
|
0
|
my @methods = @{$ALTERNATE_FROM_CLASS{$via_class}{$from_class}}; |
|
|
0
|
|
|
|
|
0
|
|
|
909
|
0
|
|
|
|
|
0
|
my $method; |
|
910
|
0
|
0
|
0
|
|
|
0
|
if (@methods > 1 && !$via_method && !$ENV{UR_NO_REQUIRE_USER_VERIFY}) { |
|
|
|
|
0
|
|
|
|
|
|
911
|
0
|
|
|
|
|
0
|
$self->status_message("Trying to find $via_class via $from_class...\n"); |
|
912
|
0
|
|
|
|
|
0
|
my $method_choices; |
|
913
|
0
|
|
|
|
|
0
|
for (my $i = 0; $i < @methods; $i++) { |
|
914
|
0
|
|
|
|
|
0
|
$method_choices .= ($i + 1) . ": " . $methods[$i]; |
|
915
|
0
|
0
|
|
|
|
0
|
$method_choices .= " [default]" if ($i == 0); |
|
916
|
0
|
|
|
|
|
0
|
$method_choices .= "\n"; |
|
917
|
|
|
|
|
|
|
} |
|
918
|
0
|
|
|
|
|
0
|
$method_choices .= (scalar(@methods) + 1) . ": none\n"; |
|
919
|
0
|
|
|
|
|
0
|
$method_choices .= "Which method would you like to use?"; |
|
920
|
0
|
|
|
|
|
0
|
my $response = $self->_ask_user_question($method_choices, 0, '\d+', 1, '#'); |
|
921
|
0
|
0
|
|
|
|
0
|
if ($response =~ /^\d+$/) { |
|
|
|
0
|
|
|
|
|
|
|
922
|
0
|
|
|
|
|
0
|
$response--; |
|
923
|
0
|
0
|
0
|
|
|
0
|
if ($response == @methods) { |
|
|
|
0
|
|
|
|
|
|
|
924
|
0
|
|
|
|
|
0
|
$method = undef; |
|
925
|
|
|
|
|
|
|
} |
|
926
|
|
|
|
|
|
|
elsif ($response >= 0 && $response <= $#methods) { |
|
927
|
0
|
|
|
|
|
0
|
$method = $methods[$response]; |
|
928
|
|
|
|
|
|
|
} |
|
929
|
|
|
|
|
|
|
else { |
|
930
|
0
|
|
|
|
|
0
|
$self->error_message("Response was out of bounds, exiting..."); |
|
931
|
0
|
|
|
|
|
0
|
exit; |
|
932
|
|
|
|
|
|
|
} |
|
933
|
0
|
|
|
|
|
0
|
$ALTERNATE_FROM_CLASS{$via_class}{$from_class} = [$method]; |
|
934
|
|
|
|
|
|
|
} |
|
935
|
|
|
|
|
|
|
elsif (!$response) { |
|
936
|
0
|
|
|
|
|
0
|
$self->status_message("Exiting..."); |
|
937
|
|
|
|
|
|
|
} |
|
938
|
|
|
|
|
|
|
} |
|
939
|
|
|
|
|
|
|
else { |
|
940
|
0
|
|
|
|
|
0
|
$method = $methods[0]; |
|
941
|
|
|
|
|
|
|
} |
|
942
|
0
|
0
|
|
|
|
0
|
unless($SEEN_FROM_CLASS{$from_class}) { |
|
943
|
|
|
|
|
|
|
#$self->debug_message("Trying to find $via_class via $from_class->$method..."); |
|
944
|
0
|
|
|
|
|
0
|
@results = eval {$self->resolve_param_value_from_text($param_arg, $from_class, $method)}; |
|
|
0
|
|
|
|
|
0
|
|
|
945
|
|
|
|
|
|
|
} |
|
946
|
|
|
|
|
|
|
} # END for my $from_class (@from_classes) |
|
947
|
|
|
|
|
|
|
} # END if ($via_class) |
|
948
|
0
|
|
|
|
|
0
|
return @results; |
|
949
|
|
|
|
|
|
|
} |
|
950
|
|
|
|
|
|
|
|
|
951
|
|
|
|
|
|
|
sub _resolve_param_value_from_text_by_bool_expr { |
|
952
|
2
|
|
|
2
|
|
4
|
my ($self, $param_class, $arg) = @_; |
|
953
|
|
|
|
|
|
|
|
|
954
|
2
|
|
|
|
|
2
|
my @results; |
|
955
|
2
|
|
|
|
|
2
|
my $bx = eval { |
|
956
|
2
|
|
|
|
|
7
|
UR::BoolExpr->resolve_for_string($param_class, $arg); |
|
957
|
|
|
|
|
|
|
}; |
|
958
|
2
|
50
|
|
|
|
6
|
if ($bx) { |
|
959
|
0
|
|
|
|
|
0
|
@results = $param_class->get($bx); |
|
960
|
|
|
|
|
|
|
} |
|
961
|
|
|
|
|
|
|
else { |
|
962
|
2
|
|
|
|
|
14
|
die "Not a valid BoolExpr"; |
|
963
|
|
|
|
|
|
|
} |
|
964
|
|
|
|
|
|
|
#$self->debug_message("B: $param_class '$arg' " . scalar(@results)); |
|
965
|
|
|
|
|
|
|
|
|
966
|
0
|
|
|
|
|
0
|
return @results; |
|
967
|
|
|
|
|
|
|
} |
|
968
|
|
|
|
|
|
|
|
|
969
|
|
|
|
|
|
|
sub _try_get_by_id { |
|
970
|
2
|
|
|
2
|
|
1
|
my ($self, $param_class, $str) = @_; |
|
971
|
|
|
|
|
|
|
|
|
972
|
2
|
|
|
|
|
7
|
my $class_meta = $param_class->__meta__; |
|
973
|
2
|
|
|
|
|
7
|
my @id_property_names = $class_meta->id_property_names; |
|
974
|
2
|
50
|
|
|
|
10
|
if (@id_property_names == 0) { |
|
|
|
50
|
|
|
|
|
|
|
975
|
0
|
|
|
|
|
0
|
die "Failed to determine ID property names for class ($param_class)."; |
|
976
|
|
|
|
|
|
|
} elsif (@id_property_names == 1) { |
|
977
|
2
|
|
50
|
|
|
5
|
my $id_data_type = $class_meta->property_meta_for_name($id_property_names[0])->_data_type_as_class_name || ''; |
|
978
|
|
|
|
|
|
|
# Validate $str, if possible, to prevent warnings from database if $str does not fit column type. |
|
979
|
2
|
50
|
|
|
|
14
|
if ($id_data_type->isa('UR::Value::Number')) { # Oracle's Number data type includes floats but we just use integers for numeric IDs |
|
980
|
0
|
|
|
|
|
0
|
return ($str =~ /^[+-]?\d+$/); |
|
981
|
|
|
|
|
|
|
} |
|
982
|
|
|
|
|
|
|
} |
|
983
|
2
|
|
|
|
|
7
|
return 1; |
|
984
|
|
|
|
|
|
|
} |
|
985
|
|
|
|
|
|
|
|
|
986
|
|
|
|
|
|
|
sub _resolve_param_value_from_text_by_name_or_id { |
|
987
|
2
|
|
|
2
|
|
3
|
my ($self, $param_class, $str) = @_; |
|
988
|
2
|
|
|
|
|
3
|
my (@results); |
|
989
|
2
|
50
|
|
|
|
7
|
if ($self->_try_get_by_id($param_class, $str)) { |
|
990
|
2
|
|
|
|
|
3
|
@results = eval { $param_class->get($str) }; |
|
|
2
|
|
|
|
|
7
|
|
|
991
|
|
|
|
|
|
|
} |
|
992
|
2
|
50
|
33
|
|
|
10
|
if (!@results && $param_class->can('name')) { |
|
993
|
2
|
|
|
|
|
18
|
@results = $param_class->get(name => $str); |
|
994
|
2
|
50
|
|
|
|
6
|
unless (@results) { |
|
995
|
0
|
|
|
|
|
0
|
@results = $param_class->get("name like" => "$str"); |
|
996
|
|
|
|
|
|
|
} |
|
997
|
|
|
|
|
|
|
} |
|
998
|
|
|
|
|
|
|
|
|
999
|
2
|
|
|
|
|
5
|
return @results; |
|
1000
|
|
|
|
|
|
|
} |
|
1001
|
|
|
|
|
|
|
|
|
1002
|
|
|
|
|
|
|
sub _get_user_verification_for_param_value { |
|
1003
|
0
|
|
|
0
|
|
|
my ($self, $param_name, @list) = @_; |
|
1004
|
|
|
|
|
|
|
|
|
1005
|
0
|
|
|
|
|
|
my $n_list = scalar(@list); |
|
1006
|
0
|
0
|
0
|
|
|
|
if ($n_list > 200 && !$ENV{UR_NO_REQUIRE_USER_VERIFY}) { |
|
1007
|
0
|
|
|
|
|
|
my $response = $self->_ask_user_question("Would you [v]iew all $n_list item(s) for '$param_name', (p)roceed, or e(x)it?", 0, '[v]|p|x', 'v'); |
|
1008
|
0
|
0
|
0
|
|
|
|
if(!$response || $response eq 'x') { |
|
1009
|
0
|
|
|
|
|
|
$self->status_message("Exiting..."); |
|
1010
|
0
|
|
|
|
|
|
exit; |
|
1011
|
|
|
|
|
|
|
} |
|
1012
|
0
|
0
|
|
|
|
|
return @list if($response eq 'p'); |
|
1013
|
|
|
|
|
|
|
} |
|
1014
|
|
|
|
|
|
|
|
|
1015
|
0
|
|
|
|
|
|
my @new_list; |
|
1016
|
0
|
|
|
|
|
|
while (!@new_list) { |
|
1017
|
0
|
|
|
|
|
|
@new_list = $self->_get_user_verification_for_param_value_drilldown($param_name, @list); |
|
1018
|
|
|
|
|
|
|
} |
|
1019
|
|
|
|
|
|
|
|
|
1020
|
0
|
|
|
|
|
|
my @ids = map { $_->id } @new_list; |
|
|
0
|
|
|
|
|
|
|
|
1021
|
0
|
|
|
|
|
|
$self->status_message("The IDs for your selection are:\n" . join(',', @ids) . "\n\n"); |
|
1022
|
0
|
|
|
|
|
|
return @new_list; |
|
1023
|
|
|
|
|
|
|
} |
|
1024
|
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
sub _get_user_verification_for_param_value_drilldown { |
|
1026
|
0
|
|
|
0
|
|
|
my ($self, $param_name, @results) = @_; |
|
1027
|
0
|
|
|
|
|
|
my $n_results = scalar(@results); |
|
1028
|
0
|
|
|
|
|
|
my $pad = length($n_results); |
|
1029
|
|
|
|
|
|
|
|
|
1030
|
|
|
|
|
|
|
# Allow an environment variable to be set to disable the require_user_verify attribute |
|
1031
|
0
|
0
|
|
|
|
|
return @results if ($ENV{UR_NO_REQUIRE_USER_VERIFY}); |
|
1032
|
0
|
0
|
|
|
|
|
return if (@results == 0); |
|
1033
|
|
|
|
|
|
|
|
|
1034
|
0
|
|
|
|
|
|
my @dnames = map {$_->__display_name__} grep { $_->can('__display_name__') } @results; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
1035
|
0
|
0
|
|
|
|
|
my $max_dname_length = @dnames ? length((sort { length($b) <=> length($a) } @dnames)[0]) : 0; |
|
|
0
|
|
|
|
|
|
|
|
1036
|
0
|
0
|
|
|
|
|
my @statuses = map {$_->status || 'missing_status'} grep { $_->can('status') } @results; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
1037
|
0
|
0
|
|
|
|
|
my $max_status_length = @statuses ? length((sort { length($b) <=> length($a) } @statuses)[0]) : 0; |
|
|
0
|
|
|
|
|
|
|
|
1038
|
|
|
|
|
|
|
|
|
1039
|
0
|
|
|
|
|
|
my @results_with_display_name_and_class = map { [ $_->__display_name__, $_->class, $_ ] } @results; |
|
|
0
|
|
|
|
|
|
|
|
1040
|
0
|
|
|
|
|
|
@results = map { $_->[2] } |
|
1041
|
0
|
|
|
|
|
|
sort { $a->[1] cmp $b->[1] } |
|
1042
|
0
|
|
|
|
|
|
sort { $a->[0] cmp $b->[0] } |
|
|
0
|
|
|
|
|
|
|
|
1043
|
|
|
|
|
|
|
@results_with_display_name_and_class; |
|
1044
|
|
|
|
|
|
|
|
|
1045
|
0
|
|
|
|
|
|
my @classes = List::MoreUtils::uniq(map {$_->class} @results); |
|
|
0
|
|
|
|
|
|
|
|
1046
|
|
|
|
|
|
|
|
|
1047
|
0
|
|
|
|
|
|
my $response; |
|
1048
|
0
|
|
|
|
|
|
my @caller = caller(1); |
|
1049
|
0
|
|
|
|
|
|
while (!$response) { |
|
1050
|
0
|
|
|
|
|
|
$self->status_message("\n"); |
|
1051
|
|
|
|
|
|
|
# TODO: Replace this with lister? |
|
1052
|
0
|
|
|
|
|
|
for (my $i = 1; $i <= $n_results; $i++) { |
|
1053
|
0
|
|
|
|
|
|
my $param = $results[$i - 1]; |
|
1054
|
0
|
|
|
|
|
|
my $num = $self->_pad_string($i, $pad); |
|
1055
|
0
|
|
|
|
|
|
my $msg = "$num:"; |
|
1056
|
0
|
|
|
|
|
|
$msg .= ' ' . $self->_pad_string($param->__display_name__, $max_dname_length, 'suffix'); |
|
1057
|
0
|
|
|
|
|
|
my $status = ' '; |
|
1058
|
0
|
0
|
|
|
|
|
if ($param->can('status')) { |
|
1059
|
0
|
|
0
|
|
|
|
$status = $param->status || 'missing_status'; |
|
1060
|
|
|
|
|
|
|
} |
|
1061
|
0
|
|
|
|
|
|
$msg .= "\t" . $self->_pad_string($status, $max_status_length, 'suffix'); |
|
1062
|
0
|
0
|
|
|
|
|
$msg .= "\t" . $param->class if (@classes > 1); |
|
1063
|
0
|
|
|
|
|
|
$self->status_message($msg); |
|
1064
|
|
|
|
|
|
|
} |
|
1065
|
0
|
0
|
|
|
|
|
if ($MESSAGE) { |
|
1066
|
0
|
|
|
|
|
|
$MESSAGE = "\n" . '*'x80 . "\n" . $MESSAGE . "\n" . '*'x80 . "\n"; |
|
1067
|
0
|
|
|
|
|
|
$self->status_message($MESSAGE); |
|
1068
|
0
|
|
|
|
|
|
$MESSAGE = ''; |
|
1069
|
|
|
|
|
|
|
} |
|
1070
|
0
|
|
|
|
|
|
my $pretty_values = '(c)ontinue, (h)elp, e(x)it'; |
|
1071
|
0
|
|
|
|
|
|
my $valid_values = '\*|c|h|x|[-+]?[\d\-\., ]+'; |
|
1072
|
0
|
0
|
|
|
|
|
if ($caller[3] =~ /_trim_list_from_response/) { |
|
1073
|
0
|
|
|
|
|
|
$pretty_values .= ', (b)ack'; |
|
1074
|
0
|
|
|
|
|
|
$valid_values .= '|b'; |
|
1075
|
|
|
|
|
|
|
} |
|
1076
|
0
|
|
|
|
|
|
$response = $self->_ask_user_question("Please confirm the above items for '$param_name' or modify your selection.", 0, $valid_values, 'h', $pretty_values.', or specify item numbers to use'); |
|
1077
|
0
|
0
|
0
|
|
|
|
if (lc($response) eq 'h' || !$self->_validate_user_response_for_param_value_verification($response)) { |
|
1078
|
0
|
0
|
|
|
|
|
$MESSAGE .= "\n" if ($MESSAGE); |
|
1079
|
0
|
|
|
|
|
|
$MESSAGE .= |
|
1080
|
|
|
|
|
|
|
"Help:\n". |
|
1081
|
|
|
|
|
|
|
"* Specify which elements to keep by listing them, e.g. '1,3,12' would keep\n". |
|
1082
|
|
|
|
|
|
|
" items 1, 3, and 12.\n". |
|
1083
|
|
|
|
|
|
|
"* Begin list with a minus to remove elements, e.g. '-1,3,9' would remove\n". |
|
1084
|
|
|
|
|
|
|
" items 1, 3, and 9.\n". |
|
1085
|
|
|
|
|
|
|
"* Ranges can be used, e.g. '-11-17, 5' would remove items 11 through 17 and\n". |
|
1086
|
|
|
|
|
|
|
" remove item 5."; |
|
1087
|
0
|
|
|
|
|
|
$response = ''; |
|
1088
|
|
|
|
|
|
|
} |
|
1089
|
|
|
|
|
|
|
} |
|
1090
|
0
|
0
|
|
|
|
|
if (lc($response) eq 'x') { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
1091
|
0
|
|
|
|
|
|
$self->status_message("Exiting..."); |
|
1092
|
0
|
|
|
|
|
|
exit; |
|
1093
|
|
|
|
|
|
|
} |
|
1094
|
|
|
|
|
|
|
elsif (lc($response) eq 'b') { |
|
1095
|
0
|
|
|
|
|
|
return; |
|
1096
|
|
|
|
|
|
|
} |
|
1097
|
|
|
|
|
|
|
elsif (lc($response) eq 'c' | $response eq '*') { |
|
1098
|
0
|
|
|
|
|
|
return @results; |
|
1099
|
|
|
|
|
|
|
} |
|
1100
|
|
|
|
|
|
|
elsif ($response =~ /^[-+]?[\d\-\., ]+$/) { |
|
1101
|
0
|
|
|
|
|
|
@results = $self->_trim_list_from_response($response, $param_name, @results); |
|
1102
|
0
|
|
|
|
|
|
return @results; |
|
1103
|
|
|
|
|
|
|
} |
|
1104
|
|
|
|
|
|
|
else { |
|
1105
|
0
|
|
|
|
|
|
die $self->error_message("Conditional exception, should not have been reached!"); |
|
1106
|
|
|
|
|
|
|
} |
|
1107
|
|
|
|
|
|
|
} |
|
1108
|
|
|
|
|
|
|
|
|
1109
|
|
|
|
|
|
|
sub terminal_input_filehandle { |
|
1110
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
|
1111
|
|
|
|
|
|
|
|
|
1112
|
0
|
|
|
|
|
|
my $fh = IO::File->new('/dev/tty', 'r'); |
|
1113
|
0
|
0
|
|
|
|
|
unless ($fh) { |
|
1114
|
0
|
|
|
|
|
|
Carp::carp("Couldn't open /dev/tty for terminal input: $!\n Using STDIN..."); |
|
1115
|
0
|
|
|
|
|
|
$fh = *STDIN; |
|
1116
|
|
|
|
|
|
|
} |
|
1117
|
0
|
|
|
|
|
|
return $fh; |
|
1118
|
|
|
|
|
|
|
} |
|
1119
|
|
|
|
|
|
|
|
|
1120
|
|
|
|
|
|
|
sub _ask_user_question { |
|
1121
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
1122
|
0
|
|
|
|
|
|
my $question = shift; |
|
1123
|
0
|
|
|
|
|
|
my $timeout = shift; |
|
1124
|
0
|
|
0
|
|
|
|
my $valid_values = shift || "yes|no"; |
|
1125
|
0
|
|
0
|
|
|
|
my $default_value = shift || undef; |
|
1126
|
0
|
|
0
|
|
|
|
my $pretty_valid_values = shift || $valid_values; |
|
1127
|
0
|
|
|
|
|
|
$valid_values = lc($valid_values); |
|
1128
|
0
|
|
|
|
|
|
my $input; |
|
1129
|
0
|
0
|
|
|
|
|
$timeout = 60 unless(defined($timeout)); |
|
1130
|
|
|
|
|
|
|
|
|
1131
|
0
|
|
|
0
|
|
|
local $SIG{ALRM} = sub { print STDERR "Exiting, failed to reply to question '$question' within '$timeout' seconds.\n"; exit; }; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
1132
|
0
|
|
|
|
|
|
print STDERR "\n$question\n"; |
|
1133
|
0
|
|
|
|
|
|
print STDERR "Reply with $pretty_valid_values: "; |
|
1134
|
|
|
|
|
|
|
|
|
1135
|
0
|
0
|
|
|
|
|
unless ($self->_can_interact_with_user) { |
|
1136
|
0
|
|
|
|
|
|
print STDERR "\n"; |
|
1137
|
0
|
|
|
|
|
|
die $self->error_message("Attempting to ask user question but cannot interact with user!"); |
|
1138
|
|
|
|
|
|
|
} |
|
1139
|
|
|
|
|
|
|
|
|
1140
|
0
|
|
|
|
|
|
my $terminal = $self->terminal_input_filehandle(); |
|
1141
|
|
|
|
|
|
|
|
|
1142
|
0
|
0
|
|
|
|
|
alarm($timeout) if ($timeout); |
|
1143
|
0
|
|
|
|
|
|
chomp($input = $terminal->getline()); |
|
1144
|
0
|
0
|
|
|
|
|
alarm(0) if ($timeout); |
|
1145
|
|
|
|
|
|
|
|
|
1146
|
0
|
|
|
|
|
|
print STDERR "\n"; |
|
1147
|
|
|
|
|
|
|
|
|
1148
|
0
|
0
|
|
|
|
|
if(lc($input) =~ /^$valid_values$/) { |
|
|
|
0
|
|
|
|
|
|
|
1149
|
0
|
|
|
|
|
|
return lc($input); |
|
1150
|
|
|
|
|
|
|
} |
|
1151
|
|
|
|
|
|
|
elsif ($default_value) { |
|
1152
|
0
|
|
|
|
|
|
return $default_value; |
|
1153
|
|
|
|
|
|
|
} |
|
1154
|
|
|
|
|
|
|
else { |
|
1155
|
0
|
|
|
|
|
|
$self->error_message("'$input' is an invalid answer to question '$question'\n\n"); |
|
1156
|
0
|
|
|
|
|
|
return; |
|
1157
|
|
|
|
|
|
|
} |
|
1158
|
|
|
|
|
|
|
} |
|
1159
|
|
|
|
|
|
|
|
|
1160
|
|
|
|
|
|
|
sub _validate_user_response_for_param_value_verification { |
|
1161
|
0
|
|
|
0
|
|
|
my ($self, $response_text) = @_; |
|
1162
|
0
|
0
|
|
|
|
|
$response_text = substr($response_text, 1) if ($response_text =~ /^[+-]/); |
|
1163
|
0
|
|
|
|
|
|
my @response = split(/[\s\,]/, $response_text); |
|
1164
|
0
|
|
|
|
|
|
for my $response (@response) { |
|
1165
|
0
|
0
|
|
|
|
|
if ($response =~ /^[xbc*]$/) { |
|
1166
|
0
|
|
|
|
|
|
return 1; |
|
1167
|
|
|
|
|
|
|
} |
|
1168
|
0
|
0
|
|
|
|
|
if ($response !~ /^(\d+)([-\.]+(\d+))?$/) { |
|
1169
|
0
|
0
|
|
|
|
|
$MESSAGE .= "\n" if ($MESSAGE); |
|
1170
|
0
|
|
|
|
|
|
$MESSAGE .= "ERROR: Invalid list provided ($response)"; |
|
1171
|
0
|
|
|
|
|
|
return 0; |
|
1172
|
|
|
|
|
|
|
} |
|
1173
|
0
|
0
|
0
|
|
|
|
if ($3 && $1 && $3 < $1) { |
|
|
|
|
0
|
|
|
|
|
|
1174
|
0
|
0
|
|
|
|
|
$MESSAGE .= "\n" if ($MESSAGE); |
|
1175
|
0
|
|
|
|
|
|
$MESSAGE .= "ERROR: Inverted range provided ($1-$3)"; |
|
1176
|
0
|
|
|
|
|
|
return 0; |
|
1177
|
|
|
|
|
|
|
} |
|
1178
|
|
|
|
|
|
|
} |
|
1179
|
0
|
|
|
|
|
|
return 1; |
|
1180
|
|
|
|
|
|
|
} |
|
1181
|
|
|
|
|
|
|
|
|
1182
|
|
|
|
|
|
|
sub _trim_list_from_response { |
|
1183
|
0
|
|
|
0
|
|
|
my ($self, $response_text, $param_name, @list) = @_; |
|
1184
|
|
|
|
|
|
|
|
|
1185
|
0
|
|
|
|
|
|
my $method; |
|
1186
|
0
|
0
|
|
|
|
|
if ($response_text =~ /^[+-]/) { |
|
1187
|
0
|
|
|
|
|
|
$method = substr($response_text, 0, 1); |
|
1188
|
0
|
|
|
|
|
|
$response_text = substr($response_text, 1); |
|
1189
|
|
|
|
|
|
|
} |
|
1190
|
|
|
|
|
|
|
else { |
|
1191
|
0
|
|
|
|
|
|
$method = '+'; |
|
1192
|
|
|
|
|
|
|
} |
|
1193
|
|
|
|
|
|
|
|
|
1194
|
0
|
|
|
|
|
|
my @response = split(/[\s\,]/, $response_text); |
|
1195
|
0
|
|
|
|
|
|
my %indices; |
|
1196
|
0
|
0
|
|
|
|
|
@indices{0..$#list} = 0..$#list if ($method eq '-'); |
|
1197
|
|
|
|
|
|
|
|
|
1198
|
0
|
|
|
|
|
|
for my $response (@response) { |
|
1199
|
0
|
|
|
|
|
|
$response =~ /^(\d+)([-\.]+(\d+))?$/; |
|
1200
|
0
|
|
|
|
|
|
my $low = $1; $low--; |
|
|
0
|
|
|
|
|
|
|
|
1201
|
0
|
|
0
|
|
|
|
my $high = $3 || $1; $high--; |
|
|
0
|
|
|
|
|
|
|
|
1202
|
0
|
0
|
|
|
|
|
die if ($high < $low); |
|
1203
|
0
|
0
|
|
|
|
|
if ($method eq '+') { |
|
1204
|
0
|
|
|
|
|
|
@indices{$low..$high} = $low..$high; |
|
1205
|
|
|
|
|
|
|
} |
|
1206
|
|
|
|
|
|
|
else { |
|
1207
|
0
|
|
|
|
|
|
delete @indices{$low..$high}; |
|
1208
|
|
|
|
|
|
|
} |
|
1209
|
|
|
|
|
|
|
} |
|
1210
|
|
|
|
|
|
|
#$self->debug_message("Indices: " . join(',', sort(keys %indices))); |
|
1211
|
0
|
|
|
|
|
|
my @new_list = $self->_get_user_verification_for_param_value_drilldown($param_name, @list[sort keys %indices]); |
|
1212
|
0
|
0
|
|
|
|
|
unless (@new_list) { |
|
1213
|
0
|
|
|
|
|
|
@new_list = $self->_get_user_verification_for_param_value_drilldown($param_name, @list); |
|
1214
|
|
|
|
|
|
|
} |
|
1215
|
0
|
|
|
|
|
|
return @new_list; |
|
1216
|
|
|
|
|
|
|
} |
|
1217
|
|
|
|
|
|
|
|
|
1218
|
|
|
|
|
|
|
sub _pad_string { |
|
1219
|
0
|
|
|
0
|
|
|
my ($self, $str, $width, $pos) = @_; |
|
1220
|
0
|
0
|
|
|
|
|
$str = '' if ! defined $str; |
|
1221
|
0
|
|
|
|
|
|
my $padding = $width - length($str); |
|
1222
|
0
|
0
|
|
|
|
|
$padding = 0 if ($padding < 0); |
|
1223
|
0
|
0
|
0
|
|
|
|
if ($pos && $pos eq 'suffix') { |
|
1224
|
0
|
|
|
|
|
|
return $str . ' 'x$padding; |
|
1225
|
|
|
|
|
|
|
} |
|
1226
|
|
|
|
|
|
|
else { |
|
1227
|
0
|
|
|
|
|
|
return ' 'x$padding . $str; |
|
1228
|
|
|
|
|
|
|
} |
|
1229
|
|
|
|
|
|
|
} |
|
1230
|
|
|
|
|
|
|
|
|
1231
|
|
|
|
|
|
|
sub _can_interact_with_user { |
|
1232
|
0
|
|
|
0
|
|
|
my $self = shift; |
|
1233
|
0
|
0
|
|
|
|
|
if ( -t STDERR ) { |
|
1234
|
0
|
|
|
|
|
|
return 1; |
|
1235
|
|
|
|
|
|
|
} |
|
1236
|
|
|
|
|
|
|
else { |
|
1237
|
0
|
|
|
|
|
|
return 0; |
|
1238
|
|
|
|
|
|
|
} |
|
1239
|
|
|
|
|
|
|
} |
|
1240
|
|
|
|
|
|
|
|
|
1241
|
|
|
|
|
|
|
|
|
1242
|
|
|
|
|
|
|
1; |
|
1243
|
|
|
|
|
|
|
|
|
1244
|
|
|
|
|
|
|
|