/[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.15 - (hide annotations)
Wed Jun 16 16:37:59 2004 UTC (20 years ago) by joko
Branch: MAIN
Changes since 1.14: +12 -6 lines
attempt to get things going in a generic way (Linux/FreeBSD/Win32)

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

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