File Coverage

blib/lib/Outthentic/Story.pm
Criterion Covered Total %
statement 30 360 8.3
branch 0 178 0.0
condition 0 38 0.0
subroutine 10 63 15.8
pod 0 38 0.0
total 40 677 5.9


line stmt bran cond sub pod time code
1             package Outthentic::Story;
2              
3 1     1   7 use strict;
  1         2  
  1         34  
4 1     1   5 use base 'Exporter';
  1         2  
  1         172  
5 1     1   665 use Outthentic::DSL;
  1         8265  
  1         36  
6 1     1   428 use Outthentic::Story::Stat;
  1         3  
  1         31  
7 1     1   526 use File::ShareDir;
  1         25846  
  1         60  
8 1     1   9 use JSON;
  1         22  
  1         8  
9 1     1   121 use Carp;
  1         2  
  1         52  
10 1     1   516 use Time::localtime;
  1         4813  
  1         57  
11              
12 1     1   472 use File::Path::Tiny;
  1         1061  
  1         33  
13 1     1   740 use Term::ANSIColor;
  1         8390  
  1         5388  
14              
15             our @EXPORT = qw{
16              
17             new_story end_of_story set_story story_cache_dir
18              
19             get_prop set_prop
20              
21             debug_mod1 debug_mod2 debug_mod12
22              
23             set_stdout get_stdout stdout_file
24              
25             dsl captures capture stream match_lines
26              
27             run_story apply_story_vars story_var story_vars_pretty
28              
29             do_perl_hook
30              
31             do_ruby_hook
32              
33             do_python_hook
34              
35             do_bash_hook
36              
37             do_ps_hook
38              
39             ignore_story_err
40              
41             quit
42              
43             outthentic_die
44              
45             project_root_dir
46              
47             test_root_dir
48              
49             cache_root_dir
50              
51             host
52              
53             dump_os
54              
55             };
56              
57             our @stories = ();
58             our $OS;
59              
60             sub new_story {
61            
62              
63 0     0 0   my $self = {
64             ID => scalar(@stories),
65             props => {
66             ignore_story_err => 0 ,
67             dsl => Outthentic::DSL->new() ,
68             story_vars => {} },
69             };
70              
71 0           push @stories, $self;
72              
73 0           1;
74              
75             }
76              
77             sub end_of_story {
78              
79 0 0   0 0   if (debug_mod12()){
80 0           main::note("end of story: ".(get_prop('story')));
81             }
82              
83 0           delete $stories[-1];
84              
85             }
86              
87             sub set_story {
88              
89 0     0 0   my $dist_lib_dir = File::ShareDir::dist_dir('Outthentic');
90              
91 0           my $ruby_run_cmd;
92              
93 0 0         if (-f project_root_dir()."/Gemfile" ){
94 0           $ruby_run_cmd = "cd ".project_root_dir()." && bundle exec ruby -I $dist_lib_dir -r outthentic -I ".story_cache_dir()
95             } else {
96 0           $ruby_run_cmd = "ruby -I $dist_lib_dir -r outthentic -I ".story_cache_dir();
97             }
98              
99 0           my $python_run_cmd = "PYTHONPATH=\$PYTHONPATH:".(story_cache_dir()).":$dist_lib_dir python";
100              
101 0           get_prop('dsl')->{languages}->{ruby} = $ruby_run_cmd;
102              
103 0           get_prop('dsl')->{languages}->{python} = $python_run_cmd;
104              
105 0           get_prop('dsl')->{cache_dir} = story_cache_dir();
106              
107 0           my $bash_run_opts = "source "._bash_glue_file()." && source $dist_lib_dir/outthentic.bash";
108              
109 0           get_prop('dsl')->{languages}->{ruby} = $ruby_run_cmd;
110              
111 0           get_prop('dsl')->{languages}->{bash} = $bash_run_opts;
112              
113 0           _make_cache_dir();
114              
115 0           _mk_perl_glue_file();
116              
117 0           _mk_ruby_glue_file();
118              
119 0           _mk_python_glue_file();
120              
121 0           _mk_bash_glue_file();
122              
123 0           _mk_ps_glue_file();
124              
125             }
126              
127             sub _story {
128 0     0     @stories[-1];
129             }
130              
131             sub _story_id {
132 0     0     _story()->{ID};
133             }
134              
135             sub get_prop {
136              
137 0     0 0   my $name = shift;
138              
139 0           _story()->{props}->{$name};
140            
141             }
142              
143             sub set_prop {
144              
145 0     0 0   my $name = shift;
146 0           my $value = shift;
147 0           _story()->{props}->{$name} = $value;
148            
149             }
150              
151              
152             sub project_root_dir {
153 0     0 0   get_prop('project_root_dir');
154             }
155              
156              
157             sub test_root_dir { # this one is deprected and exists for back compatibilty, use cache_root_dir instead
158 0     0 0   get_prop('cache_root_dir');
159             }
160              
161             sub cache_root_dir {
162 0     0 0   get_prop('cache_root_dir');
163             }
164              
165             sub host {
166 0     0 0   get_prop('host');
167             }
168              
169             sub ignore_story_err {
170              
171 0     0 0   my $val = shift;
172 0           my $rv;
173              
174 0 0         if (defined $val){
175 0           set_prop('ignore_story_err',$val);
176             } else {
177 0           $rv = get_prop('ignore_story_err');
178             }
179 0           $rv;
180             }
181              
182              
183             sub debug_mod1 {
184              
185 0     0 0   get_prop('debug') == 1
186             }
187              
188             sub debug_mod2 {
189              
190 0     0 0   get_prop('debug') == 2
191             }
192              
193             sub debug_mod12 {
194              
195 0 0   0 0   debug_mod1() or debug_mod2()
196             }
197              
198              
199             sub set_stdout {
200              
201 0     0 0   my $line = shift;
202 0 0         open FSTDOUT, ">>", stdout_file() or die $!;
203 0           print FSTDOUT $line, "\n";
204 0           close FSTDOUT;
205              
206             }
207              
208             sub get_stdout {
209              
210 0 0   0 0   return unless -f stdout_file();
211              
212 0           my $data;
213              
214 0 0         open FSTDOUT, stdout_file() or die $!;
215 0           my $data = join "", ;
216 0           close FSTDOUT;
217 0           $data;
218             }
219              
220             sub stdout_file {
221              
222 0     0 0   story_cache_dir()."/std.out"
223              
224             }
225              
226             sub _make_cache_dir {
227              
228 0     0     my $cache_dir = cache_root_dir()."/story-"._story_id();
229              
230 0 0         if (debug_mod12()){
231 0           main::note("make cache dir: $cache_dir");
232             }
233 0 0         File::Path::Tiny::mk($cache_dir) or die "can't create $cache_dir, error: $!";
234 0 0         File::Path::Tiny::empty_dir($cache_dir) or die "can't empty $cache_dir, error: $!";
235             }
236              
237             sub story_cache_dir {
238 0     0 0   cache_root_dir()."/story-"._story_id();
239             }
240              
241             sub _perl_glue_file {
242 0     0     story_cache_dir()."/glue.pm";
243             }
244              
245             sub _ruby_glue_file {
246 0     0     story_cache_dir()."/glue.rb";
247             }
248              
249             sub _python_glue_file {
250 0     0     story_cache_dir()."/glue.py";
251             }
252              
253             sub _bash_glue_file {
254 0     0     story_cache_dir()."/glue.bash";
255             }
256              
257             sub _ps_glue_file {
258 0     0     story_cache_dir()."/glue.ps1";
259             }
260              
261             sub dsl {
262 0     0 0   get_prop('dsl')
263             }
264              
265             sub stream {
266 0     0 0   dsl()->stream
267             }
268              
269             sub captures {
270              
271             dsl()->{captures}
272 0     0 0   }
273              
274             sub capture {
275 0     0 0   dsl()->{captures}->[0]
276             }
277              
278             sub match_lines {
279              
280             dsl()->{match_lines}
281 0     0 0   }
282              
283             sub run_story {
284              
285 0     0 0   my $path = shift;
286              
287 0   0       my $story_vars = shift || {};
288              
289 0           Outthentic::Story::Stat->new_story({
290             vars => $story_vars,
291             path => $path
292             });
293              
294 0           my $cache_root_dir = get_prop('cache_root_dir');
295              
296 0           my $project_root_dir = get_prop('project_root_dir');
297              
298 0           my $story_module = "$cache_root_dir/modules/$path/story.outth";
299              
300 0 0         die "story module file $story_module does not exist" unless -e $story_module;
301              
302 0 0         if (debug_mod12()){
303 0           main::note("run downstream story: $path");
304 0           for my $k (keys %{$story_vars}){
  0            
305 0           my $v = $story_vars->{$k};
306 0           main::note("downstream story var: $k => $v");
307             }
308             }
309              
310             {
311 0           package main;
312 0 0         unless (do $story_module) {
313 0 0         die "couldn't parse story module file $story_module: $@" if $@;
314             }
315             }
316              
317             # return statistic for downstream story just executed
318 0           return Outthentic::Story::Stat->current;
319             }
320              
321             sub do_perl_hook {
322              
323 0     0 0   my $hook_file = shift;
324              
325 0 0         print_hook_header() if debug_mod1;
326              
327             {
328 0           package main;
329 0 0         unless (do $hook_file) {
330 0 0         die "couldn't parse perl hook file $hook_file: $@" if $@;
331             }
332             }
333              
334 0           return 1;
335             }
336              
337             sub quit {
338 0     0 0   my $msg = shift;
339 0           chomp($msg);
340 0           main::print_story_header();
341 0           main::note("? forcefully exit: $msg");
342 0           exit(0);
343             }
344              
345             sub outthentic_die {
346 0     0 0   my $msg = shift;
347 0           chomp($msg);
348 0           main::print_story_header();
349 0           main::note("!! forcefully die: $msg");
350 0           $main::STATUS = 0;
351 0           exit(1);
352             }
353              
354             sub _mk_perl_glue_file {
355              
356 0 0   0     open PERL_GLUE, ">", _perl_glue_file() or confess "can't create perl glue file ".(_perl_glue_file())." : $!";
357              
358 0           my $cache_root_dir = cache_root_dir();
359 0           my $story_dir = get_prop('story_dir');
360 0           my $project_root_dir = project_root_dir();
361 0           my $debug_mod12 = debug_mod12();
362 0           my $cache_dir = story_cache_dir;
363              
364 0           my $os = _resolve_os();
365              
366 0           print PERL_GLUE <<"CODE";
367              
368             package glue;
369             1;
370              
371             package main;
372             use strict;
373            
374             sub debug_mod12 {
375             $debug_mod12
376             }
377              
378             sub cach_root_dir {
379             '$cache_root_dir'
380             }
381              
382             sub test_root_dir {
383             '$cache_root_dir'
384             }
385              
386             sub project_root_dir {
387             '$project_root_dir'
388             }
389              
390             sub cache_dir {
391             '$cache_dir'
392             }
393              
394             sub story_dir {
395             '$story_dir'
396             }
397              
398             sub os { '$os' }
399              
400              
401             1;
402              
403             CODE
404              
405 0           close PERL_GLUE;
406              
407             }
408              
409             sub _mk_ruby_glue_file {
410              
411 0 0   0     open RUBY_GLUE, ">", _ruby_glue_file() or die $!;
412              
413 0           my $stdout_file = stdout_file();
414 0           my $cache_root_dir = cache_root_dir();
415 0           my $story_dir = get_prop('story_dir');
416 0           my $project_root_dir = project_root_dir();
417 0           my $debug_mod12 = debug_mod12();
418              
419 0           my $cache_dir = story_cache_dir;
420              
421 0           print RUBY_GLUE <<"CODE";
422              
423             def debug_mod12
424             '$debug_mod12'
425             end
426              
427             def cache_root_dir
428             '$cache_root_dir'
429             end
430              
431             def test_root_dir
432             '$cache_root_dir'
433             end
434              
435             def project_root_dir
436             '$project_root_dir'
437             end
438              
439             def cache_dir
440             '$cache_dir'
441             end
442              
443             def story_dir
444             '$story_dir'
445             end
446              
447             def stdout_file
448             '$stdout_file'
449             end
450              
451             CODE
452              
453 0           close RUBY_GLUE;
454              
455             }
456              
457             sub _mk_python_glue_file {
458              
459 0 0   0     open PYTHON_GLUE, ">", _python_glue_file() or die $!;
460              
461 0           my $stdout_file = stdout_file();
462 0           my $cache_root_dir = cache_root_dir();
463 0           my $story_dir = get_prop('story_dir');
464 0           my $project_root_dir = project_root_dir();
465 0           my $debug_mod12 = debug_mod12();
466              
467 0           my $cache_dir = story_cache_dir;
468              
469 0           print PYTHON_GLUE <<"CODE";
470              
471             def debug_mod12():
472             return $debug_mod12
473              
474             def cache_root_dir():
475             return '$cache_root_dir'
476              
477             def test_root_dir():
478             return '$cache_root_dir'
479              
480             def project_root_dir():
481             return '$project_root_dir'
482              
483             def cache_dir():
484             return '$cache_dir'
485              
486             def story_dir():
487             return '$story_dir'
488              
489             def stdout_file():
490             return '$stdout_file'
491              
492             CODE
493              
494 0           close PYTHON_GLUE;
495              
496             }
497              
498             sub _mk_bash_glue_file {
499              
500              
501 0     0     my $story_dir = get_prop('story_dir');
502              
503 0 0         open BASH_GLUE, ">", _bash_glue_file() or die $!;
504              
505 0           my $stdout_file = stdout_file();
506 0           my $cache_root_dir = cache_root_dir();
507 0           my $project_root_dir = project_root_dir();
508 0           my $debug_mod12 = debug_mod12();
509              
510 0           my $cache_dir = story_cache_dir;
511              
512 0           my $os = _resolve_os();
513              
514 0           print BASH_GLUE <<"CODE";
515              
516             debug_mod=debug_mod12
517              
518             test_root_dir=$cache_root_dir
519              
520             cache_root_dir=$cache_root_dir
521              
522             project_root_dir=$project_root_dir
523              
524             cache_dir=$cache_dir
525              
526             story_dir=$story_dir
527              
528             stdout_file=$stdout_file
529              
530             os=$os
531              
532             CODE
533              
534 0           close BASH_GLUE;
535              
536             }
537              
538             sub _mk_ps_glue_file {
539              
540 0 0   0     open PS_GLUE, ">", _ps_glue_file() or die $!;
541              
542 0           my $stdout_file = stdout_file();
543 0           my $cache_root_dir = cache_root_dir();
544 0           my $story_dir = get_prop('story_dir');
545 0           my $project_root_dir = project_root_dir();
546 0           my $debug_mod12 = debug_mod12();
547              
548 0           my $cache_dir = story_cache_dir;
549              
550 0           print PS_GLUE <<"CODE";
551              
552             function debug_mod12 {
553             '$debug_mod12'
554             }
555              
556             function cache_root_dir {
557             '$cache_root_dir'
558             }
559              
560             function test_root_dir {
561             '$cache_root_dir'
562             }
563              
564             function project_root_dir {
565             '$project_root_dir'
566             }
567              
568             function cache_dir {
569             '$cache_dir'
570             }
571              
572             function story_dir {
573             '$story_dir'
574             }
575              
576             function stdout_file {
577             '$stdout_file'
578             }
579              
580             CODE
581              
582 0           close PS_GLUE;
583              
584             }
585              
586             sub do_ruby_hook {
587              
588 0     0 0   my $file = shift;
589              
590 0           my $ruby_lib_dir = File::ShareDir::dist_dir('Outthentic');
591              
592 0           my $cmd;
593              
594 0 0         print_hook_header() if debug_mod1;
595              
596 0 0         if (-f project_root_dir()."/Gemfile" ){
597 0           $cmd = "cd ".project_root_dir()." && bundle exec ruby -I $ruby_lib_dir -r outthentic -I ".story_cache_dir()." $file"
598             } else {
599 0           $cmd = "ruby -I $ruby_lib_dir -r outthentic -I ".story_cache_dir()." $file"
600             }
601              
602 0 0         if (debug_mod12()){
603 0           main::note("do_ruby_hook: $cmd");
604             }
605              
606              
607 0           my $rand = int(rand(1000));
608              
609 0           my $st = system("$cmd 2>".story_cache_dir()."/$rand.err 1>".story_cache_dir()."/$rand.out");
610              
611 0 0         if($st != 0){
612 0           die "do_ruby_hook failed. \n see ".story_cache_dir()."/$rand.err for details";
613             }
614              
615 0           my $out_file = story_cache_dir()."/$rand.out";
616              
617 0 0         open RUBY_HOOK_OUT, $out_file or die "can't open RUBY_HOOK_OUT file $out_file to read!";
618              
619 0           my @out = ;
620              
621 0           close RUBY_HOOK_OUT;
622              
623 0           my $story_vars_json;
624              
625 0           for my $l (@out) {
626              
627 0 0         next if $l=~/#/;
628              
629 0 0         quit($1) if $l=~/quit:(.*)/;
630              
631 0 0         outthentic_die($1) if $l=~/outthentic_die:(.*)/;
632              
633 0 0         ignore_story_err($1) if $l=~/ignore_story_err:\s+(\d)/;
634            
635 0 0         if ($l=~s/story_var_json_begin.*// .. $l=~s/story_var_json_end.*//){
636 0           $story_vars_json.=$l;
637 0           next;
638             }
639              
640              
641 0 0         if ($l=~/story:\s+(\S+)/){
642              
643 0           my $path = $1;
644              
645 0 0         if (debug_mod12()){
646 0           main::note("run downstream story from ruby hook");
647             }
648              
649 0   0       run_story($path, decode_json($story_vars_json||{}));
650 0           $story_vars_json = undef;
651              
652             }
653             }
654              
655 0           return 1;
656             }
657              
658             sub do_python_hook {
659              
660 0     0 0   my $file = shift;
661              
662 0           my $python_lib_dir = File::ShareDir::dist_dir('Outthentic');
663              
664 0           my $cmd = "PYTHONPATH=\$PYTHONPATH:".(story_cache_dir()).":$python_lib_dir python $file";
665            
666 0 0         print_hook_header() if debug_mod1;
667              
668 0 0         if (debug_mod12()){
669 0           main::note("do_python_hook: $cmd");
670             }
671              
672              
673 0           my $rand = int(rand(1000));
674              
675 0           my $st = system("$cmd 2>".story_cache_dir()."/$rand.err 1>".story_cache_dir()."/$rand.out");
676              
677 0 0         if($st != 0){
678 0           die "do_python_hook failed. \n see ".story_cache_dir()."/$rand.err for details";
679             }
680              
681 0           my $out_file = story_cache_dir()."/$rand.out";
682              
683 0 0         open PYTHON_HOOK_OUT, $out_file or die "can't open PYTHON_HOOK_OUT file $out_file to read!";
684              
685 0           my @out = ;
686              
687 0           close PYTHON_HOOK_OUT;
688              
689 0           my $story_vars_json;
690              
691 0           for my $l (@out) {
692              
693 0 0         next if $l=~/#/;
694              
695 0 0         quit($1) if $l=~/quit:(.*)/;
696              
697 0 0         outthentic_die($1) if $l=~/outthentic_die:(.*)/;
698              
699 0 0         ignore_story_err($1) if $l=~/ignore_story_err:\s+(\d)/;
700            
701 0 0         if ($l=~s/story_var_json_begin.*// .. $l=~s/story_var_json_end.*//){
702 0           $story_vars_json.=$l;
703 0           next;
704             }
705              
706              
707 0 0         if ($l=~/story:\s+(\S+)/){
708              
709 0           my $path = $1;
710              
711 0 0         if (debug_mod12()){
712 0           main::note("run downstream story from python hook");
713             }
714              
715 0   0       run_story($path, decode_json($story_vars_json||{}));
716              
717 0           $story_vars_json = undef;
718              
719             }
720             }
721              
722 0           return 1;
723             }
724              
725             sub do_bash_hook {
726              
727 0     0 0   my $file = shift;
728              
729 0           my $bash_lib_dir = File::ShareDir::dist_dir('Outthentic');
730              
731 0           my $cmd = "source "._bash_glue_file()." && source $bash_lib_dir/outthentic.bash";
732              
733 0           $cmd.=" && source $file";
734              
735 0           $cmd="bash -c '$cmd'";
736              
737 0 0         print_hook_header() if debug_mod1;
738              
739 0 0         if (debug_mod12()){
740 0           main::note("do_bash_hook: $cmd");
741             }
742              
743              
744 0           my $rand = int(rand(1000));
745              
746 0           my $st = system("$cmd 2>".story_cache_dir()."/$rand.err 1>".story_cache_dir()."/$rand.out");
747              
748 0 0         if($st != 0){
749 0           die "do_bash_hook failed. \n see ".story_cache_dir()."/$rand.err for details";
750             }
751              
752 0           my $out_file = story_cache_dir()."/$rand.out";
753              
754 0 0         open HOOK_OUT, $out_file or die "can't open HOOK_OUT file $out_file to read!";
755              
756 0           my @out = ;
757              
758 0           close HOOK_OUT;
759              
760 0           my %story_vars_bash = ();
761              
762 0           for my $l (@out) {
763              
764 0 0         next if $l=~/#/;
765            
766 0 0         quit($1) if $l=~/quit:(.*)/;
767              
768 0 0         outthentic_die($1) if $l=~/outthentic_die:(.*)/;
769              
770 0 0         ignore_story_err($1) if $l=~/ignore_story_err:\s+(\d)/;
771            
772 0 0         if ($l=~/story_var_bash:\s+(\S+)\s+(.*)/){
773 0           $story_vars_bash{$1}=$2;
774             #warn %story_vars_bash;
775 0           next;
776             }
777              
778 0 0         if ($l=~/story:\s+(\S+)/){
779 0           my $path = $1;
780 0 0         if (debug_mod12()){
781 0           main::note("run downstream story from bash hook");
782             }
783 0           run_story($path, {%story_vars_bash});
784 0           %story_vars_bash = ();
785             }
786             }
787              
788 0           return 1;
789              
790             }
791              
792              
793             sub do_ps_hook {
794              
795 0     0 0   my $file = shift;
796              
797 0           my $ps_lib_dir = File::ShareDir::dist_dir('Outthentic');
798              
799 0           my $cmd;
800              
801 0 0         print_hook_header() if debug_mod1;
802              
803 0 0         if ( $^O =~ 'MSWin' ){
804 0           $cmd = "powershell.exe -NoProfile -c \". ".story_cache_dir()."/glue.ps1; . $ps_lib_dir/outthentic.ps1; . $file; \"";
805             } else {
806 0           $cmd = "pwsh -c \". ".story_cache_dir()."/glue.ps1; . $ps_lib_dir/outthentic.ps1; . $file; \"";
807             }
808              
809 0 0         if (debug_mod12()){
810 0           main::note("do_ps_hook: $cmd");
811             }
812              
813              
814 0           my $rand = int(rand(1000));
815              
816 0           my $st = system("$cmd 2>".story_cache_dir()."/$rand.err 1>".story_cache_dir()."/$rand.out");
817              
818 0 0         if($st != 0){
819 0           die "do_ps_hook failed. \n see ".story_cache_dir()."/$rand.err for details";
820             }
821              
822 0           my $out_file = story_cache_dir()."/$rand.out";
823              
824 0 0         open HOOK_OUT, $out_file or die "can't open HOOK_OUT file $out_file to read!";
825              
826 0           my @out = ;
827              
828 0           close HOOK_OUT;
829              
830 0           my $story_vars_json;
831              
832 0           for my $l (@out) {
833              
834 0 0         next if $l=~/#/;
835            
836 0 0         quit($1) if $l=~/quit:(.*)/;
837              
838 0 0         outthentic_die($1) if $l=~/outthentic_die:(.*)/;
839              
840 0 0         ignore_story_err($1) if $l=~/ignore_story_err:\s+(\d)/;
841            
842 0 0         if ($l=~s/story_var_json_begin.*// .. $l=~s/story_var_json_end.*//){
843 0           $story_vars_json.=$l;
844 0           next;
845             }
846              
847 0 0         if ($l=~/story:\s+(\S+)/){
848              
849 0           my $path = $1;
850              
851 0 0         if (debug_mod12()){
852 0           main::note("run downstream story from powershell hook");
853             }
854              
855 0   0       run_story($path, decode_json($story_vars_json||{}));
856              
857 0           $story_vars_json = undef;
858              
859             }
860              
861             }
862              
863 0           return 1;
864              
865             }
866              
867              
868             sub apply_story_vars {
869              
870 0     0 0   my $story_vars = Outthentic::Story::Stat->current->{vars};
871              
872 0           set_prop( story_vars => $story_vars );
873              
874 0 0         open STORY_VARS, ">", (story_cache_dir())."/variables.json"
875             or die "can't open ".(story_cache_dir())."/variables.json write: $!";
876              
877 0           print STORY_VARS encode_json($story_vars);
878              
879 0           close STORY_VARS;
880              
881 0 0         open STORY_VARS, ">", (story_cache_dir())."/variables.bash"
882             or die "can't open ".(story_cache_dir())."/variables.bash write: $!";
883              
884 0           for my $name (keys %{$story_vars} ){
  0            
885 0           print STORY_VARS "$name=".$story_vars->{$name}."\n";
886             }
887              
888 0           close STORY_VARS;
889              
890             }
891              
892             sub story_var {
893              
894 0     0 0   my $name = shift;
895              
896 0           get_prop( 'story_vars' )->{$name};
897              
898             }
899              
900             sub story_vars_pretty {
901              
902 0     0 0   join " ", map { "$_:".(story_var($_)) } sort keys %{get_prop( 'story_vars' ) };
  0            
  0            
903              
904             }
905              
906             sub print_hook_header {
907              
908 0     0 0   my $task_name = get_prop('task_name');
909              
910 0           my $format = get_prop('format');
911              
912 0           my $data;
913              
914 0 0         if ($format eq 'production') {
    0          
915 0   0       $data = timestamp().' : '.($task_name || '').' '.'[hook]'
916             } elsif ($format ne 'concise') {
917 0 0 0       $data = timestamp().' : '.($task_name || '' ).' '.(nocolor() ? ' hook' : colored(['yellow'],'[hook]'))
918             }
919              
920 0 0         note($data) if $format ne 'concise';
921             }
922              
923             sub note {
924              
925 0     0 0   my $message = shift;
926 0           my $no_new_line = shift;
927              
928 0           binmode(STDOUT, ":utf8");
929 0           print $message;
930 0 0         print "\n" unless $no_new_line;
931              
932             }
933              
934             sub nocolor {
935 0     0 0   get_prop('nocolor')
936             }
937              
938             sub timestamp {
939              
940 0     0 0   sprintf '%02d-%02d-%02d %02d:%02d:%02d',
941             localtime->year()+1900,
942             localtime->mon()+1, localtime->mday,
943             localtime->hour, localtime->min, localtime->sec;
944              
945             }
946              
947             sub dump_os {
948              
949 0 0   0 0   return $^O if $^O =~ 'MSWin';
950              
951 0           my $cmd = <<'HERE';
952             #! /usr/bin/env sh
953              
954             # Find out the target OS
955             if [ -s /etc/os-release ]; then
956             # freedesktop.org and systemd
957             . /etc/os-release
958             OS=$NAME
959             VER=$VERSION_ID
960             elif lsb_release -h >/dev/null 2>&1; then
961             # linuxbase.org
962             OS=$(lsb_release -si)
963             VER=$(lsb_release -sr)
964             elif [ -s /etc/lsb-release ]; then
965             # For some versions of Debian/Ubuntu without lsb_release command
966             . /etc/lsb-release
967             OS=$DISTRIB_ID
968             VER=$DISTRIB_RELEASE
969             elif [ -s /etc/debian_version ]; then
970             # Older Debian/Ubuntu/etc.
971             OS=Debian
972             VER=$(cat /etc/debian_version)
973             elif [ -s /etc/SuSe-release ]; then
974             # Older SuSE/etc.
975             printf "TODO\n"
976             elif [ -s /etc/redhat-release ]; then
977             # Older Red Hat, CentOS, etc.
978             OS=$(cat /etc/redhat-release| head -n 1)
979             else
980             RELEASE_INFO=$(cat /etc/*-release 2>/dev/null | head -n 1)
981              
982             if [ ! -z "$RELEASE_INFO" ]; then
983             OS=$(printf -- "$RELEASE_INFO" | awk '{ print $1 }')
984             VER=$(printf -- "$RELEASE_INFO" | awk '{ print $NF }')
985             else
986             # Fall back to uname, e.g. "Linux ", also works for BSD, etc.
987             OS=$(uname -s)
988             VER=$(uname -r)
989             fi
990             fi
991              
992             echo "$OS$VER"
993              
994             HERE
995              
996 0           `$cmd`
997              
998             }
999              
1000             sub _resolve_os {
1001              
1002            
1003 0 0   0     if (!$OS){
1004              
1005 0           DONE: while (1) {
1006 0           my $data = dump_os();
1007 0 0 0       $data=~/alpine/i and $OS = 'alpine' and last DONE;
1008 0 0 0       $data=~/minoca/i and $OS = "minoca" and last DONE;
1009 0 0 0       $data=~/centos linux(\d+)/i and $OS = "centos$1" and last DONE;
1010 0 0 0       $data=~/Red Hat.*release\s+(\d)/i and $OS = "centos$1" and last DONE;
1011 0 0 0       $data=~/arch/i and $OS = 'archlinux' and last DONE;
1012 0 0 0       $data=~/funtoo/i and $OS = 'funtoo' and last DONE;
1013 0 0 0       $data=~/fedora/i and $OS = 'fedora' and last DONE;
1014 0 0 0       $data=~/amazon/i and $OS = 'amazon' and last DONE;
1015 0 0 0       $data=~/ubuntu/i and $OS = 'ubuntu' and last DONE;
1016 0 0 0       $data=~/debian/i and $OS = 'debian' and last DONE;
1017 0 0 0       $data=~/darwin/i and $OS = 'darwin' and last DONE;
1018 0 0 0       $data=~/MSWin/i and $OS = 'windows' and last DONE;
1019 0           warn "unknown os: $data";
1020 0           last DONE;
1021             }
1022             }
1023 0           return $OS;
1024             }
1025              
1026             package main;
1027              
1028 0     0     sub os { Outthentic::Story::_resolve_os }
1029              
1030              
1031              
1032             1;
1033              
1034             __END__