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