Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of git+ssh://scm.gforge.inria.fr//gitroot//simgrid/simgrid
[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 TESH_FILE, $tesh_file or die "[Tesh/CRITICAL] Unable to open $tesh_file $!\n";
125
126 my %cmd; # everything about the next command to run
127 while (defined(my $line1=<TESH_FILE>)) {
128     chomp $line1;
129     if($line1 =~ /^\< \$ /){    # arg command line
130         $line1 =~ s/\${EXEEXT:=}//g;
131         $line1 =~ s/^\< \$\ *//g;
132         $line1 =~ s|^./lua|lua|g;
133         $line1 =~ s|^./ruby|ruby|g;
134         $line1 =~ s|^./||g;
135         $line1 =~ s|^tesh|./tesh|g;
136         $line1 =~ s/\(%i:%P@%h\)/\\\(%i:%P@%h\\\)/g;
137         $command_tesh = $line1;
138         print "[Tesh/INFO] arg_exec_line   : $command_tesh\n";
139     }
140     elsif($line1 =~ /^\< \< /){  # arg buffer line
141         $line1 =~ s/^\< \<\ *//g;
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         push @list2, $line1;
149         print "[Tesh/INFO] arg_output_line : $line1\n";
150         $expected_result_line = 1;
151     }
152     elsif($line1 =~ /^\$ mkfile/){      # "mkfile" command line
153         $line1 =~ s/\$ //g;
154         $line1 =~ s/mkfile//g;
155         $fich_name = $line1;
156         $line1 =();
157         print "[Tesh/INFO] exec_line : mkfile $fich_name\n";
158         `rm -f $fich_name`;
159         open(FILE,">$fich_name") or die "[Tesh/CRITICAL] Unable to make file : $fich_name. $!\n";
160         print FILE @buffer;
161         close(FILE);
162         @buffer = ();   
163     }
164     elsif($line1 =~ /^\$ cd/){          # "cd" command line
165         $line1 =~ s/\$ //g;
166         print "[Tesh/INFO] exec_line : $line1\n";
167                 $line1 =~ s/cd //g;
168         chdir("$line1") or die "[Tesh/CRITICAL] Unable to open $line1. $!\n";   
169     }
170     elsif($line1 =~ /^\$ /){    #command line
171         if($line1 =~ m|^\$ ./tesh|){    # tesh command line
172                         $tesh_command = 1;
173                         @buffer = @buffer_tesh;
174                         @buffer_tesh=();
175         }
176         $line1 =~ s/\${EXEEXT:=}//g;
177         $line1 =~ s/^\$\ *//g;
178         $line1 =~ s|^./lua|lua|g;
179         $line1 =~ s|^./ruby|ruby|g;
180         $line1 =~ s|^./||g;
181         $line1 =~ s|^tesh|./tesh|g;
182         $line1 =~ s/\(%i:%P@%h\)/\\\(%i:%P@%h\\\)/g;
183         $line1 = "$line1 $config";
184         
185         if(@list1){
186             print color("red");
187             print "[Tesh/CRITICAL] -\n";
188             print "[Tesh/CRITICAL] + @list1";
189             print color("reset"), "\n";
190             die;}               
191         if(@list_of_commands){ # need parallel execution
192             push @list_of_commands, $line1;
193             print "[Tesh/INFO] exec_line : $line1\n";
194         }
195         else{
196             print "[Tesh/INFO] exec_line : $line1\n";
197             if($tesh_command)
198             {   $execline = $command_tesh;
199                 $tesh_command=0;}
200             else
201             {   $execline = $line1;}
202             $pid = open3(\*IN, \*OUT, \*OUT, $execline );
203             if( $timeout){
204                 $forked = fork();die "fork() failed: $!" unless defined $forked;
205                 if ( $forked == 0 )
206                 {
207                     sleep $timeout;
208                     kill(9, $pid);
209                     exit;
210                 }
211             }
212             
213             while(@buffer)
214             {
215                 $line1 = shift (@buffer);
216                 print IN $line1;
217             }
218             close IN ;
219             
220             waitpid( $pid, 0 );
221             if($timeout){kill(9, $forked);$timeout=0;}
222             $timeout = 0;
223             
224             while(defined($linebis=<OUT>))
225             {
226                 $linebis =~ s/\r//g;
227                 $linebis =~ s/^( )*//g;
228                 chomp $linebis;
229                 push @list1,"$linebis";
230             }   
231             close OUT;
232             $command_executed = 1;
233         }
234     }
235     elsif($line1 =~ /^\& /){    # parallel command line
236         $command_executed = 0;
237         $expected_result_line = 0;
238         $line1 =~ s/\${EXEEXT:=}//g;
239         $line1 =~ s/^\& //g;
240         $line1 =~ s|^./lua|lua|g;
241         $line1 =~ s|^./ruby|ruby|g;
242         $line1 =~ s|^./||g;
243         $line1 =~ s/\(%i:%P@%h\)/\\\(%i:%P@%h\\\)/g;
244         $line1 = "$line1 $config";
245         
246         $execline = "$line1";
247         print "[Tesh/INFO] exec_line : $execline\n";
248         push @list_of_commands, $execline;      
249     }   
250     elsif($line1 =~ /^\>/){     #expected result line
251         $line1 =~ s/^\>( )*//g;
252         $line1 =~ s/\r//g;
253         push @list2, $line1;
254         $expected_result_line = 1;
255     }
256     elsif($line1 =~ /^\</ or $encore==1){       #need to buffer
257         $line1 =~ s/^\<( )*//g; #delete < with space or tab after
258         $line1 =~ s/\r//g;
259         if($line1 =~ /\\$/) # need to store this line into old_buff
260         {
261             $encore=1;
262             $line1 =~ s/\\$//g;
263             $old_buffer = "$old_buffer$line1";
264         }
265         else
266         {
267             if($encore == 1){push @buffer, "$old_buffer$line1";}
268             else{push @buffer, "$line1\n";}
269             $old_buffer = ();
270             $encore = 0;        
271         }
272     }
273     elsif($line1 =~ /^p/){      #comment
274         $line1 =~ s/^p //g;
275         $line1 =~ s/\r//g;
276         print "[Tesh/INFO] comment_line :$line1\n";
277     }
278     elsif($line1 =~ /^! output sort/){  #output sort
279         $sort=1;
280     }
281     elsif($line1 =~ /^! output ignore/){        #output ignore
282         $no_output_ignore=0;
283     }
284     elsif($line1 =~ /^! expect signal SIGABRT$/) #expect signal SIGABRT
285     {
286         $SIGABRT=1;
287     }
288     elsif($line1 =~ /^! expect return/){        #expect return
289         $line1 =~ s/^! expect return //g;
290         $line1 =~ s/\r//g;
291         $return = $line1;
292         print color("red"), "[Tesh/INFO] expect return $return";
293         print color("reset"), "\n";
294         die;
295     }
296     elsif($line1 =~ /^! setenv/){       #setenv
297         $line1 =~ s/^! setenv //g;
298         $line1 =~ s/\r//g;
299         $line1 =~ /^(.*)=(.*)$/;
300         $ENV{$1} = $2;
301         print "[Tesh/INFO] setenv: $1=$2\n";
302     }
303     elsif($line1 =~ /^! include/){      #output sort
304         print color("red"), "[Tesh/CRITICAL] need include";
305         print color("reset"), "\n";
306         die;
307     }
308     elsif($line1 =~ /^! timeout/){      #timeout
309         $line1 =~ s/^! timeout //g;
310         $line1 =~ s/\r//g;
311         if($timeout != $line1){
312             $timeout = $line1;
313             print "[Tesh/INFO] timeout   : $timeout\n";}
314     }
315     elsif($line1 =~ /^! need execute/){ #need execute // commands
316         $execline = ();
317         $sort = 1; # need sort output
318         while(@list_of_commands)
319         {
320             $command = shift (@list_of_commands);
321             if($execline){$execline = "$command & $execline";}
322             else{$execline = "$command";}
323         }
324         $pid = open3(\*IN, \*OUT, \*OUT, $execline);
325         if( $timeout){
326             $forked = fork();die "fork() failed: $!" unless defined $forked;
327             if ( $forked == 0 )
328             {
329                 sleep $timeout;
330                 kill(9, $pid);
331                 exit;
332             }
333         }
334         
335         while(@buffer)
336         {
337             $line1 = shift (@buffer);
338             print IN $line1;
339         }
340         close IN ;
341         waitpid( $pid, 0 );
342         if($timeout){kill(9, $forked);$timeout=0;}
343         $timeout = 0;
344         
345         @list1=();
346         while(defined($linebis=<OUT>))
347         {
348             $linebis =~ s/\r//g;
349             $linebis =~ s/^( )*//g;
350             chomp $linebis;
351             push @list1,"$linebis";
352         }       
353         close OUT;
354         $command_executed = 1;
355     }
356     elsif($command_executed and $expected_result_line)
357     {
358         if($no_output_ignore){
359             @buffer = ();
360             if($sort == 1)
361             {
362                 @list3 = sort @list1;
363                 @list1=();
364                 @list1=@list3;
365                 @list3=();
366                 
367                 @list3 = sort @list2;
368                 @list2=();
369                 @list2=@list3;
370                 @list3=();
371                 
372                 $sort=0;
373             }
374             if($SIGABRT)
375             {
376                 push @list2,"Aborted";
377                 $SIGABRT = 0;
378             }
379             
380             while(@list1 or @list2)
381             {
382                 if(@list1){$line1 = shift (@list1);$expected_result_line = "x$line1";}
383                 if(@list2){$line2 = shift (@list2);$command_executed = "x$line2";}
384                 if($command_executed and $expected_result_line)
385                 {
386                     
387                     if($line1 eq $line2){
388                         if($verbose == 1){print color("green"),"[Tesh/VERB] $line1\n",color("reset");}
389                         else{push @buffer, "[Tesh/CRITICAL]   $line1\n";}
390                         
391                     }
392                     else
393                     {   if($verbose == 0){print color("green"),@buffer,color("reset");}
394                         if($line2) {print color("red"), "[Tesh/CRITICAL] - $line2",color("reset"),"\n";}
395                         if($line1) {print color("red"), "[Tesh/CRITICAL] + $line1",color("reset"),"\n";}
396                         die;
397                     }
398                 }
399                 else
400                 {       if($verbose == 0){print color("green"),@buffer,color("reset");}
401                         if($line2) {print color("red"), "[Tesh/CRITICAL] - $line2",color("reset"),"\n";}
402                         if($line1) {print color("red"), "[Tesh/CRITICAL] + $line1",color("reset"),"\n";}
403                         die;
404                 }
405             }
406         }else{$no_output_ignore = 1;}
407         $command_executed = 0;
408         $expected_result_line = 0;
409         @list1=();
410         @list2=();
411         @buffer = ();
412         $tesh_command=0;
413         @buffer_tesh=();
414     }
415     
416 }
417
418 if(@list_of_commands){ # need parallel execution
419     $execline = ();
420     $sort = 1; # need sort output
421     while(@list_of_commands)
422     {
423         $command = shift (@list_of_commands);
424         if($execline){$execline = "$command & $execline";}
425         else{$execline = "$command";}
426     }
427     print "[Tesh/INFO] exec_line : $execline\n";
428     $pid = open3(\*IN, \*OUT, \*OUT,"$execline");
429     
430     if( $timeout){
431         $forked = fork();die "fork() failed: $!" unless defined $forked;
432         if ( $forked == 0 )
433         {
434             sleep $timeout;
435             kill(9, $pid);
436             exit;
437         }
438     }
439     
440     while(@buffer)
441     {
442         $line1 = shift (@buffer);
443         print IN $line1;
444     }
445     close IN ;
446     waitpid( $pid, 0 );
447     if($timeout){kill(9, $forked);$timeout=0;}
448     $timeout = 0;
449
450     @list1=();
451     while(defined($linebis=<OUT>))
452     {
453         $linebis =~ s/\r//g;
454         $linebis =~ s/^( )*//g;
455         chomp $linebis;
456         push @list1,"$linebis";
457     }   
458     close OUT;
459     $command_executed = 1;
460 }
461
462 if($command_executed and $expected_result_line ){
463     if($no_output_ignore){
464         @buffer = ();
465         if($sort == 1)
466         {
467             @list3 = sort @list1;
468             @list1=();
469             @list1=@list3;
470             @list3=();
471             
472             @list3 = sort @list2;
473             @list2=();
474             @list2=@list3;
475             @list3=();
476             
477             $sort=0;
478         }
479         if($SIGABRT)
480         {
481             push @list2,"Aborted";
482             $SIGABRT = 0;
483         }
484         
485         while(@list1 or @list2)
486         {
487             if(@list1){$line1 = shift (@list1);$expected_result_line = "x$line1";}
488             if(@list2){$line2 = shift (@list2);$command_executed = "x$line2";}
489             if($command_executed and $expected_result_line)
490             {
491                 if($line1 eq $line2){
492                     if($verbose == 1){print color("green"),"[Tesh/VERB] $line1\n",color("reset");}
493                     else{push @buffer, "[Tesh/CRITICAL]   $line1\n";}
494                     
495                 }
496                 else
497                 {       if($verbose == 0){print color("green"),@buffer,color("reset");}
498                         if($line2) {print color("red"), "[Tesh/CRITICAL] - $line2",color("reset"),"\n";}
499                         if($line1) {print color("red"), "[Tesh/CRITICAL] + $line1",color("reset"),"\n";}
500                         die;
501                 }
502             }
503             else
504             {   if($verbose == 0){print color("green"),@buffer,color("reset");}
505                 if($line2) {print color("red"), "[Tesh/CRITICAL] - $line2",color("reset"),"\n";}
506                 if($line1) {print color("red"), "[Tesh/CRITICAL] + $line1",color("reset"),"\n";}
507                 die;
508             }
509         }
510     }else{$no_output_ignore = 1;}
511     $command_executed = 0;
512     $expected_result_line= 0;
513     @list1=();
514     @list2=();
515     @buffer = ();
516 }