line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package App::Task; |
2
|
|
|
|
|
|
|
|
3
|
4
|
|
|
4
|
|
535022
|
use strict; |
|
4
|
|
|
|
|
38
|
|
|
4
|
|
|
|
|
125
|
|
4
|
4
|
|
|
4
|
|
23
|
use warnings; |
|
4
|
|
|
|
|
6
|
|
|
4
|
|
|
|
|
172
|
|
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
our $VERSION = '0.02'; |
7
|
|
|
|
|
|
|
|
8
|
4
|
|
|
4
|
|
2226
|
use IPC::Open3::Utils (); |
|
4
|
|
|
|
|
37615
|
|
|
4
|
|
|
|
|
119
|
|
9
|
4
|
|
|
4
|
|
1829
|
use Text::OutputFilter; |
|
4
|
|
|
|
|
5680
|
|
|
4
|
|
|
|
|
134
|
|
10
|
4
|
|
|
4
|
|
2147
|
use IO::Interactive::Tiny (); |
|
4
|
|
|
|
|
57
|
|
|
4
|
|
|
|
|
131
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
BEGIN { |
13
|
4
|
|
|
4
|
|
22
|
no warnings "redefine"; |
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
237
|
|
14
|
4
|
|
|
4
|
|
1890
|
require Tie::Handle::Base; |
15
|
4
|
|
|
|
|
5955
|
*Text::OutputFilter::OPEN = \&Tie::Handle::Base::OPEN; |
16
|
|
|
|
|
|
|
} |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
sub import { |
19
|
4
|
|
|
4
|
|
27
|
no strict 'refs'; ## no critic |
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
5032
|
|
20
|
4
|
|
|
4
|
|
49
|
*{ caller() . '::task' } = \&task; |
|
4
|
|
|
|
|
6071
|
|
21
|
|
|
|
|
|
|
} |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
our $depth = 0; |
24
|
|
|
|
|
|
|
our $level = 0; |
25
|
|
|
|
|
|
|
our $steps = {}; |
26
|
|
|
|
|
|
|
our $prev_depth = 1; |
27
|
|
|
|
|
|
|
|
28
|
0
|
|
|
0
|
|
0
|
sub _nl { local $depth = 0; print "\n" } |
|
0
|
|
|
|
|
0
|
|
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
sub _sys { |
31
|
0
|
|
|
0
|
|
0
|
my @cmd = @_; |
32
|
|
|
|
|
|
|
|
33
|
0
|
|
|
|
|
0
|
my $rv = IPC::Open3::Utils::run_cmd( |
34
|
|
|
|
|
|
|
@cmd, |
35
|
|
|
|
|
|
|
{ |
36
|
|
|
|
|
|
|
autoflush => { stdout => 1, stderr => 1 }, |
37
|
|
|
|
|
|
|
carp_open3_errors => 1, |
38
|
|
|
|
|
|
|
close_stdin => 1, |
39
|
|
|
|
|
|
|
} |
40
|
|
|
|
|
|
|
); |
41
|
|
|
|
|
|
|
|
42
|
0
|
|
|
|
|
0
|
return $rv; |
43
|
|
|
|
|
|
|
} |
44
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
sub _escape { |
46
|
0
|
|
|
0
|
|
0
|
my ( $str, $leave_slashes ) = @_; |
47
|
|
|
|
|
|
|
|
48
|
0
|
0
|
|
|
|
0
|
$str =~ s/\\/\\\\/g unless $leave_slashes; |
49
|
0
|
|
|
|
|
0
|
$str =~ s/\n/\\n/g; |
50
|
0
|
|
|
|
|
0
|
$str =~ s/\t/\\t/g; |
51
|
|
|
|
|
|
|
|
52
|
0
|
|
|
|
|
0
|
return $str; |
53
|
|
|
|
|
|
|
} |
54
|
|
|
|
|
|
|
|
55
|
|
|
|
|
|
|
sub _indent { |
56
|
135
|
|
|
135
|
|
5140
|
my ($string) = @_; |
57
|
|
|
|
|
|
|
|
58
|
135
|
50
|
|
|
|
269
|
warn "_indent() called outside of task()\n" if $depth < 0; |
59
|
135
|
100
|
|
|
|
259
|
my $i = $depth <= 0 ? "" : " " x $depth; |
60
|
|
|
|
|
|
|
|
61
|
135
|
|
|
|
|
229
|
$string =~ s/\n/\n$i/msg; |
62
|
135
|
|
|
|
|
338
|
return "$i$string"; |
63
|
|
|
|
|
|
|
} |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
sub tie_task { |
66
|
11
|
|
|
11
|
1
|
101
|
close ORIGOUT; |
67
|
11
|
|
|
|
|
65
|
close ORIGERR; |
68
|
11
|
|
|
|
|
222
|
open( *ORIGOUT, ">&", \*STDOUT ); |
69
|
11
|
|
|
|
|
191
|
open( *ORIGERR, ">&", \*STDERR ); |
70
|
|
|
|
|
|
|
|
71
|
11
|
|
|
|
|
69
|
ORIGOUT->autoflush(); |
72
|
11
|
|
|
|
|
421
|
ORIGERR->autoflush(); |
73
|
11
|
|
|
|
|
316
|
my $o = tie( *STDOUT, "Text::OutputFilter", 0, \*ORIGOUT, \&_indent ); |
74
|
11
|
|
|
|
|
810
|
my $e = tie( *STDERR, "Text::OutputFilter", 0, \*ORIGERR, \&_indent ); |
75
|
|
|
|
|
|
|
|
76
|
11
|
|
|
|
|
752
|
return ( $o, $e ); |
77
|
|
|
|
|
|
|
} |
78
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub task { |
80
|
11
|
|
|
11
|
1
|
5228
|
my ( $msg, $code, $cmdhr ) = @_; |
81
|
11
|
|
|
|
|
21
|
chomp($msg); |
82
|
|
|
|
|
|
|
|
83
|
11
|
|
|
|
|
20
|
local *STDOUT = *STDOUT; |
84
|
11
|
|
|
|
|
15
|
local *STDERR = *STDERR; |
85
|
11
|
|
|
|
|
13
|
local *ORIGOUT = *ORIGOUT; |
86
|
11
|
|
|
|
|
27
|
local *ORIGERR = *ORIGERR; |
87
|
|
|
|
|
|
|
|
88
|
11
|
|
|
|
|
30
|
my ( $o, $e ) = tie_task(); |
89
|
|
|
|
|
|
|
|
90
|
11
|
|
|
|
|
17
|
my $task = $code; |
91
|
11
|
|
|
|
|
20
|
my $type = ref($code); |
92
|
11
|
50
|
|
|
|
37
|
if ( $type eq 'ARRAY' ) { |
|
|
50
|
|
|
|
|
|
93
|
|
|
|
|
|
|
my $disp = join " ", map { |
94
|
0
|
|
|
|
|
0
|
my $copy = "$_"; |
95
|
0
|
|
|
|
|
0
|
$copy = _escape( $copy, 1 ); |
96
|
0
|
0
|
|
|
|
0
|
if ( $copy =~ m/ / ) { $copy =~ s/'/\\'/g; $copy = "'$copy'" } |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
97
|
|
|
|
|
|
|
$copy |
98
|
0
|
|
|
|
|
0
|
} @{$code}; |
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
99
|
0
|
0
|
|
|
|
0
|
if ( $ENV{App_Task_DRYRUN} ) { |
100
|
0
|
|
|
0
|
|
0
|
$task = sub { print "(DRYRUN) >_ $disp\n" }; |
|
0
|
|
|
|
|
0
|
|
101
|
|
|
|
|
|
|
} |
102
|
|
|
|
|
|
|
else { |
103
|
0
|
0
|
|
0
|
|
0
|
$task = $cmdhr->{fatal} ? sub { _sys( @{$code} ) or die "`$disp` did not exit cleanly: $?\n" } : sub { _sys( @{$code} ) }; |
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
104
|
|
|
|
|
|
|
} |
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
elsif ( !$type ) { |
108
|
0
|
|
|
|
|
0
|
my $disp = _escape( $code, 0 ); |
109
|
0
|
0
|
|
|
|
0
|
if ( $ENV{App_Task_DRYRUN} ) { |
110
|
0
|
|
|
0
|
|
0
|
$task = sub { print "(DRYRUN) >_ $disp\n" }; |
|
0
|
|
|
|
|
0
|
|
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
else { |
113
|
0
|
0
|
|
0
|
|
0
|
$task = $cmdhr->{fatal} ? sub { _sys($code) or die "`$disp` did not exit cleanly: $?\n" } : sub { _sys($code) }; |
|
0
|
0
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
114
|
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
|
117
|
11
|
|
|
|
|
17
|
my $cur_depth = $depth; |
118
|
11
|
|
|
|
|
18
|
local $depth = $depth + 1; |
119
|
11
|
|
|
|
|
19
|
local $level = $level + 1; |
120
|
|
|
|
|
|
|
|
121
|
11
|
100
|
|
|
|
37
|
$steps->{$depth} = defined $steps->{$depth} ? $steps->{$depth} + 1 : 1; |
122
|
|
|
|
|
|
|
|
123
|
11
|
100
|
|
|
|
23
|
if ( $prev_depth > $cur_depth ) { |
124
|
6
|
|
|
|
|
8
|
for my $k ( keys %{$steps} ) { |
|
6
|
|
|
|
|
19
|
|
125
|
13
|
100
|
|
|
|
40
|
delete $steps->{$k} if $k > $depth; |
126
|
|
|
|
|
|
|
} |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
|
129
|
11
|
|
|
|
|
17
|
$prev_depth = $depth; |
130
|
|
|
|
|
|
|
|
131
|
11
|
50
|
|
|
|
38
|
my $pre = $steps->{$depth} ? "[$level.$steps->{$depth}]" : "[$level]"; |
132
|
|
|
|
|
|
|
|
133
|
11
|
50
|
|
|
|
36
|
my $fmt_pre = IO::Interactive::Tiny::is_interactive() ? "\e[1;107;30m" : ""; # ANSI code to highlight the heading/footing |
134
|
11
|
50
|
|
|
|
143
|
my $fmt_pst = $fmt_pre ? "\e[0m" : ""; |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
{ |
137
|
11
|
|
|
|
|
16
|
local $depth = $depth - 1; |
|
11
|
|
|
|
|
16
|
|
138
|
11
|
|
|
|
|
53
|
print "$fmt_pre➜➜➜➜ $pre $msg …$fmt_pst\n"; |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
11
|
|
|
|
|
322
|
my $ok = $task->(); |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
{ |
144
|
11
|
|
|
|
|
199
|
local $depth = $depth - 1; |
|
11
|
|
|
|
|
19
|
|
145
|
11
|
100
|
|
|
|
23
|
if ($ok) { |
146
|
2
|
|
|
|
|
10
|
print "$fmt_pre … $pre done ($msg).$fmt_pst\n"; |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
else { |
149
|
9
|
|
|
|
|
74
|
warn "$fmt_pre … $pre failed ($msg).$fmt_pst\n"; |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
} |
152
|
|
|
|
|
|
|
|
153
|
11
|
100
|
|
|
|
251
|
if ( $depth < 2 ) { |
154
|
3
|
|
|
|
|
13
|
undef $o; |
155
|
3
|
|
|
|
|
86
|
untie *STDOUT; |
156
|
3
|
|
|
|
|
86
|
undef $e; |
157
|
3
|
|
|
|
|
71
|
untie *STDERR; |
158
|
|
|
|
|
|
|
} |
159
|
|
|
|
|
|
|
|
160
|
11
|
|
|
|
|
120
|
return $ok; |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
1; |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
__END__ |