[libparse-debianchangelog-perl] 02/03: * New upstream release - adapt Build-Depends-Indep and Recommends to new requirements - install new TODO file - install templates and CSS files to /usr/share/libparse-debianchangelog-perl/ and adapt the default paths in the module

Intrigeri intrigeri at moszumanska.debian.org
Sun May 24 12:37:47 UTC 2015


This is an automated email from the git hooks/post-receive script.

intrigeri pushed a commit to tag debian_version_0_4-1
in repository libparse-debianchangelog-perl.

commit 6d0d728e3de3cb26bb31795ba8c19dc48188a799
Author: Frank Lichtenheld <frank at lichtenheld.de>
Date:   Tue Jul 5 01:40:03 2005 +0000

      * New upstream release
        - adapt Build-Depends-Indep and Recommends to new requirements
        - install new TODO file
        - install templates and CSS files to
          /usr/share/libparse-debianchangelog-perl/ and adapt the default
          paths in the module
---
 debian/changelog             |  11 +
 debian/control               |   4 +-
 debian/install               |   1 +
 debian/rules                 |   3 +-
 lib/Parse/DebianChangelog.pm | 648 +++++++++++++++++++++++++++++++------------
 t/Parse-DebianChangelog.t    |  44 ++-
 6 files changed, 530 insertions(+), 181 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index e3c4e03..cbadea5 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,14 @@
+libparse-debianchangelog-perl (0.4-1) unstable; urgency=low
+
+  * New upstream release
+    - adapt Build-Depends-Indep and Recommends to new requirements
+    - install new TODO file
+    - install templates and CSS files to
+      /usr/share/libparse-debianchangelog-perl/ and adapt the default
+      paths in the module
+
+ -- Frank Lichtenheld <djpig at debian.org>  Tue,  5 Jul 2005 03:28:10 +0200
+
 libparse-debianchangelog-perl (0.3a-1) unstable; urgency=low
 
   * Initial Release (Closes: #314559).
diff --git a/debian/control b/debian/control
index 963fb36..e9ed9d3 100644
--- a/debian/control
+++ b/debian/control
@@ -2,14 +2,14 @@ Source: libparse-debianchangelog-perl
 Section: perl
 Priority: optional
 Build-Depends: debhelper (>= 4.0.2)
-Build-Depends-Indep: perl (>= 5.8.0-7), libtimedate-perl
+Build-Depends-Indep: perl (>= 5.8.0-7), libtimedate-perl, libhtml-parser-perl, libhtml-template-perl, tidy
 Maintainer: Frank Lichtenheld <djpig at debian.org>
 Standards-Version: 3.6.2
 
 Package: libparse-debianchangelog-perl
 Architecture: all
 Depends: ${perl:Depends}, ${misc:Depends}, libtimedate-perl
-Recommends: dpkg-dev, libhtml-parser-perl, liburi-perl
+Recommends: libhtml-parser-perl, libhtml-template-perl
 Description: parse Debian changelogs and output them in other formats
  Replacement for the very limited dpkg-parsechangelog.
  .
diff --git a/debian/install b/debian/install
new file mode 100644
index 0000000..19290db
--- /dev/null
+++ b/debian/install
@@ -0,0 +1 @@
+tmpl/* usr/share/libparse-debianchangelog-perl
diff --git a/debian/rules b/debian/rules
index f86eb26..a6035df 100755
--- a/debian/rules
+++ b/debian/rules
@@ -59,8 +59,9 @@ binary-arch:
 binary-indep: build install
 	dh_testdir
 	dh_testroot
+	dh_install
 #	dh_installexamples
-	dh_installdocs
+	dh_installdocs TODO
 	dh_installchangelogs Changes
 	dh_perl
 	dh_link
diff --git a/lib/Parse/DebianChangelog.pm b/lib/Parse/DebianChangelog.pm
index e607c90..0e2e7e9 100644
--- a/lib/Parse/DebianChangelog.pm
+++ b/lib/Parse/DebianChangelog.pm
@@ -29,17 +29,68 @@ Parse::DebianChangelog - parse Debian changelogs and output them in other format
 
     my $chglog = Parse::DebianChangelog->init( { infile => 'debian/changelog',
                                                  HTML => { outfile => 'changelog.html' } );
-    $chglog->html_out;
+    $chglog->html;
 
     # the following is semantically equivalent
     my $chglog = Parse::DebianChangelog->init();
     $chglog->parse( { infile => 'debian/changelog' } );
-    $chglog->html_out( { outfile => 'changelog.html' } );
-    $chglog->dpkg_out( { since => '1.0-1' } );
+    $chglog->html( { outfile => 'changelog.html' } );
 
+    my $changes = $chglog->dpkg_str( { since => '1.0-1' } );
+    print $changes;
 
 =head1 DESCRIPTION
 
+Parse::DebianChangelog parses Debian changelogs as desribed in the Debian
+policy (version 3.6.2.1 at the time of this writing). See section
+L<"SEE ALSO"> for locations where to find this definition.
+
+The parser tries to ignore most cruft like # or /* */ style comments,
+CVS comments, vim variables, emacs local variables and stuff from
+older changelogs with other formats at the end of the file.
+NOTE: most of these are ignored silently currently, there is no
+parser error issued for them. This should become configurable in the
+future.
+
+Parse::DebianChangelog also supports converting these changelogs then
+to various other formats. These are currently:
+
+=over 4
+
+=item dpkg
+
+Format as know from L<dpkg-parsechangelog(1)>. All requested entries
+(see L<"METHODS"> for an explanation what this means) are returned in
+the usual Debian control format, merged in one stanza, ready to be used
+a F<.changes> file.
+
+=item rfc822
+
+Similar to the C<dpkg> format, but the requested entries are returned
+as one stanza each, i.e. they are not merged. This is probably the format
+to use if you want a machine-usable representation of the changelog.
+
+=item html
+
+The changelog is converted to a somewhat nice looking HTML file with
+some niće features as a quicklink bar with direct links to every entry.
+NOTE: This is not very configurable yet and was specifically designed
+to be used on L<http://packages.debian.org/>. This is planned to be
+changed until version 1.0.
+
+=item custom
+
+All the nitty-gritty details of what the parser found out in a
+machine-usable format.
+NOTE: Not implemented yet. You can of course use the internal
+representation but don't expect that to work in future versions of
+this module. It is planned to encapsulate each entry's data in an
+own object and then make these available to the user...
+
+=back
+
+=head2 METHODS
+
 =cut
 
 package Parse::DebianChangelog;
@@ -66,7 +117,22 @@ our @EXPORT = qw(
 );
 
 our $CLASSNAME = 'Parse::DebianChangelog';
-our $VERSION = 0.3;
+our $VERSION = 0.4;
+
+=pod
+
+=head3 init
+
+Creates a new object instance. Takes a reference to a hash as
+optional argument, which is interpreted as configuration options.
+There are currently no supported general configuration options, but
+see the other methods for more specifc configuration options which
+can also specified to C<init>.
+
+If C<infile> is specified (see L<parse>), C<parse()> is called
+from C<init>.
+
+=cut
 
 sub init {
     my $classname = shift;
@@ -85,13 +151,22 @@ sub init {
     return $self;
 }
 
+=pod
+
+=head3 reset_parse_errors
+
+Can be used to delete all information about errors ocurred during
+previous L<parse> runs. Note that C<parse()> also calls this method.
+
+=cut
+
 sub reset_parse_errors {
     my ($self) = @_;
 
     $self->{errors}{parser} = [];
 }
 
-sub do_parse_error {
+sub _do_parse_error {
     my ($self, $file, $line_nr, $error, $line) = @_;
     shift;
 
@@ -107,6 +182,40 @@ sub do_parse_error {
     }
 }
 
+=pod
+
+=head3 get_parse_errors
+
+Returns all error messages from the last L<parse> run.
+If called in scalar context returns a human readable
+string represenation. If called in list context returns
+a reference to an array of arrays. Each of these arrays contains
+
+=over 4
+
+=item 1.
+
+the filename of the parsed file
+
+=item 2.
+
+the line number where the error occoured
+
+=item 3.
+
+an error description
+
+=item 4.
+
+the original line
+
+=back
+
+NOTE: This format isn't stable yet and may change in later versions
+of this module.
+
+=cut
+
 sub get_parse_errors {
     my ($self) = @_;
 
@@ -125,6 +234,31 @@ sub get_parse_errors {
     }
 }
 
+sub __find_closes {
+    my $changes = shift;
+    my @closes = ();
+
+    while ($changes && ($changes =~ /closes:\s*(?:bug)?\#?\s?\d+(?:,\s*(?:bug)?\#?\s?\d+)*/ig)) {
+	push(@closes, $& =~ /\#?\s?(\d+)/g);
+    }
+    
+    @closes = sort { $a <=> $b } @closes;
+    return \@closes;
+}
+
+=pod
+
+=head3 parse
+
+Parses the file that is saved in the configuration item C<infile>.
+Accepts a hash ref as optional argument which can contains configuration
+items.
+
+Returns undef in case of error (e.g. "file not found", B<not> parse errors)
+and the object if successfull.
+
+=cut
+
 sub parse {
     my ($self, $config) = @_;
 
@@ -154,14 +288,10 @@ sub parse {
 		    || $expect eq 'next heading or eof') {
 		$entry{ERROR} = [ $file, $NR,
 				  "found start of entry where expected $expect", "$_" ];
-		$self->do_parse_error(@{$entry{ERROR}});
+		$self->_do_parse_error(@{$entry{ERROR}});
 	    }
 	    if (%entry) {
-		my @closes;
-		while ($entry{'Changes'} && ($entry{'Changes'} =~ /closes:\s*(?:bug)?\#?\s?\d+(?:,\s*(?:bug)?\#?\s?\d+)*/ig)) {
-		    push(@closes, $& =~ /\#?\s?(\d+)/g);
-		}
-		$entry{'Closes'} = [ sort { $a <=> $b } @closes ];
+		$entry{'Closes'} = __find_closes( $entry{Changes} );
 		
 #		    print STDERR, Dumper(%entry);
 		push @{$self->{data}}, { %entry };
@@ -180,14 +310,14 @@ sub parse {
 #	    print STDERR "RHS: $rhs\n";
 	    for my $kv (split(/\s*,\s*/,$rhs)) {
 		$kv =~ m/^([-0-9a-z]+)\=\s*(.*\S)$/i ||
-		    $self->do_parse_error($file, $NR, "bad key-value after \`;': \`$kv'");
+		    $self->_do_parse_error($file, $NR, "bad key-value after \`;': \`$kv'");
 		my $k = ucfirst $1;
 		my $v = $2;
-		$kvdone{$k}++ && $self->do_parse_error($file, $NR,
+		$kvdone{$k}++ && $self->_do_parse_error($file, $NR,
 						       "repeated key-value $k");
 		if ($k eq 'Urgency') {
 		    $v =~ m/^([-0-9a-z]+)((\s+.*)?)$/i ||
-			$self->do_parse_error($file, $NR,
+			$self->_do_parse_error($file, $NR,
 					      "badly formatted urgency value",
 					      $v);
 		    $entry{'Urgency'} = $1;
@@ -198,7 +328,7 @@ sub parse {
 		    # XC for putting in Control, XS for putting in Source
 		    $entry{$k}= $v;
 		} else {
-		    $self->do_parse_error($file, $NR,
+		    $self->_do_parse_error($file, $NR,
 					  "unknown key-value key $k - copying to XS-$k");
 		    $entry{"XS-$k"} = $v;
 		}
@@ -229,14 +359,14 @@ sub parse {
 	    $self->{oldformat} = "$_\n";
 	    $self->{oldformat} .= join "", <$fh>;
 	} elsif (m/^\S/) {
-	    $self->do_parse_error($file, $NR,
+	    $self->_do_parse_error($file, $NR,
 				  "badly formatted heading line", "$_");
 	} elsif (m/^ \-\- (.*) <(.*)>(  ?)((\w+\,\s*)?\d{1,2}\s+\w+\s+\d{4}\s+\d{1,2}:\d\d:\d\d\s+[-+]\d{4}(\s+\([^\\\(\)]\))?)$/o) {
 	    $expect eq 'more change data or trailer' ||
-		$self->do_parse_error($file, $NR,
+		$self->_do_parse_error($file, $NR,
 			"found trailer where expected $expect", "$_");
 	    if ($3 ne '  ') {
-		$self->do_parse_error($file, $NR,
+		$self->_do_parse_error($file, $NR,
 				      "badly formatted trailer line", "$_");
 	    }
 	    $entry{'Trailer'} = $_;
@@ -244,29 +374,25 @@ sub parse {
 	    unless($entry{'Date'} && $entry{'Parsed_Date'}) {
 		$entry{'Date'} = $4;
 		$entry{'Parsed_Date'} = str2time($4)
-		    or $self->do_parse_error( $file, $NR, "couldn't parse date $4" );
+		    or $self->_do_parse_error( $file, $NR, "couldn't parse date $4" );
 	    }
 	    $expect = 'next heading or eof';
 	} elsif (m/^ \-\-/) {
 	    $entry{ERROR} = [ $file, $NR,
 			      "badly formatted trailer line", "$_" ];
-	    $self->do_parse_error(@{$entry{ERROR}});
+	    $self->_do_parse_error(@{$entry{ERROR}});
 #	    $expect = 'next heading or eof'
 #		if $expect eq 'more change data or trailer';
 	} elsif (m/^\s{2,}(\S)/) {
 	    $expect eq 'start of change data'
 		|| $expect eq 'more change data or trailer'
 		|| do {
-		    $self->do_parse_error($file, $NR,
+		    $self->_do_parse_error($file, $NR,
 			    "found change data where expected $expect", "$_");
 		    if (($expect eq 'next heading or eof')
 			&& %entry) {
 			# lets assume we have missed the actual header line
-			my @closes;
-			while ($entry{'Changes'} && ($entry{'Changes'} =~ /closes:\s*(?:bug)?\#?\s?\d+(?:,\s*(?:bug)?\#?\s?\d+)*/igo)) {
-			    push(@closes, $& =~ /\#?\s?(\d+)/g);
-			}
-			$entry{'Closes'} = [ sort { $a <=> $b } @closes ];
+			$entry{'Closes'} = __find_closes( $entry{Changes} );
 			
 #		    print STDERR, Dumper(%entry);
 			push @{$self->{data}}, { %entry };
@@ -293,11 +419,11 @@ sub parse {
 	    next if $expect eq 'start of change data'
 		|| $expect eq 'next heading or eof';
 	    $expect eq 'more change data or trailer'
-		|| $self->do_parse_error($file, $NR,
+		|| $self->_do_parse_error($file, $NR,
 					 "found blank line where expected $expect");
 	    $blanklines++;
 	} else {
-	    $self->do_parse_error($file, $NR, "unrecognised line", "$_");
+	    $self->_do_parse_error($file, $NR, "unrecognised line", "$_");
 	    ($expect eq 'start of change data'
 		|| $expect eq 'more change data or trailer')
 		&& do {
@@ -319,14 +445,10 @@ sub parse {
     $expect eq 'next heading or eof'
 	|| do {
 	    $entry{ERROR} = [ $file, $NR, "found eof where expected $expect" ];
-	    $self->do_parse_error( @{$entry{ERROR}} );
+	    $self->_do_parse_error( @{$entry{ERROR}} );
 	};
     if (%entry) {
-	my @closes;
-	while ($entry{'Changes'} =~ /closes:\s*(?:bug)?\#?\s?\d+(?:,\s*(?:bug)?\#?\s?\d+)*/ig) {
-	    push(@closes, $& =~ /\#?\s?(\d+)/g);
-	}
-	$entry{'Closes'} = join(' ', sort { $a <=> $b } @closes);
+	$entry{'Closes'} = __find_closes( $entry{Changes} );
 	
 	push @{$self->{data}}, \%entry;
     }
@@ -339,66 +461,270 @@ sub parse {
     return $self;
 }
 
-sub dpkg_out {
-    my ($self, $config) = @_;
 
-    $self->{config}{DPKG} = $config if $config;
+sub __data2rfc822_mult {
+    my ($data, $fieldimps) = @_;
+    my @rfc822 = ();
 
-    $config = $self->{config}{DPKG} || {};
-    my $data = $self->{data} or return undef;
-    my $since = $config->{since} || '';
+    foreach my $entry (@$data) {
+	push @rfc822, __data2rfc822($entry,$fieldimps);
+    }
 
-    my $dpkglibdir="/usr/lib/dpkg";
-    push @INC, $dpkglibdir;
-    require 'controllib.pl';
+    return join "\n", @rfc822;
+}
+
+sub __data2rfc822 {
+    my ($data, $fieldimps) = @_;
+    my $rfc822_str = '';
+
+# based on /usr/lib/dpkg/controllib.pl
+    for my $f (sort { $fieldimps->{$b} <=> $fieldimps->{$a} } keys %$data) {
+        my $v= $data->{$f};
+        $v =~ m/\S/o || next; # delete whitespace-only fields
+        $v =~ m/\n\S/o && warn("field $f has newline then non whitespace >$v<");
+        $v =~ m/\n[ \t]*\n/o && warn("field $f has blank lines >$v<");
+        $v =~ m/\n$/o && warn("field $f has trailing newline >$v<");
+        $v =~ s/\$\{\}/\$/go;
+        $rfc822_str .= "$f: $v\n";
+    }
 
-    our ( %fieldimps, %urgencies, %f );
+    return $rfc822_str;
+}
+
+sub __get_dpkg_changes {
+    my $changes = "\n $_[0]->{Header}\n .\n$_[0]->{Changes}";
+    chomp $changes;
+    $changes =~ s/^ $/ ./mgo;
+    return $changes;
+}
+
+our ( %FIELDIMPS, %URGENCIES );
+BEGIN {
     my $i=100;
-    grep($fieldimps{$_}=$i--,
+    grep($FIELDIMPS{$_}=$i--,
 	 qw(Source Version Distribution Urgency Maintainer Date Closes
 	    Changes));
     $i=1;
-    grep($urgencies{$_}=$i++,
+    grep($URGENCIES{$_}=$i++,
 	 qw(low medium high critical emergency));
+}
+
+=pod
+
+=head3 dpkg
+
+(and B<dpkg_str>)
+
+C<dpkg> returns a hash (in list context) or a hash reference
+(in scalar context) where the keys are field names and the values are
+field values. The following fields are given:
+
+=over 4
+
+=item Source
+
+package name (in the first entry)
+
+=item Version
+
+packages' version (from first entry)
+
+=item Distribution
+
+target distribution (from first entry)
+
+=item Urgency
+
+urgency (highest of all printed entries)
+
+=item Maintainer
+
+person that created the (first) entry
+
+=item Date
+
+date of the (first) entry
+
+=item Closes
+
+bugs closed by the entry/entries, sorted by bug number
+
+=item Changes
+
+content of the the entry/entries
+
+=back
 
+C<dpkg_str> returns a stringified version of this hash which should look
+exactly like the output of L<dpkg-parsechangelog(1)>. The fields are
+ordered like in the list above.
+
+Both methods support the configuration item C<since> which works exactly
+like the C<-v> option of dpkg-parsechangelog.
+
+=cut
+
+sub dpkg {
+    my ($self, $config) = @_;
+
+    $self->{config}{DPKG} = $config if $config;
+
+    $config = $self->{config}{DPKG} || {};
+    my $data = $self->{data} or return undef;
+    my $since = $config->{since} || '';
+
+    my %f;
     foreach my $field (qw( Urgency Source Version
 			   Distribution Maintainer Date )) {
 	$f{$field} = $data->[0]{$field};
     }
 
-    error( "-v<since> option specifies most recent version" )
+    warn( "-v<since> option specifies most recent version" )
 	if $f{Version} eq $since;
 
-    $f{Changes} = "\n $data->[0]{Header}\n .\n$data->[0]{Changes}";
-    chomp $f{Changes};
-    $f{Closes} = "@{$data->[0]{Closes}}";
+    $f{Changes} = __get_dpkg_changes( $data->[0] );
+    $f{Closes} = [ @{$data->[0]{Closes}} ];
 
-    my $first = 1;
+    my $first = 1; my $urg_comment = '';
     foreach my $entry (@$data) {
 	$first = 0, next if $first;
 	last if !$since or $entry->{Version} eq $since;
 
 	my $oldurg = $f{Urgency} || '';
-	my $oldurgn = $urgencies{$f{Urgency}} || -1;
+	my $oldurgn = $URGENCIES{$f{Urgency}} || -1;
 	my $newurg = $entry->{Urgency_LC} || '';
-	my $newurgn = $urgencies{$entry->{Urgency_LC}} || -1;
+	my $newurgn = $URGENCIES{$entry->{Urgency_LC}} || -1;
 	$f{Urgency} = ($newurgn > $oldurgn) ? $newurg : $oldurg;
-	$f{Urgency_Comment} .= $entry->{Urgency_Comment};
+	$urg_comment .= $entry->{Urgency_Comment};
        
-	$f{Changes} .= "\n .\n $entry->{Header}\n .\n$entry->{Changes}";
-	chomp $f{Changes};
-	$f{Closes} .= " @{$entry->{Closes}}";
+	$f{Changes} .= "\n .".__get_dpkg_changes( $entry );
+	push @{$f{Closes}}, @{$entry->{Closes}};
 
     }
 
-    $f{Changes} =~ s/^ $/ ./mgo;
-    $f{Urgency} .= $f{Urgency_Comment};
-    delete $f{Urgency_Comment};
+    $f{Closes} = join " ", sort { $a <=> $b } @{$f{Closes}};
+    $f{Urgency} .= $urg_comment;
+
+    return %f if wantarray;
+    return \%f;
+}
 
-    outputclose(0);
+sub dpkg_str {
+    return __data2rfc822( scalar dpkg(@_), \%FIELDIMPS );
 }
 
-sub html_out {
+=pod
+
+=head3 rfc822
+
+(and B<rfc822_str>)
+
+C<rfc822> returns an array of hashes (in list context) or a reference
+to this array (in scalar context) where each hash represents one entry
+in the changelog. For the format of such a hash see the description
+of the L<"dpkg"> method (while ignoring the remarks about which
+values are taken from the first entry).
+
+C<rfc822_str> returns a stringified version of this hash which looks
+similar to the output of dpkg-parsechangelog but instead of one
+stanza the output contains one stanza for each entry.
+
+Both methods support the configuration item C<since> which works exactly
+like the C<-v> option of dpkg-parsechangelog.
+
+=cut
+
+sub rfc822 {
+    my ($self, $config) = @_;
+
+    $self->{config}{RFC822} = $config if $config;
+
+    $config = $self->{config}{RFC822} || {};
+    my $data = $self->{data} or return undef;
+    my $since = $config->{since} || '';
+
+    my @out_data;
+    warn( "-v<since> option specifies most recent version" )
+	if $data->[0]{Version} eq $since;
+
+    my $first = 1;
+    foreach my $entry (@$data) {
+	last if (!$since and !$first) or $entry->{Version} eq $since;
+	$first = 0;
+
+	my %f;
+	foreach my $field (qw( Urgency Source Version
+			   Distribution Maintainer Date )) {
+	    $f{$field} = $entry->{$field};
+	}
+
+	$f{Urgency} .= $entry->{Urgency_Comment};
+	$f{Changes} = __get_dpkg_changes( $entry );
+	$f{Closes} = join " ", sort { $a <=> $b } @{$entry->{Closes}};
+	push @out_data, \%f;
+    }
+
+    return @out_data if wantarray;
+    return \@out_data;
+}
+
+sub rfc822_str {
+    return __data2rfc822_mult( scalar rfc822(@_), \%FIELDIMPS );
+}
+
+sub __version2id {
+    my $version = shift;
+    $version =~ s/[^\w.:-]/_/go;
+    return "version$version";
+}
+
+=pod
+
+=head3 html
+
+(and B<html_str>)
+
+C<html> converts the changelog to a HTML file with some nice features
+such as a quicklink bar with direct links to every entry. The HTML
+is generated with the help of HTML::Template. If you want to change
+the output you should use the default template provided with this module
+as a base and read the documentation of HTML::Template to understand
+how to edit it.
+
+The method C<html_str> is an alias for C<html>.
+
+Both methods support the following configuration items (as usual to give
+in a hash reference as parameter to the method call):
+
+=over 4
+
+=item outfile
+
+directly write the output to the file specified
+
+=item template
+
+template file to use, defaults to
+/usr/share/libparse-debianchangelog-perl/default.tmpl.
+NOTE: The plan is to provide a configuration file for the module
+later to be able to use sane defaults here.
+
+=item style
+
+path to the CSS stylesheet to use (a default might be specified
+in the template and will be honoured, see the default template
+for an example)
+
+=item print_style
+
+path to the CSS stylesheet to use for printing (see the notes for
+C<style> about default values)
+
+=back
+
+=cut
+
+sub html {
     my ($self, $config) = @_;
     
     $self->{config}{HTML} = $config if $config;
@@ -409,52 +735,25 @@ sub html_out {
     import CGI qw( -no_xhtml -no_debug );
     require HTML::Entities;
     import HTML::Entities;
-    require URI::Escape;
-    import URI::Escape;
+    require HTML::Template;
+    
+    my $template = HTML::Template->new(filename => $config->{template}
+				       || '/usr/share/libparse-debianchangelog-perl/default.tmpl');
+    $template->param( MODULE_NAME => $CLASSNAME,
+		      MODULE_VERSION => $VERSION,
+		      GENERATED_DATE => gmtime()." UTC",
+		      SOURCE_NEWEST => $data->[0]{Source},
+		      VERSION_NEWEST => $data->[0]{Version},
+		      MAINTAINER_NEWEST => $data->[0]{Maintainer},
+		      );
+
+    $template->param( CSS_FILE_SCREEN => $config->{style} )
+	if $config->{style};
+    $template->param( CSS_FILE_PRINT => $config->{print_style} )
+	if $config->{print_style};
 
-    my $outfile = $config->{outfile} or return undef;
     my $cgi = new CGI;
 
-    open my $fh, '>', $outfile or return undef;
-    flock $fh, LOCK_EX or return undef;
-
-    print $fh $cgi->start_html( -title => $config->{title}
-				|| "Debian Changelog $data->[0]{Source} ($data->[0]{Version})",
-				-author => $config->{author}
-				|| $data->[0]{Maintainer},
-				-meta=>{ keywords => $config->{keywords}
-					 || "Debian Changelog $data->[0]{Source} $data->[0]{Version}",
-					 generator => "$CLASSNAME (v$VERSION)" },
-				-head=>[ $cgi->meta({ -http_equiv => 'Content-Type',
-						      -content => 'text/html; charset=UTF-8' }),
-					 $cgi->Link({-rel=>'stylesheet',
-						     -href => $config->{style}
-						     || 'changelogs.css',
-						     -type => 'text/css',
-						     -media => 'screen' }),
-					 $cgi->Link({-rel=>'stylesheet',
-						     -href => $config->{print_style}
-						     || 'changelogs-print.css',
-						     -type => 'text/css',
-						     -media => 'print' }),
-					 ],
-				);
-
-    print $fh $cgi->p({ -class=>'hide' },
-		      $cgi->a({ -href=>'#content' },
-			      'Skip to content' ));
-
-    print $fh $cgi->ul( { -class=>'navbar' },
-			$cgi->li( [
-				   $cgi->a({ -href=>"http://packages.debian.org/src:$data->[0]{Source}" }, 'Package Information' ),
-				   $cgi->a({ -href=>"http://packages.qa.debian.org/$data->[0]{Source}" }, 'Package Developer Information' ),
-				   $cgi->a({ -href=>"http://bugs.debian.org/src:$data->[0]{Source}" }, 'Bug Information' ),
-				   ] ) );
-
-    print $fh $cgi->h1( { -class=>"document_header" },
-			$config->{title}
-			|| "Debian Changelog $data->[0]{Source} ($data->[0]{Version})" );
-
     my %navigation;
     my $last_year;
     foreach my $entry (@$data) {
@@ -463,27 +762,29 @@ sub html_out {
 	    $year = (gmtime($entry->{Parsed_Date}))[5] + 1900;
 	    $last_year = $year;
 	}
-	
+
 	$year ||= (($entry->{Date} =~ /\s(\d{4})\s/) ? $1 : (gmtime)[5] + 1900);
-	$navigation{$year} ||= [];
-	$entry->{Maintainer} ||= 'unkown';
-	$entry->{Date} ||= 'unkown';
-	push @{$navigation{$year}}, $cgi->a({-href=>"#version$entry->{Version}",
-					     -title=>encode_entities("$entry->{Maintainer} $entry->{Date}",'<>&"')},
-					    $entry->{Version});
+
+	$navigation{$year}{NAV_VERSIONS} ||= [];
+	$navigation{$year}{NAV_YEAR} ||= $year;
+
+	$entry->{Maintainer} ||= 'unknown';
+	$entry->{Date} ||= 'unknown';
+	push @{$navigation{$year}{NAV_VERSIONS}},
+	       { NAV_VERSION_ID => __version2id($entry->{Version}),
+		 NAV_VERSION => $entry->{Version},
+		 NAV_MAINTAINER => $entry->{Maintainer},
+		 NAV_DATE => $entry->{Date} };
     }
-    print $fh $cgi->start_ul( { -class=>'outline' } );
+    my @nav_years;
     foreach my $y (reverse sort keys %navigation) {
-	print $fh $cgi->li(
-			   $cgi->a({ -href=>"#year$y" },$y).": ".
-			   $cgi->ul( $cgi->li( $navigation{$y} ) ) );
-    }
-    if ($self->{oldformat}) {
-	print $fh $cgi->li($cgi->a({ -href=>'#oldformat' }, 'old format'));
+	push @nav_years, $navigation{$y};
     }
-    print $fh $cgi->end_ul;
-	
-    print $fh $cgi->start_div({ -id=>'content'});
+    $template->param( OLDFORMAT => (($self->{oldformat}||'') ne ''),
+		      NAV_YEARS => \@nav_years );
+
+
+    my %years;
     $last_year = undef;
     foreach my $entry (@$data) {
 	my $year = $last_year; # try to deal gracefully with unparsable dates
@@ -491,29 +792,15 @@ sub html_out {
 	    $year = (gmtime($entry->{Parsed_Date}))[5] + 1900;
 	}
 	$year ||= (($entry->{Date} =~ /\s(\d{4})\s/) ? $1 : (gmtime)[5] + 1900);	
-
+	
 	if (!$last_year || ($year < $last_year)) {
-	    print $fh $cgi->h2( { -class=>'year_header',
-				  -id=>"year$year" }, $year );
 	    $last_year = $year;
 	}
 
-	my $pkg = $cgi->a({ -href=>"http://packages.debian.org/src:".
-				uri_escape($entry->{Source}),
-			    -class=>'packagelink' }, 
-			  $entry->{Source} );
-
-	print $fh $cgi->h3( { -class=>'entry_header',
-			      -id=>"version$entry->{Version}" },
-			    "$pkg ($entry->{Version}) ".
-			    $cgi->span( { -class=>$entry->{Distribution} },
-					$entry->{Distribution} ).
-			    "; urgency=".
-			    $cgi->span( { -class=>$entry->{Urgency_LC} },
-					$entry->{Urgency}.
-					$entry->{Urgency_Comment} ) );
-	
-	my $text = encode_entities( $entry->{Changes}, '<>&"' ) || "";
+	$years{$last_year}{CONTENT_VERSIONS} ||= [];
+	$years{$last_year}{CONTENT_YEAR} ||= $last_year;
+
+	my $text = encode_entities( $entry->{Changes}, '<>&"' ) || '';
 	$text=~ s|<URL:([-\w\.\/:~_\@]+):([a-zA-Z0-9\'() ]+)>
 	         |$cgi->a({ -href=>$1 }, $2)
 		 |xego;
@@ -556,48 +843,61 @@ sub html_out {
 	         |$cgi->a({ -href=>"http://www.debian.org/misc/bsd.license" }, $&)
 		 |xego;
 
-	print $fh $cgi->pre($text);
+	(my $maint_name = $entry->{Maintainer} ) =~ s|<([a-zA-Z0-9_\+\-\.]+\@([a-zA-Z0-9][\w\.+\-]+\.[a-zA-Z]{2,}))>||o;
+	my $maint_mail = $1;
+
+	my $parse_error;
+	$parse_error = $cgi->p( { -class=>'parse_error' },
+				"(There has been a parse error in the entry above, if some values don't make sense please check the original changelog)" ) if $entry->{ERROR};
+	
+	push @{$years{$last_year}{CONTENT_VERSIONS}}, {
+	    CONTENT_VERSION => $entry->{Version},
+	    CONTENT_VERSION_ID => __version2id($entry->{Version}),
+	    CONTENT_URGENCY => $entry->{Urgency}.$entry->{Urgency_Comment},
+	    CONTENT_URGENCY_NORM => $entry->{Urgency_LC},
+	    CONTENT_DISTRIBUTION => $entry->{Distribution},
+	    CONTENT_DISTRIBUTION_NORM => lc($entry->{Distribution}),
+	    CONTENT_SOURCE => $entry->{Source},
+	    CONTENT_CHANGES => $text,
+	    CONTENT_DATE => $entry->{Date},
+	    CONTENT_MAINTAINER_NAME => $maint_name,
+	    CONTENT_MAINTAINER_EMAIL => $maint_mail,
+	    CONTENT_PARSE_ERROR => $parse_error,
+	};
+	
+    }
+    my @content_years;
+    foreach my $y (reverse sort keys %years) {
+	push @content_years, $years{$y};
+    }
+    $template->param( OLDFORMAT_CHANGES => $self->{oldformat},
+		      CONTENT_YEARS => \@content_years );
+
+    my $html_str = $template->output;
 
-	my $maint = encode_entities( $entry->{Maintainer}, '<>&"' );
-	$maint =~ s|[a-zA-Z0-9_\+\-\.]+\@([a-zA-Z0-9][\w\.+\-]+\.[a-zA-Z]{2,})
-	           |$cgi->a({ -href=>"http://qa.debian.org/developer.php?login=$&" }, $&)
-		   |xego;
+    if ($config->{outfile}) {
+	open my $fh, '>', $config->{outfile} or return undef;
+	flock $fh, LOCK_EX or return undef;
 
-	print $fh $cgi->p( { -class=>'trailer' }, "  -- $maint $entry->{Date}" );
-	print $fh $cgi->p( { -class=>'parse_error' },
-			   "(There has been a parse error in the entry above, if some values don't make sense please check the original changelog)" ) if $entry->{ERROR};
+	print $fh $html_str;
 
+	close $fh or return undef;
     }
-    if ($self->{oldformat}) {
-	print $fh $cgi->h2({ -class=>'year_header', -id=>'oldformat' },
-			   'Old changelog format(s), not parsed' );
-	print $fh $cgi->pre({ -class=>'oldformat' },
-			    encode_entities( $self->{oldformat}, '<>&"' ) );
-    }
-    print $fh $cgi->end_div; # content
-    
-    print $fh $cgi->div({-class=>'footer'},
-			$cgi->hr({-class=>'hide'}).
-			$cgi->address(
-				      'Generated '.
-				      gmtime().
-				      ' UTC by '.
-				      $cgi->tt("$CLASSNAME (v$VERSION)").
-				      $cgi->br().
-				      'Contact '.
-				      $cgi->a({ -href=>'mailto:debian-www at lists.debian.org' },
-					      'debian-www at lists.debian.org' ).
-				      ' in case of problems.'
-				      ) );
-
-    print $fh $cgi->end_html;
-    close $fh or return undef;
 
-    return $self;
+    return $html_str;
+}
+
+sub html_str {
+    return html(@_);
 }
 
 1;
 __END__
+=head1 SEE ALSO
+
+Description of the Debian changelog format in the Debian policy:
+L<http://www.debian.org/doc/debian-policy/ch-source.html#s-dpkgchangelog>.
+
 =head1 AUTHOR
 
 Frank Lichtenheld, E<lt>frank at lichtenheld.deE<gt>
diff --git a/t/Parse-DebianChangelog.t b/t/Parse-DebianChangelog.t
index 1a46d28..12c6791 100644
--- a/t/Parse-DebianChangelog.t
+++ b/t/Parse-DebianChangelog.t
@@ -1,3 +1,4 @@
+# -*- perl -*-
 # Before `make install' is performed this script should be runnable with
 # `make test'. After `make install' it should work as `perl Parse-DebianChangelog.t'
 
@@ -5,12 +6,47 @@
 
 # change 'tests => 1' to 'tests => last_test_to_print';
 
-use Test::More tests => 2;
+use strict;
+use warnings;
+
+use File::Basename;
+
+use Test::More tests => 7;
 BEGIN { use_ok('Parse::DebianChangelog') };
 
 #########################
 
-my $changes = Parse::DebianChangelog->init( { infile => 'Changes' } );
-my $errors = $changes->get_parse_errors();
+foreach my $file (qw(Changes)) {
+
+    my $changes = Parse::DebianChangelog->init( { infile => $file } );
+    my $errors = $changes->get_parse_errors();
+    my $basename = basename( $file );
+    
+    ok( !$errors, "Parse example changelog $file without errors" );
+
+    $changes->html( { outfile => "t/$basename.html.tmp",
+		      template => 'tmpl/default.tmpl' } );
+
+    ok( !`tidy -qe t/$basename.html.tmp 2>&1`, 'Generated HTML has no tidy errors' );
+
+    unlink "t/$basename.html.tmp";
+
+    my $str = $changes->dpkg_str();
+
+    ok( $str eq `dpkg-parsechangelog -l$file 2>&1`, 'Output of dpkg_out equal to output of dpkg-parsechangelog' );
+
+    my $oldest_version = $changes->{data}[-1]{Version};
+
+    $str = $changes->dpkg_str({ since => $oldest_version });
+
+    ok( $str eq `dpkg-parsechangelog -v$oldest_version -l$file 2>&1`, 'Output of dpkg_out equal to output of dpkg-parsechangelog' );
+
+    $str = $changes->rfc822_str();
+
+    ok( 1 );
+
+    $str = $changes->rfc822_str({ since => $oldest_version });
+
+    ok( 1 );
+}
 
-ok( !$errors, 'Parse the own changelog without errors' );

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-perl/packages/libparse-debianchangelog-perl.git



More information about the Pkg-perl-cvs-commits mailing list