/[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.12 - (hide annotations)
Tue Jun 24 20:59:51 2003 UTC (21 years ago) by jonen
Branch: MAIN
Changes since 1.11: +9 -3 lines
added option 'detach'

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

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