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

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

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