| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Respite::CommandLine; |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
=head1 NAME |
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
Respite::CommandLine - Provide an easy way to get commandline abstraction of Respite::Base |
|
6
|
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
=cut |
|
8
|
|
|
|
|
|
|
|
|
9
|
1
|
|
|
1
|
|
1396
|
use strict; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
42
|
|
|
10
|
1
|
|
|
1
|
|
5
|
use warnings; |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
70
|
|
|
11
|
1
|
|
|
1
|
|
6
|
use Throw qw(throw); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
5
|
|
|
12
|
1
|
|
|
1
|
|
51
|
use Scalar::Util qw(blessed); |
|
|
1
|
|
|
|
|
2
|
|
|
|
1
|
|
|
|
|
4263
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
sub new { |
|
15
|
0
|
|
|
0
|
0
|
|
my ($class, $args) = @_; |
|
16
|
0
|
0
|
|
|
|
|
return bless {%{$args || {}}}, $class; |
|
|
0
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
} |
|
18
|
|
|
|
|
|
|
|
|
19
|
0
|
|
|
0
|
1
|
|
sub api_meta { shift->{'api_meta'} } |
|
20
|
0
|
|
|
0
|
0
|
|
sub dispatch_class { shift->{'dispatch_class'} } |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
sub dispatch_factory { # this is identical to code in Respite::Server |
|
23
|
0
|
|
|
0
|
0
|
|
my ($self, $preload) = @_; |
|
24
|
0
|
|
0
|
|
|
|
return $self->{'dispatch_factory'} ||= do { |
|
25
|
0
|
|
0
|
|
|
|
my $meta = $self->api_meta || $self->dispatch_class || throw "Missing one of api_meta or dispatch_class"; |
|
26
|
0
|
0
|
|
|
|
|
if (!ref $meta) { |
|
|
|
0
|
|
|
|
|
|
|
27
|
0
|
|
|
|
|
|
(my $file = "$meta.pm") =~ s|::|/|g; |
|
28
|
0
|
0
|
0
|
|
|
|
throw "Failed to load dispatch class", {class => $meta, file => $file, msg => $@} if !$meta->can('new') && !eval { require $file }; |
|
|
0
|
|
|
|
|
|
|
|
29
|
0
|
0
|
|
|
|
|
throw "Specified class does not have a run_method method", {class => $meta} if ! $meta->can('run_method'); |
|
30
|
0
|
|
|
0
|
|
|
sub { $meta->new(@_) }; |
|
|
0
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
} elsif ($meta->{'remote'}) { |
|
32
|
0
|
|
|
|
|
|
require Respite::Client; |
|
33
|
0
|
0
|
|
0
|
|
|
sub { Respite::Client->new({%{shift() || {}}, %$meta}) }; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
} else { |
|
35
|
0
|
|
|
|
|
|
require Respite::Base; |
|
36
|
0
|
0
|
|
|
|
|
Respite::Base->new({api_meta => $meta})->api_preload if $preload; |
|
37
|
0
|
0
|
|
0
|
|
|
sub { Respite::Base->new({%{shift() || {}}, api_meta => $meta}) }; |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
} |
|
39
|
|
|
|
|
|
|
}; |
|
40
|
|
|
|
|
|
|
} |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
###----------------------------------------------------------------### |
|
43
|
|
|
|
|
|
|
|
|
44
|
0
|
|
|
0
|
0
|
|
sub run_commandline { shift->run(@_) } |
|
45
|
|
|
|
|
|
|
|
|
46
|
|
|
|
|
|
|
sub run { |
|
47
|
0
|
|
|
0
|
0
|
|
my ($self, $args) = @_; |
|
48
|
0
|
0
|
|
|
|
|
$self = $self->new($args) if ! ref($self); |
|
49
|
|
|
|
|
|
|
|
|
50
|
0
|
|
|
|
|
|
my $obj = $self->dispatch_factory->(); |
|
51
|
0
|
|
0
|
|
|
|
my $ARGV = $args->{'argv'} || $self->{'argv'} || \@ARGV; |
|
52
|
|
|
|
|
|
|
|
|
53
|
0
|
|
0
|
|
|
|
my $method = shift(@$ARGV) || return print $self->_pod($obj, {brief => 1}); |
|
54
|
0
|
0
|
|
|
|
|
return print $self->_pod($obj, {format => $1}) if $method =~ /^-{0,2}(help|h|pod|p)$/; |
|
55
|
0
|
|
|
|
|
|
return print $self->_pod($obj, {method => $method, format => $_}) for grep {/^-{1,2}(help|h|pod|p)$/} @ARGV; |
|
|
0
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
|
|
57
|
0
|
0
|
|
|
|
|
throw "Odd number of args passed to commandline. If you want the last value to be undef pass a :null", {argv => $ARGV, _pretty=>1} if @$ARGV % 2; |
|
58
|
0
|
|
|
|
|
|
my $req = {@$ARGV}; |
|
59
|
0
|
0
|
|
|
|
|
throw "Cannot use '' as a keyname - possible invalid args", {argv => $ARGV} if exists $req->{''}; |
|
60
|
0
|
0
|
0
|
|
|
|
foreach my $key (keys %$req) { $req->{$key} = __PACKAGE__->can("_$1")->() if $req->{$key} && $req->{$key} =~ /^:(null|true|false)$/ } |
|
|
0
|
|
|
|
|
|
|
|
61
|
0
|
0
|
0
|
|
|
|
$req = Data::URIEncode::flat_to_complex($req) || {} if !$self->{'no_data_uriencode'} && eval { require Data::URIEncode }; |
|
|
0
|
|
0
|
|
|
|
|
|
62
|
|
|
|
|
|
|
|
|
63
|
0
|
|
|
|
|
|
my $data = $self->_run_method($obj,$method, $req); |
|
64
|
0
|
0
|
|
|
|
|
my $meta = $ENV{'SHOW_META'} ? $self->_run_method($obj,"${method}__meta", $req) : undef; |
|
65
|
0
|
|
|
|
|
|
$self->print_data($data, $req, $meta); |
|
66
|
0
|
0
|
0
|
|
|
|
exit(1) if ref($data) && $data->{'error'}; |
|
67
|
|
|
|
|
|
|
} |
|
68
|
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
sub run_method { |
|
70
|
0
|
|
|
0
|
0
|
|
my ($self, $method, $args) = @_; |
|
71
|
0
|
0
|
|
|
|
|
$self = $self->new($args) if ! ref($self); |
|
72
|
0
|
|
|
|
|
|
my $obj = $self->dispatch_factory->(); |
|
73
|
0
|
|
|
|
|
|
return $self->_run_method($obj, $method, $args); |
|
74
|
|
|
|
|
|
|
} |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
sub _run_method { |
|
77
|
0
|
|
|
0
|
|
|
my ($self, $obj, $method, $args, $extra) = @_; |
|
78
|
|
|
|
|
|
|
|
|
79
|
0
|
0
|
|
|
|
|
local $args->{'_c'} = ['commandline'] if $obj->can('config') ? !$obj->config(no_trace => undef) : 1; |
|
|
|
0
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
|
|
81
|
0
|
0
|
0
|
|
|
|
local $obj->{'remote_ip'} = local $obj->{'api_ip'} = ($ENV{'REALUSER'} || $ENV{'SUDO_USER'}) ? 'sudo' : 'cmdline'; |
|
82
|
0
|
0
|
0
|
|
|
|
local $obj->{'api_brand'} = $ENV{'BRAND'} || $ENV{'PROV'} if $obj->isa('Respite::Base') && ($ENV{'BRAND'} || $ENV{'PROV'}); |
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
83
|
0
|
|
0
|
|
|
|
local $obj->{'remote_user'} = $ENV{'REALUSER'} || $ENV{'SUDO_USER'} || $ENV{'REMOTE_USER'} || $ENV{'USER'} || (getpwuid($<))[0] || '-unknown-'; |
|
84
|
0
|
0
|
0
|
|
|
|
local $obj->{'token'} = $self->{'token'} || $ENV{'ADMIN_Respite_TOKEN'} if $self->{'token'} || $ENV{'ADMIN_Respite_TOKEN'}; |
|
|
|
|
0
|
|
|
|
|
|
85
|
0
|
|
|
|
|
|
local $obj->{'transport'} = 'cmdline'; |
|
86
|
0
|
0
|
|
|
|
|
$obj->commandline_init($method, $args, $self) if $obj->can('commandline_init'); |
|
87
|
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
my $run = sub { |
|
89
|
0
|
0
|
|
0
|
|
|
my $data = eval { $obj->can('run_method') ? $obj->run_method(@_) : $obj->$method($args, ($extra ? $extra : ())) }; |
|
|
0
|
0
|
|
|
|
|
|
|
90
|
0
|
0
|
|
|
|
|
$data = $@ if ! ref $data; |
|
91
|
0
|
0
|
0
|
|
|
|
return !ref($data) ? {error => 'Commandline failed', msg => $data} : (blessed($data) && $data->can('data')) ? $data->data : $data; |
|
|
|
0
|
|
|
|
|
|
|
92
|
0
|
|
|
|
|
|
}; |
|
93
|
0
|
|
|
|
|
|
my $ref = $run->($method, $args, $extra); |
|
94
|
0
|
|
|
|
|
|
while ($ref->{'error'}) { |
|
95
|
0
|
0
|
0
|
|
|
|
last if !$ref->{'type'} || $ref->{'type'} !~ /^token_\w+$/; |
|
96
|
0
|
0
|
|
|
|
|
last if $self->{'no_token_retry'}; |
|
97
|
0
|
|
|
|
|
|
warn "Prompting for authorization and retry ($ref->{'type'}: $ref->{'error'})\n"; |
|
98
|
0
|
0
|
|
|
|
|
eval { require IO::Prompt } || throw "Please install IO::Prompt to authenticate from commandline", {msg => $@}; |
|
|
0
|
|
|
|
|
|
|
|
99
|
0
|
|
0
|
|
|
|
my $user = ''.IO::Prompt::prompt(" Web Auth Username: ", -d => $obj->{'remote_user'}) || $obj->{'remote_user'}; |
|
100
|
0
|
|
0
|
|
|
|
my $pass = ''.IO::Prompt::prompt(" Web Auth Password ($user): ", -e => '*') || throw "Cannot proceed without password"; |
|
101
|
|
|
|
|
|
|
my $key = !$obj->can('config') ? $config::config{'plaintext_public_key'} |
|
102
|
0
|
0
|
|
0
|
|
|
: $obj->config(plaintext_public_key => sub { $obj->config(plaintext_public_key => sub { $obj->_configs->{'plaintext_public_key'} }, 'emp_auth') }); |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
103
|
0
|
0
|
|
|
|
|
if (!$key) { |
|
|
|
0
|
|
|
|
|
|
|
104
|
0
|
|
|
|
|
|
warn " Could not find plaintext_public_key in config - sending plaintext password\n"; |
|
105
|
0
|
|
|
|
|
|
} elsif (!eval { require Crypt::OpenSSL::RSA }) { |
|
106
|
0
|
|
|
|
|
|
warn " (Crypt::OpenSSL::RSA is not installed - install to avoid sending plaintext password)\n"; |
|
107
|
|
|
|
|
|
|
} else { |
|
108
|
0
|
|
|
|
|
|
my $c = Crypt::OpenSSL::RSA->new_public_key($key); |
|
109
|
0
|
|
|
|
|
|
my $len = length($pass) + 1; |
|
110
|
0
|
|
|
|
|
|
$pass = pack 'u*', $c->encrypt(pack "Z$len", $pass); |
|
111
|
0
|
|
|
|
|
|
$pass = "RSA".length($pass).":$pass"; |
|
112
|
|
|
|
|
|
|
} |
|
113
|
0
|
|
|
|
|
|
$obj->{'token'} = "$user/i:cmdline/$pass"; |
|
114
|
0
|
|
|
|
|
|
$ref = $run->(hello => {test_auth => 1}); |
|
115
|
0
|
|
0
|
|
|
|
$self->{'token'} = $obj->{'token'} = $ref->{'token'} || throw "Did not get a token back from successful test_auth", {data => $ref}; |
|
116
|
0
|
|
|
|
|
|
warn "\nexport ADMIN_Respite_TOKEN=$obj->{'token'}\n\n"; |
|
117
|
0
|
|
|
|
|
|
$ref = $run->($method, $args, $extra); |
|
118
|
|
|
|
|
|
|
} |
|
119
|
0
|
|
|
|
|
|
return $ref; |
|
120
|
|
|
|
|
|
|
} |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
sub print_data { |
|
123
|
0
|
|
|
0
|
0
|
|
my ($self, $data, $args, $meta) = @_; |
|
124
|
0
|
0
|
0
|
|
|
|
if ($ENV{'CSV'} and my @fields = grep {ref($data->{$_}) eq 'ARRAY' && ref($data->{$_}->[0]) eq 'HASH'} sort keys %$data) { |
|
|
0
|
0
|
|
|
|
|
|
|
125
|
0
|
|
|
|
|
|
require Text::CSV_XS; |
|
126
|
0
|
|
|
|
|
|
my $csv = Text::CSV_XS->new({eol => "\n"}); |
|
127
|
0
|
|
|
|
|
|
foreach my $field (@fields) { |
|
128
|
0
|
0
|
|
|
|
|
print "----- $field -------------------------\n" if @fields > 1; |
|
129
|
0
|
0
|
|
|
|
|
my @keys = sort {($a eq 'id') ? -1 : ($b eq 'id') ? 1 : $a cmp $b } keys %{ $data->{'rows'}->[0] }; |
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
130
|
0
|
|
|
|
|
|
$csv->print(\*STDOUT, \@keys); |
|
131
|
0
|
0
|
|
|
|
|
$csv->print(\*STDOUT, [map {ref($_) eq 'ARRAY' ? join(",",@$_) : ref($_) eq 'HASH' ? join(",",%$_) : $_} @$_{@keys}]) for @{ $data->{'rows'} }; |
|
|
0
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
} |
|
133
|
0
|
|
|
|
|
|
exit; |
|
134
|
|
|
|
|
|
|
} |
|
135
|
0
|
0
|
0
|
|
|
|
if ($ENV{'YAML'}) { |
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
136
|
0
|
0
|
|
|
|
|
eval { require YAML } || throw "Could not load YAML for output", {msg => $@}; |
|
|
0
|
|
|
|
|
|
|
|
137
|
0
|
|
|
|
|
|
print YAML->new->Dump($data); |
|
138
|
0
|
|
|
|
|
|
} elsif ($ENV{'JSON'} || ! eval { require Text::PrettyTable }) { |
|
139
|
0
|
0
|
|
|
|
|
eval { require JSON } || throw "Could not load JSON for output", {msg => $@}; |
|
|
0
|
|
|
|
|
|
|
|
140
|
0
|
|
|
|
|
|
my $json = JSON->new->utf8->allow_nonref->convert_blessed->pretty->canonical; |
|
141
|
0
|
0
|
|
|
|
|
print "meta = ".$json->encode($meta) if $ENV{'SHOW_META'}; |
|
142
|
0
|
|
|
|
|
|
print "args = ".$json->encode($args); |
|
143
|
0
|
|
|
|
|
|
print "data = ".$json->encode($data); |
|
144
|
|
|
|
|
|
|
} elsif ($ENV{'PERL'}) { |
|
145
|
0
|
0
|
|
|
|
|
if (eval { require Data::Debug }) { |
|
|
0
|
|
|
|
|
|
|
|
146
|
0
|
|
|
|
|
|
Data::Debug::debug($args, $data); |
|
147
|
|
|
|
|
|
|
} else { |
|
148
|
0
|
|
|
|
|
|
require Data::Dumper; |
|
149
|
0
|
0
|
|
|
|
|
print Data::Dumper::Dumper($_) for $ENV{'SHOW_META'} ? $meta : (), $args, $data; |
|
150
|
|
|
|
|
|
|
} |
|
151
|
|
|
|
|
|
|
} else { |
|
152
|
0
|
|
|
|
|
|
my $p = PrettyTable->new({auto_collapse => 1}); |
|
153
|
0
|
0
|
|
|
|
|
if ($ENV{'SHOW_META'}) { |
|
154
|
0
|
|
|
|
|
|
print "Meta:\n"; |
|
155
|
0
|
|
|
|
|
|
print $p->tablify($meta); |
|
156
|
|
|
|
|
|
|
} |
|
157
|
0
|
|
|
|
|
|
print "Arguments:\n"; |
|
158
|
0
|
|
|
|
|
|
print $p->tablify($args); |
|
159
|
0
|
0
|
0
|
|
|
|
if ((scalar(keys %$data) == 1 || $data->{'n_pages'} && $data->{'n_pages'} == 1) && $data->{'rows'}) { |
|
|
|
|
0
|
|
|
|
|
|
160
|
0
|
|
|
|
|
|
print "Data Rows:\n"; |
|
161
|
0
|
|
|
|
|
|
print $p->tablify($data->{'rows'}); |
|
162
|
|
|
|
|
|
|
} else { |
|
163
|
0
|
|
|
|
|
|
print "Data:\n"; |
|
164
|
0
|
|
|
|
|
|
print $p->tablify($data); |
|
165
|
|
|
|
|
|
|
} |
|
166
|
|
|
|
|
|
|
} |
|
167
|
|
|
|
|
|
|
} |
|
168
|
|
|
|
|
|
|
|
|
169
|
0
|
|
|
0
|
|
|
sub _false { require JSON; JSON::false() } |
|
|
0
|
|
|
|
|
|
|
|
170
|
0
|
|
|
0
|
|
|
sub _null { undef } |
|
171
|
0
|
|
|
0
|
|
|
sub _true { require JSON; JSON::true() } |
|
|
0
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
sub _pod { |
|
174
|
0
|
|
|
0
|
|
|
my ($self, $obj, $args) = @_; |
|
175
|
0
|
|
|
|
|
|
my $class = ref($obj); |
|
176
|
0
|
|
0
|
|
|
|
my $script = $args->{'script'} || $0; |
|
177
|
0
|
|
0
|
|
|
|
my $meth = $args->{'method'} || 'methodname'; |
|
178
|
0
|
|
|
|
|
|
my $out = "=head1 NAME\n\n" |
|
179
|
|
|
|
|
|
|
."$script - commandline interface to $class methods\n\n" |
|
180
|
|
|
|
|
|
|
."=head1 SYNOPSIS\n\n" |
|
181
|
|
|
|
|
|
|
." $script $meth\n\n" |
|
182
|
|
|
|
|
|
|
." $script $meth --help\n\n" |
|
183
|
|
|
|
|
|
|
." $script $meth methods # brief list of methods \n\n" |
|
184
|
|
|
|
|
|
|
." $script $meth key1 value1 key2 value2\n\n" |
|
185
|
|
|
|
|
|
|
." $script $meth key1:0 arrayvalue1 key1:1 arrayvalue2\n\n" |
|
186
|
|
|
|
|
|
|
." JSON=1 $script $meth key1 value1 key2 value2\n\n" |
|
187
|
|
|
|
|
|
|
." YAML=1 $script $meth key1 value1 key2 value2\n\n" |
|
188
|
|
|
|
|
|
|
." PERL=1 $script $meth key1 value1 key2 value2\n\n" |
|
189
|
|
|
|
|
|
|
." CSV=1 $script $meth key1 value1 key2 value2 (only works for fields that are arrays of hashes)\n\n" |
|
190
|
|
|
|
|
|
|
." SHOW_META=1 $script $meth key1 value1 key2 value2 (includes meta information for $meth)\n\n" |
|
191
|
|
|
|
|
|
|
."Arguments for the hashref should be passed on the commandline as" |
|
192
|
|
|
|
|
|
|
." simple key value pairs. If the arguments are more complex, you can" |
|
193
|
|
|
|
|
|
|
." pass values in any of the ways that L supports.\n\n" |
|
194
|
|
|
|
|
|
|
."=head1 METHODS\n\n"; |
|
195
|
0
|
0
|
|
|
|
|
if ($args->{'brief'}) { |
|
196
|
0
|
|
|
|
|
|
$out .= join(", ", sort keys %{ $self->_run_method($obj, methods => {})->{'methods'} })."\n\n"; |
|
|
0
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
} else { |
|
198
|
0
|
0
|
|
|
|
|
my $methods = ($_ = $args->{'method'}) ? {$_ => $self->_run_method($obj, "${_}__meta", {_flat => 1})} : $self->_run_method($obj, methods => {meta => 1, _flat => 1})->{'methods'}; |
|
199
|
0
|
|
|
|
|
|
foreach my $meth (sort keys %$methods) { |
|
200
|
0
|
|
|
|
|
|
my $m = $methods->{$meth}; |
|
201
|
0
|
|
|
|
|
|
$out .= "=head2 C<$meth>\n\n"; |
|
202
|
0
|
0
|
|
|
|
|
$out .= "$m->{'desc'}\n\n" if $m->{'desc'}; |
|
203
|
0
|
|
|
|
|
|
$out .= "=over 4\n\n"; |
|
204
|
0
|
|
|
|
|
|
my $args = $m->{'args'}; my %uk; |
|
|
0
|
|
|
|
|
|
|
|
205
|
0
|
0
|
0
|
|
|
|
foreach my $field (grep {!$uk{$_}++} (map {split /\s*,\s*/} ref($args->{'group order'}) ? @{$args->{'group order'}} : $args->{'group order'}||()), grep {!/^group /} sort keys %$args) { |
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
206
|
0
|
|
|
|
|
|
$out .= "=item C<$field>\n\n"; |
|
207
|
0
|
0
|
0
|
|
|
|
Data::Debug::debug($meth, $field, $args->{$field}) if ! ref($args->{$field}) && eval {require Data::Debug}; |
|
|
0
|
|
|
|
|
|
|
|
208
|
0
|
0
|
|
|
|
|
$out .= "(required)\n\n" if $args->{$field}->{'required'}; |
|
209
|
0
|
0
|
|
|
|
|
$out .= "$args->{$field}->{'desc'}\n\n" if $args->{$field}->{'desc'}; |
|
210
|
|
|
|
|
|
|
} |
|
211
|
0
|
|
|
|
|
|
$out .= "=back\n\n"; |
|
212
|
|
|
|
|
|
|
} |
|
213
|
|
|
|
|
|
|
} |
|
214
|
0
|
|
|
|
|
|
$out .= "=cut\n"; |
|
215
|
0
|
0
|
0
|
|
|
|
if (!$args->{'format'} || ($args->{'format'} && $args->{'format'} =~ /h/)) { |
|
|
|
|
0
|
|
|
|
|
|
216
|
0
|
|
|
|
|
|
require Pod::Text; |
|
217
|
0
|
|
|
|
|
|
require IO::String; |
|
218
|
0
|
|
0
|
|
|
|
my $cols = $ENV{'COLUMNS'} || eval { |
|
219
|
|
|
|
|
|
|
require IO::Interactive; |
|
220
|
|
|
|
|
|
|
die if ! IO::Interactive::is_interactive(*STDOUT); |
|
221
|
|
|
|
|
|
|
require Term::ReadKey; (Term::ReadKey::GetTerminalSize(\*STDOUT))[0] |
|
222
|
|
|
|
|
|
|
} || 80; |
|
223
|
0
|
|
|
|
|
|
Pod::Text->new(width => $cols)->parse_from_file(IO::String->new($out), IO::String->new(my $txt)); |
|
224
|
0
|
|
|
|
|
|
return $txt; |
|
225
|
|
|
|
|
|
|
} |
|
226
|
0
|
|
|
|
|
|
return $out; |
|
227
|
|
|
|
|
|
|
} |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
1; |