/[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.14 - (hide annotations)
Wed May 12 14:23:31 2004 UTC (20 years, 1 month ago) by jonen
Branch: MAIN
Changes since 1.13: +12 -5 lines
 add comment/code related to PERL5LIB var at different OS's

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

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