/[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.10 - (hide annotations)
Tue May 13 07:56:12 2003 UTC (21 years, 1 month ago) by joko
Branch: MAIN
Changes since 1.9: +49 -8 lines
enhanced: *hierarchical* containers for context handling
fixes: some pre-flight checks
new: propagate "end-tag" event to e.g. close containers

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

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