[lintian] 07/07: Add support for passing .buildinfo files to Lintian. (Closes: #853274)
This is an automated email from the git hooks/post-receive script.
lamby pushed a commit to branch master
in repository lintian.
commit 459ff1784653250fdbd1fd1802a0e9667bec68fd
Author: Chris Lamb <lamby@debian.org>
Date: Mon Jan 29 10:08:04 2018 +0000
Add support for passing .buildinfo files to Lintian. (Closes: #853274)
---
README.md | 4 +-
commands/lintian.pm | 8 +-
debian/changelog | 4 +
lib/Lintian/Collect.pm | 3 +
lib/Lintian/Collect/Buildinfo.pm | 189 +++++++++++++++++++++++++++++++++++++
lib/Lintian/Lab.pm | 1 +
lib/Lintian/Lab/Manifest.pm | 12 +++
lib/Lintian/Processable/Package.pm | 8 +-
lib/Lintian/ProcessableGroup.pm | 73 ++++++++------
lib/Lintian/ProcessablePool.pm | 28 ++++--
t/scripts/Lintian/Lab/repair.t | 2 +-
11 files changed, 284 insertions(+), 48 deletions(-)
diff --git a/README.md b/README.md
index 2d6c7b8..7184412 100644
--- a/README.md
+++ b/README.md
@@ -4,8 +4,8 @@ Lintian - Static Debian package analysis tool
Lintian is a static analysis tool for finding many bugs, policy
violations and other issues in Debian based packages. It can process
binary Debian packages (.deb), micro/installer packages (.udeb),
-Debian source packages (.dsc) and (to a limited degree) the "changes"
-files.
+Debian source packages (.dsc) and (to a limited degree) the "buildinfo"
+and "changes" files.
Running Lintian
diff --git a/commands/lintian.pm b/commands/lintian.pm
index 0c80a6f..9f2a838 100755
--- a/commands/lintian.pm
+++ b/commands/lintian.pm
@@ -1508,17 +1508,15 @@ sub setup_work_pool {
for my $arg (@ARGV) {
# file?
if (-f $arg) {
- if ($arg =~ m/\.(?:u?deb|dsc|changes)$/o){
+ if ($arg =~ m/\.(?:u?deb|dsc|changes|buildinfo)$/o){
eval {$pool->add_file($arg);};
if ($@) {
print STDERR "Skipping $arg: $@";
$exit_code = 2;
}
} else {
- fatal_error(
- join(q{ },
- "bad package file name $arg",
- '(neither .deb, .udeb, .changes or .dsc file)'));
+ fatal_error("bad package file name $arg (neither .deb, "
+ . '.udeb, .changes .dsc or .buildinfo file)');
}
} else {
# parameter is a package name--so look it up
diff --git a/debian/changelog b/debian/changelog
index bb301ed..e9c825c 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -43,6 +43,10 @@ lintian (2.5.73) UNRELEASED; urgency=medium
+ [CL] Detect "backports" (and "backport") as overly generic Python
module names. (Closes: #888559)
+ * lib/Lintian/*:
+ + [CL] Add support for passing .buildinfo files to Lintian.
+ (Closes: #853274)
+
-- Chris Lamb <lamby@debian.org> Fri, 26 Jan 2018 16:33:51 +1100
lintian (2.5.72) unstable; urgency=medium
diff --git a/lib/Lintian/Collect.pm b/lib/Lintian/Collect.pm
index b1a4e30..60bc49d 100644
--- a/lib/Lintian/Collect.pm
+++ b/lib/Lintian/Collect.pm
@@ -87,6 +87,9 @@ sub new {
} elsif ($type eq 'binary' or $type eq 'udeb') {
require Lintian::Collect::Binary;
$object = Lintian::Collect::Binary->new($pkg);
+ } elsif ($type eq 'buildinfo') {
+ require Lintian::Collect::Buildinfo;
+ $object = Lintian::Collect::Buildinfo->new($pkg);
} elsif ($type eq 'changes') {
require Lintian::Collect::Changes;
$object = Lintian::Collect::Changes->new($pkg);
diff --git a/lib/Lintian/Collect/Buildinfo.pm b/lib/Lintian/Collect/Buildinfo.pm
new file mode 100644
index 0000000..6b2b399
--- /dev/null
+++ b/lib/Lintian/Collect/Buildinfo.pm
@@ -0,0 +1,189 @@
+# -*- perl -*-
+# Lintian::Collect::Buildinfo -- interface to .buildinfo file data collection
+
+# Copyright (C) 2018 Chris Lamb
+#
+# 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, see <http://www.gnu.org/licenses/>.
+
+package Lintian::Collect::Buildinfo;
+
+use strict;
+use warnings;
+use parent 'Lintian::Collect';
+
+use Lintian::Util qw(strip);
+
+=head1 NAME
+
+Lintian::Collect::Buildinfo - Lintian interface to .buildinfo file data collection
+
+=head1 SYNOPSIS
+
+ my ($name, $type) = ('foobar_1.2_i386.buildinfo', 'changes');
+ my $collect = Lintian::Collect->new($name, $type);
+ my $files = $collect->files;
+
+ foreach my $file (keys %{$files}) {
+ my $size = $files->{$file}{size};
+ print "File $file has size $size\n";
+ }
+
+=head1 DESCRIPTION
+
+Lintian::Collect::Buildinfo provides an interface to data for .buildinfo
+files. It implements data collection methods specific to .buildinfo
+files.
+
+=head1 CLASS METHODS
+
+=over 4
+
+=item new (PACKAGE)
+
+Creates a new Lintian::Collect::Buildinfo object. Currently, PACKAGE is
+ignored. Normally, this method should not be called directly, only via
+the L<Lintian::Collect> constructor.
+
+=cut
+
+# Initialize a new .buildinfo file collect object. Takes the package name,
+# which is currently unused.
+sub new {
+ my ($class, $pkg) = @_;
+ my $self = {};
+ bless($self, $class);
+ return $self;
+}
+
+=back
+
+=head1 INSTANCE METHODS
+
+In addition to the instance methods listed below, all instance methods
+documented in the L<Lintian::Collect> module are also available.
+
+=over 4
+
+=item files
+
+Returns a reference to a hash containing information about files listed
+in the .buildinfo file. Each hash may have the following keys:
+
+=over 4
+
+=item name
+
+Name of the file.
+
+=item size
+
+The size of the file in bytes.
+
+=item section
+
+The archive section to which the file belongs.
+
+=item priority
+
+The priority of the file.
+
+=item checksums
+
+A hash with the keys being checksum algorithms and the values themselves being
+hashes containing
+
+=over 4
+
+=item sum
+
+The result of applying the given algorithm to the file.
+
+=item filesize
+
+The size of the file as given in the .buildinfo section relating to the given
+checksum.
+
+=back
+
+=back
+
+Needs-Info requirements for using I<files>: L<Lintian::Collect/field ([FIELD[, DEFAULT]])>
+
+=cut
+
+sub files {
+ my ($self) = @_;
+
+ return $self->{files} if exists $self->{files};
+
+ my %files;
+
+ my $file_list = $self->field('files') || '';
+ local $_;
+ for (split /\n/, $file_list) {
+ strip;
+ next if $_ eq '';
+
+ my ($md5sum,$size,$section,$priority,$file) = split(/\s+/o, $_);
+ next if $file =~ m,/,;
+
+ $files{$file}{checksums}{md5} = {
+ 'sum' => $md5sum,
+ 'filesize' => $size,
+ };
+ $files{$file}{name} = $file;
+ $files{$file}{size} = $size;
+ $files{$file}{section} = $section;
+ $files{$file}{priority} = $priority;
+ }
+
+ foreach my $alg (qw(sha1 sha256)) {
+ my $list = $self->field("checksums-$alg") || '';
+ for (split /\n/, $list) {
+ strip;
+ next if $_ eq '';
+
+ my ($checksum, $size, $file) = split(/\s+/o, $_);
+ next if $file =~ m,/,;
+
+ $files{$file}{checksums}{$alg} = {
+ 'sum' => $checksum,
+ 'filesize' => $size
+ };
+ }
+ }
+
+ $self->{files} = \%files;
+ return $self->{files};
+}
+
+=back
+
+=head1 AUTHOR
+
+Originally written by Adam D. Barratt <adsb@debian.org> for Lintian.
+
+=head1 SEE ALSO
+
+lintian(1), L<Lintian::Collect>
+
+=cut
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et
diff --git a/lib/Lintian/Lab.pm b/lib/Lintian/Lab.pm
index d2a798e..0c3c120 100644
--- a/lib/Lintian/Lab.pm
+++ b/lib/Lintian/Lab.pm
@@ -44,6 +44,7 @@ use constant {
# A private table of supported types.
my %SUPPORTED_TYPES = (
'binary' => 1,
+ 'buildinfo' => 1,
'changes' => 1,
'source' => 1,
'udeb' => 1,
diff --git a/lib/Lintian/Lab/Manifest.pm b/lib/Lintian/Lab/Manifest.pm
index 4a44c67e..d01dbc1 100644
--- a/lib/Lintian/Lab/Manifest.pm
+++ b/lib/Lintian/Lab/Manifest.pm
@@ -77,6 +77,8 @@ use constant BINLIST_FORMAT =>
q{Lintian's list of binary packages in the archive--V5};
use constant SRCLIST_FORMAT =>
q{Lintian's list of source packages in the archive--V5};
+use constant BLDLIST_FORMAT =>
+ q{Lintian's list of buildinfo packages in the archive--V1};
use constant CHGLIST_FORMAT =>
q{Lintian's list of changes packages in the archive--V1};
@@ -95,6 +97,9 @@ my @BIN_FILE_FIELDS = (
'architecture','file','timestamp','area',
);
+# buildinfo packages lists
+my @BLD_FILE_FIELDS = ('source','version','architecture','file','timestamp',);
+
# changes packages lists
my @CHG_FILE_FIELDS = ('source','version','architecture','file','timestamp',);
@@ -107,6 +112,8 @@ my @GROUP_QUERY = ('source','version','identifier',);
my @BIN_QUERY = ('package','version','architecture',);
+my @BLD_QUERY = ('source','version','architecture',);
+
my @CHG_QUERY = ('source','version','architecture',);
my %TYPE2INFO = (
@@ -120,6 +127,11 @@ my %TYPE2INFO = (
'file-header' => BINLIST_FORMAT,
'query-fields' => \@BIN_QUERY
},
+ 'buildinfo' => {
+ 'file-fields' => \@BLD_FILE_FIELDS,
+ 'file-header' => BLDLIST_FORMAT,
+ 'query-fields' => \@BLD_QUERY
+ },
'changes' => {
'file-fields' => \@CHG_FILE_FIELDS,
'file-header' => CHGLIST_FORMAT,
diff --git a/lib/Lintian/Processable/Package.pm b/lib/Lintian/Processable/Package.pm
index 6c9bd77..4dcb7ce 100644
--- a/lib/Lintian/Processable/Package.pm
+++ b/lib/Lintian/Processable/Package.pm
@@ -16,7 +16,7 @@
# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
# MA 02110-1301, USA.
-## Represents something Lintian can process (e.g. a deb, dsc or a changes)
+## Represents something Lintian can process (e.g. a deb, dsc, buildinfo or a changes)
package Lintian::Processable::Package;
use parent qw(Lintian::Processable Class::Accessor::Fast);
@@ -144,13 +144,13 @@ sub new {
$self->{pkg_src} = $pkg_name; # it is own source pkg
$self->{pkg_src_version} = $pkg_version;
$self->{'extra-fields'} = $dinfo;
- } elsif ($pkg_type eq 'changes'){
+ } elsif ($pkg_type eq 'buildinfo' or $pkg_type eq 'changes'){
my $cinfo = get_dsc_info($pkg_path)
- or croak "$pkg_path is not a valid changes file";
+ or croak "$pkg_path is not a valid $pkg_type file";
my $pkg_version = $cinfo->{version};
my $pkg_name = $cinfo->{source}//'';
unless ($pkg_name) {
- $pkg_name = _derive_name($pkg_path, 'changes')
+ $pkg_name = _derive_name($pkg_path, $pkg_type)
or croak "Cannot determine the name of $pkg_path";
}
$self->{pkg_name} = $pkg_name;
diff --git a/lib/Lintian/ProcessableGroup.pm b/lib/Lintian/ProcessableGroup.pm
index 1eab039..8732374 100644
--- a/lib/Lintian/ProcessableGroup.pm
+++ b/lib/Lintian/ProcessableGroup.pm
@@ -45,16 +45,17 @@ Lintian::ProcessableGroup -- A group of objects that Lintian can process
Instances of this perl class are sets of
L<processables|Lintian::Processable>. It allows at most one source
-and one changes package per set, but multiple binary packages
+and one changes or buildinfo package per set, but multiple binary packages
(provided that the binary is not already in the set).
=head1 METHODS
=over 4
-=item Lintian::ProcessableGroup->new ([LAB[, CHANGES]])
+=item Lintian::ProcessableGroup->new ([LAB[, FILE]])
-Creates a group and optionally add all processables from CHANGES.
+Creates a group and optionally add all processables from .changes
+or .buildinfo file FILE.
If the LAB parameter is given, all processables added to this group
will be stored as a L<lab entry|Lintian::Lab::Entry> from LAB.
@@ -62,11 +63,12 @@ will be stored as a L<lab entry|Lintian::Lab::Entry> from LAB.
=cut
sub new {
- my ($class, $lab, $changes) = @_;
+ my ($class, $lab, $file) = @_;
my $self = {'lab' => $lab,};
bless $self, $class;
- $self->_init_group_from_changes($changes)
- if defined $changes;
+ if (defined $file and $file =~ m/\.(buildinfo|changes)$/) {
+ $self->_init_group_from_file($1, $file);
+ }
return $self;
}
@@ -81,42 +83,43 @@ sub _lab_proc {
}
# Internal initialization sub
-# populates $self from a changes file.
-sub _init_group_from_changes {
- my ($self, $changes) = @_;
- my ($cinfo, $cdir);
- internal_error("$changes does not exist") unless -e $changes;
- $cinfo = get_dsc_info($changes)
- or internal_error("$changes is not a valid changes file");
- $self->add_new_processable($changes, 'changes');
- $cdir = $changes;
- if ($changes =~ m,^/+[^/]++$,o){
+# populates $self from a buildinfo or changes file.
+sub _init_group_from_file {
+ my ($self, $type, $filename) = @_;
+ my ($info, $dir);
+ internal_error("$filename does not exist") unless -e $filename;
+ $info = get_dsc_info($filename)
+ or internal_error("$filename is not a valid $type file");
+ $self->add_new_processable($filename, $type);
+ $dir = $filename;
+ if ($filename =~ m,^/+[^/]++$,o){
# it is "/files.changes?"
# - In case you were wondering, we were told not to ask :)
# See #624149
- $cdir = '/';
+ $dir = '/';
} else {
# it is "<something>/files.changes"
- $cdir =~ s,(.+)/[^/]+$,$1,;
+ $dir =~ s,(.+)/[^/]+$,$1,;
}
- for my $line (split(/\n/o, $cinfo->{'files'}//'')) {
+ my $key = $type eq 'buildinfo' ? 'checksums-sha256' : 'files';
+ for my $line (split(/\n/o, $info->{$key}//'')) {
my ($file);
next unless defined $line;
strip($line);
next if $line eq '';
# Ignore files that may lead to path traversal issues.
- # We do not need (in order) md5sum, size, section or priority
+ # We do not need (eg.) md5sum, size, section or priority
# - just the file name please.
- (undef, undef, undef, undef, $file) = split(/\s+/o, $line);
+ $file = (split(/\s+/o, $line))[-1];
# If the field is malformed, $file may be undefined; we also
# skip it, if it contains a "/" since that is most likely a
# traversal attempt
next if !$file || $file =~ m,/,o;
- if (not -f "$cdir/$file") {
- print STDERR "$cdir/$file does not exist, exiting\n";
+ if (not -f "$dir/$file") {
+ print STDERR "$dir/$file does not exist, exiting\n";
exit 2;
}
@@ -125,7 +128,7 @@ sub _init_group_from_changes {
next;
}
- $self->add_new_processable("$cdir/$file");
+ $self->add_new_processable("$dir/$file");
}
return 1;
@@ -165,10 +168,10 @@ sub add_processable{
my ($self, $processable) = @_;
my $pkg_type = $processable->pkg_type;
- if ($pkg_type eq 'changes'){
- internal_error('Cannot add another changes file')
- if (exists $self->{changes});
- $self->{changes} = $self->_lab_proc($processable);
+ if ($pkg_type eq 'changes' or $pkg_type eq 'buildinfo'){
+ internal_error("Cannot add another $pkg_type file")
+ if (exists $self->{$pkg_type});
+ $self->{$pkg_type} = $self->_lab_proc($processable);
} elsif ($pkg_type eq 'source'){
internal_error('Cannot add another source package')
if (exists $self->{source});
@@ -264,6 +267,20 @@ sub get_source_processable {
return $self->{source};
}
+=item $group->get_buildinfo_processable
+
+Returns the processable identified as the "buildinfo" processable (e.g.
+the buildinfo file).
+
+If $group does not have a buildinfo processable, this method returns C<undef>.
+
+=cut
+
+sub get_buildinfo_processable {
+ my ($self) = @_;
+ return $self->{buildinfo};
+}
+
=item $group->get_changes_processable
Returns the processable identified as the "changes" processable (e.g.
diff --git a/lib/Lintian/ProcessablePool.pm b/lib/Lintian/ProcessablePool.pm
index b11bf73..2917e62 100644
--- a/lib/Lintian/ProcessablePool.pm
+++ b/lib/Lintian/ProcessablePool.pm
@@ -42,6 +42,7 @@ Lintian::ProcessablePool -- Pool of processables
$pool->add_file('foo.changes');
$pool->add_file('bar.dsc');
$pool->add_file('baz.deb');
+ $pool->add_file('qux.buildinfo');
foreach my $gname ($pool->get_group_names){
my $group = $pool->get_group($gname);
process($gname, $group);
@@ -81,11 +82,12 @@ processables from the same source package (if any).
sub add_file {
my ($self, $file) = @_;
- if ($file =~ m/\.changes$/o){
+ if ($file =~ m/\.(buildinfo|changes)$/o){
+ my $type = $1;
croak "$file does not exist" unless -f $file;
my $pkg_path = Cwd::abs_path($file);
croak "Cannot resolve $file: $!" unless $pkg_path;
- return $self->_add_changes_file($pkg_path);
+ return $self->_add_file($type, $pkg_path);
}
my $proc = Lintian::Processable::Package->new($file);
@@ -186,11 +188,16 @@ sub empty{
#### Internal subs ####
-sub _add_changes_file{
- my ($self, $pkg_path) = @_;
+sub _add_file{
+ my ($self, $type, $pkg_path) = @_;
my $group = Lintian::ProcessableGroup->new($self->{'lab'}, $pkg_path);
- my $cproc = $group->get_changes_processable;
- my $gid = $self->_get_group_id($cproc);
+ my $proc;
+ if ($type eq 'buildinfo') {
+ $proc = $group->get_buildinfo_processable;
+ } elsif ($type eq 'changes') {
+ $proc = $group->get_changes_processable;
+ }
+ my $gid = $self->_get_group_id($proc);
my $ogroup = $self->{groups}{$gid};
if (defined($ogroup)){
# Group already exists...
@@ -198,8 +205,13 @@ sub _add_changes_file{
# Merge architectures/packages ...
# Accept all new
- if (!defined($ogroup->get_changes_processable)) {
- $ogroup->add_processable($cproc);
+ if ($type eq 'buildinfo'
+ && !defined($ogroup->get_buildinfo_processable)) {
+ $ogroup->add_processable($proc);
+ $added = 1;
+ }elsif ($type eq 'changes'
+ && !defined($ogroup->get_changes_processable)) {
+ $ogroup->add_processable($proc);
$added = 1;
}
diff --git a/t/scripts/Lintian/Lab/repair.t b/t/scripts/Lintian/Lab/repair.t
index 777e7da..12cfc1b 100755
--- a/t/scripts/Lintian/Lab/repair.t
+++ b/t/scripts/Lintian/Lab/repair.t
@@ -60,7 +60,7 @@ sub do_tests {
opendir(my $dirfd, "$DATADIR/changes");
foreach my $pkgbase (readdir $dirfd) {
- next unless $pkgbase =~ m/\.(?:changes|u?deb|dsc)$/;
+ next unless $pkgbase =~ m/\.(?:buildinfo|changes|u?deb|dsc)$/;
my $path = "$DATADIR/changes/$pkgbase";
my $proc = Lintian::Processable::Package->new($path);
my $entry = $LAB_A->get_package($proc);
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/lintian/lintian.git
Reply to: