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

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

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