[libconfig-model-dpkg-perl] 02/11: handle comments in list parameter (wip: #849500)
dod at debian.org
dod at debian.org
Fri Jan 13 13:01:39 UTC 2017
This is an automated email from the git hooks/post-receive script.
dod pushed a commit to branch master
in repository libconfig-model-dpkg-perl.
commit 19bfbacd682ea60b87c21ba8a9e8266c8b327394
Author: Dominique Dumont <dod at debian.org>
Date: Sat Jan 7 19:30:40 2017 +0100
handle comments in list parameter (wip: #849500)
Warning: this breaks dpkg and dpkg-copyright tests.
---
lib/Config/Model/Backend/Dpkg/Control.pm | 145 +++++++---
lib/Config/Model/Backend/DpkgSyntax.pm | 295 +++++++++++++--------
.../dpkg-control-examples/comments-in-dep-list | 74 ++++++
t/model_tests.d/dpkg-control-test-conf.pl | 7 +
4 files changed, 371 insertions(+), 150 deletions(-)
diff --git a/lib/Config/Model/Backend/Dpkg/Control.pm b/lib/Config/Model/Backend/Dpkg/Control.pm
index 205d5a5..d35da18 100644
--- a/lib/Config/Model/Backend/Dpkg/Control.pm
+++ b/lib/Config/Model/Backend/Dpkg/Control.pm
@@ -1,7 +1,11 @@
-
package Config::Model::Backend::Dpkg::Control ;
-use 5.10.1;
+use strict;
+use warnings;
+
+use 5.20.1;
use Mouse ;
+use feature qw/postderef signatures/;
+no warnings qw/experimental::postderef experimental::signatures/;
extends 'Config::Model::Backend::Any';
@@ -58,7 +62,7 @@ sub read {
my $package_name;
foreach (my $i = 0; $i < $#$section; $i += 2) {
next unless $section->[$i] =~ /^package$/i;
- $package_name = $section->[ $i+1 ][0];
+ $package_name = $section->[ $i+1 ][0][0];
splice @$section,$i,2 ;
last ;
}
@@ -66,34 +70,43 @@ sub read {
if (not defined $package_name) {
my $msg = "Cannot find package_name in section beginning at line $section_line";
Config::Model::Exception::Syntax
- -> throw (object => $root, error => $msg, parsed_line => $section_line) ;
- }
-
+ -> throw (object => $root, error => $msg, parsed_line => $section_line) ;
+ }
+
$node = $root->grab("binary:$package_name") ;
$self->read_sections ($node, $section_line, $section, $args{check});
}
return 1 ;
}
-sub fill_package_cache {
- my $self = shift;
- my $c = shift;
+sub fill_package_cache ($self, $c) {
# scan data to find package name and query madison for info for all packages in a single call
- my %packages; # use a hash to elliminate duplicates
+ my %packages; # use a hash to eliminate duplicates
foreach my $s (@$c) {
next unless ref $s eq 'ARRAY' ;
my %section = @$s ; # don't care about order
+
foreach my $found (keys %section) {
if ($found =~ /Depends|Suggests|Recommends|Enhances|Breaks|Conflicts|Replaces/) {
- my $v = $section{$found}[0] ; # $section{found} array is [ value, line_nb, altered_value , comment ]
- my @v = grep { not /\$/ } map { s/\[.*\]//g; s/<.*>//; s/\(.*\)//; s/\s//g; $_;} split /[\s\n]*[,|][\s\n]*/, $v;
- chomp @v;
- map {$packages{$_} =1 ;} @v;
+ # $section{found} array is [ [ dep, line_nb, altered_value , comment ], ..]
+ map { $packages{$_} = 1 }
+ grep { not /\$/ } # skip debhelper variables
+ map {
+ chomp;
+ s/\[.*\]//g; # remove arch details
+ s/<.*>//; # remove build profile
+ s/\(.*\)//; # remove version details
+ s/\s//g;
+ s/,\s*$//; # remove trailing comma
+ $_;
+ }
+ map { split /\s*[,|]\s*/ , $_->[0] } # extract dependency info from array ref
+ grep { ref $_ } # skip emtpy data
+ $section{$found}->@*;
}
}
}
-
my @pkgs = keys %packages;
Config::Model::Dpkg::Dependency::cache_info_from_madison ($self->node->instance, at pkgs);
}
@@ -144,45 +157,82 @@ sub store_section_element_in_tree {
# error message
my $found = $node->find_element( $key, case => 'any' ) || $key;
- my ($v,$l,$a, at c) = @$v_ref;
+ # v_ref is a list of ($value, $line_nb ,$note, at comment) = @$v_ref;
- $logger->debug("$key value: $v");
my $elt_obj = $node->fetch_element( name => $found, check => $check );
my $type = $node->element_type($found);
- $elt_obj->annotation(join("\n", at c)) if @c ;
- $elt_obj->notify_change(note => $a, really => 1) if $a ;
-
- $v =~ s/^\s*\n//;
- chomp $v;
-
if ( $type eq 'list' ) {
- my @v = split /[\s\n]*,[\s\n]*/, $v;
- chomp @v;
- $logger->debug( "list $key store set '" . join( "','", @v ) . "'" );
- $elt_obj->store_set( \@v, check => $check );
+ $self->store_section_list_element ( $elt_obj, $check, $v_ref);
}
elsif ($found eq 'Description' and $elt_obj) {
- my ($synopsis,$desc) = split /\n/, $v, 2 ;
- $logger->debug("storing Synopsis value: $synopsis");
- $node->fetch_element('Synopsis')->store( value => $synopsis, check => $check );
- $logger->debug("storing Description value: $desc");
- $elt_obj->store( value => $desc, check => $check );
+ my ($synopsis_ref, @desc_ref) = $v_ref->@*;
+ $self->store_section_leaf_element ($node->fetch_element('Synopsis'), $check, [$synopsis_ref]);
+ $self->store_section_leaf_element ($node->fetch_element('Description'), $check, \@desc_ref);
}
elsif ($elt_obj ) {
- my @elt = ($found);
- my @v = ( $found eq 'Description' ) ? ( split /\n/, $v, 2 ) : ($v);
- unshift @elt, 'Synopsis' if $found eq 'Description';
- foreach (@elt) {
- my $sub_v = shift @v;
- $logger->debug("storing $_ value: $sub_v");
- $elt_obj->store( value => $sub_v, check => $check );
- }
+ $self->store_section_leaf_element ( $elt_obj, $check, $v_ref);
}
else {
# try anyway to trigger an error message
- $node->fetch_element($key)->store( value => $v, check => $check );
+ my $unexpected_obj = $node->fetch_element($key);
+ $self->store_section_leaf_element ( $unexpected_obj, $check, $v_ref);
+ }
+}
+
+sub store_section_list_element ($self, $list_obj, $check, $v_ref) {
+ # v_ref is a list of ($value, $line_nb ,$note, at comment)
+ $list_obj->clear();
+
+ my $idx = 0;
+ my @list_comment;
+ foreach my $v_info ( $v_ref->@* ) {
+ if (ref $v_info) {
+ my ($v,$l,$note, at c) = @$v_info;
+ # $v can be ' foo,' or 'foo, bar, baz'. This depends on input format
+ # there can only be one comment for all these values (constrained by syntax)
+ $v =~ s/\s*,\s*$//;
+ $v =~ s/^\s+//;
+ my @items = split /\s*,\s*/, $v;
+ my $comment = join("\n", @c);
+ my $item_idx = 0;
+
+ foreach my $item (@items) {
+ $logger->debug( "list store $idx:'$item'" . ($comment ? " comment '$comment'" : ''));
+ my $elt_obj = $list_obj->fetch_with_id($idx++);
+ $elt_obj->store( $item, check => $check );
+ $elt_obj->annotation($comment) if $comment and $item_idx++ == 0;
+ $elt_obj->notify_change(note => $note, really => 1) if $note ;
+ }
+ }
+ else {
+ push @list_comment, $v_info;
+ }
+ }
+ $list_obj->annotation(@list_comment) if @list_comment;
+}
+
+sub store_section_leaf_element ($self, $elt_obj, $check, $v_ref) {
+ # v_ref is a list of (@comment , [ value, $line_nb ,$note ] )
+
+ my ($l, at v, at comment, at note);
+ foreach my $v_item ( $v_ref ->@* ) {
+ if (ref $v_item) {
+ push @v, $v_item->[0];
+ $l //= $v_item->[1]; # use only first indicated line number
+ push @note, $v_item->[2];
+ }
+ else {
+ push @comment, $ v_item;
+ }
}
+ my $v = join("\n", @v);
+ my $note = join("\n", @note);
+
+ $logger->debug("storing ",$elt_obj->element_name," value: $v");
+ $elt_obj->store( value => $v, check => $check );
+ $elt_obj->annotation(@comment) if @comment ;
+ $elt_obj->notify_change(note => $note, really => 1) if $note ;
}
sub write {
@@ -233,7 +283,18 @@ sub package_spec {
die "package_spec: unexpected hash type in ".$node->name." element $elt\n" ;
}
elsif ($type eq 'list') {
- my @v = $elt_obj->fetch_all_values ;
+ my @v;
+ my @indexes = $elt_obj->fetch_all_indexes;
+
+ foreach my $idx (@indexes) {
+ my $value_obj = $elt_obj->fetch_with_id($idx);
+ my $value = $value_obj->fetch;
+ next unless defined $value;
+
+ my $note = $value_obj->annotation;
+ my $comment = $note ? join ("\n",map {'# '.$_} split /\n/,$note ) : undef;
+ push @v, $comment ? [ $value, $comment ] : $value;
+ }
push @section, $elt , \@v if @v;
}
elsif ($elt eq 'Synopsis') {
diff --git a/lib/Config/Model/Backend/DpkgSyntax.pm b/lib/Config/Model/Backend/DpkgSyntax.pm
index acfe7a8..bed8d8e 100644
--- a/lib/Config/Model/Backend/DpkgSyntax.pm
+++ b/lib/Config/Model/Backend/DpkgSyntax.pm
@@ -1,5 +1,7 @@
package Config::Model::Backend::DpkgSyntax ;
+use strict;
+use warnings;
use Mouse::Role;
use Carp;
@@ -9,7 +11,7 @@ use 5.20.0;
use feature qw/postderef signatures/;
no warnings qw/experimental::postderef experimental::signatures/;
-
+use XXX;
use base qw/Config::Model::Backend::Any/;
my $logger = get_logger("Backend::DpkgSyntax") ;
@@ -35,7 +37,7 @@ sub parse_dpkg_lines {
my ($self, $file_path, $lines, $check, $comment_allowed, $handle_garbage) = @_ ;
my $field;
- my $store_ref ; # hold field data
+ my $store_list_ref ; # hold field data
my @comments; # hold comment data
my $store_list = [] ; # holds sections
@@ -44,7 +46,7 @@ sub parse_dpkg_lines {
my $section_line = 1 ;
# list of list ( $line_nb_nb, section, ... ) where section is
- # [keyword, [ value, line_nb, altered , comment ] ])
+ # [keyword,[ maybe keyword comments, .. , [ value, line_nb, altered , comment ] , ... ])
my @res ;
foreach my $l (@$lines) {
@@ -74,11 +76,11 @@ sub parse_dpkg_lines {
$logger->trace("$file_path line $line_nb start new field $key with '$text'");
# @$store_list will be used in a hash, where the $field is key
- # store value found, file line number, is value altered (used later, o for now)
+ # store value found, file line number, is value altered (used later, not for now)
# and comments
- push @$store_list, $field, [ $text , $line_nb, '', @comments ] ;
+ $store_list_ref = [ @comments, [ $text , $line_nb, '' ] ];
@comments = () ;
- $store_ref = \$store_list->[$#$store_list][0] ;
+ push @$store_list, $field, $store_list_ref ;
}
elsif ( $key and $l =~ /^\s*$/ ) { # first empty line after a section
$logger->trace("$file_path empty line $line_nb: starting new section");
@@ -86,8 +88,7 @@ sub parse_dpkg_lines {
push @res, $section_line, $store_list if @$store_list ; # don't store empty sections
$store_list = [] ;
$section_line = $line_nb + 1; # next line, will be clobbered if next line is empty
- chomp $$store_ref if defined $$store_ref; # remove trailing \n
- undef $store_ref ; # to ensure that next line contains a keyword
+ undef $store_list_ref ; # to ensure that next line contains a keyword
}
elsif ( $l =~ /^\s*$/ ) { # "extra" empty line
$handle_garbage->($l, $line_nb) if $handle_garbage ;
@@ -96,15 +97,15 @@ sub parse_dpkg_lines {
}
elsif ( $l =~ /^\s+\.$/) { # line with a single dot
$logger->trace("dot line: adding blank line to field $key");
- _store_line($store_ref,$file_path,"",$check,$line_nb, $handle_garbage) ;
+ _store_line_and_comments($store_list_ref,$file_path,"",$check,$line_nb, $handle_garbage, \@comments) ;
}
elsif ( $l =~ s/^\s//) { # non empty line
$logger->trace("text line: adding '$l' to field $key");
- _store_line($store_ref,$file_path,$l , $check,$line_nb, $handle_garbage);
+ _store_line_and_comments($store_list_ref,$file_path,$l , $check,$line_nb, $handle_garbage, \@comments);
}
elsif ($handle_garbage) {
$logger->trace("storing garbage in line $line_nb: $l");
- $handle_garbage->($l, $line_nb) ;
+ $handle_garbage->($l, $line_nb, \@comments) ;
}
else {
my $msg = "DpkgSyntax error: Invalid line (missing ':' ?) : $l" ;
@@ -118,8 +119,6 @@ sub parse_dpkg_lines {
$line_nb++;
}
- # remove trailing \n of last stored value
- chomp $$store_ref if defined $$store_ref;
# store last section if not empty
push @res, $section_line, $store_list if @$store_list;
@@ -132,24 +131,25 @@ sub parse_dpkg_lines {
$logger->debug("Parse result section $i, found:") ;
foreach my $key (keys %section_data) {
- $logger->debug( "$key: ". substr ($section_data{$key}[0],0,35)) ;
+ my $data = $section_data{$key};
+ $logger->debug( "$key: ". $data->[0][0]. (@$data > 1 ? ' ...':'')) ;
}
}
}
$logger->warn("No section found in file $file_path") unless @res ;
- return wantarray ? @res : \@res ;
+ return wantarray ? @res : \@res ;
}
-sub _store_line ($store_ref,$file_path,$line,$check,$line_nb, $handle_garbage) {
+sub _store_line_and_comments ($store_ref,$file_path,$line,$check,$line_nb, $handle_garbage, $comments) {
if (defined $store_ref) {
- $$store_ref .= "\n$line" ;
+ push $store_ref->@* , [ $line , $line_nb, '', $comments->@* ]
}
elsif ($handle_garbage) {
$logger->trace("storing garbage in line $line_nb: $line");
- $handle_garbage->($line, $line_nb) ;
+ $handle_garbage->($line, $line_nb, $comments->@*) ;
}
else {
my $msg = "Did not find a keyword before: '$line''";
@@ -160,7 +160,7 @@ sub _store_line ($store_ref,$file_path,$line,$check,$line_nb, $handle_garbage) {
) if $check eq 'yes' ;
$logger->error($msg) if $check eq 'skip';
}
-
+ $comments->@* = (); # reset comments, they are now stored
}
# input is [ section [ keyword => value | value_list_ref ] ]
@@ -175,6 +175,8 @@ sub write_dpkg_file {
$ioh->print ( join("\n", @lines ), "\n");
}
+# TODO: also rework coyright and dpkgpatch to cope with new data structure
+
# input is [ may_be_comment, keyword => value | value_list_ref, ... ]
sub format_dpkg_section {
my ($self, $array_ref,$list_sep) = @_ ;
@@ -191,11 +193,7 @@ sub format_dpkg_section {
my $value = $array_ref->[$i + 1];
if (ref ($value)) {
- my $sep = $list_sep // ",\n" ;
- $sep .= ' ' x (length ($name) + 2) if $sep =~ /\n$/ ;
-
- my $line0 = $self->format_label_line($name, shift @$value);
- push @lines, join ($sep, $line0, @$value ) ;
+ push @lines, $self->format_dpkg_list($name, $value, $list_sep) ;
}
else {
push @lines, $self->format_dpkg_text($name, $value) ;
@@ -205,6 +203,37 @@ sub format_dpkg_section {
return @lines;
}
+# since list_sep may contain a \n or not, the list is formatted as a string
+sub format_dpkg_list ($self, $name, $value_list_ref, $list_sep) {
+ my $result = '';
+
+ my $sep = $list_sep // ",\n" ;
+ my $pad = $sep =~ /\n$/ ? ' ' x (length ($name) + 2) : '' ;
+
+ my $idx = 0;
+ foreach my $item ($value_list_ref->@*) {
+ my ($list_elt, $comment_elt) = ref($item) ? $item->@* : ($item);
+ if ($comment_elt and $sep !~ /\n/) {
+ $logger->error("Cannot store comment when list is stored on a single line\nDropping '$comment_elt'");
+ $comment_elt = '';
+ }
+ if ($idx == 0 and $comment_elt) {
+ $result .= $self->format_label_line($name, '');
+ $result .= $comment_elt . "\n" . $pad . $list_elt ;
+ }
+ elsif ($idx == 0) {
+ $result .= $self->format_label_line($name, $list_elt) ;
+ }
+ else {
+ $result .= $comment_elt."\n" if $comment_elt;
+ $result .= $pad.$list_elt;
+ }
+ $result .= $sep unless $idx == $value_list_ref->$#*;
+ $idx++ ;
+ }
+ return $result;
+}
+
sub write_dpkg_text {
my ($self, $ioh, $text) = @_ ;
$ioh->print ( join("\n", $self->format_dpkg_text('',$text)), "\n" );
@@ -242,81 +271,142 @@ Config::Model::Backend::DpkgSyntax - Role to read and write files with Dpkg synt
=head1 SYNOPSIS
+With a dpkg file containing:
+
+ Name: Foo
+ Version: 1.2
+
+ # section comment
+ Name: Bar
+ # data comment
+ Version: 1.3
+ Files: file1,
+ # inline comment
+ file2
+ Description: A very
+ .
+ long description
+
+Parse the file with:
+
+ package MyParser ;
+ use strict;
+ use warnings;
+
+ use Log::Log4perl qw(:easy);
+ Log::Log4perl->easy_init($WARN);
+
+ # load role
+ use Mouse ;
+ with 'Config::Model::Backend::DpkgSyntax';
+
+ package main ;
+ use IO::File;
+ use Data::Dumper;
+
+ my $file = 'examples/dpkg-test'; # replace with any file name
+ my $fh = IO::File->new();
+ $fh->open("< $file");
+
+ my $parser = MyParser->new() ;
+ my $data = $parser->parse_dpkg_file($file, $fh, 'yes', 1);
+ $fh->close;
+
+ print Dumper $data;
+
+Data contains:
+
+ [
+ 1, # section 1 found in line 1
+ [
+ 'Name', # first parameter
+ [
+ 'section comment',
+ [
+ 'Foo', # first parameter data
+ 1, # also found in line 1
+ '' # currently always empty
+ ]
+ ],
+ 'Version', [ 'data comment', ['1.2', 2, '']]
+ ], # end of section 1
+ 4, # section 2 found in line 4
+ [
+ 'Name', [['Bar', 5, '']],
+ 'Version', [['1.3', 7, '']],
+ 'Files', # param with 2 lines
+ [
+ ['file1,', 8, ''],
+ [' file2', 10, '', 'inline comment'] # padding is kept
+ ],
+ 'Description', # param with 3 lines
+ [
+ ['A very', 11, ''],
+ ['', 12, ''], # empty line, note: dot was removed
+ ['long description', 13, '']
+ ]
+ ] # end of section 2
+ ]; # end of data
+
+To write Dpkg file back:
+
package MyParser ;
+
+ use strict;
+ use warnings;
+
+ use 5.20.1;
+
use Log::Log4perl qw(:easy);
Log::Log4perl->easy_init($WARN);
+ # load role
use Mouse ;
with 'Config::Model::Backend::DpkgSyntax';
package main ;
- use IO::File ;
- use Data::Dumper ;
+ use IO::File;
+ use Data::Dumper;
- my $data = [ [ qw/Name Foo Version 1.2/ ],
- [ qw/Name Bar Version 1.3/ ,
- Files => [qw/file1 file2/] ,
- Description => "A very\n\nlong description"
- ]
- ] ;
+ # note: the structure is different compared to the one returned by
+ # the parser (no line number)
+ my $data = [
+ [ '# section comment', qw/Name Foo/, '# data comment', qw/Version 1.2/ ],
+ [
+ qw/Name Bar Version 1.3/ ,
+ Files => [qw/file1/, [ 'file2' , '# inline comment'] ] ,
+ Description => "A very\n\nlong description"
+ ]
+ ];
- my $fhw = IO::File->new ;
- $fhw -> open ( 'dpkg_file' ,'>' ) ;
my $parser = MyParser->new() ;
+ my $fhw = IO::File->new ;
+ $fhw -> open ( 'examples/dpkg-new' ,'>',"," ) ;
+
$parser->write_dpkg_file($fhw,$data) ;
-
-C<dpkg_file> will contain:
+ $fhw->close;
- Name: Foo
- Version: 1.2
-
- Name: Bar
- Version: 1.3
- Files: file1,
- file2
- Description: A very
- .
- long description
=head1 DESCRIPTION
This module is a Moose role to read and write dpkg control files.
-Debian control file are read and transformed in a list of list
+Debian control file are read and transformed in a structure
matching the control file. The top level list of a list of section.
-Each section is mapped to a list made of keywords and values. Since
-this explanation is probably too abstract, here's an example of a file
-written with Dpkg syntax:
+Each section is mapped to a structure containing the parameter names and values,
+comments and line numbers. See the synopsis for an example.
- Name: Foo
- Version: 1.1
-
- Name: Bar
- # boy, new version
- Version: 1.2
- Description: A very
- .
- long description
-
-Once parsed, this file will be stored in the following list of list :
-
- (
- [ Name => 'Foo', Version => '1.1' ],
- [ Name => 'Bar', Version => [ '1.2' 'boy, new version' ],
- Description => "A very\n\nlong description"
- ]
- )
-
Note: The description is changed into a paragraph without the Dpkg
-syntax idiosyncrasies. The leading white space is removed and the single
-dot is transformed in to a "\n". These characters will be restored
+syntax idiosyncrasies. The leading white space is removed and the
+single dot is transformed in to a "\n". These characters are restored
when the file is written back.
-Last not but not least, this module can be re-used outside of C<Config::Model> with some
-small modifications in exception handing. Ask the author
-if you want this module shipped in its own distribution.
+Last not but not least, this module could re-used outside of
+C<Config::Model> with some small modifications in exception
+handing. Ask the author if you want this module shipped in its own
+distribution.
=head1
@@ -327,32 +417,11 @@ Parameters: C<( file_path, file_handle, [ check, [ comment_allowed ]] )>
Read a control file from C<file_handle> and returns a nested list (or
a list ref) containing data from the file.
-The returned list is of the form :
-
- [
- # section 1
- [ keyword1 => value1, # for text or simple values
- keyword2 => value2, # etc
- ],
- # section 2
- [ ... ]
- # etc ...
- ]
+See sysnopsis for the returned structure.
C<check> is C<yes>, C<skip> or C<no> (default C<yes>).
C<comment_allowed> is boolean (default 0)
-When comments are provided in the dpkg files, the returned list is of
-the form :
-
- [
- [
- keyword1 => [ value1, 'value1 comment']
- keyword2 => value2, # no comment
- ],
- [ ... ]
- ]
-
=head2 parse_dpkg_lines
Parameters: C< ( file_path, lines, check, comment_allowed ) >
@@ -360,38 +429,48 @@ Parameters: C< ( file_path, lines, check, comment_allowed ) >
Parse the dpkg date from lines (which is an array ref) and return a data
structure like L<parse_dpkg_file>.
-=head2 write_dpkg_file ( io_handle, list_ref, list_sep )
+=head2 write_dpkg_file
+
+Parameters C< ( io_handle, list_ref, list_sep ) >
Munge the passed list ref into a string compatible with control files
and write it in the passed file handle.
The input is a list of list in a form similar to the one generated by
-L<parse_dpkg_file>:
-
- [ section [ keyword => value | value_list ] ]
+L<parse_dpkg_file>. See the synopsis for an example
-Except that the value may be a SCALAR or a list ref. In case, of a list ref, the list
-items will be joined with the value C<list_sep> before being written. Values will be aligned
-in case of multi-line output of a list.
+List items (like C<Depends> field in C<debian/control>) are joined
+with the value C<list_sep> before being written. Values are aligned in
+case of multi-line output of a list. Default value of C<list_sep> is "C<,\n>"
For instance the following code :
- my $ref = [ [ Foo => 'foo value' , Bar => [ qw/v1 v2/ ] ];
+ my $ref = [ [ Foo => 'foo value' , Bar => [ 'v1', 'v2' ] ];
write_dpkg_file ( $ioh, $ref, ', ' )
-will yield:
+yields:
Foo: foo value
Bar: v1, v2
+Here's an example using default C<$sep_list>:
+
+ write_dpkg_file ( $ioh, $ref )
+
+yields:
+
+ Foo: foo value
+ Bar: v1,
+ v2
+
=head1 AUTHOR
Dominique Dumont, (ddumont at cpan dot org)
=head1 SEE ALSO
-L<Config::Model>,
-L<Config::Model::AutoRead>,
-L<Config::Model::Backend::Any>,
+L<Config::Model>,
+L<Config::Model::BackendMgr>,
+L<Config::Model::Backend::Any>,
=cut
diff --git a/t/model_tests.d/dpkg-control-examples/comments-in-dep-list b/t/model_tests.d/dpkg-control-examples/comments-in-dep-list
new file mode 100644
index 0000000..1582963
--- /dev/null
+++ b/t/model_tests.d/dpkg-control-examples/comments-in-dep-list
@@ -0,0 +1,74 @@
+Source: python-bx
+Section: python
+Priority: optional
+Maintainer: Debian Med Packaging Team <debian-med-packaging at lists.alioth.debian.org>
+Build-Depends:
+ debhelper (>= 9),
+ dh-python,
+ zlib1g-dev,
+# Python2
+ python-setuptools,
+ python-all-dev,
+ python-nose,
+ python-numpy,
+ cython,
+# Python3
+ python3-setuptools,
+ python3-all-dev,
+ python3-nose,
+ python3-numpy,
+ cython3,
+Standards-Version: 3.9.8
+Homepage: https://github.com/bxlab/bx-python
+Vcs-Git: https://anonscm.debian.org/git/debian-med/python-bx.git
+Vcs-Browser: https://anonscm.debian.org/cgit/debian-med/python-bx.git
+
+Package: python-bx
+Architecture: any
+Depends:
+ ${shlibs:Depends},
+ ${misc:Depends},
+ ${python:Depends},
+Description: manipulating multiple sequence alignments and other biological data -- Python 2
+ The bx-python project is a python library and associated set of scripts to
+ allow for rapid implementation of genome scale analyses. The library contains
+ a variety of useful modules, but the particular strengths are:
+ * Classes for reading and working with genome-scale multiple local
+ alignments (in MAF, AXT, and LAV formats)
+ * Generic data structure for indexing on disk files that contain blocks of
+ data associated with intervals on various sequences (used, for example, to
+ provide random access to individual alignments in huge files; optimized for
+ use over network filesystems)
+ * Data structures for working with intervals on sequences
+ * "Binned bitsets" which act just like chromosome sized bit arrays, but
+ lazily allocate regions and allow large blocks of all set or all unset bits
+ to be stored compactly
+ * "Intersecter" for performing fast intersection tests that preserve both
+ query and target intervals and associated annotation
+ .
+ This package provides the Python 2 library.
+
+Package: python3-bx
+Architecture: any
+Depends:
+ ${shlibs:Depends},
+ ${misc:Depends},
+ ${python3:Depends},
+Description: manipulating multiple sequence alignments and other biological data -- Python 3
+ The bx-python project is a python library and associated set of scripts to
+ allow for rapid implementation of genome scale analyses. The library contains
+ a variety of useful modules, but the particular strengths are:
+ * Classes for reading and working with genome-scale multiple local
+ alignments (in MAF, AXT, and LAV formats)
+ * Generic data structure for indexing on disk files that contain blocks of
+ data associated with intervals on various sequences (used, for example, to
+ provide random access to individual alignments in huge files; optimized for
+ use over network filesystems)
+ * Data structures for working with intervals on sequences
+ * "Binned bitsets" which act just like chromosome sized bit arrays, but
+ lazily allocate regions and allow large blocks of all set or all unset bits
+ to be stored compactly
+ * "Intersecter" for performing fast intersection tests that preserve both
+ query and target intervals and associated annotation
+ .
+ This package provides the Python 3 library.
diff --git a/t/model_tests.d/dpkg-control-test-conf.pl b/t/model_tests.d/dpkg-control-test-conf.pl
index 303514a..67035be 100644
--- a/t/model_tests.d/dpkg-control-test-conf.pl
+++ b/t/model_tests.d/dpkg-control-test-conf.pl
@@ -193,6 +193,13 @@ providing the following file:
'binary:pkg-config-stage1 Build-Profiles' => '<stage1>',
'source Build-Depends:3' => 'libglib2.0-dev <!stage1>'
},
+ },
+
+ {
+ name => 'comments-in-dep-list',
+ file_contents_like => {
+ "debian/control" => qr/# Python/,
+ }
}
);
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/libconfig-model-dpkg-perl.git
More information about the Pkg-perl-cvs-commits
mailing list