Debian.pm 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. # Copyright © 1996 Ian Jackson
  2. # Copyright © 2005 Frank Lichtenheld <frank@lichtenheld.de>
  3. # Copyright © 2009 Raphaël Hertzog <hertzog@debian.org>
  4. # Copyright © 2012-2015 Guillem Jover <guillem@debian.org>
  5. #
  6. # This program is free software; you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation; either version 2 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  18. =encoding utf8
  19. =head1 NAME
  20. Dpkg::Changelog::Debian - parse Debian changelogs
  21. =head1 DESCRIPTION
  22. Dpkg::Changelog::Debian parses Debian changelogs as described in the Debian
  23. policy (version 3.6.2.1 at the time of this writing). See section
  24. L<"SEE ALSO"> for locations where to find this definition.
  25. The parser tries to ignore most cruft like # or /* */ style comments,
  26. CVS comments, vim variables, emacs local variables and stuff from
  27. older changelogs with other formats at the end of the file.
  28. NOTE: most of these are ignored silently currently, there is no
  29. parser error issued for them. This should become configurable in the
  30. future.
  31. =cut
  32. package Dpkg::Changelog::Debian;
  33. use strict;
  34. use warnings;
  35. our $VERSION = '1.00';
  36. use Dpkg::Gettext;
  37. use Dpkg::File;
  38. use Dpkg::Changelog qw(:util);
  39. use Dpkg::Changelog::Entry::Debian qw(match_header match_trailer);
  40. use parent qw(Dpkg::Changelog);
  41. use constant {
  42. FIRST_HEADING => g_('first heading'),
  43. NEXT_OR_EOF => g_('next heading or end of file'),
  44. START_CHANGES => g_('start of change data'),
  45. CHANGES_OR_TRAILER => g_('more change data or trailer'),
  46. };
  47. my $ancient_delimiter_re = qr{
  48. ^
  49. (?: # Ancient GNU style changelog entry with expanded date
  50. (?:
  51. \w+\s+ # Day of week (abbreviated)
  52. \w+\s+ # Month name (abbreviated)
  53. \d{1,2} # Day of month
  54. \Q \E
  55. \d{1,2}:\d{1,2}:\d{1,2}\s+ # Time
  56. [\w\s]* # Timezone
  57. \d{4} # Year
  58. )
  59. \s+
  60. (?:.*) # Maintainer name
  61. \s+
  62. [<\(]
  63. (?:.*) # Maintainer email
  64. [\)>]
  65. | # Old GNU style changelog entry with expanded date
  66. (?:
  67. \w+\s+ # Day of week (abbreviated)
  68. \w+\s+ # Month name (abbreviated)
  69. \d{1,2},?\s* # Day of month
  70. \d{4} # Year
  71. )
  72. \s+
  73. (?:.*) # Maintainer name
  74. \s+
  75. [<\(]
  76. (?:.*) # Maintainer email
  77. [\)>]
  78. | # Ancient changelog header w/o key=value options
  79. (?:\w[-+0-9a-z.]*) # Package name
  80. \Q \E
  81. \(
  82. (?:[^\(\) \t]+) # Package version
  83. \)
  84. \;?
  85. | # Ancient changelog header
  86. (?:[\w.+-]+) # Package name
  87. [- ]
  88. (?:\S+) # Package version
  89. \ Debian
  90. \ (?:\S+) # Package revision
  91. |
  92. Changes\ from\ version\ (?:.*)\ to\ (?:.*):
  93. |
  94. Changes\ for\ [\w.+-]+-[\w.+-]+:?\s*$
  95. |
  96. Old\ Changelog:\s*$
  97. |
  98. (?:\d+:)?
  99. \w[\w.+~-]*:?
  100. \s*$
  101. )
  102. }xi;
  103. =head1 METHODS
  104. =over 4
  105. =item $c->parse($fh, $description)
  106. Read the filehandle and parse a Debian changelog in it. Returns the number
  107. of changelog entries that have been parsed with success.
  108. =cut
  109. sub parse {
  110. my ($self, $fh, $file) = @_;
  111. $file = $self->{reportfile} if exists $self->{reportfile};
  112. $self->reset_parse_errors;
  113. $self->{data} = [];
  114. $self->set_unparsed_tail(undef);
  115. my $expect = FIRST_HEADING;
  116. my $entry = Dpkg::Changelog::Entry::Debian->new();
  117. my @blanklines = ();
  118. my $unknowncounter = 1; # to make version unique, e.g. for using as id
  119. local $_;
  120. while (<$fh>) {
  121. chomp;
  122. if (match_header($_)) {
  123. unless ($expect eq FIRST_HEADING || $expect eq NEXT_OR_EOF) {
  124. $self->parse_error($file, $.,
  125. sprintf(g_('found start of entry where expected %s'),
  126. $expect), "$_");
  127. }
  128. unless ($entry->is_empty) {
  129. push @{$self->{data}}, $entry;
  130. $entry = Dpkg::Changelog::Entry::Debian->new();
  131. last if $self->abort_early();
  132. }
  133. $entry->set_part('header', $_);
  134. foreach my $error ($entry->check_header()) {
  135. $self->parse_error($file, $., $error, $_);
  136. }
  137. $expect= START_CHANGES;
  138. @blanklines = ();
  139. } elsif (m/^(?:;;\s*)?Local variables:/io) {
  140. last; # skip Emacs variables at end of file
  141. } elsif (m/^vim:/io) {
  142. last; # skip vim variables at end of file
  143. } elsif (m/^\$\w+:.*\$/o) {
  144. next; # skip stuff that look like a CVS keyword
  145. } elsif (m/^\# /o) {
  146. next; # skip comments, even that's not supported
  147. } elsif (m{^/\*.*\*/}o) {
  148. next; # more comments
  149. } elsif (m/$ancient_delimiter_re/) {
  150. # save entries on old changelog format verbatim
  151. # we assume the rest of the file will be in old format once we
  152. # hit it for the first time
  153. $self->set_unparsed_tail("$_\n" . file_slurp($fh));
  154. } elsif (m/^\S/) {
  155. $self->parse_error($file, $., g_('badly formatted heading line'), "$_");
  156. } elsif (match_trailer($_)) {
  157. unless ($expect eq CHANGES_OR_TRAILER) {
  158. $self->parse_error($file, $.,
  159. sprintf(g_('found trailer where expected %s'), $expect), "$_");
  160. }
  161. $entry->set_part('trailer', $_);
  162. $entry->extend_part('blank_after_changes', [ @blanklines ]);
  163. @blanklines = ();
  164. foreach my $error ($entry->check_trailer()) {
  165. $self->parse_error($file, $., $error, $_);
  166. }
  167. $expect = NEXT_OR_EOF;
  168. } elsif (m/^ \-\-/) {
  169. $self->parse_error($file, $., g_('badly formatted trailer line'), "$_");
  170. } elsif (m/^\s{2,}(?:\S)/) {
  171. unless ($expect eq START_CHANGES or $expect eq CHANGES_OR_TRAILER) {
  172. $self->parse_error($file, $., sprintf(g_('found change data' .
  173. ' where expected %s'), $expect), "$_");
  174. if ($expect eq NEXT_OR_EOF and not $entry->is_empty) {
  175. # lets assume we have missed the actual header line
  176. push @{$self->{data}}, $entry;
  177. $entry = Dpkg::Changelog::Entry::Debian->new();
  178. $entry->set_part('header', 'unknown (unknown' . ($unknowncounter++) . ') unknown; urgency=unknown');
  179. }
  180. }
  181. # Keep raw changes
  182. $entry->extend_part('changes', [ @blanklines, $_ ]);
  183. @blanklines = ();
  184. $expect = CHANGES_OR_TRAILER;
  185. } elsif (!m/\S/) {
  186. if ($expect eq START_CHANGES) {
  187. $entry->extend_part('blank_after_header', $_);
  188. next;
  189. } elsif ($expect eq NEXT_OR_EOF) {
  190. $entry->extend_part('blank_after_trailer', $_);
  191. next;
  192. } elsif ($expect ne CHANGES_OR_TRAILER) {
  193. $self->parse_error($file, $.,
  194. sprintf(g_('found blank line where expected %s'), $expect));
  195. }
  196. push @blanklines, $_;
  197. } else {
  198. $self->parse_error($file, $., g_('unrecognized line'), "$_");
  199. unless ($expect eq START_CHANGES or $expect eq CHANGES_OR_TRAILER) {
  200. # lets assume change data if we expected it
  201. $entry->extend_part('changes', [ @blanklines, $_]);
  202. @blanklines = ();
  203. $expect = CHANGES_OR_TRAILER;
  204. }
  205. }
  206. }
  207. unless ($expect eq NEXT_OR_EOF) {
  208. $self->parse_error($file, $.,
  209. sprintf(g_('found end of file where expected %s'),
  210. $expect));
  211. }
  212. unless ($entry->is_empty) {
  213. push @{$self->{data}}, $entry;
  214. }
  215. return scalar @{$self->{data}};
  216. }
  217. 1;
  218. __END__
  219. =back
  220. =head1 SEE ALSO
  221. Dpkg::Changelog
  222. Description of the Debian changelog format in the Debian policy:
  223. L<https://www.debian.org/doc/debian-policy/ch-source.html#s-dpkgchangelog>.
  224. =head1 CHANGES
  225. =head2 Version 1.00 (dpkg 1.15.6)
  226. Mark the module as public.
  227. =head1 AUTHORS
  228. Frank Lichtenheld, E<lt>frank@lichtenheld.deE<gt>
  229. Raphaël Hertzog, E<lt>hertzog@debian.orgE<gt>
  230. =cut