Added lots more modules from lintian. Maemian appears to work.
[maemian] / checks / patch-systems
1 # patch-systems -- lintian check script -*- perl -*-
2 #
3 # Copyright (C) 2007 Marc Brockschmidt
4 # Copyright (C) 2008 Raphael Hertzog
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, you can find it on the World Wide
18 # Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free
19 # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
20 # MA 02110-1301, USA.
21
22 package Maemian::patch_systems;
23 use strict;
24
25 use Tags;
26 use Util;
27
28 sub run {
29         my ($pkg, $type, $info) = @_;
30
31         unless (-d "fields") {
32         fail("directory in lintian laboratory for $type package $pkg missing: fields");
33         }
34
35         #Some (cruft) checks are valid for every patch system, so we need to record that:
36         my $uses_patch_system = 0;
37
38         #Get build deps so we can decide which build system the maintainer
39         #meant to use:
40         my $build_deps = $info->relation('build-depends-all');
41         # Get source package format
42         my $format = "";
43         if (defined $info->field('format')) {
44                 $format = $info->field('format');
45         }
46         my $quilt_format = ($format =~ /3\.\d+ \(quilt\)/) ? 1 : 0;
47
48         #----- dpatch
49         if ($build_deps->implies("dpatch")) {
50                 $uses_patch_system++;
51                 #check for a debian/patches file:
52                 if (! -r "debfiles/patches/00list") {
53                         tag "dpatch-build-dep-but-no-patch-list", $pkg;
54                 } else {
55                         my $list_uses_cpp = 0;
56                         if (open(OPTS, '<', "debfiles/patches/00options")) {
57                                 while(<OPTS>) {
58                                         if (/DPATCH_OPTION_CPP=1/) {
59                                                 $list_uses_cpp = 1;
60                                                 last;
61                                         }
62                                 }
63                                 close(OPTS);
64                         }
65                         foreach my $listfile (glob("debfiles/patches/00list*")) {
66                                 my @patches;
67                                 if (open(IN, '<', "$listfile")) {
68                                         while(<IN>) {
69                                                 chomp;
70                                                 next if (/^\#/); #ignore comments or CPP directive
71                                                 s%//.*%% if $list_uses_cpp; # remove C++ style comments
72                                                 if ($list_uses_cpp && m%/\*%) {
73                                                         # remove C style comments
74                                                         $_ .= <IN> while($_ !~ m%\*/%);
75                                                         s%/\*[^*]*\*/%%g;
76                                                 }
77                                                 next if (/^\s*$/); #ignore blank lines
78                                                 push @patches, split(' ', $_);
79                                         }
80                                         close(IN);
81                                 }
82
83                                 # Check each patch.
84                                 foreach my $patch_file (@patches) {
85                                         $patch_file .= ".dpatch" if -e "debfiles/patches/$patch_file.dpatch"
86                                                 and not -e "debfiles/patches/$patch_file";
87                                         if (! -r "debfiles/patches/$patch_file") {
88                                                 tag "dpatch-index-references-non-existent-patch", $patch_file;
89                                                 next;
90                                         }
91                                         if (open(PATCH_FILE, '<', "debfiles/patches/$patch_file")) {
92                                                 my $has_comment = 0;
93                                                 while (<PATCH_FILE>) {
94                                                         #stop if something looking like a patch starts:
95                                                         last if /^---/;
96                                                         #note comment if we find a proper one
97                                                         $has_comment = 1 if (/^\#+\s*DP:\s*(\S.*)$/ && $1 !~ /^no description\.?$/i)
98                                                 }
99                                                 close(PATCH_FILE);
100                                                 unless ($has_comment) {
101                                                         tag "dpatch-missing-description", $patch_file;
102                                                 }
103                                         }
104                                         check_patch($patch_file);
105                                 }
106                         }
107                 }
108         }
109
110         #----- quilt
111         if ($build_deps->implies("quilt") or $quilt_format) {
112                 $uses_patch_system++;
113                 #check for a debian/patches file:
114                 if (! -r "debfiles/patches/series") {
115                         tag "quilt-build-dep-but-no-series-file", $pkg unless $quilt_format;
116                 } else {
117                         if (open(IN, '<', "debfiles/patches/series")) {
118                                 my @patches;
119                                 my @badopts;
120                                 while(<IN>) {
121                                         chomp; s/^\s+//; s/\s+$//; # Strip leading/trailing spaces
122                                         s/(^|\s+)#.*$//; # Strip comment
123                                         next unless $_;
124                                         if (/^(\S+)\s+(\S.*)$/) {
125                                                 $_ = $1;
126                                                 if ($2 ne '-p1') {
127                                                         push @badopts, $_;
128                                                 }
129                                         }
130                                         push @patches, $_;
131                                 }
132                                 close(IN);
133                                 if (scalar(@badopts)) {
134                                         tag "quilt-patch-with-non-standard-options", @badopts;
135                                 }
136
137                                 # Check each patch.
138                                 foreach my $patch_file (@patches) {
139                                         if (! -r "debfiles/patches/$patch_file") {
140                                                 tag "quilt-series-references-non-existent-patch", $patch_file;
141                                                 next;
142                                         }
143                                         if (open(PATCH_FILE, '<', "debfiles/patches/$patch_file")) {
144                                                 my $has_description = 0;
145                                                 while (<PATCH_FILE>) {
146                                                         # stop if something looking like a patch starts:
147                                                         last if /^---/;
148                                                         next if /^\s*$/;
149                                                         # Skip common "lead-in" lines
150                                                         $has_description = 1 unless (/^(Index: |=+$|diff .+)/);
151                                                 }
152                                                 close(PATCH_FILE);
153                                                 unless ($has_description) {
154                                                         tag "quilt-patch-missing-description", $patch_file;
155                                                 }
156                                         }
157                                         check_patch($patch_file);
158                                 }
159                         }
160                 }
161         } else {
162                 if (-r "debfiles/patches/series" and
163                     -f "debfiles/patches/series") {
164                         # 3.0 (quilt) sources don't need quilt as dpkg-source will do the work
165                         tag "quilt-series-but-no-build-dep" unless $quilt_format;
166                 }
167         }
168
169
170         #----- general cruft checking:
171         if ($uses_patch_system > 1) {
172                 tag "more-than-one-patch-system";
173         }
174         my @direct;
175         open(STAT, '<', "diffstat") or fail("cannot open diffstat file: $!");
176         while (<STAT>) {
177                 my ($file) = (m,^\s+(.*?)\s+\|,)
178                      or fail("syntax error in diffstat file: $_");
179                 push (@direct, $file) if ($file !~ m,^debian/,);
180         }
181         close (STAT) or fail("error reading diffstat file: $!");
182         if (@direct) {
183                 my $files = (@direct > 1) ? "$direct[0] and $#direct more" : $direct[0];
184
185                 tag "patch-system-but-direct-changes-in-diff", $files
186                         if ($uses_patch_system);
187                 tag "direct-changes-in-diff-but-no-patch-system", $files
188                         if (not $uses_patch_system);
189         }
190 }
191
192 # Checks on patches common to all build systems
193 sub check_patch($) {
194         my $patch_file = shift;
195         open(DIFFSTAT, "-|", "diffstat -p0 -l debfiles/patches/$patch_file")
196           or fail("can't fork diffstat");
197         while (<DIFFSTAT>) {
198                 chomp;
199                 if (m|^(\./)?debian/| or m|^(\./)?[^/]+/debian/|) {
200                         tag "patch-modifying-debian-files", $patch_file, $_;
201                 }
202         }
203         close(DIFFSTAT) or fail("cannot close pipe to diffstat on $patch_file: $!");
204 }
205
206 1;
207
208 # Local Variables:
209 # indent-tabs-mode: t
210 # cperl-indent-level: 8
211 # End:
212 # vim: syntax=perl sw=4 ts=4 noet shiftround