Trying to fix unititalized split problem.
[maemian] / checks / debhelper
1 # debhelper format -- lintian check script -*- perl -*-
2
3 # Copyright (C) 1999 by Joey Hess
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program.  If not, you can find it on the World Wide
17 # Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free
18 # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
19 # MA 02110-1301, USA.
20
21 package Maemian::debhelper;
22 use strict;
23
24 use lib "$ENV{'MAEMIAN_ROOT'}/lib";
25 use Tags;
26 use Util;
27 use Maemian::Data;
28
29 # If there is no debian/compat file present but cdbs is being used, cdbs will
30 # create one automatically.  Currently it always uses compatibility level 5.
31 # It may be better to look at what version of cdbs the package depends on and
32 # from that derive the compatibility level....
33 my $cdbscompat = 5;
34
35 my $maint_commands = Maemian::Data->new ('debhelper/maint_commands');
36 my $miscDeps_commands = Maemian::Data->new ('debhelper/miscDepends_commands');
37 my $dh_commands_depends = Maemian::Data->new ('debhelper/dh_commands', '=');
38 my $filename_configs = Maemian::Data->new ('debhelper/filename-config-files');
39
40 # The version at which debhelper commands were introduced.  Packages that use
41 # one of these commands must have a dependency on that version of debhelper or
42 # newer.
43 my %versions
44     = (dh                 => '7',
45        dh_auto_configure  => '7',
46        dh_auto_build      => '7',
47        dh_auto_clean      => '7',
48        dh_auto_install    => '7',
49        dh_bugfiles        => '7.2.3~',
50        dh_icons           => '5.0.51~',
51        dh_installifupdown => '5.0.44~',
52        dh_lintian         => '6.0.7~',
53        dh_prep            => '7');
54
55 sub run {
56
57 my $pkg = shift;
58 my $type = shift;
59 my $info = shift;
60
61 my $seencommand = '';
62 my $needbuilddepends = '';
63 my $needtomodifyscripts = '';
64 my $level;
65 my $seenversiondepends = '0';
66 my $compat = 0;
67 my $usescdbs = '';
68 my $seendhpython = '';
69 my $usescdbspython = '';
70 my $seendhcleank = '';
71 my $needmiscdepends = 0;
72 my %missingbdeps;
73
74 open(RULES, '<', "debfiles/rules") or fail("cannot read debian/rules: $!");
75 my $dhcompatvalue;
76 my @versioncheck;
77 while (<RULES>) {
78     if (m/^\s+-?(dh_\w+)/) {
79         my $dhcommand = $1;
80         if ($dhcommand =~ /dh_testversion(?:\s+([^\s]+))?/) {
81             $level = $1 if ($1);
82             tag "dh_testversion-is-deprecated", "";
83         }
84         if ($dhcommand eq 'dh_dhelp') {
85             tag "dh_dhelp-is-deprecated", "";
86         }
87         if ($dhcommand eq 'dh_suidregister') {
88             tag "dh_suidregister-is-obsolete", "";
89         }
90         if ($dhcommand eq 'dh_clean' and m/\s+\-k(\s+.*)?$/) {
91             $seendhcleank = 1;
92         }
93         # if command is passed -n, it does not modify the scripts
94         if ($maint_commands->known($dhcommand) and not m/\s+\-n\s+/) {
95             $needtomodifyscripts = 1;
96         }
97         if ($miscDeps_commands->known($dhcommand)) {
98             $needmiscdepends = 1;
99         }
100         if ($dh_commands_depends->known($dhcommand)) {
101             my $dep = $dh_commands_depends->value($dhcommand);
102
103             # Special-case default-jdk-builddep.  It appears to be a sort of
104             # build-essential for Java applications.
105             if ($dhcommand eq 'dh_nativejava') {
106                 $dep = "$dep | default-jdk | default-jdk-builddep";
107             }
108             $missingbdeps{$dep} = $dhcommand;
109         }
110         if ($versions{$dhcommand}) {
111             push (@versioncheck, $dhcommand);
112         }
113         $seencommand = 1;
114         $needbuilddepends = 1;
115     } elsif (m,^\s+dh\s+,) {
116         $seencommand = 1;
117         $needbuilddepends = 1;
118         $needtomodifyscripts = 1;
119         $needmiscdepends = 1;
120         push (@versioncheck, 'dh');
121     } elsif (m,^include\s+/usr/share/cdbs/1/rules/debhelper.mk,) {
122         $seencommand = 1;
123         $needbuilddepends = 1;
124         $needtomodifyscripts = 1;
125         $needmiscdepends = 1;
126
127         # CDBS sets DH_COMPAT but doesn't export it.  It does, however, create
128         # a debian/compat file if none was found; that logic is handled later.
129         $dhcompatvalue = $cdbscompat;
130         $usescdbs = 1;
131     } elsif (/^\s*export\s+DH_COMPAT\s*:?=\s*([^\s]+)/) {
132         $level = $1;
133     } elsif (/^\s*export\s+DH_COMPAT/) {
134         $level = $dhcompatvalue if $dhcompatvalue;
135     } elsif (/^\s*DH_COMPAT\s*:?=\s*([^\s]+)/) {
136         $dhcompatvalue = $1;
137         # one can export and then set the value:
138         $level = $1 if ($level);
139     }
140     if (/^\s+dh_python\s/) {
141         $seendhpython = 1;
142     } elsif (m,^include\s+/usr/share/cdbs/1/class/python-distutils.mk,) {
143         $usescdbspython = 1;
144     }
145 }
146 close RULES;
147
148 return unless $seencommand;
149
150 my $pkgs = $info->binaries;
151 my $single_pkg = keys(%$pkgs) == 1 ? $pkgs->{(keys(%$pkgs))[0]} : '';
152
153 for my $binpkg (keys %$pkgs) {
154     my ($weak_depends, $strong_depends, $depends) = ('','','');
155
156     foreach my $field (qw(pre-depends depends)) {
157         $strong_depends .= $info->binary_field($binpkg, $field);
158     }
159     foreach my $field (qw(recommends suggests)) {
160         $weak_depends .= $info->binary_field($binpkg, $field);
161     }
162     $depends = $weak_depends . $strong_depends;
163
164     tag 'debhelper-but-no-misc-depends', $binpkg
165         if $needmiscdepends and $depends !~ m/\$\{misc:Depends\}/
166            and $pkgs->{$binpkg} eq 'deb';
167
168     tag 'weak-dependency-on-misc-depends', $binpkg
169         if $weak_depends =~ m/\$\{misc:Depends\}/
170            and $pkgs->{$binpkg} eq 'deb';
171 }
172
173 my $compatnan = 0;
174 # Check the compat file.  Do this separately from looping over all of the
175 # other files since we use the compat value when checking for brace expansion.
176 if (-f 'debfiles/compat') {
177     my $compat_file = slurp_entire_file('debfiles/compat');
178     ($compat) = split(/\n/, $compat_file);
179     $compat =~ s/^\s+$//;
180     if ($compat) {
181         chomp $compat;
182         if ($compat !~ m/^\d+$/) {
183             tag 'debhelper-compat-not-a-number', $compat;
184             $compat =~ s/[^\d]//g;
185             $compatnan = 1;
186         }
187         if ($level) {
188             tag 'declares-possibly-conflicting-debhelper-compat-versions',
189                 "rules=$level compat=$compat";
190         } else {
191             # this is not just to fill in the gap, but because debhelper
192             # prefers DH_COMPAT over debian/compat
193             $level = $compat;
194         }
195     } else {
196         tag 'debhelper-compat-file-is-empty';
197     }
198 }
199 if (defined($level) and $level !~ m/^\d+$/ and not $compatnan) {
200     tag 'debhelper-compatibility-level-not-a-number', $level;
201     $level =~ s/[^\d]//g;
202     $compatnan = 1;
203 }
204
205 if ($usescdbs and not defined($level)) {
206     $level = $cdbscompat;
207 }
208 $level ||= 1;
209 if ($level < 5) {
210     tag "package-uses-deprecated-debhelper-compat-version", $level;
211 }
212
213 if ($seendhcleank and $level >= 7) {
214     tag "dh-clean-k-is-deprecated";
215 }
216
217
218 # Check the files in the debian directory for various debhelper-related
219 # things.
220 opendir(DEBIAN, 'debfiles')
221     or fail("Can't open debfiles directory.");
222 while (defined(my $file=readdir(DEBIAN))) {
223     if ($file =~ m/^(?:(.*)\.)?(?:post|pre)(?:inst|rm)$/) {
224         next unless $needtomodifyscripts;
225
226         # They need to have #DEBHELPER# in their scripts.  Search for scripts
227         # that look like maintainer scripts and make sure the token is there.
228         my $binpkg = $1 || '';
229         open(IN, '<', "debfiles/$file")
230             or fail("Can't open debfiles/$file: $!");
231         my $seentag = '';
232         while (<IN>) {
233             if (m/\#DEBHELPER\#/) {
234                 $seentag = 1;
235                 last;
236             }
237         }
238         close IN;
239         if (!$seentag) {
240             unless (($binpkg && exists($pkgs->{$binpkg})
241                      && ($pkgs->{$binpkg} eq 'udeb'))
242                     or (!$binpkg && ($single_pkg eq 'udeb'))) {
243                 tag "maintainer-script-lacks-debhelper-token", "debian/$file";
244             }
245         }
246     } elsif ($file =~ m/^control$/) {
247         my $bdepends_noarch = $info->relation_noarch('build-depends-all');
248         my $bdepends = $info->relation('build-depends-all');
249         if ($needbuilddepends && ! $bdepends->implies('debhelper')) {
250             tag "package-uses-debhelper-but-lacks-build-depends", "";
251         }
252         while (my ($dep, $command) = each %missingbdeps) {
253             next if $dep eq 'debhelper'; #handled above
254             tag 'missing-build-dependency-for-dh_-command', "$command=$dep"
255                 unless ($bdepends_noarch->implies($dep));
256         }
257         my $needed = "debhelper (>= $level)";
258         if ($level > 5 && ! $bdepends->implies($needed)) {
259             tag "package-lacks-versioned-build-depends-on-debhelper", $level;
260         } elsif (@versioncheck) {
261             my %seen;
262             @versioncheck = grep { !$seen{$_}++ } @versioncheck;
263             for my $program (@versioncheck) {
264                 my $required = $versions{$program};
265                 my $needed = "debhelper (>= $required)";
266                 unless ($bdepends->implies($needed)) {
267                     tag 'debhelper-script-needs-versioned-build-depends',
268                         $program, "(>= $required)";
269                 }
270             }
271         }
272     } elsif ($file =~ m/^ex\.|\.ex$/i) {
273         tag "dh-make-template-in-source", "debian/$file";
274     } else {
275         my $base = $file;
276         $base =~ s/^[.]+\.//;
277
278         # Check whether this is a debhelper config file that takes a list of
279         # filenames.  If so, check it for brace expansions, which aren't
280         # supported.
281         if ($filename_configs->known($base)) {
282             next if $level < 3;
283             open (IN, '<', "debfiles/$file")
284                 or fail("Can't open debfiles/$file: $!");
285             local $_;
286             while (<IN>) {
287                 next if /^\s*$/;
288                 next if (/^\#/ and $level >= 5);
289                 if (m/(?<!\\)\{(?:[^\s\\\}]+?,)+[^\\\}\s]+\}/) {
290                     tag 'brace-expansion-in-debhelper-config-file',
291                         "debian/$file";
292                 }
293             }
294             close IN;
295         }
296     }
297 }
298 closedir(DEBIAN);
299
300 # Check for Python policy usage and the required debhelper dependency for
301 # dh_python policy support.  Assume people who intentionally set pycompat to
302 # something earlier than 2 know what they're doing.  Skip CDBS packages since
303 # CDBS creates pycompat internally at build time.
304 if ($seendhpython && !$usescdbspython) {
305     if (open(PYCOMPAT, '<', "debfiles/pycompat")) {
306         local $/;
307         my $pycompat = <PYCOMPAT>;
308         close PYCOMPAT;
309     } else {
310         tag "uses-dh-python-with-no-pycompat", "";
311     }
312 }
313
314 }
315
316 1;
317
318 # Local Variables:
319 # indent-tabs-mode: t
320 # cperl-indent-level: 4
321 # End:
322 # vim: syntax=perl sw=4 ts=8 noet shiftround