[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