Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(672)

Side by Side Diff: third_party/dpkg-dev/scripts/Dpkg/Control/HashCore.pm

Issue 2411423002: Linux build: Use sysroot when calculating dependencies (Closed)
Patch Set: Update expected_deps Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright © 2007-2009 Raphaël Hertzog <hertzog@debian.org>
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 <https://www.gnu.org/licenses/>.
15
16 package Dpkg::Control::HashCore;
17
18 use strict;
19 use warnings;
20
21 our $VERSION = '1.01';
22
23 use Dpkg::Gettext;
24 use Dpkg::ErrorHandling;
25 use Dpkg::Control::FieldsCore;
26
27 # This module cannot use Dpkg::Control::Fields, because that one makes use
28 # of Dpkg::Vendor which at the same time uses this module, which would turn
29 # into a compilation error. We can use Dpkg::Control::FieldsCore instead.
30
31 use parent qw(Dpkg::Interface::Storable);
32
33 use overload
34 '%{}' => sub { ${$_[0]}->{fields} },
35 'eq' => sub { "$_[0]" eq "$_[1]" };
36
37 =encoding utf8
38
39 =head1 NAME
40
41 Dpkg::Control::HashCore - parse and manipulate a block of RFC822-like fields
42
43 =head1 DESCRIPTION
44
45 The Dpkg::Control::Hash object is a hash-like representation of a set of
46 RFC822-like fields. The fields names are case insensitive and are always
47 capitalized the same when output (see field_capitalize function in
48 Dpkg::Control::Fields).
49 The order in which fields have been set is remembered and is used
50 to be able to dump back the same content. The output order can also be
51 overridden if needed.
52
53 You can store arbitrary values in the hash, they will always be properly
54 escaped in the output to conform to the syntax of control files. This is
55 relevant mainly for multilines values: while the first line is always output
56 unchanged directly after the field name, supplementary lines are
57 modified. Empty lines and lines containing only dots are prefixed with
58 " ." (space + dot) while other lines are prefixed with a single space.
59
60 During parsing, trailing spaces are stripped on all lines while leading
61 spaces are stripped only on the first line of each field.
62
63 =head1 FUNCTIONS
64
65 =over 4
66
67 =item my $c = Dpkg::Control::Hash->new(%opts)
68
69 Creates a new object with the indicated options. Supported options
70 are:
71
72 =over 8
73
74 =item allow_pgp
75
76 Configures the parser to accept PGP signatures around the control
77 information. Value can be 0 (default) or 1.
78
79 =item allow_duplicate
80
81 Configures the parser to allow duplicate fields in the control
82 information. Value can be 0 (default) or 1.
83
84 =item drop_empty
85
86 Defines if empty fields are dropped during the output. Value can be 0
87 (default) or 1.
88
89 =item name
90
91 The user friendly name of the information stored in the object. It might
92 be used in some error messages or warnings. A default name might be set
93 depending on the type.
94
95 =back
96
97 =cut
98
99 sub new {
100 my ($this, %opts) = @_;
101 my $class = ref($this) || $this;
102
103 # Object is a scalar reference and not a hash ref to avoid
104 # infinite recursion due to overloading hash-derefencing
105 my $self = \{
106 in_order => [],
107 out_order => [],
108 is_pgp_signed => 0,
109 allow_pgp => 0,
110 allow_duplicate => 0,
111 drop_empty => 0,
112 };
113 bless $self, $class;
114
115 $$self->{fields} = Dpkg::Control::HashCore::Tie->new($self);
116
117 # Options set by the user override default values
118 $$self->{$_} = $opts{$_} foreach keys %opts;
119
120 return $self;
121 }
122
123 # There is naturally a circular reference between the tied hash and its
124 # containing object. Happily, the extra layer of scalar reference can
125 # be used to detect the destruction of the object and break the loop so
126 # that everything gets garbage-collected.
127
128 sub DESTROY {
129 my ($self) = @_;
130 delete $$self->{fields};
131 }
132
133 =item $c->set_options($option, %opts)
134
135 Changes the value of one or more options.
136
137 =cut
138
139 sub set_options {
140 my ($self, %opts) = @_;
141 $$self->{$_} = $opts{$_} foreach keys %opts;
142 }
143
144 =item my $value = $c->get_option($option)
145
146 Returns the value of the corresponding option.
147
148 =cut
149
150 sub get_option {
151 my ($self, $k) = @_;
152 return $$self->{$k};
153 }
154
155 =item $c->load($file)
156
157 Parse the content of $file. Exits in case of errors. Returns true if some
158 fields have been parsed.
159
160 =item $c->parse_error($file, $fmt, ...)
161
162 Prints an error message and dies on syntax parse errors.
163
164 =cut
165
166 sub parse_error {
167 my ($self, $file, $msg) = (shift, shift, shift);
168
169 $msg = sprintf($msg, @_) if (@_);
170 error(_g('syntax error in %s at line %d: %s'), $file, $., $msg);
171 }
172
173 =item $c->parse($fh, $description)
174
175 Parse a control file from the given filehandle. Exits in case of errors.
176 $description is used to describe the filehandle, ideally it's a filename
177 or a description of where the data comes from. It's used in error
178 messages. Returns true if some fields have been parsed.
179
180 =cut
181
182 sub parse {
183 my ($self, $fh, $desc) = @_;
184
185 my $paraborder = 1;
186 my $parabody = 0;
187 my $cf; # Current field
188 my $expect_pgp_sig = 0;
189
190 while (<$fh>) {
191 chomp;
192 next if m/^\s*$/ and $paraborder;
193 next if (m/^#/);
194 $paraborder = 0;
195 if (m/^(\S+?)\s*:\s*(.*)$/) {
196 $parabody = 1;
197 if ($1 =~ m/^-/) {
198 $self->parse_error($desc, _g('field cannot start with a hyphen') );
199 }
200 my ($name, $value) = ($1, $2);
201 if (exists $self->{$name}) {
202 unless ($$self->{allow_duplicate}) {
203 $self->parse_error($desc, _g('duplicate field %s found'), $n ame);
204 }
205 }
206 $value =~ s/\s*$//;
207 $self->{$name} = $value;
208 $cf = $name;
209 } elsif (m/^\s(\s*\S.*)$/) {
210 my $line = $1;
211 unless (defined($cf)) {
212 $self->parse_error($desc, _g('continued value line not in field' ));
213 }
214 if ($line =~ /^\.+$/) {
215 $line = substr $line, 1;
216 }
217 $line =~ s/\s*$//;
218 $self->{$cf} .= "\n$line";
219 } elsif (m/^-----BEGIN PGP SIGNED MESSAGE-----[\r\t ]*$/) {
220 $expect_pgp_sig = 1;
221 if ($$self->{allow_pgp} and not $parabody) {
222 # Skip PGP headers
223 while (<$fh>) {
224 last if m/^\s*$/;
225 }
226 } else {
227 $self->parse_error($desc, _g('PGP signature not allowed here'));
228 }
229 } elsif (m/^\s*$/ ||
230 ($expect_pgp_sig && m/^-----BEGIN PGP SIGNATURE-----[\r\t ]*$/) ) {
231 if ($expect_pgp_sig) {
232 # Skip empty lines
233 $_ = <$fh> while defined($_) && $_ =~ /^\s*$/;
234 unless (length $_) {
235 $self->parse_error($desc, _g('expected PGP signature, ' .
236 'found EOF after blank line'));
237 }
238 chomp;
239 unless (m/^-----BEGIN PGP SIGNATURE-----[\r\t ]*$/) {
240 $self->parse_error($desc, _g('expected PGP signature, ' .
241 "found something else \`%s'"), $_);
242 }
243 # Skip PGP signature
244 while (<$fh>) {
245 chomp;
246 last if m/^-----END PGP SIGNATURE-----[\r\t ]*$/;
247 }
248 unless (defined($_)) {
249 $self->parse_error($desc, _g('unfinished PGP signature'));
250 }
251 # This does not mean the signature is correct, that needs to
252 # be verified by gnupg.
253 $$self->{is_pgp_signed} = 1;
254 }
255 last; # Finished parsing one block
256 } else {
257 $self->parse_error($desc,
258 _g('line with unknown format (not field-colon-val ue)'));
259 }
260 }
261
262 if ($expect_pgp_sig and not $$self->{is_pgp_signed}) {
263 $self->parse_error($desc, _g('unfinished PGP signature'));
264 }
265
266 return defined($cf);
267 }
268
269 =item $c->find_custom_field($name)
270
271 Scan the fields and look for a user specific field whose name matches the
272 following regex: /X[SBC]*-$name/i. Return the name of the field found or
273 undef if nothing has been found.
274
275 =cut
276
277 sub find_custom_field {
278 my ($self, $name) = @_;
279 foreach my $key (keys %$self) {
280 return $key if $key =~ /^X[SBC]*-\Q$name\E$/i;
281 }
282 return;
283 }
284
285 =item $c->get_custom_field($name)
286
287 Identify a user field and retrieve its value.
288
289 =cut
290
291 sub get_custom_field {
292 my ($self, $name) = @_;
293 my $key = $self->find_custom_field($name);
294 return $self->{$key} if defined $key;
295 return;
296 }
297
298 =item $c->save($filename)
299
300 Write the string representation of the control information to a
301 file.
302
303 =item my $str = $c->output()
304
305 =item "$c"
306
307 Get a string representation of the control information. The fields
308 are sorted in the order in which they have been read or set except
309 if the order has been overridden with set_output_order().
310
311 =item $c->output($fh)
312
313 Print the string representation of the control information to a
314 filehandle.
315
316 =cut
317
318 sub output {
319 my ($self, $fh) = @_;
320 my $str = '';
321 my @keys;
322 if (@{$$self->{out_order}}) {
323 my $i = 1;
324 my $imp = {};
325 $imp->{$_} = $i++ foreach @{$$self->{out_order}};
326 @keys = sort {
327 if (defined $imp->{$a} && defined $imp->{$b}) {
328 $imp->{$a} <=> $imp->{$b};
329 } elsif (defined($imp->{$a})) {
330 -1;
331 } elsif (defined($imp->{$b})) {
332 1;
333 } else {
334 $a cmp $b;
335 }
336 } keys %$self;
337 } else {
338 @keys = @{$$self->{in_order}};
339 }
340
341 foreach my $key (@keys) {
342 if (exists $self->{$key}) {
343 my $value = $self->{$key};
344 # Skip whitespace-only fields
345 next if $$self->{drop_empty} and $value !~ m/\S/;
346 # Escape data to follow control file syntax
347 my @lines = split(/\n/, $value);
348 $value = (scalar @lines) ? shift @lines : '';
349 foreach (@lines) {
350 s/\s+$//;
351 if (/^$/ or /^\.+$/) {
352 $value .= "\n .$_";
353 } else {
354 $value .= "\n $_";
355 }
356 }
357 # Print it out
358 if ($fh) {
359 print { $fh } "$key: $value\n"
360 or syserr(_g('write error on control data'));
361 }
362 $str .= "$key: $value\n" if defined wantarray;
363 }
364 }
365 return $str;
366 }
367
368 =item $c->set_output_order(@fields)
369
370 Define the order in which fields will be displayed in the output() method.
371
372 =cut
373
374 sub set_output_order {
375 my ($self, @fields) = @_;
376
377 $$self->{out_order} = [@fields];
378 }
379
380 =item $c->apply_substvars($substvars)
381
382 Update all fields by replacing the variables references with
383 the corresponding value stored in the Dpkg::Substvars object.
384
385 =cut
386
387 sub apply_substvars {
388 my ($self, $substvars, %opts) = @_;
389
390 # Add substvars to refer to other fields
391 foreach my $f (keys %$self) {
392 $substvars->set_as_used("F:$f", $self->{$f});
393 }
394
395 foreach my $f (keys %$self) {
396 my $v = $substvars->substvars($self->{$f}, %opts);
397 if ($v ne $self->{$f}) {
398 my $sep;
399
400 $sep = field_get_sep_type($f);
401
402 # If we replaced stuff, ensure we're not breaking
403 # a dependency field by introducing empty lines, or multiple
404 # commas
405
406 if ($sep & (FIELD_SEP_COMMA | FIELD_SEP_LINE)) {
407 # Drop empty/whitespace-only lines
408 $v =~ s/\n[ \t]*(\n|$)/$1/;
409 }
410
411 if ($sep & FIELD_SEP_COMMA) {
412 $v =~ s/,[\s,]*,/,/g;
413 $v =~ s/^\s*,\s*//;
414 $v =~ s/\s*,\s*$//;
415 }
416 }
417 $v =~ s/\$\{\}/\$/g; # XXX: what for?
418
419 $self->{$f} = $v;
420 }
421 }
422
423 package Dpkg::Control::HashCore::Tie;
424
425 # This object is used to tie a hash. It implements hash-like functions by
426 # normalizing the name of fields received in keys (using
427 # Dpkg::Control::Fields::field_capitalize). It also stores the order in
428 # which fields have been added in order to be able to dump them in the
429 # same order. But the order information is stored in a parent object of
430 # type Dpkg::Control.
431
432 use Dpkg::Checksums;
433 use Dpkg::Control::FieldsCore;
434
435 use Carp;
436 use Tie::Hash;
437 use parent -norequire, qw(Tie::ExtraHash);
438
439 # $self->[0] is the real hash
440 # $self->[1] is a reference to the hash contained by the parent object.
441 # This reference bypasses the top-level scalar reference of a
442 # Dpkg::Control::Hash, hence ensuring that that reference gets DESTROYed
443 # properly.
444
445 # Dpkg::Control::Hash->new($parent)
446 #
447 # Return a reference to a tied hash implementing storage of simple
448 # "field: value" mapping as used in many Debian-specific files.
449
450 sub new {
451 my $class = shift;
452 my $hash = {};
453 tie %{$hash}, $class, @_;
454 return $hash;
455 }
456
457 sub TIEHASH {
458 my ($class, $parent) = @_;
459 croak 'parent object must be Dpkg::Control::Hash'
460 if not $parent->isa('Dpkg::Control::HashCore') and
461 not $parent->isa('Dpkg::Control::Hash');
462 return bless [ {}, $$parent ], $class;
463 }
464
465 sub FETCH {
466 my ($self, $key) = @_;
467 $key = lc($key);
468 return $self->[0]->{$key} if exists $self->[0]->{$key};
469 return;
470 }
471
472 sub STORE {
473 my ($self, $key, $value) = @_;
474 my $parent = $self->[1];
475 $key = lc($key);
476 if (not exists $self->[0]->{$key}) {
477 push @{$parent->{in_order}}, field_capitalize($key);
478 }
479 $self->[0]->{$key} = $value;
480 }
481
482 sub EXISTS {
483 my ($self, $key) = @_;
484 $key = lc($key);
485 return exists $self->[0]->{$key};
486 }
487
488 sub DELETE {
489 my ($self, $key) = @_;
490 my $parent = $self->[1];
491 my $in_order = $parent->{in_order};
492 $key = lc($key);
493 if (exists $self->[0]->{$key}) {
494 delete $self->[0]->{$key};
495 @$in_order = grep { lc($_) ne $key } @$in_order;
496 return 1;
497 } else {
498 return 0;
499 }
500 }
501
502 sub FIRSTKEY {
503 my $self = shift;
504 my $parent = $self->[1];
505 foreach (@{$parent->{in_order}}) {
506 return $_ if exists $self->[0]->{lc($_)};
507 }
508 }
509
510 sub NEXTKEY {
511 my ($self, $last) = @_;
512 my $parent = $self->[1];
513 my $found = 0;
514 foreach (@{$parent->{in_order}}) {
515 if ($found) {
516 return $_ if exists $self->[0]->{lc($_)};
517 } else {
518 $found = 1 if $_ eq $last;
519 }
520 }
521 return;
522 }
523
524 1;
525
526 =back
527
528 =head1 CHANGES
529
530 =head2 Version 1.01
531
532 New method: parse_error().
533
534 =head1 AUTHOR
535
536 Raphaël Hertzog <hertzog@debian.org>.
537
538 =cut
539
540 1;
OLDNEW
« no previous file with comments | « third_party/dpkg-dev/scripts/Dpkg/Control/Hash.pm ('k') | third_party/dpkg-dev/scripts/Dpkg/Control/Info.pm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698