File Coverage

blib/lib/CIPP/Compile/PerlCheck.pm
Criterion Covered Total %
statement 24 145 16.5
branch 0 32 0.0
condition 0 6 0.0
subroutine 8 27 29.6
pod 0 17 0.0
total 32 227 14.1


line stmt bran cond sub pod time code
1             # $Id: PerlCheck.pm,v 1.9 2004/11/04 13:22:13 joern Exp $
2              
3             package CIPP::Compile::PerlCheck;
4              
5             @ISA = qw( CIPP::Debug );
6              
7             $VERSION = "0.01";
8              
9 1     1   8 use strict;
  1         2  
  1         39  
10 1     1   5 use Carp;
  1         2  
  1         49  
11 1     1   5 use FileHandle;
  1         2  
  1         7  
12 1     1   1354 use IPC::Open2;
  1         3832  
  1         54  
13 1     1   7 use Config;
  1         2  
  1         41  
14 1     1   6 use CIPP::Compile::Message;
  1         1  
  1         17  
15 1     1   4 use CIPP::Debug;
  1         2  
  1         794  
16              
17 0     0 0   sub get_fh_read { shift->{fh_read} }
18 0     0 0   sub get_fh_write { shift->{fh_write} }
19 0     0 0   sub get_tmp_dir { shift->{tmp_dir} }
20 0     0 0   sub get_pid { shift->{pid} }
21              
22 0     0 0   sub get_lib_path { shift->{lib_path} }
23 0     0 0   sub get_config_dir { shift->{config_dir} }
24 0     0 0   sub get_directory { shift->{directory} }
25 0     0 0   sub get_name { shift->{name} }
26              
27 0     0 0   sub set_lib_path { shift->{lib_path} = $_[1] }
28 0     0 0   sub set_config_dir { shift->{config_dir} = $_[1] }
29 0     0 0   sub set_directory { shift->{directory} = $_[1] }
30 0     0 0   sub set_name { shift->{name} = $_[1] }
31              
32             sub new {
33 0     0 0   my $type = shift;
34 0           my %par = @_;
35 0           my ($directory, $lib_path, $config_dir, $name) =
36             @par{'directory','lib_path','config_dir','name'};
37            
38 0           my $fh_read = FileHandle->new;
39 0           my $fh_write = FileHandle->new;
40            
41             # find perlcheck.pl
42 0           my $perlcheck_program;
43            
44 0           for ( @INC ) {
45 0 0         if ( -x "$_/CIPP/Compile/cipp_perlcheck.pl" ) {
46 0           $perlcheck_program =
47             "$_/CIPP/Compile/cipp_perlcheck.pl";
48 0           last;
49             }
50             }
51              
52 0 0         croak "No executable cipp_perlcheck.pl found"
53             if not -x $perlcheck_program;
54              
55 0           my $perl = $Config{perlpath};
56              
57 0 0         my $pid = open2 ($fh_read, $fh_write, "$perl $perlcheck_program")
58             or croak "can't call open2('$perl $perlcheck_program')";
59            
60 0 0         my $tmp_dir = ($^O =~ /win/i) ? "C:/TEMP" : "/tmp";
61              
62 0   0       $directory ||= $tmp_dir;
63              
64 0           my $self = {
65             fh_read => $fh_read,
66             fh_write => $fh_write,
67             tmp_dir => $tmp_dir,
68             config_dir => $config_dir,
69             lib_path => $lib_path,
70             directory => $directory,
71             pid => $pid,
72             name => $name,
73             };
74            
75 0           return bless $self, $type;
76             }
77              
78             sub check {
79 0     0 0   my $self = shift;
80 0           my %par = @_;
81 0           my ($code_sref, $parse_result, $output_file) =
82             @par{'code_sref','parse_result','output_file'};
83              
84 0 0         croak "code_sref missing" if not $code_sref;
85              
86 0 0         my $action = $output_file ? "execute $output_file" : "check";
87              
88 0           my $fh_write = $self->get_fh_write;
89            
90 0           my $delimiter = "__PERL_CODE_DELIMITER__";
91 0           while ( $$code_sref =~ /$delimiter/ ) {
92 0           $delimiter .= $$;
93             }
94            
95             # send request to perlcheck.pl process
96              
97 0           my $directory = $self->get_directory;
98 0           my $lib_path = $self->get_lib_path;
99 0           my $tmp_dir = $self->get_tmp_dir;
100 0           my $config_dir = $self->get_config_dir;
101              
102 0           writelog("write request data: action='$action'");
103              
104 0           print $fh_write <<__EOP;
105             $action
106             $directory
107             $lib_path
108             $tmp_dir
109             $config_dir
110             $delimiter
111             $$code_sref
112             $delimiter
113             __EOP
114              
115             # read answer
116 0           $delimiter = $self->read_line;
117 0           chomp $delimiter;
118              
119 0           my $result = "";
120 0           my $line;
121 0           while ( $line = $self->read_line($delimiter) ) {
122 0           chomp $line;
123 0 0         last if $line eq $delimiter;
124 0           $result .= "$line\n";
125             }
126              
127 0           writelog("finished reading");
128            
129 0 0         return $result if not $parse_result;
130              
131 0           writelog("now parse result and return");
132              
133 0           my $messages = $self->parse_result (
134             code_sref => $code_sref,
135             error_sref => \$result
136             );
137            
138 1     1   7 use Data::Dumper;
  1         2  
  1         984  
139 0           writelog("result parsed, messages=".Dumper($messages));
140              
141 0           return $messages;
142             }
143              
144             sub read_line {
145 0     0 0   my $self = shift;
146 0           my ($delimiter) = @_;
147              
148 0           my $fh = $self->get_fh_read;
149              
150 0           my $line;
151              
152 0           writelog("read_line");
153            
154 0           eval {
155 0     0     local $SIG{ALRM} = sub { die "timeout" };
  0            
156 0 0         return $delimiter if eof($fh);
157 0           alarm 5;
158 0           $line = <$fh>;
159 0           alarm 0;
160             };
161              
162 0 0         if ( $@ =~ /timeout/ ) {
163 0           writelog("got timeout");
164 0           $line = $delimiter;
165             }
166            
167 0           writelog("left read_line");
168              
169 0           return $line;
170             }
171              
172             sub parse_result {
173 0     0 0   my $self = shift;
174 0           my %par = @_;
175 0           my ($code_sref, $error_sref) =
176             @par{'code_sref','error_sref'};
177              
178 0           my @errors = split (/\n/, $$error_sref);
179 0           my @code = split (/\n/, $$code_sref);
180              
181 0           my $found_error;
182             my @messages;
183              
184 0           foreach my $error ( @errors ) {
185 0 0         next if $error =~ /BEGIN not safe/;
186 0           my ($line) = $error =~ m!\(eval\s+\d+\)\s+line\s+(\d+)!;
187 0 0         next if not $line;
188              
189 0           my $i = $line+1;
190              
191 0           my $cipp_line = -1;
192 0           my $cipp_call_path = "";
193              
194 0           $error =~ s/at\s+\(eval\s+\d+\).*//;
195              
196 0           my $code_line_found = 0;
197 0           while ( $i > 0 ) {
198 0 0         if ( $code[$i] =~ /^#\s+cipp_line_nr=(\d+)\s+(\w+)/ ) {
199 0           push @messages, CIPP::Compile::Message->new (
200             type => 'perl_err',
201             name => $self->get_name,
202             line_nr => $1,
203             tag => $2,
204             message => $error,
205             );
206 0           $code_line_found = 1;
207 0           last;
208             }
209 0           --$i;
210             }
211              
212 0 0         if ( not $code_line_found ) {
213 0           push @messages, CIPP::Compile::Message->new (
214             type => 'perl_err',
215             name => $self->get_name,
216             line_nr => "unknown",
217             tag => "unknown",
218             message => $error,
219             );
220             }
221              
222 0           $found_error = 1;
223             }
224              
225 0 0 0       if ( not $found_error and $$error_sref ne '' ) {
226 0           push @messages, CIPP::Compile::Message->new (
227             type => 'perl_err',
228             name => $self->get_name,
229             line_nr => 0,
230             tag => 'unknown',
231             message => $$error_sref,
232             );
233             }
234              
235 0           return \@messages;
236             }
237              
238             sub DESTROY {
239 0     0     my $self = shift;
240              
241 0           my $fh_write = $self->get_fh_write;
242 0           my $fh_read = $self->get_fh_read;
243            
244             # an empty line let the perlcheck.pl process exit
245 0           print $fh_write "\n";
246              
247             # close the filehandles
248 0           close $fh_read;
249 0           close $fh_write;
250            
251             # this prevents zombies, open2 doesn't call wait
252 0           waitpid ($self->get_pid, 0);
253            
254 0           1;
255             }
256              
257             sub writelog {
258 0     0 0   my ($msg) = @_;
259 0 0         return if not -f "/tmp/do.the.cipp3debug";
260 0           my $date = scalar(localtime(time));
261 0           open (LOG, ">> /tmp/perlcheck.log");
262 0           select LOG; $| = 1; select STDOUT;
  0            
  0            
263 0           print LOG "-" x 80, "\n";
264 0           print LOG "PerlCheck: $date $$\t$msg\n";
265 0           close LOG;
266            
267 0           1;
268             }
269              
270             1;