Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
reindenting and cosmetics (ignore me)
[simgrid.git] / buildtools / Cmake / tesh.pl
1 #! /usr/bin/perl -w
2 eval 'exec perl -S $0 ${1+"$@"}'
3     if $running_under_some_shell;
4
5 =encoding UTF-8
6
7 =head1 NAME
8
9 tesh -- testing shell
10
11 =head1 SYNOPSIS
12
13 B<tesh> [I<options>] I<tesh_file>
14
15 =cut
16
17 use Pod::Usage qw(pod2usage);
18 use Getopt::Long qw(GetOptions);
19 use strict;
20 use Term::ANSIColor;
21 use IPC::Open3;
22
23
24 # make sure we received a tesh file
25 scalar @ARGV > 0 || pod2usage(-exitval => 1);
26
27 #Add current directory to path
28 $ENV{PATH} = "$ENV{PATH}:.";
29
30
31 ##
32 ## Command line option handling
33 ##
34
35 # option handling helper subs
36 sub cd_cmd {
37     my $directory=$_[1];
38     if (-e $directory) {
39         chdir("$directory");
40         print "[Tesh/INFO] change directory to $directory\n";
41     } else {
42         die "[Tesh/CRITICAL] Directory not found : \"$directory\"\n";
43     }
44 }
45
46 sub setenv_cmd {
47     if ($_[1] =~ /^(.*)=(.*)$/) {
48         my($var,$ctn)=($1,$2);
49         $ENV{$var} = $ctn;
50         print "[Tesh/INFO] setenv $var=$ctn\n";
51     } else { 
52         die "[Tesh/CRITICAL] Malformed argument to setenv: expected 'name=value' but got '$_[1]'\n";
53     }
54 }
55
56 # Main option parsing sub
57 my $tesh_file;
58 sub get_options {
59     # remove the tesh file from the ARGV used
60     my @ARGV = @_;
61     $tesh_file = pop @ARGV;
62
63     # temporary arrays for GetOption
64     my @verbose = ();
65     my @cfg;
66
67     my %opt = (
68         "help"    => 0,
69         "debug"   => 0,
70         "verbose" => 0
71         );
72
73     Getopt::Long::config('bundling', 'no_getopt_compat', 'no_auto_abbrev');
74     
75     GetOptions(
76         'help|h'     => \$opt{'help'},
77
78         'verbose|v'  => \@verbose,
79         'debug|d'    => \$opt{"debug"},
80
81         'cd=s'       => \&cd_cmd,
82         'setenv=s'   => \&setenv_cmd,
83         'cfg=s'      => \@cfg,
84         );
85
86     $opt{'verbose'} = scalar @verbose;
87     foreach (@cfg) {
88         $opt{'cfg'} .= " --cfg=$_";
89     }
90     return %opt;
91 }
92
93 my %opts = get_options(@ARGV);
94
95 ##
96 ## File parsing
97 ##
98 my($line2,$execline,$command,$command_tesh);
99 my($command_executed)=0;
100 my($expected_result_line)=0;
101 my($sort)=0;
102 my($nb_arg)=0;
103 my(@list1,@list2,@list3,@list_of_commands)=();
104 my(@buffer)=();
105 my($timeout)=0;
106 my($encore)=0;
107 my($old_buffer);
108 my($linebis);
109 my($SIGABRT)=0;
110 my($no_output_ignore)=1;
111 my($verbose)=0;
112 my($return)=-1;
113 my($pid);
114 my($result);
115 my($result_err);
116 my($fich_name);
117 my($forked);
118 my($config)="";
119
120 my($tesh_command)=0;
121 my(@buffer_tesh)=();
122
123 # parse tesh file
124 open SH_LIGNE, $tesh_file or die "[Tesh/CRITICAL] Unable to open $tesh_file $!\n";
125
126 while (defined(my $line1=<SH_LIGNE>)) {
127     if($line1 =~ /^\< \$ /){    # arg command line
128         $line1 =~ s/\${EXEEXT:=}//g;
129         $line1 =~ s/^\< \$\ *//g;
130         $line1 =~ s/^.\/lua/lua/g;
131         $line1 =~ s/^.\/ruby/ruby/g;
132         $line1 =~ s/^.\///g;
133         $line1 =~ s/^tesh/.\/tesh/g;
134         $line1 =~ s/\(%i:%P@%h\)/\\\(%i:%P@%h\\\)/g;
135         chomp $line1;
136         $command_tesh = $line1;
137         print "[Tesh/INFO] arg_exec_line   : $command_tesh\n";
138     }
139     elsif($line1 =~ /^\< \< /){  # arg buffer line
140         $line1 =~ s/^\< \<\ *//g;
141         chomp $line1;
142         print "[Tesh/INFO] arg_buffer_line : $line1\n";
143         push @buffer_tesh, "$line1\n";
144     }
145     elsif($line1 =~ /^\< \> /){  # arg output line
146         $line1 =~ s/^\< \>\ *//g;
147         $line1 =~ s/\r//g;
148         chomp $line1;
149                 push @list2, $line1;
150         print "[Tesh/INFO] arg_output_line : $line1\n";
151         $expected_result_line = 1;
152     }
153     elsif($line1 =~ /^\$ mkfile/){      # "mkfile" command line
154         $line1 =~ s/\$ //g;
155         $line1 =~ s/mkfile//g;
156         chomp $line1;
157         $fich_name = $line1;
158         $line1 =();
159         print "[Tesh/INFO] exec_line : mkfile $fich_name\n";
160         `rm -f $fich_name`;
161         open(FILE,">$fich_name") or die "[Tesh/CRITICAL] Unable to make file : $fich_name. $!\n";
162         print FILE @buffer;
163         close(FILE);
164         @buffer = ();   
165     }
166     elsif($line1 =~ /^\$ cd/){          # "cd" command line
167         $line1 =~ s/\$ //g;
168         chomp $line1;
169         print "[Tesh/INFO] exec_line : $line1\n";
170                 $line1 =~ s/cd //g;
171         chdir("$line1") or die "[Tesh/CRITICAL] Unable to open $line1. $!\n";   
172     }
173     elsif($line1 =~ /^\$ /){    #command line
174         if($line1 =~ /^\$ .\/tesh/){    # tesh command line
175                         $tesh_command = 1;
176                         @buffer = @buffer_tesh;
177                         @buffer_tesh=();
178         }
179         $line1 =~ s/\${EXEEXT:=}//g;
180         $line1 =~ s/^\$\ *//g;
181         $line1 =~ s/^.\/lua/lua/g;
182         $line1 =~ s/^.\/ruby/ruby/g;
183         $line1 =~ s/^.\///g;
184         $line1 =~ s/^tesh/.\/tesh/g;
185         $line1 =~ s/\(%i:%P@%h\)/\\\(%i:%P@%h\\\)/g;
186         chomp $line1;
187         $line1 = "$line1 $config";
188         
189         if(@list1){
190             print color("red");
191             print "[Tesh/CRITICAL] -\n";
192             print "[Tesh/CRITICAL] + @list1";
193             print color("reset"), "\n";
194             die;}               
195         if(@list_of_commands){ # need parallel execution
196             push @list_of_commands, $line1;
197             print "[Tesh/INFO] exec_line : $line1\n";
198         }
199         else{
200             print "[Tesh/INFO] exec_line : $line1\n";
201             if($tesh_command)
202             {   $execline = $command_tesh;
203                 $tesh_command=0;}
204             else
205             {   $execline = $line1;}
206             $pid = open3(\*IN, \*OUT, \*OUT, $execline );
207             if( $timeout){
208                 $forked = fork();die "fork() failed: $!" unless defined $forked;
209                 if ( $forked == 0 )
210                 {
211                     sleep $timeout;
212                     kill(9, $pid);
213                     exit;
214                 }
215             }
216             
217             while(@buffer)
218             {
219                 $line1 = shift (@buffer);
220                 print IN $line1;
221             }
222             close IN ;
223             
224             waitpid( $pid, 0 );
225             if($timeout){kill(9, $forked);$timeout=0;}
226             $timeout = 0;
227             
228             while(defined($linebis=<OUT>))
229             {
230                 $linebis =~ s/\r//g;
231                 $linebis =~ s/^( )*//g;
232                 chomp $linebis;
233                 push @list1,"$linebis";
234             }   
235             close OUT;
236             $command_executed = 1;
237         }
238     }
239     elsif($line1 =~ /^\& /){    # parallel command line
240         $command_executed = 0;
241         $expected_result_line = 0;
242         $line1 =~ s/\${EXEEXT:=}//g;
243         $line1 =~ s/^\& //g;
244         $line1 =~ s/^.\/lua/lua/g;
245         $line1 =~ s/^.\/ruby/ruby/g;
246         $line1 =~ s/^.\///g;
247         $line1 =~ s/\(%i:%P@%h\)/\\\(%i:%P@%h\\\)/g;
248         chomp $line1;
249         $line1 = "$line1 $config";
250         
251         $execline = "$line1";
252         print "[Tesh/INFO] exec_line : $execline\n";
253         push @list_of_commands, $execline;      
254     }   
255     elsif($line1 =~ /^\>/){     #expected result line
256         $line1 =~ s/^\>( )*//g;
257         $line1 =~ s/\r//g;
258         chomp $line1;
259         push @list2, $line1;
260         $expected_result_line = 1;
261     }
262     elsif($line1 =~ /^\</ or $encore==1){       #need to buffer
263         $line1 =~ s/^\<( )*//g; #delete < with space or tab after
264         $line1 =~ s/\r//g;
265         chomp $line1;
266         if($line1 =~ /\\$/) # need to store this line into old_buff
267         {
268             $encore=1;
269             $line1 =~ s/\\$//g;
270             $old_buffer = "$old_buffer$line1";
271         }
272         else
273         {
274             if($encore == 1){push @buffer, "$old_buffer$line1";}
275             else{push @buffer, "$line1\n";}
276             $old_buffer = ();
277             $encore = 0;        
278         }
279     }
280     elsif($line1 =~ /^p/){      #comment
281         $line1 =~ s/^p //g;
282         $line1 =~ s/\r//g;
283         chomp $line1;
284         print "[Tesh/INFO] comment_line :$line1\n";
285     }
286     elsif($line1 =~ /^! output sort/){  #output sort
287         $sort=1;
288     }
289     elsif($line1 =~ /^! output ignore/){        #output ignore
290         $no_output_ignore=0;
291     }
292     elsif($line1 =~ /^! expect signal SIGABRT$/) #expect signal SIGABRT
293     {
294         $SIGABRT=1;
295     }
296     elsif($line1 =~ /^! expect return/){        #expect return
297         $line1 =~ s/^! expect return //g;
298         $line1 =~ s/\r//g;
299         chomp $line1;
300         $return = $line1;
301         print color("red"), "[Tesh/INFO] expect return $return";
302         print color("reset"), "\n";
303         die;
304     }
305     elsif($line1 =~ /^! setenv/){       #setenv
306         $line1 =~ s/^! setenv //g;
307         $line1 =~ s/\r//g;
308         chomp $line1;
309         $line1 =~ /^(.*)=(.*)$/;
310         $ENV{$1} = $2;
311         print "[Tesh/INFO] setenv: $1=$2\n";
312     }
313     elsif($line1 =~ /^! include/){      #output sort
314         print color("red"), "[Tesh/CRITICAL] need include";
315         print color("reset"), "\n";
316         die;
317     }
318     elsif($line1 =~ /^! timeout/){      #timeout
319         $line1 =~ s/^! timeout //g;
320         $line1 =~ s/\r//g;
321         chomp $line1;
322         if($timeout != $line1){
323             $timeout = $line1;
324             print "[Tesh/INFO] timeout   : $timeout\n";}
325     }
326     elsif($line1 =~ /^! need execute/){ #need execute // commands
327         $execline = ();
328         $sort = 1; # need sort output
329         while(@list_of_commands)
330         {
331             $command = shift (@list_of_commands);
332             if($execline){$execline = "$command & $execline";}
333             else{$execline = "$command";}
334         }
335         $pid = open3(\*IN, \*OUT, \*OUT, $execline);
336         if( $timeout){
337             $forked = fork();die "fork() failed: $!" unless defined $forked;
338             if ( $forked == 0 )
339             {
340                 sleep $timeout;
341                 kill(9, $pid);
342                 exit;
343             }
344         }
345         
346         while(@buffer)
347         {
348             $line1 = shift (@buffer);
349             print IN $line1;
350         }
351         close IN ;
352         waitpid( $pid, 0 );
353         if($timeout){kill(9, $forked);$timeout=0;}
354         $timeout = 0;
355         
356         @list1=();
357         while(defined($linebis=<OUT>))
358         {
359             $linebis =~ s/\r//g;
360             $linebis =~ s/^( )*//g;
361             chomp $linebis;
362             push @list1,"$linebis";
363         }       
364         close OUT;
365         $command_executed = 1;
366     }
367     elsif($command_executed and $expected_result_line)
368     {
369         if($no_output_ignore){
370             @buffer = ();
371             if($sort == 1)
372             {
373                 @list3 = sort @list1;
374                 @list1=();
375                 @list1=@list3;
376                 @list3=();
377                 
378                 @list3 = sort @list2;
379                 @list2=();
380                 @list2=@list3;
381                 @list3=();
382                 
383                 $sort=0;
384             }
385             if($SIGABRT)
386             {
387                 push @list2,"Aborted";
388                 $SIGABRT = 0;
389             }
390             
391             while(@list1 or @list2)
392             {
393                 if(@list1){$line1 = shift (@list1);$expected_result_line = "x$line1";}
394                 if(@list2){$line2 = shift (@list2);$command_executed = "x$line2";}
395                 if($command_executed and $expected_result_line)
396                 {
397                     
398                     if($line1 eq $line2){
399                         if($verbose == 1){print color("green"),"[Tesh/VERB] $line1\n",color("reset");}
400                         else{push @buffer, "[Tesh/CRITICAL]   $line1\n";}
401                         
402                     }
403                     else
404                     {   if($verbose == 0){print color("green"),@buffer,color("reset");}
405                         if($line2) {print color("red"), "[Tesh/CRITICAL] - $line2",color("reset"),"\n";}
406                         if($line1) {print color("red"), "[Tesh/CRITICAL] + $line1",color("reset"),"\n";}
407                         die;
408                     }
409                 }
410                 else
411                 {       if($verbose == 0){print color("green"),@buffer,color("reset");}
412                         if($line2) {print color("red"), "[Tesh/CRITICAL] - $line2",color("reset"),"\n";}
413                         if($line1) {print color("red"), "[Tesh/CRITICAL] + $line1",color("reset"),"\n";}
414                         die;
415                 }
416             }
417         }else{$no_output_ignore = 1;}
418         $command_executed = 0;
419         $expected_result_line = 0;
420         @list1=();
421         @list2=();
422         @buffer = ();
423         $tesh_command=0;
424         @buffer_tesh=();
425     }
426     
427 }
428
429 if(@list_of_commands){ # need parallel execution
430     $execline = ();
431     $sort = 1; # need sort output
432     while(@list_of_commands)
433     {
434         $command = shift (@list_of_commands);
435         if($execline){$execline = "$command & $execline";}
436         else{$execline = "$command";}
437     }
438     print "[Tesh/INFO] exec_line : $execline\n";
439     $pid = open3(\*IN, \*OUT, \*OUT,"$execline");
440     
441     if( $timeout){
442         $forked = fork();die "fork() failed: $!" unless defined $forked;
443         if ( $forked == 0 )
444         {
445             sleep $timeout;
446             kill(9, $pid);
447             exit;
448         }
449     }
450     
451     while(@buffer)
452     {
453         $line1 = shift (@buffer);
454         print IN $line1;
455     }
456     close IN ;
457     waitpid( $pid, 0 );
458     if($timeout){kill(9, $forked);$timeout=0;}
459     $timeout = 0;
460
461     @list1=();
462     while(defined($linebis=<OUT>))
463     {
464         $linebis =~ s/\r//g;
465         $linebis =~ s/^( )*//g;
466         chomp $linebis;
467         push @list1,"$linebis";
468     }   
469     close OUT;
470     $command_executed = 1;
471 }
472
473 if($command_executed and $expected_result_line ){
474     if($no_output_ignore){
475         @buffer = ();
476         if($sort == 1)
477         {
478             @list3 = sort @list1;
479             @list1=();
480             @list1=@list3;
481             @list3=();
482             
483             @list3 = sort @list2;
484             @list2=();
485             @list2=@list3;
486             @list3=();
487             
488             $sort=0;
489         }
490         if($SIGABRT)
491         {
492             push @list2,"Aborted";
493             $SIGABRT = 0;
494         }
495         
496         while(@list1 or @list2)
497         {
498             if(@list1){$line1 = shift (@list1);$expected_result_line = "x$line1";}
499             if(@list2){$line2 = shift (@list2);$command_executed = "x$line2";}
500             if($command_executed and $expected_result_line)
501             {
502                 if($line1 eq $line2){
503                     if($verbose == 1){print color("green"),"[Tesh/VERB] $line1\n",color("reset");}
504                     else{push @buffer, "[Tesh/CRITICAL]   $line1\n";}
505                     
506                 }
507                 else
508                 {       if($verbose == 0){print color("green"),@buffer,color("reset");}
509                         if($line2) {print color("red"), "[Tesh/CRITICAL] - $line2",color("reset"),"\n";}
510                         if($line1) {print color("red"), "[Tesh/CRITICAL] + $line1",color("reset"),"\n";}
511                         die;
512                 }
513             }
514             else
515             {   if($verbose == 0){print color("green"),@buffer,color("reset");}
516                 if($line2) {print color("red"), "[Tesh/CRITICAL] - $line2",color("reset"),"\n";}
517                 if($line1) {print color("red"), "[Tesh/CRITICAL] + $line1",color("reset"),"\n";}
518                 die;
519             }
520         }
521     }else{$no_output_ignore = 1;}
522     $command_executed = 0;
523     $expected_result_line= 0;
524     @list1=();
525     @list2=();
526     @buffer = ();
527 }