File Coverage

blib/lib/Dpkg/Substvars.pm
Criterion Covered Total %
statement 141 146 96.5
branch 22 30 73.3
condition 19 26 73.0
subroutine 30 30 100.0
pod 18 18 100.0
total 230 250 92.0


line stmt bran cond sub pod time code
1             # Copyright © 2006-2009, 2012-2015 Guillem Jover
2             # Copyright © 2007-2010 Raphaël Hertzog
3             #
4             # This program is free software; you can redistribute it and/or modify
5             # it under the terms of the GNU General Public License as published by
6             # the Free Software Foundation; either version 2 of the License, or
7             # (at your option) any later version.
8             #
9             # This program is distributed in the hope that it will be useful,
10             # but WITHOUT ANY WARRANTY; without even the implied warranty of
11             # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12             # GNU General Public License for more details.
13             #
14             # You should have received a copy of the GNU General Public License
15             # along with this program. If not, see .
16              
17             package Dpkg::Substvars;
18              
19 1     1   799 use strict;
  1         16  
  1         30  
20 1     1   6 use warnings;
  1         1  
  1         38  
21              
22             our $VERSION = '2.00';
23              
24 1     1   6 use Dpkg ();
  1         1  
  1         17  
25 1     1   5 use Dpkg::Arch qw(get_host_arch);
  1         1  
  1         45  
26 1     1   511 use Dpkg::Vendor qw(get_current_vendor);
  1         4  
  1         81  
27 1     1   616 use Dpkg::Version;
  1         3  
  1         79  
28 1     1   8 use Dpkg::ErrorHandling;
  1         2  
  1         63  
29 1     1   6 use Dpkg::Gettext;
  1         2  
  1         52  
30              
31 1     1   6 use parent qw(Dpkg::Interface::Storable);
  1         2  
  1         6  
32              
33             my $maxsubsts = 50;
34              
35             =encoding utf8
36              
37             =head1 NAME
38              
39             Dpkg::Substvars - handle variable substitution in strings
40              
41             =head1 DESCRIPTION
42              
43             It provides a class which is able to substitute variables in strings.
44              
45             =cut
46              
47             use constant {
48 1         1991 SUBSTVAR_ATTR_USED => 1,
49             SUBSTVAR_ATTR_AUTO => 2,
50             SUBSTVAR_ATTR_AGED => 4,
51 1     1   86 };
  1         2  
52              
53             =head1 METHODS
54              
55             =over 8
56              
57             =item $s = Dpkg::Substvars->new($file)
58              
59             Create a new object that can do substitutions. By default it contains
60             generic substitutions like ${Newline}, ${Space}, ${Tab}, ${dpkg:Version}
61             and ${dpkg:Upstream-Version}.
62              
63             Additional substitutions will be read from the $file passed as parameter.
64              
65             It keeps track of which substitutions were actually used (only counting
66             substvars(), not get()), and warns about unused substvars when asked to. The
67             substitutions that are always present are not included in these warnings.
68              
69             =cut
70              
71             sub new {
72 4     4 1 18 my ($this, $arg) = @_;
73 4   33     35 my $class = ref($this) || $this;
74 4         36 my $self = {
75             vars => {
76             'Newline' => "\n",
77             'Space' => ' ',
78             'Tab' => "\t",
79             'dpkg:Version' => $Dpkg::PROGVERSION,
80             'dpkg:Upstream-Version' => $Dpkg::PROGVERSION,
81             },
82             attr => {},
83             msg_prefix => '',
84             };
85 4         14 $self->{vars}{'dpkg:Upstream-Version'} =~ s/-[^-]+$//;
86 4         9 bless $self, $class;
87              
88 4         8 my $attr = SUBSTVAR_ATTR_USED | SUBSTVAR_ATTR_AUTO;
89 4         4 $self->{attr}{$_} = $attr foreach keys %{$self->{vars}};
  4         56  
90 4 100       25 if ($arg) {
91 3 50       67 $self->load($arg) if -e $arg;
92             }
93 4         46 return $self;
94             }
95              
96             =item $s->set($key, $value)
97              
98             Add/replace a substitution.
99              
100             =cut
101              
102             sub set {
103 48     48 1 138 my ($self, $key, $value, $attr) = @_;
104              
105 48   100     150 $attr //= 0;
106              
107 48         116 $self->{vars}{$key} = $value;
108 48         173 $self->{attr}{$key} = $attr;
109             }
110              
111             =item $s->set_as_used($key, $value)
112              
113             Add/replace a substitution and mark it as used (no warnings will be produced
114             even if unused).
115              
116             =cut
117              
118             sub set_as_used {
119 1     1 1 3 my ($self, $key, $value) = @_;
120              
121 1         3 $self->set($key, $value, SUBSTVAR_ATTR_USED);
122             }
123              
124             =item $s->set_as_auto($key, $value)
125              
126             Add/replace a substitution and mark it as used and automatic (no warnings
127             will be produced even if unused).
128              
129             =cut
130              
131             sub set_as_auto {
132 4     4 1 10 my ($self, $key, $value) = @_;
133              
134 4         8 $self->set($key, $value, SUBSTVAR_ATTR_USED | SUBSTVAR_ATTR_AUTO);
135             }
136              
137             =item $s->get($key)
138              
139             Get the value of a given substitution.
140              
141             =cut
142              
143             sub get {
144 39     39 1 1933 my ($self, $key) = @_;
145 39         208 return $self->{vars}{$key};
146             }
147              
148             =item $s->delete($key)
149              
150             Remove a given substitution.
151              
152             =cut
153              
154             sub delete {
155 23     23 1 135 my ($self, $key) = @_;
156 23         44 delete $self->{attr}{$key};
157 23         54 return delete $self->{vars}{$key};
158             }
159              
160             =item $s->mark_as_used($key)
161              
162             Prevents warnings about a unused substitution, for example if it is provided by
163             default.
164              
165             =cut
166              
167             sub mark_as_used {
168 5     5 1 46 my ($self, $key) = @_;
169 5         17 $self->{attr}{$key} |= SUBSTVAR_ATTR_USED;
170             }
171              
172             =item $s->parse($fh, $desc)
173              
174             Add new substitutions read from the filehandle. $desc is used to identify
175             the filehandle in error messages.
176              
177             Returns the number of substitutions that have been parsed with success.
178              
179             =cut
180              
181             sub parse {
182 4     4 1 10 my ($self, $fh, $varlistfile) = @_;
183 4         6 my $count = 0;
184 4         6 local $_;
185              
186 4         13 binmode($fh);
187 4         51 while (<$fh>) {
188 30 100 100     887 next if m/^\s*\#/ || !m/\S/;
189 24         133 s/\s*\n$//;
190 24 50       91 if (! m/^(\w[-:0-9A-Za-z]*)\=(.*)$/) {
191 0         0 error(g_('bad line in substvars file %s at line %d'),
192             $varlistfile, $.);
193             }
194 24         72 $self->set($1, $2);
195 24         67 $count++;
196             }
197              
198 4         140 return $count
199             }
200              
201             =item $s->load($file)
202              
203             Add new substitutions read from $file.
204              
205             =item $s->set_version_substvars($sourceversion, $binaryversion)
206              
207             Defines ${binary:Version}, ${source:Version} and
208             ${source:Upstream-Version} based on the given version strings.
209              
210             These will never be warned about when unused.
211              
212             =cut
213              
214             sub set_version_substvars {
215 3     3 1 383 my ($self, $sourceversion, $binaryversion) = @_;
216              
217             # Handle old function signature taking only one argument.
218 3   66     15 $binaryversion //= $sourceversion;
219              
220             # For backwards compatibility on binNMUs that do not use the Binary-Only
221             # field on the changelog, always fix up the source version.
222 3         18 $sourceversion =~ s/\+b[0-9]+$//;
223              
224 3         27 my $vs = Dpkg::Version->new($sourceversion, check => 1);
225 3 50       8 if (not defined $vs) {
226 0         0 error(g_('invalid source version %s'), $sourceversion);
227             }
228 3         13 my $upstreamversion = $vs->as_string(omit_revision => 1);
229              
230 3         5 my $attr = SUBSTVAR_ATTR_USED | SUBSTVAR_ATTR_AUTO;
231              
232 3         8 $self->set('binary:Version', $binaryversion, $attr);
233 3         7 $self->set('source:Version', $sourceversion, $attr);
234 3         7 $self->set('source:Upstream-Version', $upstreamversion, $attr);
235              
236             # XXX: Source-Version is now obsolete, remove in 1.19.x.
237 3         10 $self->set('Source-Version', $binaryversion, $attr | SUBSTVAR_ATTR_AGED);
238             }
239              
240             =item $s->set_arch_substvars()
241              
242             Defines architecture variables: ${Arch}.
243              
244             This will never be warned about when unused.
245              
246             =cut
247              
248             sub set_arch_substvars {
249 1     1 1 2 my $self = shift;
250              
251 1         2 my $attr = SUBSTVAR_ATTR_USED | SUBSTVAR_ATTR_AUTO;
252              
253 1         5 $self->set('Arch', get_host_arch(), $attr);
254             }
255              
256             =item $s->set_vendor_substvars()
257              
258             Defines vendor variables: ${vendor:Name} and ${vendor:Id}.
259              
260             These will never be warned about when unused.
261              
262             =cut
263              
264             sub set_vendor_substvars {
265 1     1 1 3 my ($self, $desc) = @_;
266              
267 1         8 my $attr = SUBSTVAR_ATTR_USED | SUBSTVAR_ATTR_AUTO;
268              
269 1         40 my $vendor = get_current_vendor();
270 1         5 $self->set('vendor:Name', $vendor, $attr);
271 1         4 $self->set('vendor:Id', lc $vendor, $attr);
272             }
273              
274             =item $s->set_desc_substvars()
275              
276             Defines source description variables: ${source:Synopsis} and
277             ${source:Extended-Description}.
278              
279             These will never be warned about when unused.
280              
281             =cut
282              
283             sub set_desc_substvars {
284 1     1 1 365 my ($self, $desc) = @_;
285              
286 1         5 my ($synopsis, $extended) = split /\n/, $desc, 2;
287              
288 1         2 my $attr = SUBSTVAR_ATTR_USED | SUBSTVAR_ATTR_AUTO;
289              
290 1         4 $self->set('source:Synopsis', $synopsis, $attr);
291 1         3 $self->set('source:Extended-Description', $extended, $attr);
292             }
293              
294             =item $s->set_field_substvars($ctrl, $prefix)
295              
296             Defines field variables from a Dpkg::Control object, with each variable
297             having the form "${$prefix:$field}".
298              
299             They will never be warned about when unused.
300              
301             =cut
302              
303             sub set_field_substvars {
304 1     1 1 367 my ($self, $ctrl, $prefix) = @_;
305              
306 1         4 foreach my $field (keys %{$ctrl}) {
  1         9  
307 3         12 $self->set_as_auto("$prefix:$field", $ctrl->{$field});
308             }
309             }
310              
311             =item $newstring = $s->substvars($string)
312              
313             Substitutes variables in $string and return the result in $newstring.
314              
315             =cut
316              
317             sub substvars {
318 4     4 1 11 my ($self, $v, %opts) = @_;
319 4         9 my $lhs;
320             my $vn;
321 4         15 my $rhs = '';
322 4         6 my $count = 0;
323 4   66     24 $opts{msg_prefix} //= $self->{msg_prefix};
324 4   50     22 $opts{no_warn} //= 0;
325              
326 4         35 while ($v =~ m/^(.*?)\$\{([-:0-9a-z]+)\}(.*)$/si) {
327             # If we have consumed more from the leftover data, then
328             # reset the recursive counter.
329 5 100       19 $count = 0 if (length($3) < length($rhs));
330              
331 5 50       11 if ($count >= $maxsubsts) {
332             error($opts{msg_prefix} .
333 0         0 g_("too many substitutions - recursive ? - in '%s'"), $v);
334             }
335 5         11 $lhs = $1;
336 5         10 $vn = $2;
337 5         8 $rhs = $3;
338 5 100       16 if (defined($self->{vars}{$vn})) {
339 4         13 $v = $lhs . $self->{vars}{$vn} . $rhs;
340 4         14 $self->mark_as_used($vn);
341 4         5 $count++;
342              
343 4 50       24 if ($self->{attr}{$vn} & SUBSTVAR_ATTR_AGED) {
344             error($opts{msg_prefix} .
345 0         0 g_('obsolete substitution variable ${%s}'), $vn);
346             }
347             } else {
348             warning($opts{msg_prefix} .
349             g_('substitution variable ${%s} used, but is not defined'),
350 1 50       20 $vn) unless $opts{no_warn};
351 1         11 $v = $lhs . $rhs;
352             }
353             }
354 4         23 return $v;
355             }
356              
357             =item $s->warn_about_unused()
358              
359             Issues warning about any variables that were set, but not used.
360              
361             =cut
362              
363             sub warn_about_unused {
364 2     2 1 5 my ($self, %opts) = @_;
365 2   33     20 $opts{msg_prefix} //= $self->{msg_prefix};
366              
367 2         3 foreach my $vn (sort keys %{$self->{vars}}) {
  2         30  
368 43 100       91 next if $self->{attr}{$vn} & SUBSTVAR_ATTR_USED;
369             # Empty substitutions variables are ignored on the basis
370             # that they are not required in the current situation
371             # (example: debhelper's misc:Depends in many cases)
372 1 50       4 next if $self->{vars}{$vn} eq '';
373             warning($opts{msg_prefix} .
374 1         4 g_('substitution variable ${%s} unused, but is defined'),
375             $vn);
376             }
377             }
378              
379             =item $s->set_msg_prefix($prefix)
380              
381             Define a prefix displayed before all warnings/error messages output
382             by the module.
383              
384             =cut
385              
386             sub set_msg_prefix {
387 1     1 1 9 my ($self, $prefix) = @_;
388 1         6 $self->{msg_prefix} = $prefix;
389             }
390              
391             =item $s->filter(remove => $rmfunc)
392              
393             =item $s->filter(keep => $keepfun)
394              
395             Filter the substitution variables, either removing or keeping all those
396             that return true when $rmfunc->($key) or $keepfunc->($key) is called.
397              
398             =cut
399              
400             sub filter {
401 3     3 1 62 my ($self, %opts) = @_;
402              
403 3   100 12   16 my $remove = $opts{remove} // sub { 0 };
  12         27  
404 3   100 10   19 my $keep = $opts{keep} // sub { 1 };
  10         63  
405              
406 3         5 foreach my $vn (keys %{$self->{vars}}) {
  3         15  
407 36 100 100     80 $self->delete($vn) if $remove->($vn) or not $keep->($vn);
408             }
409             }
410              
411             =item "$s"
412              
413             Return a string representation of all substitutions variables except the
414             automatic ones.
415              
416             =item $str = $s->output([$fh])
417              
418             Return all substitutions variables except the automatic ones. If $fh
419             is passed print them into the filehandle.
420              
421             =cut
422              
423             sub output {
424 4     4 1 22 my ($self, $fh) = @_;
425 4         7 my $str = '';
426             # Store all non-automatic substitutions only
427 4         6 foreach my $vn (sort keys %{$self->{vars}}) {
  4         26  
428 24 100       52 next if $self->{attr}{$vn} & SUBSTVAR_ATTR_AUTO;
429 13         30 my $line = "$vn=" . $self->{vars}{$vn} . "\n";
430 13 50       24 print { $fh } $line if defined $fh;
  0         0  
431 13         24 $str .= $line;
432             }
433 4         21 return $str;
434             }
435              
436             =item $s->save($file)
437              
438             Store all substitutions variables except the automatic ones in the
439             indicated file.
440              
441             =back
442              
443             =head1 CHANGES
444              
445             =head2 Version 2.00 (dpkg 1.20.0)
446              
447             Remove method: $s->no_warn().
448              
449             New method: $s->set_vendor_substvars().
450              
451             =head2 Version 1.06 (dpkg 1.19.0)
452              
453             New method: $s->set_desc_substvars().
454              
455             =head2 Version 1.05 (dpkg 1.18.11)
456              
457             Obsolete substvar: Emit an error on Source-Version substvar usage.
458              
459             New return: $s->parse() now returns the number of parsed substvars.
460              
461             New method: $s->set_field_substvars().
462              
463             =head2 Version 1.04 (dpkg 1.18.0)
464              
465             New method: $s->filter().
466              
467             =head2 Version 1.03 (dpkg 1.17.11)
468              
469             New method: $s->set_as_auto().
470              
471             =head2 Version 1.02 (dpkg 1.16.5)
472              
473             New argument: Accept a $binaryversion in $s->set_version_substvars(),
474             passing a single argument is still supported.
475              
476             New method: $s->mark_as_used().
477              
478             Deprecated method: $s->no_warn(), use $s->mark_as_used() instead.
479              
480             =head2 Version 1.01 (dpkg 1.16.4)
481              
482             New method: $s->set_as_used().
483              
484             =head2 Version 1.00 (dpkg 1.15.6)
485              
486             Mark the module as public.
487              
488             =cut
489              
490             1;