Debian.pm 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  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. The data in the
  106. object is reset before parsing new data.
  107. Returns the number 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->parse_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->parse_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 CHANGES
  221. =head2 Version 1.00 (dpkg 1.15.6)
  222. Mark the module as public.
  223. =head1 SEE ALSO
  224. Dpkg::Changelog
  225. =cut