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

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

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