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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.11 - (hide annotations)
Mon Jun 23 17:54:32 2003 UTC (21 years ago) by joko
Branch: MAIN
Changes since 1.10: +16 -1 lines
prepared execution of in-process perl-code via eval (not activated yet!)

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

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