/[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.13 - (hide annotations)
Fri Dec 5 05:02:08 2003 UTC (20 years, 7 months ago) by joko
Branch: MAIN
Changes since 1.12: +10 -6 lines
+ minor update: disabled some unnecessary loggers or changed to debug-level

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

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