File Coverage

blib/lib/Dpkg/BuildFlags.pm
Criterion Covered Total %
statement 74 145 51.0
branch 16 62 25.8
condition 1 6 16.6
subroutine 21 29 72.4
pod 22 22 100.0
total 134 264 50.7


line stmt bran cond sub pod time code
1             # Copyright © 2010-2011 Raphaël Hertzog
2             #
3             # This program is free software; you can redistribute it and/or modify
4             # it under the terms of the GNU General Public License as published by
5             # the Free Software Foundation; either version 2 of the License, or
6             # (at your option) any later version.
7             #
8             # This program is distributed in the hope that it will be useful,
9             # but WITHOUT ANY WARRANTY; without even the implied warranty of
10             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11             # GNU General Public License for more details.
12             #
13             # You should have received a copy of the GNU General Public License
14             # along with this program. If not, see .
15              
16             package Dpkg::BuildFlags;
17              
18 2     2   142767 use strict;
  2         24  
  2         61  
19 2     2   11 use warnings;
  2         3  
  2         75  
20              
21             our $VERSION = '1.04';
22              
23 2     2   838 use Dpkg ();
  2         6  
  2         45  
24 2     2   843 use Dpkg::Gettext;
  2         6  
  2         126  
25 2     2   901 use Dpkg::Build::Env;
  2         5  
  2         68  
26 2     2   900 use Dpkg::ErrorHandling;
  2         6  
  2         158  
27 2     2   856 use Dpkg::Vendor qw(run_vendor_hook);
  2         6  
  2         3811  
28              
29             =encoding utf8
30              
31             =head1 NAME
32              
33             Dpkg::BuildFlags - query build flags
34              
35             =head1 DESCRIPTION
36              
37             This class is used by dpkg-buildflags and can be used
38             to query the same information.
39              
40             =head1 METHODS
41              
42             =over 4
43              
44             =item $bf = Dpkg::BuildFlags->new()
45              
46             Create a new Dpkg::BuildFlags object. It will be initialized based
47             on the value of several configuration files and environment variables.
48              
49             =cut
50              
51             sub new {
52 3     3 1 213 my ($this, %opts) = @_;
53 3   33     22 my $class = ref($this) || $this;
54              
55 3         7 my $self = {
56             };
57 3         8 bless $self, $class;
58 3         15 $self->load_vendor_defaults();
59 3         36 return $self;
60             }
61              
62             =item $bf->load_vendor_defaults()
63              
64             Reset the flags stored to the default set provided by the vendor.
65              
66             =cut
67              
68             sub load_vendor_defaults {
69 3     3 1 9 my $self = shift;
70              
71 3         19 $self->{features} = {};
72             $self->{flags} = {
73 3         35 CPPFLAGS => '',
74             CFLAGS => '',
75             CXXFLAGS => '',
76             OBJCFLAGS => '',
77             OBJCXXFLAGS => '',
78             GCJFLAGS => '',
79             DFLAGS => '',
80             FFLAGS => '',
81             FCFLAGS => '',
82             LDFLAGS => '',
83             };
84             $self->{origin} = {
85 3         24 CPPFLAGS => 'vendor',
86             CFLAGS => 'vendor',
87             CXXFLAGS => 'vendor',
88             OBJCFLAGS => 'vendor',
89             OBJCXXFLAGS => 'vendor',
90             GCJFLAGS => 'vendor',
91             DFLAGS => 'vendor',
92             FFLAGS => 'vendor',
93             FCFLAGS => 'vendor',
94             LDFLAGS => 'vendor',
95             };
96             $self->{maintainer} = {
97 3         28 CPPFLAGS => 0,
98             CFLAGS => 0,
99             CXXFLAGS => 0,
100             OBJCFLAGS => 0,
101             OBJCXXFLAGS => 0,
102             GCJFLAGS => 0,
103             DFLAGS => 0,
104             FFLAGS => 0,
105             FCFLAGS => 0,
106             LDFLAGS => 0,
107             };
108             # The vendor hook will add the feature areas build flags.
109 3         19 run_vendor_hook('update-buildflags', $self);
110             }
111              
112             =item $bf->load_system_config()
113              
114             Update flags from the system configuration.
115              
116             =cut
117              
118             sub load_system_config {
119 0     0 1 0 my $self = shift;
120              
121 0         0 $self->update_from_conffile("$Dpkg::CONFDIR/buildflags.conf", 'system');
122             }
123              
124             =item $bf->load_user_config()
125              
126             Update flags from the user configuration.
127              
128             =cut
129              
130             sub load_user_config {
131 0     0 1 0 my $self = shift;
132              
133 0         0 my $confdir = $ENV{XDG_CONFIG_HOME};
134 0 0 0     0 $confdir ||= $ENV{HOME} . '/.config' if length $ENV{HOME};
135 0 0       0 if (length $confdir) {
136 0         0 $self->update_from_conffile("$confdir/dpkg/buildflags.conf", 'user');
137             }
138             }
139              
140             =item $bf->load_environment_config()
141              
142             Update flags based on user directives stored in the environment. See
143             dpkg-buildflags(1) for details.
144              
145             =cut
146              
147             sub load_environment_config {
148 0     0 1 0 my $self = shift;
149              
150 0         0 foreach my $flag (keys %{$self->{flags}}) {
  0         0  
151 0         0 my $envvar = 'DEB_' . $flag . '_SET';
152 0 0       0 if (Dpkg::Build::Env::has($envvar)) {
153 0         0 $self->set($flag, Dpkg::Build::Env::get($envvar), 'env');
154             }
155 0         0 $envvar = 'DEB_' . $flag . '_STRIP';
156 0 0       0 if (Dpkg::Build::Env::has($envvar)) {
157 0         0 $self->strip($flag, Dpkg::Build::Env::get($envvar), 'env');
158             }
159 0         0 $envvar = 'DEB_' . $flag . '_APPEND';
160 0 0       0 if (Dpkg::Build::Env::has($envvar)) {
161 0         0 $self->append($flag, Dpkg::Build::Env::get($envvar), 'env');
162             }
163 0         0 $envvar = 'DEB_' . $flag . '_PREPEND';
164 0 0       0 if (Dpkg::Build::Env::has($envvar)) {
165 0         0 $self->prepend($flag, Dpkg::Build::Env::get($envvar), 'env');
166             }
167             }
168             }
169              
170             =item $bf->load_maintainer_config()
171              
172             Update flags based on maintainer directives stored in the environment. See
173             dpkg-buildflags(1) for details.
174              
175             =cut
176              
177             sub load_maintainer_config {
178 0     0 1 0 my $self = shift;
179              
180 0         0 foreach my $flag (keys %{$self->{flags}}) {
  0         0  
181 0         0 my $envvar = 'DEB_' . $flag . '_MAINT_SET';
182 0 0       0 if (Dpkg::Build::Env::has($envvar)) {
183 0         0 $self->set($flag, Dpkg::Build::Env::get($envvar), undef, 1);
184             }
185 0         0 $envvar = 'DEB_' . $flag . '_MAINT_STRIP';
186 0 0       0 if (Dpkg::Build::Env::has($envvar)) {
187 0         0 $self->strip($flag, Dpkg::Build::Env::get($envvar), undef, 1);
188             }
189 0         0 $envvar = 'DEB_' . $flag . '_MAINT_APPEND';
190 0 0       0 if (Dpkg::Build::Env::has($envvar)) {
191 0         0 $self->append($flag, Dpkg::Build::Env::get($envvar), undef, 1);
192             }
193 0         0 $envvar = 'DEB_' . $flag . '_MAINT_PREPEND';
194 0 0       0 if (Dpkg::Build::Env::has($envvar)) {
195 0         0 $self->prepend($flag, Dpkg::Build::Env::get($envvar), undef, 1);
196             }
197             }
198             }
199              
200              
201             =item $bf->load_config()
202              
203             Call successively load_system_config(), load_user_config(),
204             load_environment_config() and load_maintainer_config() to update the
205             default build flags defined by the vendor.
206              
207             =cut
208              
209             sub load_config {
210 0     0 1 0 my $self = shift;
211              
212 0         0 $self->load_system_config();
213 0         0 $self->load_user_config();
214 0         0 $self->load_environment_config();
215 0         0 $self->load_maintainer_config();
216             }
217              
218             =item $bf->unset($flag)
219              
220             Unset the build flag $flag, so that it will not be known anymore.
221              
222             =cut
223              
224             sub unset {
225 0     0 1 0 my ($self, $flag) = @_;
226              
227 0         0 delete $self->{flags}->{$flag};
228 0         0 delete $self->{origin}->{$flag};
229 0         0 delete $self->{maintainer}->{$flag};
230             }
231              
232             =item $bf->set($flag, $value, $source, $maint)
233              
234             Update the build flag $flag with value $value and record its origin as
235             $source (if defined). Record it as maintainer modified if $maint is
236             defined and true.
237              
238             =cut
239              
240             sub set {
241 8     8 1 17 my ($self, $flag, $value, $src, $maint) = @_;
242 8         14 $self->{flags}->{$flag} = $value;
243 8 100       20 $self->{origin}->{$flag} = $src if defined $src;
244 8 50       21 $self->{maintainer}->{$flag} = $maint if $maint;
245             }
246              
247             =item $bf->set_feature($area, $feature, $enabled)
248              
249             Update the boolean state of whether a specific feature within a known
250             feature area has been enabled. The only currently known feature areas
251             are "future", "qa", "sanitize", "hardening" and "reproducible".
252              
253             =cut
254              
255             sub set_feature {
256 51     51 1 76 my ($self, $area, $feature, $enabled) = @_;
257 51         115 $self->{features}{$area}{$feature} = $enabled;
258             }
259              
260             =item $bf->strip($flag, $value, $source, $maint)
261              
262             Update the build flag $flag by stripping the flags listed in $value and
263             record its origin as $source (if defined). Record it as maintainer modified
264             if $maint is defined and true.
265              
266             =cut
267              
268             sub strip {
269 1     1 1 4 my ($self, $flag, $value, $src, $maint) = @_;
270 1         16 foreach my $tostrip (split(/\s+/, $value)) {
271 1 50       7 next unless length $tostrip;
272 1         58 $self->{flags}->{$flag} =~ s/(^|\s+)\Q$tostrip\E(\s+|$)/ /g;
273             }
274 1         6 $self->{flags}->{$flag} =~ s/^\s+//g;
275 1         10 $self->{flags}->{$flag} =~ s/\s+$//g;
276 1 50       7 $self->{origin}->{$flag} = $src if defined $src;
277 1 50       5 $self->{maintainer}->{$flag} = $maint if $maint;
278             }
279              
280             =item $bf->append($flag, $value, $source, $maint)
281              
282             Append the options listed in $value to the current value of the flag $flag.
283             Record its origin as $source (if defined). Record it as maintainer modified
284             if $maint is defined and true.
285              
286             =cut
287              
288             sub append {
289 88     88 1 164 my ($self, $flag, $value, $src, $maint) = @_;
290 88 100       168 if (length($self->{flags}->{$flag})) {
291 58         147 $self->{flags}->{$flag} .= " $value";
292             } else {
293 30         69 $self->{flags}->{$flag} = $value;
294             }
295 88 100       152 $self->{origin}->{$flag} = $src if defined $src;
296 88 50       177 $self->{maintainer}->{$flag} = $maint if $maint;
297             }
298              
299             =item $bf->prepend($flag, $value, $source, $maint)
300              
301             Prepend the options listed in $value to the current value of the flag $flag.
302             Record its origin as $source (if defined). Record it as maintainer modified
303             if $maint is defined and true.
304              
305             =cut
306              
307             sub prepend {
308 3     3 1 12 my ($self, $flag, $value, $src, $maint) = @_;
309 3 50       22 if (length($self->{flags}->{$flag})) {
310 3         17 $self->{flags}->{$flag} = "$value " . $self->{flags}->{$flag};
311             } else {
312 0         0 $self->{flags}->{$flag} = $value;
313             }
314 3 100       12 $self->{origin}->{$flag} = $src if defined $src;
315 3 100       16 $self->{maintainer}->{$flag} = $maint if $maint;
316             }
317              
318              
319             =item $bf->update_from_conffile($file, $source)
320              
321             Update the current build flags based on the configuration directives
322             contained in $file. See dpkg-buildflags(1) for the format of the directives.
323              
324             $source is the origin recorded for any build flag set or modified.
325              
326             =cut
327              
328             sub update_from_conffile {
329 0     0 1 0 my ($self, $file, $src) = @_;
330 0         0 local $_;
331              
332 0 0       0 return unless -e $file;
333 0 0       0 open(my $conf_fh, '<', $file) or syserr(g_('cannot read %s'), $file);
334 0         0 while (<$conf_fh>) {
335 0         0 chomp;
336 0 0       0 next if /^\s*#/; # Skip comments
337 0 0       0 next if /^\s*$/; # Skip empty lines
338 0 0       0 if (/^(append|prepend|set|strip)\s+(\S+)\s+(\S.*\S)\s*$/i) {
339 0         0 my ($op, $flag, $value) = ($1, $2, $3);
340 0 0       0 unless (exists $self->{flags}->{$flag}) {
341 0         0 warning(g_('line %d of %s mentions unknown flag %s'), $., $file, $flag);
342 0         0 $self->{flags}->{$flag} = '';
343             }
344 0 0       0 if (lc($op) eq 'set') {
    0          
    0          
    0          
345 0         0 $self->set($flag, $value, $src);
346             } elsif (lc($op) eq 'strip') {
347 0         0 $self->strip($flag, $value, $src);
348             } elsif (lc($op) eq 'append') {
349 0         0 $self->append($flag, $value, $src);
350             } elsif (lc($op) eq 'prepend') {
351 0         0 $self->prepend($flag, $value, $src);
352             }
353             } else {
354 0         0 warning(g_('line %d of %s is invalid, it has been ignored'), $., $file);
355             }
356             }
357 0         0 close($conf_fh);
358             }
359              
360             =item $bf->get($flag)
361              
362             Return the value associated to the flag. It might be undef if the
363             flag doesn't exist.
364              
365             =cut
366              
367             sub get {
368 26     26 1 4244 my ($self, $key) = @_;
369 26         84 return $self->{flags}{$key};
370             }
371              
372             =item $bf->get_feature_areas()
373              
374             Return the feature areas (i.e. the area values has_features will return
375             true for).
376              
377             =cut
378              
379             sub get_feature_areas {
380 1     1 1 2 my $self = shift;
381              
382 1         3 return keys %{$self->{features}};
  1         27  
383             }
384              
385             =item $bf->get_features($area)
386              
387             Return, for the given area, a hash with keys as feature names, and values
388             as booleans indicating whether the feature is enabled or not.
389              
390             =cut
391              
392             sub get_features {
393 5     5 1 12 my ($self, $area) = @_;
394 5         7 return %{$self->{features}{$area}};
  5         31  
395             }
396              
397             =item $bf->get_origin($flag)
398              
399             Return the origin associated to the flag. It might be undef if the
400             flag doesn't exist.
401              
402             =cut
403              
404             sub get_origin {
405 5     5 1 22 my ($self, $key) = @_;
406 5         28 return $self->{origin}{$key};
407             }
408              
409             =item $bf->is_maintainer_modified($flag)
410              
411             Return true if the flag is modified by the maintainer.
412              
413             =cut
414              
415             sub is_maintainer_modified {
416 4     4 1 16 my ($self, $key) = @_;
417 4         20 return $self->{maintainer}{$key};
418             }
419              
420             =item $bf->has_features($area)
421              
422             Returns true if the given area of features is known, and false otherwise.
423             The only currently recognized feature areas are "future", "qa", "sanitize",
424             "hardening" and "reproducible".
425              
426             =cut
427              
428             sub has_features {
429 5     5 1 2248 my ($self, $area) = @_;
430 5         25 return exists $self->{features}{$area};
431             }
432              
433             =item $bf->has($option)
434              
435             Returns a boolean indicating whether the flags exists in the object.
436              
437             =cut
438              
439             sub has {
440 1     1 1 21 my ($self, $key) = @_;
441 1         18 return exists $self->{flags}{$key};
442             }
443              
444             =item @flags = $bf->list()
445              
446             Returns the list of flags stored in the object.
447              
448             =cut
449              
450             sub list {
451 0     0 1   my $self = shift;
452 0           my @list = sort keys %{$self->{flags}};
  0            
453 0           return @list;
454             }
455              
456             =back
457              
458             =head1 CHANGES
459              
460             =head2 Version 1.04 (dpkg 1.20.0)
461              
462             New method: $bf->unset().
463              
464             =head2 Version 1.03 (dpkg 1.16.5)
465              
466             New method: $bf->get_feature_areas() to list possible values for
467             $bf->get_features.
468              
469             New method $bf->is_maintainer_modified() and new optional parameter to
470             $bf->set(), $bf->append(), $bf->prepend(), $bf->strip().
471              
472             =head2 Version 1.02 (dpkg 1.16.2)
473              
474             New methods: $bf->get_features(), $bf->has_features(), $bf->set_feature().
475              
476             =head2 Version 1.01 (dpkg 1.16.1)
477              
478             New method: $bf->prepend() very similar to append(). Implement support of
479             the prepend operation everywhere.
480              
481             New method: $bf->load_maintainer_config() that update the build flags
482             based on the package maintainer directives.
483              
484             =head2 Version 1.00 (dpkg 1.15.7)
485              
486             Mark the module as public.
487              
488             =cut
489              
490             1;