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