/lib/CIPP/Compile/PerlCheck.pm

https://github.com/gitpan/CIPP · Perl · 270 lines · 199 code · 64 blank · 7 comment · 17 complexity · df0d527884b143bc52570ff0946352e9 MD5 · raw file

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