File Coverage

blib/lib/Gruntmaster/Daemon/Format.pm
Criterion Covered Total %
statement 83 128 64.8
branch 12 44 27.2
condition 1 2 50.0
subroutine 24 25 96.0
pod 1 7 14.2
total 121 206 58.7


line stmt bran cond sub pod time code
1             package Gruntmaster::Daemon::Format;
2              
3 14     14   212 use 5.014000;
  14         42  
4 14     14   69 use strict;
  14         15  
  14         294  
5 14     14   56 use warnings;
  14         41  
  14         386  
6 14     14   56 use parent qw/Exporter/;
  14         28  
  14         58  
7 14     14   13097 no if $] > 5.017011, warnings => 'experimental::smartmatch';
  14         138  
  14         103  
8              
9 14     14   13793 use Digest::SHA qw/sha256_hex/;
  14         57577  
  14         1288  
10 14     14   18364 use Expect;
  14         622045  
  14         1282  
11 14     14   139 use File::Basename qw/fileparse/;
  14         28  
  14         1102  
12 14     14   11816 use File::Copy qw/cp/;
  14         73795  
  14         921  
13 14     14   12947 use File::Slurp qw/read_file write_file/;
  14         65390  
  14         989  
14 14     14   12070 use List::MoreUtils qw/natatime/;
  14         171421  
  14         99  
15 14     14   26943 use Log::Log4perl qw/get_logger/;
  14         766800  
  14         83  
16 14     14   10727 use String::ShellQuote qw/shell_quote/;
  14         12505  
  14         1036  
17 14     14   10554 use Try::Tiny;
  14         20205  
  14         21170  
18              
19             our $VERSION = '5999.000_005';
20             our @EXPORT_OK = qw/prepare_files stopvms/;
21              
22             ##################################################
23              
24             our (%vm, %pid);
25              
26             sub runvm {
27 122     122 0 269 my ($name, $arg) = @_;
28 122 50       666 return unless $ENV{GRUNTMASTER_VM};
29 0         0 my $cmd = $ENV{GRUNTMASTER_VM};
30 0 0       0 $cmd .= ' ' . $arg if $arg;
31 0         0 get_logger->trace("Starting VM $name ($cmd)");
32 0         0 $vm{$name} = Expect->new;
33 0         0 $vm{$name}->raw_pty(1);
34 0         0 $vm{$name}->log_stdout(0);
35 0         0 $vm{$name}->spawn($cmd);
36 0 0       0 $vm{$name}->expect(5, '# ') or get_logger->logdie("Error while starting VM $name: ". $vm{$name}->error);
37             }
38              
39             sub stopvms {
40 87     87 0 473 kill KILL => $_->pid for values %vm;
41 87         671 %vm = %pid = ();
42             }
43              
44             sub execlist_finish {
45 78     78 0 604 my ($vm, $kill) = @_;
46              
47 78 50       476 if ($vm{$vm}) {
48 0 0       0 warn "Cannot kill VM\n" if $kill;
49 0         0 $vm{$vm}->expect(5, '# ');
50             } else {
51 78 50       263 kill KILL => $pid{$vm} if $kill;
52 78         47825653 waitpid $pid{$vm}, 0;
53             }
54 78 50       863 return if $kill;
55              
56 78         571 my $er = "exec-result-$vm";
57 78 50       6133 die "gruntmaster-exec died\n" if -z $er;
58 0         0 my ($excode, $exmsg) = read_file $er;
59 0         0 unlink $er;
60 0         0 chomp ($excode, $exmsg); ## no critic (ProhibitParensWithBuiltins)
61 0         0 get_logger->trace("Exec result from $vm: $excode $exmsg");
62 0 0       0 die [$excode, $exmsg] if $excode; ## no critic (RequireCarping)
63             }
64              
65             sub execlist {
66 90     90 0 409 my ($vm, @args) = @_;
67 90         237 my $er = "exec-result-$vm";
68 90 50       384 if ($vm{$vm}) {
69 0         0 my $cmd = ">$er " . shell_quote 'gruntmaster-exec', @args;
70 0         0 get_logger->trace("Running in VM $vm: $cmd");
71 0         0 $vm{$vm}->send($cmd, "\n");
72             } else {
73 90   50     152153 $pid{$vm} = fork // die "Cannot fork\n";
74 90 100       8553 unless ($pid{$vm}) {
75 12 50       4958 open STDOUT, '>', $er or die "Cannot open $er\n";
76 12         1191 get_logger->trace("Running: gruntmaster-exec @args");
77 12         0 exec 'gruntmaster-exec', @args;
78             }
79             }
80             }
81              
82             sub mkrun{
83 90     90 0 177 my $format = shift;
84             sub{
85 0     0   0 local *__ANON__ = 'mkrun_runner';
86 0         0 my ($name, %args) = @_;
87 0         0 get_logger->trace("Running $name...");
88 0         0 my $basename = fileparse $name, qr/[.][^.]*/s;
89 0         0 my @args = ('--sudo');
90 0 0       0 push @args, '--keep-stderr' if $ENV{TEST_VERBOSE};
91 0 0       0 push @args, '--timeout', $args{timeout} if $args{timeout};
92 0 0       0 push @args, '--mlimit', $args{mlimit} if $args{mlimit};
93 0 0       0 push @args, '--olimit', $args{olimit} if $args{olimit};
94 0 0       0 my @fds = exists $args{fds} ? @{$args{fds}} : ();
  0         0  
95 0         0 my $it = natatime 2, @fds;
96 0         0 while (my ($fd, $file) = $it->()) {
97 0         0 push @args, "--fd=$fd $file";
98             }
99 0         0 execlist $basename, @args, '--', "./$basename", @{$args{args}};
  0         0  
100             execlist_finish $basename unless $args{nonblocking}
101 0 0       0 }
102 90         740 }
103              
104             sub prepare{
105 90     90 0 299 my ($name, $format) = @_;
106 90         453 get_logger->trace("Preparing file $name...");
107              
108             try {
109 90     90   4719 execlist prog => '--fd=1 >>errors', '--fd=2 >>errors', 'gruntmaster-compile', $format, $name;
110 78         1849 execlist_finish 'prog';
111             } catch {
112 78     78   8214 my $exmsg = $_->[1];
113 0         0 die "Compile error ($exmsg)\n"
114             } finally {
115 78     78   2648 $Gruntmaster::Daemon::errors .= read_file 'errors';
116 0 0       0 $Gruntmaster::Daemon::errors .= "\n" if -s 'errors';
117 0         0 unlink 'errors';
118 90         10088 };
119             }
120              
121             sub prepare_files{
122 99     99 1 203 my $meta = shift;
123 99 100       613 if ($meta->{runner} eq 'Interactive') {
124 3         12 runvm ver => '-serial unix:vm.sock,nowait,server';
125 3         9 runvm prog => '-serial unix:vm.sock,nowait';
126             } else {
127 96         263 runvm $_ for keys %{$meta->{files}};
  96         672  
128             }
129              
130 99         327 for my $file (values %{$meta->{files}}) {
  99         357  
131 90         204 my ($format, $name, $content) = @{$file}{qw/format name content/};
  90         418  
132              
133 90         411 $file->{run} = mkrun($format);
134 90         747 write_file $name, $content;
135 90 50       269812 if ($ENV{GRUNTMASTER_CCACHE}) {
136 0         0 my $key = lc sha256_hex($content) . '-' . $format;
137 0         0 my $cachefn = "$ENV{GRUNTMASTER_CCACHE}/$key";
138 0         0 my $exefn = fileparse $name, qr/[.][^.]*/s;
139 0 0       0 if (cp $cachefn, $exefn) {
140 0         0 get_logger->trace("File $name found in compilation cache")
141             } else {
142 0         0 prepare $name, $format;
143 0         0 cp $exefn, $cachefn
144             }
145             } else {
146 90         299 prepare $name, $format
147             }
148             }
149             }
150              
151             1;
152             __END__