OLD | NEW |
(Empty) | |
| 1 # Copyright © 2005, 2007 Frank Lichtenheld <frank@lichtenheld.de> |
| 2 # Copyright © 2009 Raphaël Hertzog <hertzog@debian.org> |
| 3 # |
| 4 # This program is free software; you can redistribute it and/or modify |
| 5 # it under the terms of the GNU General Public License as published by |
| 6 # the Free Software Foundation; either version 2 of the License, or |
| 7 # (at your option) any later version. |
| 8 # |
| 9 # This program is distributed in the hope that it will be useful, |
| 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 12 # GNU General Public License for more details. |
| 13 # |
| 14 # You should have received a copy of the GNU General Public License |
| 15 # along with this program. If not, see <https://www.gnu.org/licenses/>. |
| 16 |
| 17 =encoding utf8 |
| 18 |
| 19 =head1 NAME |
| 20 |
| 21 Dpkg::Changelog::Parse - generic changelog parser for dpkg-parsechangelog |
| 22 |
| 23 =head1 DESCRIPTION |
| 24 |
| 25 This module provides a single function changelog_parse() which reproduces |
| 26 all the features of dpkg-parsechangelog. |
| 27 |
| 28 =head2 FUNCTIONS |
| 29 |
| 30 =cut |
| 31 |
| 32 package Dpkg::Changelog::Parse; |
| 33 |
| 34 use strict; |
| 35 use warnings; |
| 36 |
| 37 our $VERSION = '1.00'; |
| 38 |
| 39 use Dpkg (); |
| 40 use Dpkg::Gettext; |
| 41 use Dpkg::ErrorHandling; |
| 42 use Dpkg::Control::Changelog; |
| 43 |
| 44 use Exporter qw(import); |
| 45 our @EXPORT = qw(changelog_parse); |
| 46 |
| 47 =over 4 |
| 48 |
| 49 =item my $fields = changelog_parse(%opt) |
| 50 |
| 51 This function will parse a changelog. In list context, it return as many |
| 52 Dpkg::Control object as the parser did output. In scalar context, it will |
| 53 return only the first one. If the parser didn't return any data, it will |
| 54 return an empty in list context or undef on scalar context. If the parser |
| 55 failed, it will die. |
| 56 |
| 57 The parsing itself is done by an external program (searched in the |
| 58 following list of directories: $opt{libdir}, |
| 59 F</usr/local/lib/dpkg/parsechangelog>, F</usr/lib/dpkg/parsechangelog>) That |
| 60 program is named according to the format that it's able to parse. By |
| 61 default it's either "debian" or the format name lookep up in the 40 last |
| 62 lines of the changelog itself (extracted with this perl regular expression |
| 63 "\schangelog-format:\s+([0-9a-z]+)\W"). But it can be overridden |
| 64 with $opt{changelogformat}. The program expects the content of the |
| 65 changelog file on its standard input. |
| 66 |
| 67 The changelog file that is parsed is F<debian/changelog> by default but it |
| 68 can be overridden with $opt{file}. |
| 69 |
| 70 All the other keys in %opt are forwarded as parameter to the external |
| 71 parser. If the key starts with "-", it's passed as is. If not, it's passed |
| 72 as "--<key>". If the value of the corresponding hash entry is defined, then |
| 73 it's passed as the parameter that follows. |
| 74 |
| 75 =cut |
| 76 |
| 77 sub changelog_parse { |
| 78 my (%options) = @_; |
| 79 my @parserpath = ('/usr/local/lib/dpkg/parsechangelog', |
| 80 "$Dpkg::LIBDIR/parsechangelog", |
| 81 '/usr/lib/dpkg/parsechangelog'); |
| 82 my $format = 'debian'; |
| 83 my $force = 0; |
| 84 |
| 85 # Extract and remove options that do not concern the changelog parser |
| 86 # itself (and that we shouldn't forward) |
| 87 if (exists $options{libdir}) { |
| 88 unshift @parserpath, $options{libdir}; |
| 89 delete $options{libdir}; |
| 90 } |
| 91 if (exists $options{changelogformat}) { |
| 92 $format = $options{changelogformat}; |
| 93 delete $options{changelogformat}; |
| 94 $force = 1; |
| 95 } |
| 96 |
| 97 # Set a default filename |
| 98 if (not exists $options{file}) { |
| 99 $options{file} = 'debian/changelog'; |
| 100 } |
| 101 my $changelogfile = $options{file}; |
| 102 |
| 103 # Extract the format from the changelog file if possible |
| 104 unless($force or ($changelogfile eq '-')) { |
| 105 open(my $format_fh, '-|', 'tail', '-n', '40', $changelogfile) |
| 106 or syserr(_g('cannot create pipe for %s'), 'tail'); |
| 107 while (<$format_fh>) { |
| 108 $format = $1 if m/\schangelog-format:\s+([0-9a-z]+)\W/; |
| 109 } |
| 110 close($format_fh) or subprocerr(_g('tail of %s'), $changelogfile); |
| 111 } |
| 112 |
| 113 # Find the right changelog parser |
| 114 my $parser; |
| 115 foreach my $dir (@parserpath) { |
| 116 my $candidate = "$dir/$format"; |
| 117 next if not -e $candidate; |
| 118 if (-x _) { |
| 119 $parser = $candidate; |
| 120 last; |
| 121 } else { |
| 122 warning(_g('format parser %s not executable'), $candidate); |
| 123 } |
| 124 } |
| 125 error(_g('changelog format %s is unknown'), $format) if not defined $parser; |
| 126 |
| 127 # Create the arguments for the changelog parser |
| 128 my @exec = ($parser, "-l$changelogfile"); |
| 129 foreach (keys %options) { |
| 130 if (m/^-/) { |
| 131 # Options passed untouched |
| 132 push @exec, $_; |
| 133 } else { |
| 134 # Non-options are mapped to long options |
| 135 push @exec, "--$_"; |
| 136 } |
| 137 push @exec, $options{$_} if defined($options{$_}); |
| 138 } |
| 139 |
| 140 # Fork and call the parser |
| 141 my $pid = open(my $parser_fh, '-|'); |
| 142 syserr(_g('cannot fork for %s'), $parser) unless defined $pid; |
| 143 if (not $pid) { |
| 144 exec(@exec) or syserr(_g('cannot exec format parser: %s'), $parser); |
| 145 } |
| 146 |
| 147 # Get the output into several Dpkg::Control objects |
| 148 my (@res, $fields); |
| 149 while (1) { |
| 150 $fields = Dpkg::Control::Changelog->new(); |
| 151 last unless $fields->parse($parser_fh, _g('output of changelog parser'))
; |
| 152 push @res, $fields; |
| 153 } |
| 154 close($parser_fh) or subprocerr(_g('changelog parser %s'), $parser); |
| 155 if (wantarray) { |
| 156 return @res; |
| 157 } else { |
| 158 return $res[0] if (@res); |
| 159 return; |
| 160 } |
| 161 } |
| 162 |
| 163 =back |
| 164 |
| 165 =cut |
| 166 |
| 167 1; |
OLD | NEW |