/[cvs]/nfo/perl/libs/Data/Rap/Engine.pm
ViewVC logotype

Diff of /nfo/perl/libs/Data/Rap/Engine.pm

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.1 by joko, Tue Feb 18 15:35:25 2003 UTC revision 1.16 by jonen, Mon Jun 21 14:15:06 2004 UTC
# Line 2  Line 2 
2  ##  $Id$  ##  $Id$
3  ## ----------------------------------------------------------------------  ## ----------------------------------------------------------------------
4  ##  $Log$  ##  $Log$
5    ##  Revision 1.16  2004/06/21 14:15:06  jonen
6    ##  handle path-modifications in a generic way now(fix for BSD)
7    ##
8    ##  Revision 1.15  2004/06/16 16:37:59  joko
9    ##  attempt to get things going in a generic way (Linux/FreeBSD/Win32)
10    ##
11    ##  Revision 1.14  2004/05/12 14:23:31  jonen
12    ##   add comment/code related to PERL5LIB var at different OS's
13    ##
14    ##  Revision 1.13  2003/12/05 05:02:08  joko
15    ##  + minor update: disabled some unnecessary loggers or changed to debug-level
16    ##
17    ##  Revision 1.12  2003/06/24 20:59:51  jonen
18    ##  added option 'detach'
19    ##
20    ##  Revision 1.11  2003/06/23 17:54:32  joko
21    ##  prepared execution of in-process perl-code via eval (not activated yet!)
22    ##
23    ##  Revision 1.10  2003/05/13 07:56:12  joko
24    ##  enhanced: *hierarchical* containers for context handling
25    ##  fixes: some pre-flight checks
26    ##  new: propagate "end-tag" event to e.g. close containers
27    ##
28    ##  Revision 1.9  2003/04/04 17:23:11  joko
29    ##  minor update: debugging output
30    ##
31    ##  Revision 1.8  2003/03/29 07:11:54  joko
32    ##  modified: sub run_executable
33    ##  new: sub run_script
34    ##
35    ##  Revision 1.7  2003/03/28 07:02:56  joko
36    ##  modified structure around '$wrapper_program'
37    ##
38    ##  Revision 1.6  2003/03/27 15:31:05  joko
39    ##  fixes to modules regarding new namespace(s) below Data::Mungle::*
40    ##
41    ##  Revision 1.5  2003/03/27 15:03:03  joko
42    ##  enhanced 'sub run_executable'
43    ##
44    ##  Revision 1.4  2003/02/22 16:51:21  joko
45    ##  + enhanced run_executable
46    ##  modified logging output
47    ##
48    ##  Revision 1.3  2003/02/21 01:46:17  joko
49    ##  renamed core function
50    ##
51    ##  Revision 1.2  2003/02/20 19:46:33  joko
52    ##  renamed and revamped some of modules
53    ##  renamed methods
54    ##  + sub run_executable
55    ##
56  ##  Revision 1.1  2003/02/18 15:35:25  joko  ##  Revision 1.1  2003/02/18 15:35:25  joko
57  ##  + initial commit  ##  + initial commit
58  ##  ##
# Line 15  use warnings; Line 66  use warnings;
66    
67    
68  use Data::Dumper;  use Data::Dumper;
 use Data::Transform::Deep qw( refexpr2perlref );  
 use Iterate;  
69  use Hash::Merge qw( merge );  use Hash::Merge qw( merge );
70    use Iterate;
71    
72    use shortcuts qw( run_cmd RUNNING_IN_HELL RUNNING_IN_HEAVEN );
73    use Data::Mungle::Code::Ref qw( ref_slot );
74    use Data::Mungle::Transform::Deep qw( expand deep_copy );
75    use File::Temp qw/ tempfile tempdir /;
76    
77    my $DEBUG = 0;
78    
79  sub performTarget {  sub performTarget {
80    my $self = shift;    my $self = shift;
81    my $targetname = shift;    my $targetname = shift;
82    my $target = $self->getTargetMetadata($targetname);    $self->perform_target($targetname);
83    }
84    
85    sub perform_target {
86      my $self = shift;
87      my $targetname = shift;
88    
89      # pre-flight checks
90      if (!$targetname) {
91        $self->log("Target name empty. Please try to specify (e.g.) on the command line.", 'critical');
92        return;
93      }
94    
95      my $header = ("- " x 12) . "   " . $targetname . "   " . ("- " x 6);
96      
97      # V1
98      #$self->log("- " x 35, 'notice');
99      #$self->log("Performing Target '$targetname'.", 'notice');
100    
101      # V2
102      #$self->log($header, 'notice');
103    
104      # V3
105      #$self->log("- " x 20, 'info');
106      $self->log("Performing Target '$targetname'.", 'notice');
107    
108      #exit;
109    
110      my $target = $self->getTargetDetails($targetname);
111    
112    # trace    # trace
113      #print Dumper($target);      #print Dumper($target);
114      #exit;      #exit;
115            
116      $self->perform_dependencies($target);
117      $self->perform_details($target);
118      
119      return 1;
120    
121    }
122    
123    sub perform_dependencies {
124      my $self = shift;
125      my $target = shift;
126    # resolve dependencies (just run prior)    # resolve dependencies (just run prior)
127    if (my $targetname_dep = $target->{attrib}->{depends}) {    if (my $targetname_dep = $target->{attrib}->{depends}) {
128      $self->performTarget($targetname_dep);      my @targets = split(/,\s|,/, $targetname_dep);
129        #print Dumper(@targets);
130        #$self->perform($targetname_dep);
131        #delete $target->{attrib}->{depends};
132        foreach (@targets) {
133          if (!$self->{__rap}->{dependencies}->{resolved}->{$_}++) {
134            $self->perform_target($_);
135          }
136        }
137      delete $target->{attrib}->{depends};      delete $target->{attrib}->{depends};
138    }    }
139    }
140    
141    sub perform_details {
142      my $self = shift;
143      my $target = shift;
144      
145      #print Dumper($target);
146      #exit;
147      
148    foreach my $entry (@{$target->{content}}) {    foreach my $entry (@{$target->{content}}) {
149      my $command = $entry->{name};      my $command = $entry->{name};
150      my $args = $entry->{attrib};      my $args = $entry->{attrib};
151      $self->run_command($command, $args);      my $content = $entry->{content};
152        $self->perform_command($command, $args, $content, { warn => 1 } );
153        # check recursiveness
154        # new condition: don't recurse if node is flagged to have inline-args (2003-04-17)
155        my $has_inline_args = ($entry->{attrib}->{_args} && $entry->{attrib}->{_args} eq 'inline');
156        if ($entry->{content} && ref $entry->{content} && !$has_inline_args) {
157          $self->perform_details($entry);
158        }
159        # new of 2003-05-08
160        $command ||= '';
161        $self->perform_command($command . '_end', undef, undef, { warn => 0 } );
162    }    }
163  }  }
164    
165  sub rc {  sub rc {
166    my $self = shift;    my $self = shift;
167    return $self->run_command(@_);    return $self->perform_command(@_);
168  }  }
169    
170  sub run_command {  sub perform_command {
171    my $self = shift;    my $self = shift;
172    my $command = shift;    my $command = shift;
173        my $args_list = shift;
174      my $content = shift;
175      my $options = shift;
176    
177    if (!$command) {    if (!$command) {
178      $self->log("Command was empty!", 'warning');      $self->log("Command was empty!", 'debug') if $DEBUG;
179      return;      return;
180    }    }
181    
182      # FIXME: make '__PACKAGE__' go one level deeper properly!
183      $self->log( __PACKAGE__ . "->perform_command: " . $command, 'debug') if $DEBUG;
184        
185    my $args_list = shift;    
186      # 1. make arguments from list of arguments(?)
187    
188    my $args = {};    my $args = {};
189    #print Dumper($args_list);    #print Dumper($args_list);
190    if ($args_list) {    if ($args_list) {
# Line 68  sub run_command { Line 196  sub run_command {
196        $args = $args_list;        $args = $args_list;
197      }      }
198    }    }
199    $command = '_' . $command;    
200    if ($self->can($command)) {    
201      $self->$command($args);    # 2. prepare command
202      
203      # default setting for internal rap commands
204      my $method_prefix_default = '_';
205      # setting from property database
206      my $method_prefix_setting = $self->get_property('core.method_prefix');
207      #print "setting: ", $method_prefix_setting, "\n";
208      my $prefix = $method_prefix_setting;
209      if (not defined $prefix) {
210        $prefix = $method_prefix_default;
211      }
212      $command = $prefix . $command;
213      
214      
215      # 3. determine container
216      my $container; # = $self->getInstance();
217      #$container ||= $self->getInstance();
218      $container ||= $self;
219      
220      # 4. run method
221      if ($container->can($command)) {
222        $container->$command($args, $content);
223    } else {    } else {
224      $self->log("Command \"$command\" not implemented.", "warning");      my $level = "debug";
225        $level = "warning" if $options->{warn};
226        $self->log("Command '$command' not implemented.", $level) if $DEBUG;
227    }    }
228      
229  }  }
230    
 sub set_property {  
   my $self = shift;  
   my $args = shift;  
231    
232    my $name;  sub merge_properties {
233    my $value;    my $self = shift;
234        my $name = shift;
235    if (ref $args) {    my $data = shift;
     $self->interpolate($args) ;  
     $name = $args->{name};  
     $value = $args->{value};  
236    
237    } else {    $self->log("merge-name: $name");
238      $name = $args;    #print "name: $name", "\n";
239      $value = shift;    #print Dumper($data);
240    }    #exit;
241    
242    # check if slot (or childs of it) is/are already occupied    # check if slot (or childs of it) is/are already occupied
243    if (my $oldvalue = refexpr2perlref($self, $name, undef, '.')) {    #if (my $data_old = ref_slot($self, $name, undef, '.')) {
244      if (my $data_old = $self->get_property($name)) {
245        #print "old:", "\n";
246        #print Dumper($data_old);
247        
248      # FIXME: review - any options for 'merge' here?      # FIXME: review - any options for 'merge' here?
249      $value = merge($oldvalue, $value);      my $data_new = merge($data_old, $data);
250        #print "DATA NEE! - MERGE!", "\n";
251        #print Dumper($data_new);
252        #exit;
253        #merge_to($self, $data_new);
254        $self->set_property( { name => $name, value => $data_new } );
255        
256      } else {
257    
258    =pod    
259        # make up a dummy hash matching the structure of the destination one
260          my $dummy = {};
261          ref_slot($dummy, $name, $data, '.');
262          print Dumper($dummy);
263        
264        # mix into destination
265          mixin($self, $dummy, { init => 1 });
266    =cut
267    
268          ref_slot($self, $name, $data, '.');
269    
270    }    }
271      
272      
273      #print Dumper($self);
274      #exit;
275      #$self->
276    
277    }
278    
279    sub set_property {
280      my $self = shift;
281      my $args = shift;
282    
283      $self->interpolate($args) ;
284      my $name = $args->{name};
285      my $value = $args->{value};
286      $name = '__rap.properties.' . $name;
287    
288      $self->log("set-name: $name");
289    
290      #print Dumper($name, $value, '.');
291    
292    # fill property slot with given value    # fill property slot with given value
293    if ($value) {    # fix (2003-04-17): always do fill if value is *defined*!!!
294      refexpr2perlref($self, $name, $value, '.');    if (defined $value) {
295        ref_slot($self, $name, $value, '.');
296    }    }
297        
298      #print Dumper($self);
299      
300    # FIXME!!!    # FIXME!!!
301    return if ! ref $args;    #return if ! ref $args;
302    
303    # fill property slot with (probably bigger) data structure from property-/configuration-style - file    # fill property slot with (probably bigger) data structure from property-/configuration-style - file
304    if (my $file = $args->{file}) {    if (my $file = $args->{file}) {
# Line 123  sub set_property { Line 316  sub set_property {
316      }      }
317    
318    } elsif (my $command = $args->{command}) {    } elsif (my $command = $args->{command}) {
319      $self->run_command($command, $args);      $self->perform_command($command, $args);
320        
321    }    }
322    
# Line 137  sub get_property { Line 330  sub get_property {
330    #$self->interpolate($args);    #$self->interpolate($args);
331    
332    #my $name = $args->{name};    #my $name = $args->{name};
333      my $result;
334    
335      if (!$name) {
336        $self->log( __PACKAGE__ . ": no name!", 'critical');
337        
338      } elsif ($name eq '/') {
339        $result = expand($self);
340    
341      } elsif ($name eq '.') {
342        if (my $instance = $self->getInstance()) {
343          $result = expand($instance);
344        } else {
345          $result = ref_slot($self, '__rap.properties', undef, '.');
346          
347        }
348    
349      } else {
350    
351    # get property slot and return value      $name = '__rap.properties.' . $name;
352    return refexpr2perlref($self, $name, undef, '.');      
353        $self->log("get-name: $name") if $DEBUG;
354        
355        # get property slot and return value
356        $result = ref_slot($self, $name, undef, '.');
357        
358        # FIXME: Is this okay? It's provided for now in order not
359        # to deliver an 'undef' to the regex below inside 'interpolate'.
360        # revamp this, maybe!
361        #$result ||= '';    # NO!!!
362      }
363        
364      return $result;
365  }  }
366    
367  sub interpolate {  sub interpolate {
# Line 152  sub interpolate { Line 373  sub interpolate {
373    }    }
374  }  }
375    
376    sub run_executable {
377      my $self = shift;
378      my $opts = shift;
379    
380      my $meta = deep_copy($opts);
381    
382      delete $opts->{caption};
383      delete $opts->{async};
384      delete $opts->{detach};
385    
386      #print Dumper($meta);
387    
388      if ($opts->{executable}) {
389    
390        my $program = $opts->{executable};
391        delete $opts->{executable};
392    
393        # determine execution method
394        my $wrapper_program = '';
395        
396        # check if program is a namespace-string (contains '::') - use 'do' in this case!
397        if ($program =~ /::/) {
398          #$wrapper_program = 'rap.pl';
399          $wrapper_program = $0;
400        }
401    
402        # prepare arguments
403        my @buf;
404        foreach (keys %$opts) {
405          my $value = $opts->{$_};
406          if (m/^_/) {
407            if ($_ eq '_switches') {
408              my @switches = split(/,\s|,/, $value);
409              foreach my $switch (@switches) {
410                push @buf, '--' . $switch;
411              }
412            }
413            next;
414          }
415          
416          if ($value =~ /\s/) {
417            $value = "\"$value\"";
418          }
419          push @buf, "--$_=$value";
420        }
421    
422        # build {program} & {arguments}  
423        my $cmd = ($wrapper_program ? $wrapper_program . ' ' : '') . $program . ' ' . join(' ', @buf);
424        
425        # trace
426          #print "command: $cmd", "\n";
427        
428        # start process
429          # 2004-05-11 - seems like only ONE args is valid at PERL5LIB, so we use V2!
430          # 2004-06-16 - found out delimiter required for PERL5LIB, reverting back to V1!
431          
432          # V1: join all args
433          #my $delimiter = ':';
434          #$delimiter = ';' if RUNNING_IN_HELL();
435          #$ENV{PERL5LIB} = join($delimiter, @INC);
436          # V2: insert only FIRST arg
437          #$ENV{PERL5LIB} = $INC[0];
438          # WARNING: at (free)BSD our var is the SECOND, NOT FIRST!!
439          # FIXME!! Do this in an abstract way!!
440          #$ENV{PERL5LIB} = $INC[1];
441          # V3: mix V1+V2 (because V1 doesn't fit at freeBSD..)
442          if(RUNNING_IN_HEAVEN()) {
443            $ENV{PERL5LIB} = $INC[1];
444          } else {
445            my $delimiter = ':';
446            $delimiter = ';' if RUNNING_IN_HELL();
447            $ENV{PERL5LIB} = join($delimiter, @INC);
448          }
449          
450          #print Dumper(%ENV);
451          
452          #print "command: '$cmd'", "\n";
453    
454          # V1 - basic
455          #run_cmd($cmd);
456    
457          # V1.b - enhanced: variable local method
458          $meta->{caption} ||= '';
459          $meta->{async} ||= 0;
460          $meta->{detach} ||= 0;
461          # new of 2003-05-08: USE_PATH!
462          $meta->{USE_PATH} ||= 0;
463          my $evalstr = "run_cmd('$cmd', '$meta->{caption}', { async => $meta->{async}, detach => $meta->{detach}, USE_PATH => $meta->{USE_PATH} });";
464          eval($evalstr);
465          #my $res = do "$cmd";
466          #print $res, "\n" if $res;
467    
468          #$self->log("run_executable: $evalstr", 'info');
469          $self->raiseException("run_executable: $evalstr\n$@") if $@;
470    
471          # V2: via IPC::Run
472          # ....  (TODO)
473          
474        
475      }
476      
477    }
478    
479    
480    sub run_script {
481    
482      my $self = shift;
483      my $args = shift;
484      my $code = shift;
485    
486      if ($args->{language} eq 'msdos/bat') {
487        
488        #print "code: $code", "\n";
489        
490        # reporting
491        $self->log("Executing some arbitrary unsigned code (probably unsafe). [language=$args->{language}]", 'info');
492        $self->log("\n<code>\n$code\n</code>", 'info');
493        
494        # create temporary intermediate file to execute code
495        my $tmpdir = '/tmp/rap';
496        mkdir $tmpdir;
497        (my $fh, my $filename) = tempfile( DIR => $tmpdir, SUFFIX => '.bat' );
498        print $fh $code, "\n";
499        run_cmd( $filename, '', { async => 1 } );
500        
501        # FIXME: DELETE code inside temp-files as soon as possible!
502        #print $fh '';
503        
504        # TODO: delete FILE completely!
505        # required for this: wait until execution has finished, then unlink....
506        # but: "how to wait until execution is finished"?
507        # i believe the best is to spawn *another* process directly from here,
508        # let's call it 'watcher-agent'.
509        # This one should monitor a certain running process and delete its
510        # executable file after it has finished execution.
511        # Possible extensions could be:
512        #   keep track of all stuff sent to STDOUT or STDERR and
513        #   send that stuff to the task-owner indirectly (not via shell/console)
514        #   (e.g. via email, by posting report to a newsgroup or publishing on a specified web-page: use mod-dav!)
515        
516      } elsif ($args->{language} eq 'bash') {
517        $self->log("FIXME: - - - - - -- - - --  BASH -  - -    -  - -   -    --   - ", 'error');
518    
519      } elsif ($args->{language} eq 'perl') {
520        
521        # reporting
522        #$self->log("Executing some arbitrary unsigned code (probably unsafe). [language=$args->{language}]", 'info');
523        #$self->log("\n<code>\n$code\n</code>", 'info');
524        
525        # do it
526        #eval($code);
527        #$self->log("\n<code>\n$code\n</code>", 'error') if $@;
528        
529      } else {
530        $self->log("FIXME: Script language '$args->{language}' not implemented.", 'error');
531        
532      }
533    
534    }
535    
536  1;  1;
537  __END__  __END__

Legend:
Removed from v.1.1  
changed lines
  Added in v.1.16

MailToCvsAdmin">MailToCvsAdmin
ViewVC Help
Powered by ViewVC 1.1.26 RSS 2.0 feed