lintian/private/refresh-perl-provides

223 lines
6.3 KiB
Perl
Executable File

#!/usr/bin/perl
use v5.20;
use warnings;
use utf8;
# Generate a list of packages that are provided by the Perl core packages
# and also packaged separately at a (hopefully) newer version.
# The list will have the package name and the upstream version of the
# corresponding module integrated in the currently installed Perl version.
# Copyright (C) 2008 Niko Tyni
#
# 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/>.
use Const::Fast;
use List::SomeUtils qw(none);
use Unicode::UTF8 qw(encode_utf8);
# from /usr/share/doc/libapt-pkg-perl/examples/apt-cache
use AptPkg::Config '$_config';
use AptPkg::System '$_system';
use AptPkg::Cache;
const my $EMPTY => q{};
const my $LAST_ITEM => -1;
(my $self = $0) =~ s{.*/}{};
# initialise the global config object with the default values and
# setup the $_system object
$_config->init;
$_system = $_config->system;
# suppress cache building messages
$_config->{quiet} = 2;
# set up the cache
my $cache = AptPkg::Cache->new;
# end from /usr/share/doc/libapt-pkg-perl/examples/apt-cache
# special cases when libfoo-bar-perl => Foo::Bar doesn't work
my %module_name = (
'libio-compress-perl' => 'IO::Compress::Gzip',
'libio-compress-zlib-perl' => 'IO::Compress::Gzip',
);
# special cases for where the code gets the prefix wrong
my %manual_split
= ('libautodie-perl' => qr/\A (\d++\.) (\d{2}) (\d{2})? \Z/xsmo,);
use Module::CoreList;
my $versioning = $_system->versioning;
my $perl_version = $];
# Map 5.022002 into 5.22
$perl_version =~ s/^(5)\.0*([1-9][0-9])\d+/$1.$2/;
# we look at packages provided by these
my @core_packages = (qw(perl-base perl), "perl-modules-$perl_version");
# check we have a cache of Debian sid packages available
warn encode_utf8(
join(q{ },
'Warning: this list should only be updated on a system',
'with an up to date APT cache of the Debian unstable distribution')
)
if (
none {
defined $_->{Origin}
&& defined $_->{Archive}
&& $_->{Origin} eq 'Debian'
&& $_->{Archive} eq 'unstable';
}@{$cache->files}
);
print encode_utf8(<<"EOF");
# virtual packages provided by the Perl core packages that also have a
# separate binary package available
#
# the listed version is the one included in the Perl core
#
# regenerate by running
# debian/rules refresh-perl-provides
# in the lintian source tree
#
# last updated for PERL_VERSION=$]
EOF
for my $pkg (@core_packages) {
my $cached_versions = $cache->{$pkg}
or
die encode_utf8("no such binary package found in the APT cache: $pkg");
my $latest = bin_latest($cached_versions);
for my $provides (@{$latest->{ProvidesList}}) {
my $name = $provides->{Name};
# skip virtual-only packages
next if (!$cache->{$name}{VersionList});
my $cpan_version = find_core_version($name);
next if !$cpan_version;
# the number of digits is a pain
# we use the current version in the Debian archive to determine
# how many we need
# the epoch is easier, we just copy it
my ($epoch, $digits) = epoch_and_digits($name);
my $debian_version
= cpan_version_to_deb($name, $cpan_version, $epoch, $digits);
next if !$debian_version;
print encode_utf8("$name $debian_version\n");
}
}
# look up the CPAN version of a package in the core
sub find_core_version {
my $module = shift;
my $ret;
return undef
if $module =~ /^perl(5|api)/;
if (exists $module_name{$module}) {
$module = $module_name{$module};
} else {
# mangle the package name into the module name
$module =~ s/^lib//;
$module =~ s/-perl$//;
$module =~ s/-/::/g;
}
for (Module::CoreList->find_modules(qr/^\Q$module\E$/i, 0+$])) {
$ret = $Module::CoreList::version{0+$]}{$_};
last;
}
return $ret;
}
sub cpan_version_to_deb {
my ($pkg, $cpan_version, $epoch, $digits) = @_;
$epoch ||= $EMPTY;
# cpan_version
# digits
# result
# 1.15_02, 2 => 1.15.02
# 1.15_02, 4 => 1.1502
# 1.15_02, 0 => 1.15.02
#
# 1.15_021, 2 => 1.15.021
# 1.15_021, 4 => 1.1500.021
# 1.15_021, 0 => 1.15.021
#
# 1.15, 1 => 1.15
# 1.15, 2 => 1.15
# 1.15, 4 => 1.1500
# 1.15, 0 => 1.15
# split 1.15_02 to (1, 15, 02)
my $regex = qr/^(\d+\.)(\d+)(?:_(\d+))?$/;
$regex = $manual_split{$pkg} if exists $manual_split{$pkg};
my ($major, $prefix, $suffix) = ($cpan_version =~ $regex);
die encode_utf8("no match with $cpan_version?") if !$major;
$suffix ||= $EMPTY;
if (length($suffix) + length($prefix) == $digits) {
$prefix .= $suffix;
$suffix = $EMPTY;
}
if (length($suffix) + length($prefix) < $digits) {
$prefix .= '0' while length($prefix) < $digits;
}
$suffix = ".$suffix" if $suffix ne $EMPTY;
return $epoch.$major.$prefix.$suffix;
}
# Given a Debian binary package name, look up its latest version
# and return its epoch (including the colon) if available, and
# the number of digits in its decimal part
sub epoch_and_digits {
my $p = shift;
return (0, 0) if !exists $cache->{$p};
return (0, 0) if !exists $cache->{$p}{VersionList}; # virtual package
my $latest = bin_latest($cache->{$p});
my $v = $latest->{VerStr};
$v =~ s/\+dfsg//;
my ($epoch, $major, $prefix, $suffix, $revision)
= ($v =~ /^(?:(\d+:))?((?:\d+\.))+(\d+)(?:_(\d+))?(-[^-]+)$/);
return ($epoch, length $prefix);
}
sub bin_latest {
my $p = shift;
return (sort bin_byversion @{$p->{VersionList}})[$LAST_ITEM];
}
sub bin_byversion {
return $versioning->compare($a->{VerStr}, $b->{VerStr});
}
# Local Variables:
# indent-tabs-mode: nil
# cperl-indent-level: 4
# End:
# vim: syntax=perl sw=4 sts=4 sr et