File Coverage

blib/lib/Arepa/BuilderFarm.pm
Criterion Covered Total %
statement 19 21 90.4
branch n/a
condition n/a
subroutine 7 7 100.0
pod n/a
total 26 28 92.8


line stmt bran cond sub pod time code
1             package Arepa::BuilderFarm;
2              
3 1     1   41270 use strict;
  1         2  
  1         32  
4 1     1   5 use warnings;
  1         2  
  1         29  
5              
6 1     1   4 use Carp qw(croak);
  1         3  
  1         45  
7 1     1   5 use Cwd;
  1         2  
  1         57  
8 1     1   1286 use File::Temp;
  1         26236  
  1         501  
9              
10 1     1   626 use Arepa::Config;
  1         3  
  1         34  
11 1     1   623 use Arepa::PackageDb;
  0            
  0            
12              
13             sub new {
14             my ($class, $config_path, %user_opts) = @_;
15              
16             my $config = Arepa::Config->new($config_path, %user_opts);
17             my $self = bless {
18             config_path => $config_path,
19             config => $config,
20             package_db => Arepa::PackageDb->new($config->get_key('package_db')),
21             last_build_log => undef,
22             }, $class;
23              
24             return $self;
25             }
26              
27             sub last_build_log {
28             my ($self) = @_;
29             return $self->{last_build_log};
30             }
31              
32             sub package_db {
33             my ($self) = @_;
34             return $self->{package_db};
35             }
36              
37             sub get_builder_config {
38             my ($self, $builder) = @_;
39             return $self->{config}->get_builder_config($builder);
40             }
41              
42             sub builder_type_module {
43             my ($self, $type) = @_;
44             $type =~ s/[^a-z0-9]//goi;
45             return "Arepa::Builder::" . ucfirst(lc($type));
46             }
47              
48             sub builder_module {
49             my ($self, $builder_name) = @_;
50             my %conf = $self->get_builder_config($builder_name);
51             my $module = $self->builder_type_module($conf{type});
52             eval "use $module;";
53             if ($@) {
54             croak "Couldn't load builder module '$module' for type '$conf{type}': $@";
55             }
56             return $module;
57             }
58              
59             sub builder {
60             my ($self, $builder_name) = @_;
61              
62             my $module_name = $self->builder_module($builder_name);
63             return $module_name->new($self->get_builder_config($builder_name));
64             }
65              
66             sub init_builders {
67             my ($self) = @_;
68              
69             foreach my $builder ($self->{config}->get_builders) {
70             $self->init_builder($builder);
71             }
72             }
73              
74             sub init_builder {
75             my ($self, $builder) = @_;
76              
77             my $module = $self->builder_module($builder);
78             $module->init($builder);
79             }
80              
81             sub uninit_builders {
82             my ($self) = @_;
83              
84             foreach my $builder ($self->{config}->get_builders) {
85             $self->uninit_builder($builder);
86             }
87             }
88              
89             sub uninit_builder {
90             my ($self, $builder) = @_;
91              
92             my $module = $self->builder_module($builder);
93             $module->uninit($builder);
94             }
95              
96             sub compile_package_from_dsc {
97             my ($self, $builder_name, $dsc_file, %user_opts) = @_;
98             my %opts = (output_dir => '.', %user_opts);
99              
100             my $builder = $self->builder_module($builder_name);
101             my $r = $builder->compile_package_from_dsc($dsc_file, %opts);
102             $self->{last_build_log} = $builder->last_build_log;
103             return $r;
104             }
105              
106             sub bin_nmu_id {
107             my ($self, $source_pkg_attrs, $builder) = @_;
108              
109             my %builder_cfg = $self->{config}->get_builder_config($builder);
110             my $r = scalar grep { $_ eq $source_pkg_attrs->{distribution} }
111             @{$builder_cfg{bin_nmu_for} || []};
112             if ($r) {
113             # NOTE: This bin_nmu_id thing is explicitly UNSUPPORTED. I'm not sure I
114             # want to go down that path, but it _may_ prove useful. So I'm leaving
115             # these two lines here while I make my mind. When/if I decide that it's
116             # a good idea, I'll add tests and document it.
117             if (exists $builder_cfg{bin_nmu_id}) {
118             return $builder_cfg{bin_nmu_id};
119             }
120             else {
121             my @builders = $self->{config}->get_builders;
122             for (my $i = 0; $i < scalar @builders; ++$i) {
123             return $i+1 if $builders[$i] eq $builder;
124             }
125             croak "Can't find builder '$builder'?!\n";
126             }
127             }
128             else {
129             return undef;
130             }
131             }
132              
133             sub compile_package_from_queue {
134             my ($self, $builder_name, $request_id, %user_opts) = @_;
135             my %opts = (output_dir => '.', %user_opts);
136              
137             my %request = $self->package_db->get_compilation_request_by_id($request_id);
138             $self->package_db->mark_compilation_started($request_id, $builder_name);
139              
140             my $builder = $self->builder($builder_name);
141             my %source_attrs = $self->package_db->get_source_package_by_id($request{source_package_id});
142             $opts{bin_nmu} = $self->bin_nmu_id(\%source_attrs, $builder_name);
143             my $r =
144             $builder->compile_package_from_repository($source_attrs{name},
145             $source_attrs{full_version},
146             %opts);
147             $self->{last_build_log} = $builder->last_build_log;
148              
149             # Save the build log
150             my $build_log_dir = $self->{config}->get_key('dir:build_logs');
151             my $build_log_path = File::Spec->catfile($build_log_dir,
152             $request_id);
153             open F, ">$build_log_path" or croak "Can't write in $build_log_path";
154             print F $self->{last_build_log};
155             close F;
156              
157             # Mark the compilation request appropriately
158             if ($r) {
159             $self->package_db->mark_compilation_completed($request_id);
160             }
161             else {
162             $self->package_db->mark_compilation_failed($request_id);
163             }
164             return $r;
165             }
166              
167             sub request_package_compilation {
168             my ($self, $source_id) = @_;
169              
170             foreach my $target ($self->get_compilation_targets($source_id)) {
171             my ($arch, $dist) = @$target;
172             $self->{package_db}->request_compilation($source_id, $arch, $dist);
173             }
174             }
175              
176             sub get_compilation_targets {
177             my ($self, $source_id) = @_;
178              
179             my %source_attrs = $self->{package_db}->get_source_package_by_id($source_id);
180             my @builders = $self->get_matching_builders($source_attrs{architecture},
181             $source_attrs{distribution});
182             return map {
183             my %builder_config = $self->{config}->get_builder_config($_);
184             $source_attrs{architecture} eq 'any' ?
185             [$builder_config{architecture},
186             $builder_config{distribution}] :
187             [$source_attrs {architecture},
188             $builder_config{distribution}];
189             } @builders;
190             }
191              
192             sub get_matching_builders {
193             my ($self, $arch, $distro) = @_;
194              
195             # Get the builder information once
196             my @builder_information = map { { $self->{config}->get_builder_config($_) } }
197             $self->{config}->get_builders;
198              
199             # Get builders that match *both*:
200             return map {
201             $_->{name}
202             }
203             # 1) the architecture in 'architecture' (or 'all' if applicable)
204             grep {
205             ($arch eq 'any' ||
206             $arch eq $_->{architecture} ||
207             ($arch eq 'all' && $_->{architecture_all}));
208             }
209             # 2) the $distro in *either* 'distribution' or
210             # 'distribution_aliases'
211             grep {
212             my @bdistros = ref($_->{distribution_aliases}) eq 'ARRAY' ?
213             @{$_->{distribution_aliases}} :
214             $_->{distribution_aliases};
215             my @binnmu_distros = ref($_->{bin_nmu_for}) eq 'ARRAY' ?
216             @{$_->{bin_nmu_for}} :
217             ($_->{bin_nmu_for} || ());
218              
219             $distro eq $_->{distribution} ||
220             grep({ $distro eq $_ } @bdistros) ||
221             grep({ $distro eq $_ } @binnmu_distros);
222             }
223             @builder_information;
224             }
225              
226             sub register_source_package {
227             my ($self, %source_attrs) = @_;
228              
229             my $pdb = $self->package_db;
230             my $source_id = $pdb->get_source_package_id($source_attrs{name},
231             $source_attrs{full_version});
232             if (!defined $source_id) {
233             $source_id = $pdb->insert_source_package(%source_attrs);
234             }
235             return $source_id;
236             }
237              
238             sub canonical_distribution {
239             my ($self, $arch, $distribution) = @_;
240              
241             my @builders = $self->get_matching_builders($arch, $distribution);
242             my $distro;
243             foreach my $b (@builders) {
244             my %builder_cfg = $self->{config}->get_builder_config($b);
245             if (grep { $_ eq $distribution }
246             @{$builder_cfg{distribution_aliases}},
247             $builder_cfg{distribution}) {
248             # There should be only one; if there's more than one, that's a
249             # problem
250             if ($distro) {
251             croak "There is more than one builder that " .
252             "specifies '$distribution' as alias. " .
253             "That's not correct! One of them " .
254             "should specify it as bin_nmu_for";
255             }
256             $distro = $builder_cfg{distribution};
257             }
258             }
259             return $distro;
260             }
261              
262             1;
263              
264             __END__