X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=Debbugs%2FPackages.pm;h=c7fd47c18b6f5dde189a563fe8e61ad2e8955a6e;hb=9ba3b5ba7379ac06399d7b296e7796b65fad6149;hp=8ef34515b3776f808222b0cc5704c42e1a12c457;hpb=ff1a27527b4209e9f07c97e38da373eb4f0a45d9;p=debbugs.git diff --git a/Debbugs/Packages.pm b/Debbugs/Packages.pm index 8ef3451..c7fd47c 100644 --- a/Debbugs/Packages.pm +++ b/Debbugs/Packages.pm @@ -12,7 +12,7 @@ package Debbugs::Packages; use warnings; use strict; -use base qw(Exporter); +use Exporter qw(import); use vars qw($VERSION @EXPORT_OK %EXPORT_TAGS @EXPORT); use Carp; @@ -37,7 +37,7 @@ use Fcntl qw(O_RDONLY); use MLDBM qw(DB_File Storable); use Storable qw(dclone); use Params::Validate qw(validate_with :types); -use Debbugs::Common qw(make_list globify_scalar); +use Debbugs::Common qw(make_list globify_scalar sort_versions); use List::Util qw(min max); @@ -139,6 +139,9 @@ arch(s), and verion(s) passed. In SCALAR context, only the corresponding source packages are returned, concatenated with ', ' if necessary. +If no source can be found, returns undef in scalar context, or the +empty list in list context. + =over =item binary -- binary package name(s) as a SCALAR or ARRAYREF @@ -162,7 +165,10 @@ binary_to_source. =cut +# the two global variables below are used to tie the source maps; we +# probably should be retying them in long lived processes. our %_binarytosource; +our %_sourcetobinary; sub binary_to_source{ my %param = validate_with(params => \@_, spec => {binary => {type => SCALAR|ARRAYREF, @@ -193,12 +199,12 @@ sub binary_to_source{ } my @source; - my @packages = grep {defined $_} make_list(exists $param{package}?$param{package}:[]); + my @binaries = grep {defined $_} make_list(exists $param{binary}?$param{binary}:[]); my @versions = grep {defined $_} make_list(exists $param{version}?$param{version}:[]); my @archs = grep {defined $_} make_list(exists $param{arch}?$param{arch}:[]); - return () unless @packages; + return () unless @binaries; my $cache_key = join("\1", - join("\0",@packages), + join("\0",@binaries), join("\0",@versions), join("\0",@archs), join("\0",@param{qw(source_only scalar_only)})); @@ -206,8 +212,8 @@ sub binary_to_source{ return $param{scalar_only} ? $param{cache}{$cache_key}[0]: @{$param{cache}{$cache_key}}; } - for my $package (make_list($param{package})) { - if ($package =~ m/^src:(.+)$/) { + for my $binary (@binaries) { + if ($binary =~ m/^src:(.+)$/) { push @source,[$1,'']; next; } @@ -216,23 +222,22 @@ sub binary_to_source{ die "Unable to open $config{binary_source_map} for reading"; } # avoid autovivification - my $binary = $_binarytosource{$package}; + my $bin = $_binarytosource{$binary}; + next unless defined $bin; if (not @versions) { - next unless defined $binary; - for my $ver (keys %{$binary}) { - for my $ar (keys %{$binary->{$ver}}) { - my $src = $binary->{$ver}{$ar}; + for my $ver (keys %{$bin}) { + for my $ar (keys %{$bin->{$ver}}) { + my $src = $bin->{$ver}{$ar}; next unless defined $src; push @source,[$src->[0],$src->[1]]; } } } else { - my $found_one_version = 0; for my $version (@versions) { - next unless exists $binary->{$version}; - if (exists $binary->{$version}{all}) { - push @source,dclone($binary->{$version}{all}); + next unless exists $bin->{$version}; + if (exists $bin->{$version}{all}) { + push @source,dclone($bin->{$version}{all}); next; } my @t_archs; @@ -240,20 +245,46 @@ sub binary_to_source{ @t_archs = @archs; } else { - @t_archs = keys %{$binary->{$version}}; + @t_archs = keys %{$bin->{$version}}; } for my $arch (@t_archs) { - push @source,dclone($binary->{$version}{$arch}) if - exists $binary->{$version}{$arch}; + push @source,dclone($bin->{$version}{$arch}) if + exists $bin->{$version}{$arch}; } } } } + + if (not @source and not @versions and not @archs) { + # ok, we haven't found any results at all. If we weren't given + # a specific version and architecture, then we should try + # really hard to figure out the right source + + # if any the packages we've been given are a valid source + # package name, and there's no binary of the same name (we got + # here, so there isn't), return it. + + if (not tied %_sourcetobinary) { + tie %_sourcetobinary, MLDBM => $config{source_binary_map}, O_RDONLY or + die "Unable top open $gSourceBinaryMap for reading"; + } + for my $maybe_sourcepkg (@binaries) { + if (exists $_sourcetobinary{$maybe_sourcepkg}) { + push @source,[$maybe_sourcepkg,$_] for keys %{$_sourcetobinary{$maybe_sourcepkg}}; + } + } + # if @source is still empty here, it's probably a non-existant + # source package, so don't return anything. + } + my @result; if ($param{source_only}) { my %uniq; for my $s (@source) { + # we shouldn't need to do this, but do this temporarily to + # stop the warning. + next unless defined $s->[0]; $uniq{$s->[0]} = 1; } @result = sort keys %uniq; @@ -288,13 +319,12 @@ returned, without the architecture. =cut -our %_sourcetobinary; sub sourcetobinary { my ($srcname, $srcver) = @_; if (not tied %_sourcetobinary) { - tie %_sourcetobinary, MLDBM => $gSourceBinaryMap, O_RDONLY or - die "Unable top open $gSourceBinaryMap for reading"; + tie %_sourcetobinary, MLDBM => $config{source_binary_map}, O_RDONLY or + die "Unable top open $config{source_binary_map} for reading"; } @@ -362,6 +392,11 @@ may change in the future, so if you care, please code accordingly.) =item return_archs -- returns a version=>[archs] hash indicating which architectures are at which versions. +=item largest_source_version_only -- if there is more than one source +version in a particular distribution, discards all versions but the +largest in that distribution. Defaults to 1, as this used to be the +way that the Debian archive worked. + =back When called in scalar context, this function will return hashrefs or @@ -395,6 +430,9 @@ sub get_versions{ return_archs => {type => BOOLEAN, default => 0, }, + largest_source_version_only => {type => BOOLEAN, + default => 1, + }, }, ); my $versions; @@ -416,6 +454,10 @@ sub get_versions{ } my %versions; for my $package (make_list($param{package})) { + my $source_only = 0; + if ($package =~ s/^src://) { + $source_only = 1; + } my $version = $versions->{$package}; next unless defined $version; for my $dist (make_list($param{dist})) { @@ -423,12 +465,18 @@ sub get_versions{ make_list($param{arch}): (grep {not $param{no_source_arch} or $_ ne 'source' - } keys %{$version->{$dist}})) { + } $source_only?'source':keys %{$version->{$dist}})) { next unless defined $version->{$dist}{$arch}; - for my $ver (ref $version->{$dist}{$arch} ? - keys %{$version->{$dist}{$arch}} : - $version->{$dist}{$arch} - ) { + my @vers = ref $version->{$dist}{$arch} eq 'HASH' ? + keys %{$version->{$dist}{$arch}} : + make_list($version->{$dist}{$arch}); + if ($param{largest_source_version_only} and + $arch eq 'source' and @vers > 1) { + # order the versions, then pick the biggest version number + @vers = sort_versions(@vers); + @vers = $vers[-1]; + } + for my $ver (@vers) { my $f_ver = $ver; if ($param{source}) { ($f_ver) = make_source_versions(package => $package, @@ -481,7 +529,6 @@ sub makesourceversions { arch => 'source', versions => '0.1.1', guess_source => 1, - debug => \$debug, warnings => \$warnings, ); @@ -524,7 +571,6 @@ sub make_source_versions { }, ); my ($warnings) = globify_scalar(exists $param{warnings}?$param{warnings}:undef); - my ($debug) = globify_scalar(exists $param{debug} ?$param{debug} :undef); my @packages = grep {defined $_ and length $_ } make_list($param{package}); my @archs = grep {defined $_ } make_list ($param{arch}); @@ -561,7 +607,7 @@ sub make_source_versions { my @bin_versions = sourcetobinary($1,$version); if (not @bin_versions or @{$bin_versions[0]} != 3) { - print {$warnings} "The source $1 and version $2 do not appear to match any binary packages\n"; + print {$warnings} "The source '$1' and version '$version' do not appear to match any binary packages\n"; } next; } @@ -583,7 +629,7 @@ sub make_source_versions { } my @srcinfo = binary_to_source(binary => $pkg, version => $version, - arch => $arch); + length($arch)?(arch => $arch):()); if (not @srcinfo) { # We don't have explicit information about the # binary-to-source mapping for this version