Added lots more modules from lintian. Maemian appears to work.
[maemian] / checks / control-file
diff --git a/checks/control-file b/checks/control-file
new file mode 100644 (file)
index 0000000..aa8ab0b
--- /dev/null
@@ -0,0 +1,246 @@
+# control-file -- lintian check script -*- perl -*-
+#
+# Copyright (C) 2004 Marc Brockschmidt
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, you can find it on the World Wide
+# Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+package Maemian::control_file;
+use strict;
+
+use lib "$ENV{'MAEMIAN_ROOT'}/checks/";
+use common_data;
+
+use Maemian::Relation ();
+use Tags;
+use Util;
+
+# The list of libc packages, used for checking for a hard-coded dependency
+# rather than using ${shlibs:Depends}.
+our @LIBCS = qw(libc6 libc6.1 libc0.1 libc0.3);
+
+sub run {
+
+my $pkg = shift;
+my $type = shift;
+
+if (-l "debfiles/control") {
+    tag "debian-control-file-is-a-symlink", "";
+}
+
+# check that control is UTF-8 encoded
+my $line = file_is_encoded_in_non_utf8("debfiles/control", $type, $pkg);
+if ($line) {
+    tag "debian-control-file-uses-obsolete-national-encoding", "at line $line"
+}
+
+# Check that each field is only used once:
+my $seen_fields = {};
+open (CONTROL, '<', "debfiles/control")
+    or fail "Couldn't read debfiles/control: $!";
+while (<CONTROL>) {
+       s/\s*\n$//;
+       next if /^\#/;
+
+       #Reset seen_fields if we enter a new section:
+       $seen_fields = {} if /^$/;
+
+       #line with field:
+       if (/^(\S+):/) {
+               my $field = lc ($1);
+               if ($seen_fields->{$field}) {
+                       tag "debian-control-with-duplicate-fields", "$field: $$seen_fields{$field}, $.";
+               }
+               $seen_fields->{$field} = $.;
+               if ($field =~ /^xs-vcs-/) {
+                       my $base = $field;
+                       $base =~ s/^xs-//;
+                       tag "xs-vcs-header-in-debian-control", "$field"
+                           if $known_source_fields{$base};
+               }
+               unless (/^\S+: \S/) {
+                       tag 'debian-control-has-unusual-field-spacing', "line $.";
+               }
+       }
+}
+close CONTROL;
+
+my ($header, @binary_controls) = read_dpkg_control("debfiles/control");
+
+for my $binary_control (@binary_controls) {
+       tag "build-info-in-binary-control-file-section", "Package ".$binary_control->{"package"}
+           if ($binary_control->{"build-depends"} || $binary_control->{"build-depends-indep"} ||
+               $binary_control->{"build-conflicts"} || $binary_control->{"build-conflicts-indep"});
+       for my $field (keys %$binary_control) {
+               tag 'binary-control-field-duplicates-source', "field \"$field\" in package ".$binary_control->{'package'},
+                   if ($header->{$field} && $binary_control->{$field} eq $header->{$field});
+       }
+
+       # If two substvars aren't separated by a comma, but at least one of
+       # them expands to an empty string, there will be a lurking bug.  The
+       # result will be syntactically correct, but as soon as both expand
+       # into something non-empty, there will be a syntax error.  Catch that
+       # mistake to avoid problems later.
+       #
+       # Only check the fields that use comma-separated values.
+       for my $field (qw(pre-depends depends recommends suggests breaks
+                         conflicts provides replaces enhances)) {
+               next unless $binary_control->{$field};
+               if ($binary_control->{$field} =~ /(\$\{\S+\})\s+[a-zA-Z0-9\$]/) {
+                       tag 'missing-comma-after-substvar', "in $field field near $1";
+               }
+       }
+}
+
+# Check if comma-separated values that span multiple lines omit commas as in
+# the following example:
+#   Depends: foo, bar
+#    baz
+for my $control ($header, @binary_controls) {
+       for my $field (qw(pre-depends depends recommends suggests breaks
+                         conflicts provides replaces enhances
+                         build-depends build-depends-indep
+                         build-conflics build-conflicts-indep)) {
+               next unless $control->{$field};
+               if ($control->{$field} =~ /
+                       ([^,]+)         # previous entry
+                       \s*\n\s+        # new line + space
+                       ([a-z][^,]+)    # next entry, must start with a letter
+                       /x) {
+
+                       my ($prev, $next) = ($1, $2);
+                       for ($prev, $next) {
+                               s/^\s+//; s/\s+$//;
+                       }
+                       tag "missing-comma-between-items",
+                           "in $field field between '$prev' and '$next', " .
+                           ($control->{source} ? 'source' : $control->{package});
+               }
+       }
+}
+
+# Make sure that a stronger dependency field doesn't imply any of the elements
+# of a weaker dependency field.  dpkg-gencontrol will fix this up for us, but
+# we want to check the source package since dpkg-gencontrol may silently "fix"
+# something that's a more subtle bug.
+#
+# Also check if a package declares a simple dependency on itself, since
+# similarly dpkg-gencontrol will clean this up for us but it may be a sign of
+# another problem, and check that the package doesn't hard-code a dependency
+# on libc.  We have to do the latter check here rather than in checks/fields
+# to distinguish from dependencies created by ${shlibs:Depends}.
+my @dep_fields = qw(pre-depends depends recommends suggests);
+my $libcs = Maemian::Relation->new(join(' | ', @LIBCS));
+for my $control (@binary_controls) {
+       for my $strong (0 .. $#dep_fields) {
+               next unless $control->{$dep_fields[$strong]};
+               my $relation = Maemian::Relation->new($control->{$dep_fields[$strong]});
+               tag "package-depends-on-itself", $control->{package}, $dep_fields[$strong]
+                   if $relation->implies($control->{package});
+               tag 'package-depends-on-hardcoded-libc', $control->{package}, $dep_fields[$strong]
+                   if ($relation->implies($libcs) and $pkg ne "glibc");
+               for my $weak (($strong + 1) .. $#dep_fields) {
+                       next unless $control->{$dep_fields[$weak]};
+                       for my $dependency (split /\s*,\s*/, $control->{$dep_fields[$weak]}) {
+                               next unless $dependency;
+                               tag "stronger-dependency-implies-weaker", $control->{package}, "$dep_fields[$strong] -> $dep_fields[$weak]", $dependency
+                                   if $relation->implies($dependency);
+                       }
+               }
+       }
+}
+
+# Check that every package is in the same archive area, except that
+# sources in main can deliver both main and contrib packages.  The source
+# package may or may not have a section specified; if it doesn't, derive the
+# expected archive area from the first binary package by leaving $area
+# undefined until parsing the first binary section.  Missing sections will be
+# caught by other checks.
+#
+# Also accumulate short and long descriptions for each package so that we can
+# check for duplication, but skip udeb packages.  Ideally, we should check the
+# udeb package descriptions separately for duplication, but udeb packages
+# should be able to duplicate the descriptions of non-udeb packages and the
+# package description for udebs is much less important or significant to the
+# user.
+my $area;
+if ($header->{'section'}) {
+       if ($header->{'section'} =~ m%^([^/]+)/%) {
+               $area = $1;
+       } else {
+               $area = '';
+       }
+} else {
+       tag "no-section-field-for-source", "";
+}
+my @descriptions;
+for my $binary_control (@binary_controls) {
+       if ($binary_control->{'description'}
+           and (not $binary_control->{'xc-package-type'}
+                or $binary_control->{'xc-package-type'} ne 'udeb')) {
+               push(@descriptions,
+                    [ $binary_control->{'package'},
+                      split("\n", $binary_control->{'description'}, 2) ]);
+       }
+       next unless $binary_control->{'section'};
+       if (!defined ($area)) {
+               if ($binary_control->{'section'} =~ m%^([^/]+)/%) {
+                       $area = ($1 eq 'contrib') ? '' : $1;
+               } else {
+                       $area = '';
+               }
+               next;
+       }
+       tag "section-area-mismatch", "Package " . $binary_control->{'package'}
+               if ($area && $binary_control->{'section'} !~ m%^$area/%);
+       tag "section-area-mismatch", "Package " . $binary_control->{'package'}
+               if (!$area && $binary_control->{'section'} =~ m%^([^/]+)/% && $1 ne 'contrib');
+}
+
+# Check for duplicate descriptions.
+my (%seen_short, %seen_long);
+for my $i (0 .. $#descriptions) {
+       my (@short, @long);
+       for my $j (($i + 1) .. $#descriptions) {
+               if ($descriptions[$i][1] eq $descriptions[$j][1]) {
+                       my $package = $descriptions[$j][0];
+                       push(@short, $package) unless $seen_short{$package};
+               }
+               next unless ($descriptions[$i][2] and $descriptions[$j][2]);
+               if ($descriptions[$i][2] eq $descriptions[$j][2]) {
+                       my $package = $descriptions[$j][0];
+                       push(@long, $package) unless $seen_long{$package};
+               }
+       }
+       if (@short) {
+               tag 'duplicate-short-description', $descriptions[$i][0], @short;
+               for (@short) { $seen_short{$_} = 1 }
+       }
+       if (@long) {
+               tag 'duplicate-long-description', $descriptions[$i][0], @long;
+               for (@long) { $seen_long{$_} = 1 }
+       }
+}
+
+}
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: t
+# cperl-indent-level: 8
+# End:
+# vim: syntax=perl sw=4 ts=4 noet shiftround