File Coverage

blib/lib/App/rs.pm
Criterion Covered Total %
statement 58 161 36.0
branch 12 92 13.0
condition 1 12 8.3
subroutine 9 17 52.9
pod 0 7 0.0
total 80 289 27.6


line stmt bran cond sub pod time code
1             =license
2              
3             Copyright © 2018 Yang Bo
4              
5             This file is part of RSLinux.
6              
7             RSLinux is free software: you can redistribute it and/or modify
8             it under the terms of the GNU General Public License as published by
9             the Free Software Foundation, either version 3 of the License, or
10             (at your option) any later version.
11              
12             RSLinux is distributed in the hope that it will be useful,
13             but WITHOUT ANY WARRANTY; without even the implied warranty of
14             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15             GNU General Public License for more details.
16              
17             You should have received a copy of the GNU General Public License
18             along with RSLinux. If not, see .
19              
20             =cut
21             package App::rs;
22 1     1   367 use strict;
  1         2  
  1         30  
23 1     1   4 use warnings qw/all FATAL uninitialized/;
  1         1  
  1         47  
24 1     1   5 use feature qw/state say/;
  1         2  
  1         119  
25              
26 1     1   12 use XSLoader;
  1         2  
  1         42  
27             XSLoader::load();
28              
29             BEGIN {
30 1     1   4 no strict 'refs';
  1         2  
  1         430  
31 1     1   5 my $c = {S_IFMT => 0170000,
32             S_IFLNK => 0120000,
33             S_IFREG => 0100000,
34             S_IFDIR => 0040000};
35 1         6 my @H = ($^H, ${^WARNING_BITS}, %^H);
36             sub import {
37 2     2   55 my $ns = caller . '::';
38 2         6 shift;
39 2         8 while (@_) {
40 4         7 my $q = shift;
41 4 100       13 if ($q eq 'iautoload') {
    100          
    50          
    50          
42 2         4 my (@pkg, %map, @l);
43 2         3 for (@{+shift}) {
  2         6  
44 2 100       9 my ($p, @f) = ref ? @$_ : $_;
45 2         5 push @pkg, $p;
46 2         5 for (@f) {
47 2 50       8 push @l, $ns . $_ if s/^0//;
48 2         5 $map{$_} = $p;
49             }
50             }
51 2         3 my $i = 1;
52 2         19 *{$ns . 'AUTOLOAD'} = sub {
53             # "fully qualified name of the original subroutine".
54 2     2   4 my $q = our $AUTOLOAD;
55             # to avoid possibly overwrite @_ by successful regular expression match.
56 2         4 my ($f) = do { $q =~ /.*::(.*)/ };
  2         14  
57 2   33     7 for my $p ($map{$f} || @pkg) {
58             # calculate the actual file to be loaded thus avoid eval and
59             # checking $@ mannually.
60 2         3 do { require $p =~ s|::|/|gr . '.pm' };
  2         588  
61 2 50       3643 if (my $r = *{"${p}::$f"}{CODE}) {
  2         10  
62 1     1   6 no warnings 'prototype';
  1         1  
  1         438  
63 2         6 *$q = $r;
64             # TODO: understand why using goto will lost context.
65             #goto &$r;
66 2 50       16 return $i ? undef : &$r;
67             }
68             }
69 0         0 confess("unable to autoload $q.");
70 2         11 };
71 2         11 $_->() for @l;
72 2         1223 $i = 0;
73             } elsif ($q eq 'oautoload') {
74 1         2 for my $p (@{+shift}) {
  1         2  
75 3         11 my $r = $p =~ s|::|/|gr . '.pm';
76             # ignore already loaded module.
77 3 50       8 next if $INC{$r};
78 3         28 *{"${p}::AUTOLOAD"} = sub {
79 0     0   0 my ($f) = do { our $AUTOLOAD =~ /.*::(.*)/ };
  0         0  
80 0         0 my $symtab = *{"${p}::"}{HASH};
  0         0  
81 0         0 delete $symtab->{AUTOLOAD};
82 0         0 require $r;
83 0         0 return &{$symtab->{$f}};
  0         0  
84 3         17 };
85             }
86             } elsif ($q eq 'constant') {
87 0         0 *{$ns . $_} = \&$_ for keys %$c;
  0         0  
88             } elsif ($q eq 'sane') {
89 1         9 ($^H, ${^WARNING_BITS}, %^H) = @H;
90             } else {
91 0           confess("unknown request $q");
92             }
93             }
94             };
95 1         3 for my $f (keys %$c) {
96 4         6 my $v = $c->{$f};
97             *$f = sub () {
98 0         0 $v;
99 4         1244 };
100             }
101             }
102             {my @a = qw/Cpanel::JSON::XS JSON::XS JSON::PP/;
103             App::rs->import(iautoload => ['Carp'],
104             oautoload => [@a]);
105             sub json_unparse_readable {
106 0     0 0   state $o = do {
107 0           my $o;
108 0           for (@a) {
109 0 0         last if eval {
110 0           $o = $_->new->pretty->canonical;
111             };
112             }
113 0           $o;
114             };
115 0 0         $o ? $o->encode(shift) : "what?!\n";
116             }}
117             sub xsh {
118 0     0 0   my $f = shift;
119 0 0         if (not ref $f) {
120 0           my $h = {};
121 0 0         $h->{"capture-stdout"} = 1 if $f & 1;
122 0 0         $h->{"feed-stdin"} = 1 if $f & 2;
123 0           $f = $h;
124             }
125 0           my ($h, $i, $pr, @st) = ({pid => []}, 0);
126 0 0         if ($f->{"feed-stdin"}) {
127 0           my ($fi, $pid) = shift;
128 0           pipe $pr, my $pw;
129 0 0         if (not $pid = fork) {
130 0           close $pr;
131 0           print $pw $fi;
132 0           exit;
133             } else {
134 0           push @{$h->{pid}}, $pid;
  0            
135             }
136             }
137 0           while ($i <= @_) {
138 0           my $l = $i == @_;
139 0 0         my $a = $_[$i] if not $l;
140 0 0 0       if ($l or $a eq "|") {
141 0 0 0       pipe my $r, my $w if not $l or $f->{"capture-stdout"};
142             # there's no need to fork when executing the last command and we're required
143             # to substitute current process.
144 0 0 0       my $pid = fork unless $l and $f->{substitute};
145 0 0         if (not $pid) {
146             # always true except possibly the first.
147 0 0         open STDIN, "<&", $pr if $pr;
148             # always true except possibly the last.
149 0 0         open STDOUT, ">&", $w if $w;
150 0           while (ref $st[-1]) {
151 0           my ($h, $f) = pop @st;
152 0 0         if (ref \$h->{from} eq "SCALAR") { open $f, $h->{mode}, $h->{from} or die $! }
  0 0          
153 0           else { $f = $h->{from} }
154 0           open $h->{to}, $h->{mode} . "&", $f;
155             }
156 0           exec @st;
157             } else {
158 0           $pr = $r;
159 0           push @{$h->{pid}}, $pid;
  0            
160 0           @st = ();
161             }
162             } else {
163 0           push @st, $a;
164             }
165 0           $i++;
166             }
167 0 0         if ($f->{asynchronous}) {
168 0 0         $h->{stdout} = $pr if $f->{"capture-stdout"};
169 0 0         if ($f->{compact}) { $h }
  0 0          
170 0           elsif ($f->{"capture-stdout"}) { $pr }
171 0 0         else { wantarray ? @{$h->{pid}} : $h->{pid}[-1] }
  0            
172             } else {
173 0 0         if ($f->{"capture-stdout"}) {
174 0 0         local $/ if not wantarray;
175 0           $h->{stdout} = [<$pr>];
176             }
177 0           $h->{status} = [];
178 0 0         push @{$h->{status}}, waitpid($_, 0) == -1 ? undef : $? for @{$h->{pid}};
  0            
  0            
179             # they're meaningless now as they don't exist anymore.
180 0           delete $h->{pid};
181 0 0         if ($f->{compact}) { $h }
  0 0          
182 0 0         elsif ($f->{"capture-stdout"}) { wantarray ? @{$h->{stdout}} : $h->{stdout}[0] }
  0            
183 0 0         else { wantarray ? @{$h->{status}} : not $h->{status}[-1] }
  0            
184             }
185             }
186             sub arg_parse {
187 0     0 0   my $h = {};
188 0           while (@ARGV) {
189 0           my $a = shift @ARGV;
190 0 0         if ($a !~ /^-/) { unshift @ARGV, $a; last }
  0 0          
  0 0          
    0          
191 0           elsif ($a =~ /^--?$/) { last }
192 0           elsif ($a =~ /^--(.*?)=(.*)$/) { hash_madd_key($h, $1, $2) }
193 0           elsif ($a =~ /^--?(.*)$/) { $h->{$1} = 1 }
194             }
195 0           $h;
196             }
197             sub hash_madd_key {
198 0     0 0   my ($h, $k, $v) = @_;
199 0 0         if (exists $h->{$k}) {
200 0 0         $h->{$k} = [$h->{$k}] if ref $h->{$k} ne 'ARRAY';
201 0           push @{$h->{$k}}, $v;
  0            
202             } else {
203 0           $h->{$k} = $v;
204             }
205             }
206             sub flatten {
207 0     0 0   my $v = shift;
208 0 0         ref $v eq 'ARRAY' ? @$v : $v;
209             }
210             sub linker {
211 0     0 0   my $s = shift;
212             $s->{i386} ?
213             "$s->{prefix}/lib/ld-linux.so.2" : $s->{arm} ?
214 0 0         "$s->{prefix}/lib/ld-linux-armhf.so.3" :
    0          
215             "$s->{prefix}/lib/ld-linux-x86-64.so.2";
216             }
217             sub add {
218 0     0 0   my $h = shift;
219 0           while (@_) {
220 0           my ($k, $v) = splice @_, 0, 2;
221 0           $h->{$k} = $v;
222             }
223             }
224             1;