Debian.pm 7.8 KB

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