diff -Nru sbuild-0.65.2/debian/changelog sbuild-0.65.2/debian/changelog --- sbuild-0.65.2/debian/changelog 2015-07-13 13:07:22.000000000 +0000 +++ sbuild-0.65.2/debian/changelog 2016-02-18 14:37:43.000000000 +0000 @@ -1,3 +1,30 @@ +sbuild (0.65.2-1ubuntu2~ubuntu14.04.1~ppa8) trusty; urgency=medium + + * copy-dummy-archive.patch: Sbuild::ResolverBase: use copy: for dummy + archive. Fixes launchpad-buildd crashes when analysing dep-waits. + + -- Colin Watson Thu, 18 Feb 2016 14:37:39 +0000 + +sbuild (0.65.2-1ubuntu2~ubuntu14.04.1~ppa7) trusty; urgency=medium + + * Install Build-Depends-Arch in the correct situations (LP: #1516336). + + -- Colin Watson Mon, 11 Jan 2016 12:22:15 +0000 + +sbuild (0.65.2-1ubuntu2~ubuntu14.04.1~ppa6) trusty; urgency=medium + + * Change g_ to _g in backports of dpkg modules, to account for pre-1.18.0 + Dpkg::Gettext. + + -- Colin Watson Wed, 05 Aug 2015 10:16:49 +0100 + +sbuild (0.65.2-1ubuntu2~ubuntu14.04.1~ppa5) trusty; urgency=medium + + * Backport Dpkg::Deps and minimal dependencies from dpkg 1.18.1, allowing + us to support newer build-dependency features such as build profiles. + + -- Colin Watson Tue, 28 Jul 2015 15:37:45 +0100 + sbuild (0.65.2-1ubuntu2~ubuntu14.04.1~ppa4) trusty; urgency=medium * Backport from upstream: diff -Nru sbuild-0.65.2/debian/patches/backport-dpkg-deps.patch sbuild-0.65.2/debian/patches/backport-dpkg-deps.patch --- sbuild-0.65.2/debian/patches/backport-dpkg-deps.patch 1970-01-01 00:00:00.000000000 +0000 +++ sbuild-0.65.2/debian/patches/backport-dpkg-deps.patch 2015-08-05 09:15:15.000000000 +0000 @@ -0,0 +1,2216 @@ +Description: Backport Dpkg::Deps and minimal dependencies from dpkg 1.18.1 + This allows us to support newer build-dependency features such as build + profiles. The following modules are identical to the versions in dpkg + 1.18.1 except for renaming and changing g_ to _g: + . + Dpkg::Arch → Sbuild::Arch + Dpkg::BuildProfiles → Sbuild::BuildProfiles + Dpkg::Deps → Sbuild::Deps +Author: Colin Watson + +Index: b/lib/Sbuild/Arch.pm +=================================================================== +--- /dev/null ++++ b/lib/Sbuild/Arch.pm +@@ -0,0 +1,456 @@ ++# Copyright © 2006-2015 Guillem Jover ++# ++# 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 . ++ ++package Sbuild::Arch; ++ ++use strict; ++use warnings; ++use feature qw(state); ++ ++our $VERSION = '0.01'; ++our @EXPORT_OK = qw( ++ get_raw_build_arch ++ get_raw_host_arch ++ get_build_arch ++ get_host_arch ++ get_gcc_host_gnu_type ++ get_valid_arches ++ debarch_eq ++ debarch_is ++ debarch_is_wildcard ++ debarch_is_concerned ++ debarch_to_cpuattrs ++ debarch_to_gnutriplet ++ debarch_to_debtriplet ++ debarch_to_multiarch ++ debtriplet_to_debarch ++ debtriplet_to_gnutriplet ++ gnutriplet_to_debarch ++ gnutriplet_to_debtriplet ++ gnutriplet_to_multiarch ++); ++ ++use Exporter qw(import); ++use POSIX qw(:errno_h); ++ ++use Dpkg (); ++use Dpkg::Gettext; ++use Dpkg::ErrorHandling; ++use Dpkg::Util qw(:list); ++use Dpkg::BuildEnv; ++ ++my (@cpu, @os); ++my (%cputable, %ostable); ++my (%cputable_re, %ostable_re); ++my (%cpubits, %cpuendian); ++my %abibits; ++ ++my %debtriplet_to_debarch; ++my %debarch_to_debtriplet; ++ ++sub get_raw_build_arch() ++{ ++ state $build_arch; ++ ++ return $build_arch if defined $build_arch; ++ ++ # Note: We *always* require an installed dpkg when inferring the ++ # build architecture. The bootstrapping case is handled by ++ # dpkg-architecture itself, by avoiding computing the DEB_BUILD_ ++ # variables when they are not requested. ++ ++ $build_arch = qx(dpkg --print-architecture); ++ syserr('dpkg --print-architecture failed') if $? >> 8; ++ ++ chomp $build_arch; ++ return $build_arch; ++} ++ ++sub get_build_arch() ++{ ++ return Dpkg::BuildEnv::get('DEB_BUILD_ARCH') || get_raw_build_arch(); ++} ++ ++{ ++ my $gcc_host_gnu_type; ++ ++ sub get_gcc_host_gnu_type() ++ { ++ return $gcc_host_gnu_type if defined $gcc_host_gnu_type; ++ ++ $gcc_host_gnu_type = qx(\${CC:-gcc} -dumpmachine); ++ if ($? >> 8) { ++ $gcc_host_gnu_type = ''; ++ } else { ++ chomp $gcc_host_gnu_type; ++ } ++ ++ return $gcc_host_gnu_type; ++ } ++ ++ sub get_raw_host_arch() ++ { ++ state $host_arch; ++ ++ return $host_arch if defined $host_arch; ++ ++ $gcc_host_gnu_type = get_gcc_host_gnu_type(); ++ ++ if ($gcc_host_gnu_type eq '') { ++ warning(_g("couldn't determine gcc system type, falling back to " . ++ 'default (native compilation)')); ++ } else { ++ my (@host_archtriplet) = gnutriplet_to_debtriplet($gcc_host_gnu_type); ++ $host_arch = debtriplet_to_debarch(@host_archtriplet); ++ ++ if (defined $host_arch) { ++ $gcc_host_gnu_type = debtriplet_to_gnutriplet(@host_archtriplet); ++ } else { ++ warning(_g('unknown gcc system type %s, falling back to ' . ++ 'default (native compilation)'), $gcc_host_gnu_type); ++ $gcc_host_gnu_type = ''; ++ } ++ } ++ ++ if (!defined($host_arch)) { ++ # Switch to native compilation. ++ $host_arch = get_raw_build_arch(); ++ } ++ ++ return $host_arch; ++ } ++} ++ ++sub get_host_arch() ++{ ++ return Dpkg::BuildEnv::get('DEB_HOST_ARCH') || get_raw_host_arch(); ++} ++ ++sub get_valid_arches() ++{ ++ read_cputable(); ++ read_ostable(); ++ ++ my @arches; ++ ++ foreach my $os (@os) { ++ foreach my $cpu (@cpu) { ++ my $arch = debtriplet_to_debarch(split(/-/, $os, 2), $cpu); ++ push @arches, $arch if defined($arch); ++ } ++ } ++ ++ return @arches; ++} ++ ++my %table_loaded; ++sub load_table ++{ ++ my ($table, $loader) = @_; ++ ++ return if $table_loaded{$table}; ++ ++ local $_; ++ local $/ = "\n"; ++ ++ open my $table_fh, '<', "$Dpkg::DATADIR/$table" ++ or syserr(_g('cannot open %s'), $table); ++ while (<$table_fh>) { ++ $loader->($_); ++ } ++ close $table_fh; ++ ++ $table_loaded{$table} = 1; ++} ++ ++sub read_cputable ++{ ++ load_table('cputable', sub { ++ if (m/^(?!\#)(\S+)\s+(\S+)\s+(\S+)\s+(\S+)\s+(\S+)/) { ++ $cputable{$1} = $2; ++ $cputable_re{$1} = $3; ++ $cpubits{$1} = $4; ++ $cpuendian{$1} = $5; ++ push @cpu, $1; ++ } ++ }); ++} ++ ++sub read_ostable ++{ ++ load_table('ostable', sub { ++ if (m/^(?!\#)(\S+)\s+(\S+)\s+(\S+)/) { ++ $ostable{$1} = $2; ++ $ostable_re{$1} = $3; ++ push @os, $1; ++ } ++ }); ++} ++ ++sub abitable_load() ++{ ++ load_table('abitable', sub { ++ if (m/^(?!\#)(\S+)\s+(\S+)/) { ++ $abibits{$1} = $2; ++ } ++ }); ++} ++ ++sub read_triplettable() ++{ ++ read_cputable(); ++ ++ load_table('triplettable', sub { ++ if (m/^(?!\#)(\S+)\s+(\S+)/) { ++ my $debtriplet = $1; ++ my $debarch = $2; ++ ++ if ($debtriplet =~ //) { ++ foreach my $_cpu (@cpu) { ++ (my $dt = $debtriplet) =~ s//$_cpu/; ++ (my $da = $debarch) =~ s//$_cpu/; ++ ++ next if exists $debarch_to_debtriplet{$da} ++ or exists $debtriplet_to_debarch{$dt}; ++ ++ $debarch_to_debtriplet{$da} = $dt; ++ $debtriplet_to_debarch{$dt} = $da; ++ } ++ } else { ++ $debarch_to_debtriplet{$2} = $1; ++ $debtriplet_to_debarch{$1} = $2; ++ } ++ } ++ }); ++} ++ ++sub debtriplet_to_gnutriplet(@) ++{ ++ my ($abi, $os, $cpu) = @_; ++ ++ read_cputable(); ++ read_ostable(); ++ ++ return unless defined($abi) && defined($os) && defined($cpu) && ++ exists($cputable{$cpu}) && exists($ostable{"$abi-$os"}); ++ return join('-', $cputable{$cpu}, $ostable{"$abi-$os"}); ++} ++ ++sub gnutriplet_to_debtriplet($) ++{ ++ my $gnu = shift; ++ return unless defined($gnu); ++ my ($gnu_cpu, $gnu_os) = split(/-/, $gnu, 2); ++ return unless defined($gnu_cpu) && defined($gnu_os); ++ ++ read_cputable(); ++ read_ostable(); ++ ++ my ($os, $cpu); ++ ++ foreach my $_cpu (@cpu) { ++ if ($gnu_cpu =~ /^$cputable_re{$_cpu}$/) { ++ $cpu = $_cpu; ++ last; ++ } ++ } ++ ++ foreach my $_os (@os) { ++ if ($gnu_os =~ /^(.*-)?$ostable_re{$_os}$/) { ++ $os = $_os; ++ last; ++ } ++ } ++ ++ return if !defined($cpu) || !defined($os); ++ return (split(/-/, $os, 2), $cpu); ++} ++ ++sub gnutriplet_to_multiarch($) ++{ ++ my $gnu = shift; ++ my ($cpu, $cdr) = split(/-/, $gnu, 2); ++ ++ if ($cpu =~ /^i[4567]86$/) { ++ return "i386-$cdr"; ++ } else { ++ return $gnu; ++ } ++} ++ ++sub debarch_to_multiarch($) ++{ ++ my $arch = shift; ++ ++ return gnutriplet_to_multiarch(debarch_to_gnutriplet($arch)); ++} ++ ++sub debtriplet_to_debarch(@) ++{ ++ my ($abi, $os, $cpu) = @_; ++ ++ read_triplettable(); ++ ++ if (!defined($abi) || !defined($os) || !defined($cpu)) { ++ return; ++ } elsif (exists $debtriplet_to_debarch{"$abi-$os-$cpu"}) { ++ return $debtriplet_to_debarch{"$abi-$os-$cpu"}; ++ } else { ++ return; ++ } ++} ++ ++sub debarch_to_debtriplet($) ++{ ++ my $arch = shift; ++ ++ read_triplettable(); ++ ++ if ($arch =~ /^linux-([^-]*)/) { ++ # XXX: Might disappear in the future, not sure yet. ++ $arch = $1; ++ } ++ ++ my $triplet = $debarch_to_debtriplet{$arch}; ++ ++ if (defined($triplet)) { ++ return split(/-/, $triplet, 3); ++ } else { ++ return; ++ } ++} ++ ++sub debarch_to_gnutriplet($) ++{ ++ my $arch = shift; ++ ++ return debtriplet_to_gnutriplet(debarch_to_debtriplet($arch)); ++} ++ ++sub gnutriplet_to_debarch($) ++{ ++ my $gnu = shift; ++ ++ return debtriplet_to_debarch(gnutriplet_to_debtriplet($gnu)); ++} ++ ++sub debwildcard_to_debtriplet($) ++{ ++ my $arch = shift; ++ my @tuple = split /-/, $arch, 3; ++ ++ if (any { $_ eq 'any' } @tuple) { ++ if (scalar @tuple == 3) { ++ return @tuple; ++ } elsif (scalar @tuple == 2) { ++ return ('any', @tuple); ++ } else { ++ return ('any', 'any', 'any'); ++ } ++ } else { ++ return debarch_to_debtriplet($arch); ++ } ++} ++ ++sub debarch_to_cpuattrs($) ++{ ++ my $arch = shift; ++ my ($abi, $os, $cpu) = debarch_to_debtriplet($arch); ++ ++ if (defined($cpu)) { ++ abitable_load(); ++ ++ return ($abibits{$abi} // $cpubits{$cpu}, $cpuendian{$cpu}); ++ } else { ++ return; ++ } ++} ++ ++sub debarch_eq($$) ++{ ++ my ($a, $b) = @_; ++ ++ return 1 if ($a eq $b); ++ ++ my @a = debarch_to_debtriplet($a); ++ my @b = debarch_to_debtriplet($b); ++ ++ return 0 if scalar @a != 3 or scalar @b != 3; ++ ++ return ($a[0] eq $b[0] && $a[1] eq $b[1] && $a[2] eq $b[2]); ++} ++ ++sub debarch_is($$) ++{ ++ my ($real, $alias) = @_; ++ ++ return 1 if ($alias eq $real or $alias eq 'any'); ++ ++ my @real = debarch_to_debtriplet($real); ++ my @alias = debwildcard_to_debtriplet($alias); ++ ++ return 0 if scalar @real != 3 or scalar @alias != 3; ++ ++ if (($alias[0] eq $real[0] || $alias[0] eq 'any') && ++ ($alias[1] eq $real[1] || $alias[1] eq 'any') && ++ ($alias[2] eq $real[2] || $alias[2] eq 'any')) { ++ return 1; ++ } ++ ++ return 0; ++} ++ ++sub debarch_is_wildcard($) ++{ ++ my $arch = shift; ++ ++ return 0 if $arch eq 'all'; ++ ++ my @triplet = debwildcard_to_debtriplet($arch); ++ ++ return 0 if scalar @triplet != 3; ++ return 1 if any { $_ eq 'any' } @triplet; ++ return 0; ++} ++ ++sub debarch_is_concerned ++{ ++ my ($host_arch, @arches) = @_; ++ ++ my $seen_arch = 0; ++ foreach my $arch (@arches) { ++ $arch = lc $arch; ++ ++ if ($arch =~ /^!/) { ++ my $not_arch = $arch; ++ $not_arch =~ s/^!//; ++ ++ if (debarch_is($host_arch, $not_arch)) { ++ $seen_arch = 0; ++ last; ++ } else { ++ # !arch includes by default all other arches ++ # unless they also appear in a !otherarch ++ $seen_arch = 1; ++ } ++ } elsif (debarch_is($host_arch, $arch)) { ++ $seen_arch = 1; ++ last; ++ } ++ } ++ return $seen_arch; ++} ++ ++1; +Index: b/lib/Sbuild/Build.pm +=================================================================== +--- a/lib/Sbuild/Build.pm ++++ b/lib/Sbuild/Build.pm +@@ -34,10 +34,10 @@ + use FileHandle; + use File::Copy qw(); # copy is already exported from Sbuild, so don't export + # anything. +-use Dpkg::Arch; ++use Sbuild::Arch; + use Dpkg::Control; + use Dpkg::Version; +-use Dpkg::Deps qw(deps_concat deps_parse); ++use Sbuild::Deps qw(deps_concat deps_parse); + use Scalar::Util 'refaddr'; + + use MIME::Lite; +@@ -1031,7 +1031,7 @@ + } else { + my $valid_arch; + for my $a (split(/\s+/, $dscarchs)) { +- if (Dpkg::Arch::debarch_is($host_arch, $a)) { ++ if (Sbuild::Arch::debarch_is($host_arch, $a)) { + $valid_arch = 1; + last; + } +Index: b/lib/Sbuild/BuildProfiles.pm +=================================================================== +--- /dev/null ++++ b/lib/Sbuild/BuildProfiles.pm +@@ -0,0 +1,146 @@ ++# Copyright © 2013 Guillem Jover ++# ++# 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 . ++ ++package Sbuild::BuildProfiles; ++ ++use strict; ++use warnings; ++ ++our $VERSION = '1.00'; ++our @EXPORT_OK = qw( ++ get_build_profiles ++ set_build_profiles ++ parse_build_profiles ++ evaluate_restriction_formula ++); ++ ++use Exporter qw(import); ++ ++use Dpkg::Util qw(:list); ++use Dpkg::BuildEnv; ++ ++my $cache_profiles; ++my @build_profiles; ++ ++=encoding utf8 ++ ++=head1 NAME ++ ++Sbuild::BuildProfiles - handle build profiles ++ ++=head1 DESCRIPTION ++ ++The Sbuild::BuildProfiles module provides functions to handle the build ++profiles. ++ ++=head1 FUNCTIONS ++ ++=over 4 ++ ++=item my @profiles = get_build_profiles() ++ ++Get an array with the currently active build profiles, taken from ++the environment variable B. ++ ++=cut ++ ++sub get_build_profiles { ++ return @build_profiles if $cache_profiles; ++ ++ if (Dpkg::BuildEnv::has('DEB_BUILD_PROFILES')) { ++ @build_profiles = split /\s+/, Dpkg::BuildEnv::get('DEB_BUILD_PROFILES'); ++ } ++ $cache_profiles = 1; ++ ++ return @build_profiles; ++} ++ ++=item set_build_profiles(@profiles) ++ ++Set C<@profiles> as the current active build profiles, by setting ++the environment variable B. ++ ++=cut ++ ++sub set_build_profiles { ++ my (@profiles) = @_; ++ ++ $cache_profiles = 1; ++ @build_profiles = @profiles; ++ Dpkg::BuildEnv::set('DEB_BUILD_PROFILES', join ' ', @profiles); ++} ++ ++=item my @profiles = parse_build_profiles($string) ++ ++Parses a build profiles specification, into an array of array references. ++ ++=cut ++ ++sub parse_build_profiles { ++ my $string = shift; ++ ++ $string =~ s/^\s*<(.*)>\s*$/$1/; ++ ++ return map { [ split /\s+/ ] } split />\s+ ", given as ++a nested array, is true or false, given the array of enabled build profiles. ++ ++=cut ++ ++sub evaluate_restriction_formula { ++ my ($formula, $profiles) = @_; ++ ++ # Restriction formulas are in disjunctive normal form: ++ # (foo AND bar) OR (blub AND bla) ++ foreach my $restrlist (@{$formula}) { ++ my $seen_profile = 1; ++ ++ foreach my $restriction (@$restrlist) { ++ next if $restriction !~ m/^(!)?(.+)/; ++ ++ my $negated = defined $1 && $1 eq '!'; ++ my $profile = $2; ++ my $found = any { $_ eq $profile } @{$profiles}; ++ ++ # If a negative set profile is encountered, stop processing. ++ # If a positive unset profile is encountered, stop processing. ++ if ($found == $negated) { ++ $seen_profile = 0; ++ last; ++ } ++ } ++ ++ # This conjunction evaluated to true so we don't have to evaluate ++ # the others. ++ return 1 if $seen_profile; ++ } ++ return 0; ++} ++ ++=back ++ ++=head1 CHANGES ++ ++=head2 Version 1.00 (dpkg 1.17.17) ++ ++Mark the module as public. ++ ++=cut ++ ++1; +Index: b/lib/Sbuild/Deps.pm +=================================================================== +--- /dev/null ++++ b/lib/Sbuild/Deps.pm +@@ -0,0 +1,1506 @@ ++# Copyright © 2007-2009 Raphaël Hertzog ++# Copyright © 2008-2009,2012-2014 Guillem Jover ++# ++# This program is free software; you may 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 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 . ++######################################################################### ++# Several parts are inspired by lib/Dep.pm from lintian (same license) ++# ++# Copyright © 1998 Richard Braakman ++# Portions Copyright © 1999 Darren Benham ++# Portions Copyright © 2000 Sean 'Shaleh' Perry ++# Portions Copyright © 2004 Frank Lichtenheld ++# Portions Copyright © 2006 Russ Allbery ++ ++package Sbuild::Deps; ++ ++=encoding utf8 ++ ++=head1 NAME ++ ++Sbuild::Deps - parse and manipulate dependencies of Debian packages ++ ++=head1 DESCRIPTION ++ ++The Sbuild::Deps module provides objects implementing various types of ++dependencies. ++ ++The most important function is deps_parse(), it turns a dependency line in ++a set of Sbuild::Deps::{Simple,AND,OR,Union} objects depending on the case. ++ ++=head1 FUNCTIONS ++ ++All the deps_* functions are exported by default. ++ ++=over 4 ++ ++=cut ++ ++use strict; ++use warnings; ++ ++our $VERSION = '1.05'; ++our @EXPORT = qw( ++ deps_concat ++ deps_parse ++ deps_eval_implication ++ deps_iterate ++ deps_compare ++); ++ ++use Exporter qw(import); ++ ++use Dpkg::Version; ++use Sbuild::Arch qw(get_host_arch get_build_arch); ++use Sbuild::BuildProfiles qw(get_build_profiles); ++use Dpkg::ErrorHandling; ++use Dpkg::Gettext; ++ ++=item deps_eval_implication($rel_p, $v_p, $rel_q, $v_q) ++ ++($rel_p, $v_p) and ($rel_q, $v_q) express two dependencies as (relation, ++version). The relation variable can have the following values that are ++exported by Dpkg::Version: REL_EQ, REL_LT, REL_LE, REL_GT, REL_GT. ++ ++This functions returns 1 if the "p" dependency implies the "q" ++dependency. It returns 0 if the "p" dependency implies that "q" is ++not satisfied. It returns undef when there's no implication. ++ ++The $v_p and $v_q parameter should be Dpkg::Version objects. ++ ++=cut ++ ++sub deps_eval_implication { ++ my ($rel_p, $v_p, $rel_q, $v_q) = @_; ++ ++ # If versions are not valid, we can't decide of any implication ++ return unless defined($v_p) and $v_p->is_valid(); ++ return unless defined($v_q) and $v_q->is_valid(); ++ ++ # q wants an exact version, so p must provide that exact version. p ++ # disproves q if q's version is outside the range enforced by p. ++ if ($rel_q eq REL_EQ) { ++ if ($rel_p eq REL_LT) { ++ return ($v_p <= $v_q) ? 0 : undef; ++ } elsif ($rel_p eq REL_LE) { ++ return ($v_p < $v_q) ? 0 : undef; ++ } elsif ($rel_p eq REL_GT) { ++ return ($v_p >= $v_q) ? 0 : undef; ++ } elsif ($rel_p eq REL_GE) { ++ return ($v_p > $v_q) ? 0 : undef; ++ } elsif ($rel_p eq REL_EQ) { ++ return ($v_p == $v_q); ++ } ++ } ++ ++ # A greater than clause may disprove a less than clause. An equal ++ # cause might as well. Otherwise, if ++ # p's clause is <<, <=, or =, the version must be <= q's to imply q. ++ if ($rel_q eq REL_LE) { ++ if ($rel_p eq REL_GT) { ++ return ($v_p >= $v_q) ? 0 : undef; ++ } elsif ($rel_p eq REL_GE) { ++ return ($v_p > $v_q) ? 0 : undef; ++ } elsif ($rel_p eq REL_EQ) { ++ return ($v_p <= $v_q) ? 1 : 0; ++ } else { # <<, <= ++ return ($v_p <= $v_q) ? 1 : undef; ++ } ++ } ++ ++ # Similar, but << is stronger than <= so p's version must be << q's ++ # version if the p relation is <= or =. ++ if ($rel_q eq REL_LT) { ++ if ($rel_p eq REL_GT or $rel_p eq REL_GE) { ++ return ($v_p >= $v_p) ? 0 : undef; ++ } elsif ($rel_p eq REL_LT) { ++ return ($v_p <= $v_q) ? 1 : undef; ++ } elsif ($rel_p eq REL_EQ) { ++ return ($v_p < $v_q) ? 1 : 0; ++ } else { # <<, <= ++ return ($v_p < $v_q) ? 1 : undef; ++ } ++ } ++ ++ # Same logic as above, only inverted. ++ if ($rel_q eq REL_GE) { ++ if ($rel_p eq REL_LT) { ++ return ($v_p <= $v_q) ? 0 : undef; ++ } elsif ($rel_p eq REL_LE) { ++ return ($v_p < $v_q) ? 0 : undef; ++ } elsif ($rel_p eq REL_EQ) { ++ return ($v_p >= $v_q) ? 1 : 0; ++ } else { # >>, >= ++ return ($v_p >= $v_q) ? 1 : undef; ++ } ++ } ++ if ($rel_q eq REL_GT) { ++ if ($rel_p eq REL_LT or $rel_p eq REL_LE) { ++ return ($v_p <= $v_q) ? 0 : undef; ++ } elsif ($rel_p eq REL_GT) { ++ return ($v_p >= $v_q) ? 1 : undef; ++ } elsif ($rel_p eq REL_EQ) { ++ return ($v_p > $v_q) ? 1 : 0; ++ } else { ++ return ($v_p > $v_q) ? 1 : undef; ++ } ++ } ++ ++ return; ++} ++ ++=item my $dep = deps_concat(@dep_list) ++ ++This function concatenates multiple dependency lines into a single line, ++joining them with ", " if appropriate, and always returning a valid string. ++ ++=cut ++ ++sub deps_concat { ++ my (@dep_list) = @_; ++ ++ return join ', ', grep { defined } @dep_list; ++} ++ ++=item my $dep = deps_parse($line, %options) ++ ++This function parses the dependency line and returns an object, either a ++Sbuild::Deps::AND or a Sbuild::Deps::Union. Various options can alter the ++behaviour of that function. ++ ++=over 4 ++ ++=item use_arch (defaults to 1) ++ ++Take into account the architecture restriction part of the dependencies. ++Set to 0 to completely ignore that information. ++ ++=item host_arch (defaults to the current architecture) ++ ++Define the host architecture. By default it uses ++Sbuild::Arch::get_host_arch() to identify the proper architecture. ++ ++=item build_arch (defaults to the current architecture) ++ ++Define the build architecture. By default it uses ++Sbuild::Arch::get_build_arch() to identify the proper architecture. ++ ++=item reduce_arch (defaults to 0) ++ ++If set to 1, ignore dependencies that do not concern the current host ++architecture. This implicitely strips off the architecture restriction ++list so that the resulting dependencies are directly applicable to the ++current architecture. ++ ++=item use_profiles (defaults to 1) ++ ++Take into account the profile restriction part of the dependencies. Set ++to 0 to completely ignore that information. ++ ++=item build_profiles (defaults to no profile) ++ ++Define the active build profiles. By default no profile is defined. ++ ++=item reduce_profiles (defaults to 0) ++ ++If set to 1, ignore dependencies that do not concern the current build ++profile. This implicitly strips off the profile restriction formula so ++that the resulting dependencies are directly applicable to the current ++profiles. ++ ++=item reduce_restrictions (defaults to 0) ++ ++If set to 1, ignore dependencies that do not concern the current set of ++restrictions. This implicitly strips off any architecture restriction list ++or restriction formula so that the resulting dependencies are directly ++applicable to the current restriction. ++This currently implies C and C, and overrides ++them if set. ++ ++=item union (defaults to 0) ++ ++If set to 1, returns a Sbuild::Deps::Union instead of a Sbuild::Deps::AND. Use ++this when parsing non-dependency fields like Conflicts. ++ ++=item build_dep (defaults to 0) ++ ++If set to 1, allow build-dep only arch qualifiers, that is “:native”. ++This should be set whenever working with build-deps. ++ ++=back ++ ++=cut ++ ++sub deps_parse { ++ my ($dep_line, %options) = @_; ++ ++ $options{use_arch} //= 1; ++ $options{reduce_arch} //= 0; ++ $options{host_arch} //= get_host_arch(); ++ $options{build_arch} //= get_build_arch(); ++ $options{use_profiles} //= 1; ++ $options{reduce_profiles} //= 0; ++ $options{build_profiles} //= [ get_build_profiles() ]; ++ $options{reduce_restrictions} //= 0; ++ $options{union} //= 0; ++ $options{build_dep} //= 0; ++ ++ if ($options{reduce_restrictions}) { ++ $options{reduce_arch} = 1; ++ $options{reduce_profiles} = 1; ++ } ++ ++ # Strip trailing/leading spaces ++ $dep_line =~ s/^\s+//; ++ $dep_line =~ s/\s+$//; ++ ++ my @dep_list; ++ foreach my $dep_and (split(/\s*,\s*/m, $dep_line)) { ++ my @or_list = (); ++ foreach my $dep_or (split(/\s*\|\s*/m, $dep_and)) { ++ my $dep_simple = Sbuild::Deps::Simple->new($dep_or, host_arch => ++ $options{host_arch}, ++ build_arch => ++ $options{build_arch}, ++ build_dep => ++ $options{build_dep}); ++ if (not defined $dep_simple->{package}) { ++ warning(_g("can't parse dependency %s"), $dep_or); ++ return; ++ } ++ $dep_simple->{arches} = undef if not $options{use_arch}; ++ if ($options{reduce_arch}) { ++ $dep_simple->reduce_arch($options{host_arch}); ++ next if not $dep_simple->arch_is_concerned($options{host_arch}); ++ } ++ $dep_simple->{restrictions} = undef if not $options{use_profiles}; ++ if ($options{reduce_profiles}) { ++ $dep_simple->reduce_profiles($options{build_profiles}); ++ next if not $dep_simple->profile_is_concerned($options{build_profiles}); ++ } ++ push @or_list, $dep_simple; ++ } ++ next if not @or_list; ++ if (scalar @or_list == 1) { ++ push @dep_list, $or_list[0]; ++ } else { ++ my $dep_or = Sbuild::Deps::OR->new(); ++ $dep_or->add($_) foreach (@or_list); ++ push @dep_list, $dep_or; ++ } ++ } ++ my $dep_and; ++ if ($options{union}) { ++ $dep_and = Sbuild::Deps::Union->new(); ++ } else { ++ $dep_and = Sbuild::Deps::AND->new(); ++ } ++ foreach my $dep (@dep_list) { ++ if ($options{union} and not $dep->isa('Sbuild::Deps::Simple')) { ++ warning(_g('an union dependency can only contain simple dependencies')); ++ return; ++ } ++ $dep_and->add($dep); ++ } ++ return $dep_and; ++} ++ ++=item my $bool = deps_iterate($deps, $callback_func) ++ ++This function visits all elements of the dependency object, calling the ++callback function for each element. ++ ++The callback function is expected to return true when everything is fine, ++or false if something went wrong, in which case the iteration will stop. ++ ++Return the same value as the callback function. ++ ++=cut ++ ++sub deps_iterate { ++ my ($deps, $callback_func) = @_; ++ ++ my $visitor_func; ++ $visitor_func = sub { ++ foreach my $dep (@_) { ++ return unless defined $dep; ++ ++ if ($dep->isa('Sbuild::Deps::Simple')) { ++ return unless &{$callback_func}($dep); ++ } else { ++ return unless &{$visitor_func}($dep->get_deps()); ++ } ++ } ++ return 1; ++ }; ++ ++ return &{$visitor_func}($deps); ++} ++ ++=item deps_compare($a, $b) ++ ++Implements a comparison operator between two dependency objects. ++This function is mainly used to implement the sort() method. ++ ++=back ++ ++=cut ++ ++my %relation_ordering = ( ++ undef => 0, ++ REL_GE() => 1, ++ REL_GT() => 2, ++ REL_EQ() => 3, ++ REL_LT() => 4, ++ REL_LE() => 5, ++); ++ ++sub deps_compare { ++ my ($a, $b) = @_; ++ return -1 if $a->is_empty(); ++ return 1 if $b->is_empty(); ++ while ($a->isa('Sbuild::Deps::Multiple')) { ++ return -1 if $a->is_empty(); ++ my @deps = $a->get_deps(); ++ $a = $deps[0]; ++ } ++ while ($b->isa('Sbuild::Deps::Multiple')) { ++ return 1 if $b->is_empty(); ++ my @deps = $b->get_deps(); ++ $b = $deps[0]; ++ } ++ my $ar = $a->{relation} // 'undef'; ++ my $br = $b->{relation} // 'undef'; ++ my $av = $a->{version} // ''; ++ my $bv = $a->{version} // ''; ++ return (($a->{package} cmp $b->{package}) || ++ ($relation_ordering{$ar} <=> $relation_ordering{$br}) || ++ ($av cmp $bv)); ++} ++ ++ ++package Sbuild::Deps::Simple; ++ ++=head1 OBJECTS - Sbuild::Deps::* ++ ++There are several kind of dependencies. A Sbuild::Deps::Simple dependency ++represents a single dependency statement (it relates to one package only). ++Sbuild::Deps::Multiple dependencies are built on top of this object ++and combine several dependencies in a different manners. Sbuild::Deps::AND ++represents the logical "AND" between dependencies while Sbuild::Deps::OR ++represents the logical "OR". Sbuild::Deps::Multiple objects can contain ++Sbuild::Deps::Simple object as well as other Sbuild::Deps::Multiple objects. ++ ++In practice, the code is only meant to handle the realistic cases which, ++given Debian's dependencies structure, imply those restrictions: AND can ++contain Simple or OR objects, OR can only contain Simple objects. ++ ++Sbuild::Deps::KnownFacts is a special object that is used while evaluating ++dependencies and while trying to simplify them. It represents a set of ++installed packages along with the virtual packages that they might ++provide. ++ ++=head2 COMMON METHODS ++ ++=over 4 ++ ++=item $dep->is_empty() ++ ++Returns true if the dependency is empty and doesn't contain any useful ++information. This is true when a Sbuild::Deps::Simple object has not yet ++been initialized or when a (descendant of) Sbuild::Deps::Multiple contains ++an empty list of dependencies. ++ ++=item $dep->get_deps() ++ ++Returns a list of sub-dependencies. For Sbuild::Deps::Simple it returns ++itself. ++ ++=item $dep->output([$fh]) ++ ++=item "$dep" ++ ++Returns a string representing the dependency. If $fh is set, it prints ++the string to the filehandle. ++ ++=item $dep->implies($other_dep) ++ ++Returns 1 when $dep implies $other_dep. Returns 0 when $dep implies ++NOT($other_dep). Returns undef when there's no implication. $dep and ++$other_dep do not need to be of the same type. ++ ++=item $dep->sort() ++ ++Sorts alphabetically the internal list of dependencies. It's a no-op for ++Sbuild::Deps::Simple objects. ++ ++=item $dep->arch_is_concerned($arch) ++ ++Returns true if the dependency applies to the indicated architecture. For ++multiple dependencies, it returns true if at least one of the ++sub-dependencies apply to this architecture. ++ ++=item $dep->reduce_arch($arch) ++ ++Simplifies the dependency to contain only information relevant to the given ++architecture. A Sbuild::Deps::Simple object can be left empty after this ++operation. For Sbuild::Deps::Multiple objects, the non-relevant ++sub-dependencies are simply removed. ++ ++This trims off the architecture restriction list of Sbuild::Deps::Simple ++objects. ++ ++=item $dep->get_evaluation($facts) ++ ++Evaluates the dependency given a list of installed packages and a list of ++virtual packages provided. Those lists are part of the ++Sbuild::Deps::KnownFacts object given as parameters. ++ ++Returns 1 when it's true, 0 when it's false, undef when some information ++is lacking to conclude. ++ ++=item $dep->simplify_deps($facts, @assumed_deps) ++ ++Simplifies the dependency as much as possible given the list of facts (see ++object Sbuild::Deps::KnownFacts) and a list of other dependencies that are ++known to be true. ++ ++=item $dep->has_arch_restriction() ++ ++For a simple dependency, returns the package name if the dependency ++applies only to a subset of architectures. For multiple dependencies, it ++returns the list of package names that have such a restriction. ++ ++=item $dep->reset() ++ ++Clears any dependency information stored in $dep so that $dep->is_empty() ++returns true. ++ ++=back ++ ++=head2 Sbuild::Deps::Simple ++ ++Such an object has four interesting properties: ++ ++=over 4 ++ ++=item package ++ ++The package name (can be undef if the dependency has not been initialized ++or if the simplification of the dependency lead to its removal). ++ ++=item relation ++ ++The relational operator: "=", "<<", "<=", ">=" or ">>". It can be ++undefined if the dependency had no version restriction. In that case the ++following field is also undefined. ++ ++=item version ++ ++The version. ++ ++=item arches ++ ++The list of architectures where this dependency is applicable. It's ++undefined when there's no restriction, otherwise it's an ++array ref. It can contain an exclusion list, in that case each ++architecture is prefixed with an exclamation mark. ++ ++=item archqual ++ ++The arch qualifier of the dependency (can be undef if there's none). ++In the dependency "python:any (>= 2.6)", the arch qualifier is "any". ++ ++=back ++ ++=head3 METHODS ++ ++=over 4 ++ ++=item $simple_dep->parse_string('dpkg-dev (>= 1.14.8) [!hurd-i386]') ++ ++Parses the dependency and modifies internal properties to match the parsed ++dependency. ++ ++=item $simple_dep->merge_union($other_dep) ++ ++Returns true if $simple_dep could be modified to represent the union of ++both dependencies. Otherwise returns false. ++ ++=back ++ ++=cut ++ ++use strict; ++use warnings; ++ ++use Carp; ++ ++use Sbuild::Arch qw(debarch_is_concerned); ++use Sbuild::BuildProfiles qw(parse_build_profiles evaluate_restriction_formula); ++use Dpkg::Version; ++use Dpkg::ErrorHandling; ++use Dpkg::Gettext; ++use Dpkg::Util qw(:list); ++ ++use parent qw(Dpkg::Interface::Storable); ++ ++sub new { ++ my ($this, $arg, %opts) = @_; ++ my $class = ref($this) || $this; ++ my $self = {}; ++ bless $self, $class; ++ $self->reset(); ++ $self->{host_arch} = $opts{host_arch} || Sbuild::Arch::get_host_arch(); ++ $self->{build_arch} = $opts{build_arch} || Sbuild::Arch::get_build_arch(); ++ $self->{build_dep} = $opts{build_dep} // 0; ++ $self->parse_string($arg) if defined($arg); ++ return $self; ++} ++ ++sub reset { ++ my $self = shift; ++ $self->{package} = undef; ++ $self->{relation} = undef; ++ $self->{version} = undef; ++ $self->{arches} = undef; ++ $self->{archqual} = undef; ++ $self->{restrictions} = undef; ++} ++ ++sub parse { ++ my ($self, $fh, $desc) = @_; ++ my $line = <$fh>; ++ chomp($line); ++ return $self->parse_string($line); ++} ++ ++sub parse_string { ++ my ($self, $dep) = @_; ++ return if not $dep =~ ++ m{^\s* # skip leading whitespace ++ ([a-zA-Z0-9][a-zA-Z0-9+.-]*) # package name ++ (?: # start of optional part ++ : # colon for architecture ++ ([a-zA-Z0-9][a-zA-Z0-9-]*) # architecture name ++ )? # end of optional part ++ (?: # start of optional part ++ \s* \( # open parenthesis for version part ++ \s* (<<|<=|=|>=|>>|[<>]) # relation part ++ \s* (.*?) # do not attempt to parse version ++ \s* \) # closing parenthesis ++ )? # end of optional part ++ (?: # start of optional architecture ++ \s* \[ # open bracket for architecture ++ \s* (.*?) # don't parse architectures now ++ \s* \] # closing bracket ++ )? # end of optional architecture ++ (?: # start of optional restriction ++ \s* < # open bracket for restriction ++ \s* (.*) # do not parse restrictions now ++ \s* > # closing bracket ++ )? # end of optional restriction ++ \s*$ # trailing spaces at end ++ }x; ++ if (defined($2)) { ++ return if $2 eq 'native' and not $self->{build_dep}; ++ $self->{archqual} = $2; ++ } ++ $self->{package} = $1; ++ $self->{relation} = version_normalize_relation($3) if defined($3); ++ if (defined($4)) { ++ $self->{version} = Dpkg::Version->new($4); ++ } ++ if (defined($5)) { ++ $self->{arches} = [ split(/\s+/, $5) ]; ++ } ++ if (defined($6)) { ++ $self->{restrictions} = [ parse_build_profiles($6) ]; ++ } ++} ++ ++sub output { ++ my ($self, $fh) = @_; ++ my $res = $self->{package}; ++ if (defined($self->{archqual})) { ++ $res .= ':' . $self->{archqual}; ++ } ++ if (defined($self->{relation})) { ++ $res .= ' (' . $self->{relation} . ' ' . $self->{version} . ')'; ++ } ++ if (defined($self->{arches})) { ++ $res .= ' [' . join(' ', @{$self->{arches}}) . ']'; ++ } ++ if (defined($self->{restrictions})) { ++ for my $restrlist (@{$self->{restrictions}}) { ++ $res .= ' <' . join(' ', @{$restrlist}) . '>'; ++ } ++ } ++ if (defined($fh)) { ++ print { $fh } $res; ++ } ++ return $res; ++} ++ ++# _arch_is_superset(\@p, \@q) ++# ++# Returns true if the arch list @p is a superset of arch list @q. ++# The arguments can also be undef in case there's no explicit architecture ++# restriction. ++sub _arch_is_superset { ++ my ($p, $q) = @_; ++ my $p_arch_neg = defined($p) && $p->[0] =~ /^!/; ++ my $q_arch_neg = defined($q) && $q->[0] =~ /^!/; ++ ++ # If "p" has no arches, it is a superset of q and we should fall through ++ # to the version check. ++ if (not defined $p) { ++ return 1; ++ } ++ ++ # If q has no arches, it is a superset of p and there are no useful ++ # implications. ++ elsif (not defined $q) { ++ return 0; ++ } ++ ++ # Both have arches. If neither are negated, we know nothing useful ++ # unless q is a subset of p. ++ elsif (not $p_arch_neg and not $q_arch_neg) { ++ my %p_arches = map { $_ => 1 } @{$p}; ++ my $subset = 1; ++ for my $arch (@{$q}) { ++ $subset = 0 unless $p_arches{$arch}; ++ } ++ return 0 unless $subset; ++ } ++ ++ # If both are negated, we know nothing useful unless p is a subset of ++ # q (and therefore has fewer things excluded, and therefore is more ++ # general). ++ elsif ($p_arch_neg and $q_arch_neg) { ++ my %q_arches = map { $_ => 1 } @{$q}; ++ my $subset = 1; ++ for my $arch (@{$p}) { ++ $subset = 0 unless $q_arches{$arch}; ++ } ++ return 0 unless $subset; ++ } ++ ++ # If q is negated and p isn't, we'd need to know the full list of ++ # arches to know if there's any relationship, so bail. ++ elsif (not $p_arch_neg and $q_arch_neg) { ++ return 0; ++ } ++ ++ # If p is negated and q isn't, q is a subset of p if none of the ++ # negated arches in p are present in q. ++ elsif ($p_arch_neg and not $q_arch_neg) { ++ my %q_arches = map { $_ => 1 } @{$q}; ++ my $subset = 1; ++ for my $arch (@{$p}) { ++ $subset = 0 if $q_arches{substr($arch, 1)}; ++ } ++ return 0 unless $subset; ++ } ++ return 1; ++} ++ ++# _arch_qualifier_allows_implication($p, $q) ++# ++# Returns true if the arch qualifier $p and $q are compatible with the ++# implication $p -> $q, false otherwise. $p/$q can be ++# undef/"any"/"native" or an architecture string. ++sub _arch_qualifier_allows_implication { ++ my ($p, $q) = @_; ++ if (defined $p and $p eq 'any') { ++ return 1 if defined $q and $q eq 'any'; ++ return 0; ++ } elsif (defined $p and $p eq 'native') { ++ return 1 if defined $q and ($q eq 'any' or $q eq 'native'); ++ return 0; ++ } elsif (defined $p) { ++ return 1 if defined $q and ($p eq $q or $q eq 'any'); ++ return 0; ++ } else { ++ return 0 if defined $q and $q ne 'any' and $q ne 'native'; ++ return 1; ++ } ++} ++ ++# Returns true if the dependency in parameter can deduced from the current ++# dependency. Returns false if it can be negated. Returns undef if nothing ++# can be concluded. ++sub implies { ++ my ($self, $o) = @_; ++ if ($o->isa('Sbuild::Deps::Simple')) { ++ # An implication is only possible on the same package ++ return if $self->{package} ne $o->{package}; ++ ++ # Our architecture set must be a superset of the architectures for ++ # o, otherwise we can't conclude anything. ++ return unless _arch_is_superset($self->{arches}, $o->{arches}); ++ ++ # The arch qualifier must not forbid an implication ++ return unless _arch_qualifier_allows_implication($self->{archqual}, ++ $o->{archqual}); ++ ++ # If o has no version clause, then our dependency is stronger ++ return 1 if not defined $o->{relation}; ++ # If o has a version clause, we must also have one, otherwise there ++ # can't be an implication ++ return if not defined $self->{relation}; ++ ++ return Sbuild::Deps::deps_eval_implication($self->{relation}, ++ $self->{version}, $o->{relation}, $o->{version}); ++ ++ } elsif ($o->isa('Sbuild::Deps::AND')) { ++ # TRUE: Need to imply all individual elements ++ # FALSE: Need to NOT imply at least one individual element ++ my $res = 1; ++ foreach my $dep ($o->get_deps()) { ++ my $implication = $self->implies($dep); ++ unless (defined($implication) && $implication == 1) { ++ $res = $implication; ++ last if defined $res; ++ } ++ } ++ return $res; ++ } elsif ($o->isa('Sbuild::Deps::OR')) { ++ # TRUE: Need to imply at least one individual element ++ # FALSE: Need to not apply all individual elements ++ # UNDEF: The rest ++ my $res = undef; ++ foreach my $dep ($o->get_deps()) { ++ my $implication = $self->implies($dep); ++ if (defined($implication)) { ++ if (not defined $res) { ++ $res = $implication; ++ } else { ++ if ($implication) { ++ $res = 1; ++ } else { ++ $res = 0; ++ } ++ } ++ last if defined($res) && $res == 1; ++ } ++ } ++ return $res; ++ } else { ++ croak 'Sbuild::Deps::Simple cannot evaluate implication with a ' . ++ ref($o); ++ } ++} ++ ++sub get_deps { ++ my $self = shift; ++ return $self; ++} ++ ++sub sort { ++ # Nothing to sort ++} ++ ++sub arch_is_concerned { ++ my ($self, $host_arch) = @_; ++ ++ return 0 if not defined $self->{package}; # Empty dep ++ return 1 if not defined $self->{arches}; # Dep without arch spec ++ ++ return debarch_is_concerned($host_arch, @{$self->{arches}}); ++} ++ ++sub reduce_arch { ++ my ($self, $host_arch) = @_; ++ if (not $self->arch_is_concerned($host_arch)) { ++ $self->reset(); ++ } else { ++ $self->{arches} = undef; ++ } ++} ++ ++sub has_arch_restriction { ++ my $self = shift; ++ if (defined $self->{arches}) { ++ return $self->{package}; ++ } else { ++ return (); ++ } ++} ++ ++sub profile_is_concerned { ++ my ($self, $build_profiles) = @_; ++ ++ return 0 if not defined $self->{package}; # Empty dep ++ return 1 if not defined $self->{restrictions}; # Dep without restrictions ++ return evaluate_restriction_formula($self->{restrictions}, $build_profiles); ++} ++ ++sub reduce_profiles { ++ my ($self, $build_profiles) = @_; ++ ++ if (not $self->profile_is_concerned($build_profiles)) { ++ $self->reset(); ++ } else { ++ $self->{restrictions} = undef; ++ } ++} ++ ++sub get_evaluation { ++ my ($self, $facts) = @_; ++ return if not defined $self->{package}; ++ return $facts->_evaluate_simple_dep($self); ++} ++ ++sub simplify_deps { ++ my ($self, $facts) = @_; ++ my $eval = $self->get_evaluation($facts); ++ $self->reset() if defined $eval and $eval == 1; ++} ++ ++sub is_empty { ++ my $self = shift; ++ return not defined $self->{package}; ++} ++ ++sub merge_union { ++ my ($self, $o) = @_; ++ return 0 if not $o->isa('Sbuild::Deps::Simple'); ++ return 0 if $self->is_empty() or $o->is_empty(); ++ return 0 if $self->{package} ne $o->{package}; ++ return 0 if defined $self->{arches} or defined $o->{arches}; ++ ++ if (not defined $o->{relation} and defined $self->{relation}) { ++ # Union is the non-versioned dependency ++ $self->{relation} = undef; ++ $self->{version} = undef; ++ return 1; ++ } ++ ++ my $implication = $self->implies($o); ++ my $rev_implication = $o->implies($self); ++ if (defined($implication)) { ++ if ($implication) { ++ $self->{relation} = $o->{relation}; ++ $self->{version} = $o->{version}; ++ return 1; ++ } else { ++ return 0; ++ } ++ } ++ if (defined($rev_implication)) { ++ if ($rev_implication) { ++ # Already merged... ++ return 1; ++ } else { ++ return 0; ++ } ++ } ++ return 0; ++} ++ ++package Sbuild::Deps::Multiple; ++ ++=head2 Sbuild::Deps::Multiple ++ ++This is the base class for Sbuild::Deps::{AND,OR,Union}. It implements ++the following methods: ++ ++=over 4 ++ ++=item $mul->add($dep) ++ ++Adds a new dependency object at the end of the list. ++ ++=back ++ ++=cut ++ ++use strict; ++use warnings; ++ ++use Carp; ++ ++use Dpkg::ErrorHandling; ++ ++use parent qw(Dpkg::Interface::Storable); ++ ++sub new { ++ my $this = shift; ++ my $class = ref($this) || $this; ++ my $self = { list => [ @_ ] }; ++ bless $self, $class; ++ return $self; ++} ++ ++sub reset { ++ my $self = shift; ++ $self->{list} = []; ++} ++ ++sub add { ++ my $self = shift; ++ push @{$self->{list}}, @_; ++} ++ ++sub get_deps { ++ my $self = shift; ++ return grep { not $_->is_empty() } @{$self->{list}}; ++} ++ ++sub sort { ++ my $self = shift; ++ my @res = (); ++ @res = sort { Sbuild::Deps::deps_compare($a, $b) } @{$self->{list}}; ++ $self->{list} = [ @res ]; ++} ++ ++sub arch_is_concerned { ++ my ($self, $host_arch) = @_; ++ my $res = 0; ++ foreach my $dep (@{$self->{list}}) { ++ $res = 1 if $dep->arch_is_concerned($host_arch); ++ } ++ return $res; ++} ++ ++sub reduce_arch { ++ my ($self, $host_arch) = @_; ++ my @new; ++ foreach my $dep (@{$self->{list}}) { ++ $dep->reduce_arch($host_arch); ++ push @new, $dep if $dep->arch_is_concerned($host_arch); ++ } ++ $self->{list} = [ @new ]; ++} ++ ++sub has_arch_restriction { ++ my $self = shift; ++ my @res; ++ foreach my $dep (@{$self->{list}}) { ++ push @res, $dep->has_arch_restriction(); ++ } ++ return @res; ++} ++ ++sub profile_is_concerned { ++ my ($self, $build_profiles) = @_; ++ my $res = 0; ++ ++ foreach my $dep (@{$self->{list}}) { ++ $res = 1 if $dep->profile_is_concerned($build_profiles); ++ } ++ return $res; ++} ++ ++sub reduce_profiles { ++ my ($self, $build_profiles) = @_; ++ my @new; ++ ++ foreach my $dep (@{$self->{list}}) { ++ $dep->reduce_profiles($build_profiles); ++ push @new, $dep if $dep->profile_is_concerned($build_profiles); ++ } ++ $self->{list} = [ @new ]; ++} ++ ++sub is_empty { ++ my $self = shift; ++ return scalar @{$self->{list}} == 0; ++} ++ ++sub merge_union { ++ croak 'method merge_union() is only valid for Sbuild::Deps::Simple'; ++} ++ ++package Sbuild::Deps::AND; ++ ++=head2 Sbuild::Deps::AND ++ ++This object represents a list of dependencies who must be met at the same ++time. ++ ++=over 4 ++ ++=item $and->output([$fh]) ++ ++The output method uses ", " to join the list of sub-dependencies. ++ ++=back ++ ++=cut ++ ++use strict; ++use warnings; ++ ++use parent -norequire, qw(Sbuild::Deps::Multiple); ++ ++sub output { ++ my ($self, $fh) = @_; ++ my $res = join(', ', map { $_->output() } grep { not $_->is_empty() } $self->get_deps()); ++ if (defined($fh)) { ++ print { $fh } $res; ++ } ++ return $res; ++} ++ ++sub implies { ++ my ($self, $o) = @_; ++ # If any individual member can imply $o or NOT $o, we're fine ++ foreach my $dep ($self->get_deps()) { ++ my $implication = $dep->implies($o); ++ return 1 if defined($implication) && $implication == 1; ++ return 0 if defined($implication) && $implication == 0; ++ } ++ # If o is an AND, we might have an implication, if we find an ++ # implication within us for each predicate in o ++ if ($o->isa('Sbuild::Deps::AND')) { ++ my $subset = 1; ++ foreach my $odep ($o->get_deps()) { ++ my $found = 0; ++ foreach my $dep ($self->get_deps()) { ++ $found = 1 if $dep->implies($odep); ++ } ++ $subset = 0 if not $found; ++ } ++ return 1 if $subset; ++ } ++ return; ++} ++ ++sub get_evaluation { ++ my ($self, $facts) = @_; ++ # Return 1 only if all members evaluates to true ++ # Return 0 if at least one member evaluates to false ++ # Return undef otherwise ++ my $result = 1; ++ foreach my $dep ($self->get_deps()) { ++ my $eval = $dep->get_evaluation($facts); ++ if (not defined $eval) { ++ $result = undef; ++ } elsif ($eval == 0) { ++ $result = 0; ++ last; ++ } elsif ($eval == 1) { ++ # Still possible ++ } ++ } ++ return $result; ++} ++ ++sub simplify_deps { ++ my ($self, $facts, @knowndeps) = @_; ++ my @new; ++ ++WHILELOOP: ++ while (@{$self->{list}}) { ++ my $dep = shift @{$self->{list}}; ++ my $eval = $dep->get_evaluation($facts); ++ next if defined($eval) and $eval == 1; ++ foreach my $odep (@knowndeps, @new) { ++ next WHILELOOP if $odep->implies($dep); ++ } ++ # When a dependency is implied by another dependency that ++ # follows, then invert them ++ # "a | b, c, a" becomes "a, c" and not "c, a" ++ my $i = 0; ++ foreach my $odep (@{$self->{list}}) { ++ if (defined $odep and $odep->implies($dep)) { ++ splice @{$self->{list}}, $i, 1; ++ unshift @{$self->{list}}, $odep; ++ next WHILELOOP; ++ } ++ $i++; ++ } ++ push @new, $dep; ++ } ++ $self->{list} = [ @new ]; ++} ++ ++ ++package Sbuild::Deps::OR; ++ ++=head2 Sbuild::Deps::OR ++ ++This object represents a list of dependencies of which only one must be met ++for the dependency to be true. ++ ++=over 4 ++ ++=item $or->output([$fh]) ++ ++The output method uses " | " to join the list of sub-dependencies. ++ ++=back ++ ++=cut ++ ++use strict; ++use warnings; ++ ++use parent -norequire, qw(Sbuild::Deps::Multiple); ++ ++sub output { ++ my ($self, $fh) = @_; ++ my $res = join(' | ', map { $_->output() } grep { not $_->is_empty() } $self->get_deps()); ++ if (defined($fh)) { ++ print { $fh } $res; ++ } ++ return $res; ++} ++ ++sub implies { ++ my ($self, $o) = @_; ++ ++ # Special case for AND with a single member, replace it by its member ++ if ($o->isa('Sbuild::Deps::AND')) { ++ my @subdeps = $o->get_deps(); ++ if (scalar(@subdeps) == 1) { ++ $o = $subdeps[0]; ++ } ++ } ++ ++ # In general, an OR dependency can't imply anything except if each ++ # of its member implies a member in the other OR dependency ++ if ($o->isa('Sbuild::Deps::OR')) { ++ my $subset = 1; ++ foreach my $dep ($self->get_deps()) { ++ my $found = 0; ++ foreach my $odep ($o->get_deps()) { ++ $found = 1 if $dep->implies($odep); ++ } ++ $subset = 0 if not $found; ++ } ++ return 1 if $subset; ++ } ++ return; ++} ++ ++sub get_evaluation { ++ my ($self, $facts) = @_; ++ # Returns false if all members evaluates to 0 ++ # Returns true if at least one member evaluates to true ++ # Returns undef otherwise ++ my $result = 0; ++ foreach my $dep ($self->get_deps()) { ++ my $eval = $dep->get_evaluation($facts); ++ if (not defined $eval) { ++ $result = undef; ++ } elsif ($eval == 1) { ++ $result = 1; ++ last; ++ } elsif ($eval == 0) { ++ # Still possible to have a false evaluation ++ } ++ } ++ return $result; ++} ++ ++sub simplify_deps { ++ my ($self, $facts) = @_; ++ my @new; ++ ++WHILELOOP: ++ while (@{$self->{list}}) { ++ my $dep = shift @{$self->{list}}; ++ my $eval = $dep->get_evaluation($facts); ++ if (defined($eval) and $eval == 1) { ++ $self->{list} = []; ++ return; ++ } ++ foreach my $odep (@new, @{$self->{list}}) { ++ next WHILELOOP if $odep->implies($dep); ++ } ++ push @new, $dep; ++ } ++ $self->{list} = [ @new ]; ++} ++ ++package Sbuild::Deps::Union; ++ ++=head2 Sbuild::Deps::Union ++ ++This object represents a list of relationships. ++ ++=over 4 ++ ++=item $union->output([$fh]) ++ ++The output method uses ", " to join the list of relationships. ++ ++=item $union->implies($other_dep) ++ ++=item $union->get_evaluation($other_dep) ++ ++Those methods are not meaningful for this object and always return undef. ++ ++=item $union->simplify_deps($facts) ++ ++The simplication is done to generate an union of all the relationships. ++It uses $simple_dep->merge_union($other_dep) to get its job done. ++ ++=back ++ ++=cut ++ ++use strict; ++use warnings; ++ ++use parent -norequire, qw(Sbuild::Deps::Multiple); ++ ++sub output { ++ my ($self, $fh) = @_; ++ my $res = join(', ', map { $_->output() } grep { not $_->is_empty() } $self->get_deps()); ++ if (defined($fh)) { ++ print { $fh } $res; ++ } ++ return $res; ++} ++ ++sub implies { ++ # Implication test are not useful on Union ++ return; ++} ++ ++sub get_evaluation { ++ # Evaluation are not useful on Union ++ return; ++} ++ ++sub simplify_deps { ++ my ($self, $facts) = @_; ++ my @new; ++ ++WHILELOOP: ++ while (@{$self->{list}}) { ++ my $odep = shift @{$self->{list}}; ++ foreach my $dep (@new) { ++ next WHILELOOP if $dep->merge_union($odep); ++ } ++ push @new, $odep; ++ } ++ $self->{list} = [ @new ]; ++} ++ ++package Sbuild::Deps::KnownFacts; ++ ++=head2 Sbuild::Deps::KnownFacts ++ ++This object represents a list of installed packages and a list of virtual ++packages provided (by the set of installed packages). ++ ++=over 4 ++ ++=item my $facts = Sbuild::Deps::KnownFacts->new(); ++ ++Creates a new object. ++ ++=cut ++ ++use strict; ++use warnings; ++ ++use Carp; ++ ++use Dpkg::Version; ++ ++sub new { ++ my $this = shift; ++ my $class = ref($this) || $this; ++ my $self = { ++ pkg => {}, ++ virtualpkg => {}, ++ }; ++ bless $self, $class; ++ return $self; ++} ++ ++=item $facts->add_installed_package($package, $version, $arch, $multiarch) ++ ++Records that the given version of the package is installed. If ++$version/$arch is undefined we know that the package is installed but we ++don't know which version/architecture it is. $multiarch is the Multi-Arch ++field of the package. If $multiarch is undef, it will be equivalent to ++"Multi-Arch: no". ++ ++Note that $multiarch is only used if $arch is provided. ++ ++=cut ++ ++sub add_installed_package { ++ my ($self, $pkg, $ver, $arch, $multiarch) = @_; ++ my $p = { ++ package => $pkg, ++ version => $ver, ++ architecture => $arch, ++ multiarch => $multiarch // 'no', ++ }; ++ $self->{pkg}{"$pkg:$arch"} = $p if defined $arch; ++ push @{$self->{pkg}{$pkg}}, $p; ++} ++ ++=item $facts->add_provided_package($virtual, $relation, $version, $by) ++ ++Records that the "$by" package provides the $virtual package. $relation ++and $version correspond to the associated relation given in the Provides ++field (if present). ++ ++=cut ++ ++sub add_provided_package { ++ my ($self, $pkg, $rel, $ver, $by) = @_; ++ ++ $self->{virtualpkg}{$pkg} //= []; ++ push @{$self->{virtualpkg}{$pkg}}, [ $by, $rel, $ver ]; ++} ++ ++=item my ($check, $param) = $facts->check_package($package) ++ ++$check is one when the package is found. For a real package, $param ++contains the version. For a virtual package, $param contains an array ++reference containing the list of packages that provide it (each package is ++listed as [ $provider, $relation, $version ]). ++ ++This function is obsolete and should not be used. Sbuild::Deps::KnownFacts ++is only meant to be filled with data and then passed to Sbuild::Deps ++methods where appropriate, but it should not be directly queried. ++ ++=back ++ ++=cut ++ ++sub check_package { ++ my ($self, $pkg) = @_; ++ ++ carp 'obsolete function, pass Sbuild::Deps::KnownFacts to Sbuild::Deps ' . ++ 'methods instead'; ++ ++ if (exists $self->{pkg}{$pkg}) { ++ return (1, $self->{pkg}{$pkg}[0]{version}); ++ } ++ if (exists $self->{virtualpkg}{$pkg}) { ++ return (1, $self->{virtualpkg}{$pkg}); ++ } ++ return (0, undef); ++} ++ ++## The functions below are private to Sbuild::Deps ++ ++sub _find_package { ++ my ($self, $dep, $lackinfos) = @_; ++ my ($pkg, $archqual) = ($dep->{package}, $dep->{archqual}); ++ return if not exists $self->{pkg}{$pkg}; ++ my $host_arch = $dep->{host_arch}; ++ my $build_arch = $dep->{build_arch}; ++ foreach my $p (@{$self->{pkg}{$pkg}}) { ++ my $a = $p->{architecture}; ++ my $ma = $p->{multiarch}; ++ if (not defined $a) { ++ $$lackinfos = 1; ++ next; ++ } ++ if (not defined $archqual) { ++ return $p if $ma eq 'foreign'; ++ return $p if $a eq $host_arch or $a eq 'all'; ++ } elsif ($archqual eq 'any') { ++ return $p if $ma eq 'allowed'; ++ } elsif ($archqual eq 'native') { ++ return $p if $a eq $build_arch and $ma ne 'foreign'; ++ } else { ++ return $p if $a eq $archqual; ++ } ++ } ++ return; ++} ++ ++sub _find_virtual_packages { ++ my ($self, $pkg) = @_; ++ return () if not exists $self->{virtualpkg}{$pkg}; ++ return @{$self->{virtualpkg}{$pkg}}; ++} ++ ++sub _evaluate_simple_dep { ++ my ($self, $dep) = @_; ++ my ($lackinfos, $pkg) = (0, $dep->{package}); ++ my $p = $self->_find_package($dep, \$lackinfos); ++ if ($p) { ++ if (defined $dep->{relation}) { ++ if (defined $p->{version}) { ++ return 1 if version_compare_relation($p->{version}, ++ $dep->{relation}, $dep->{version}); ++ } else { ++ $lackinfos = 1; ++ } ++ } else { ++ return 1; ++ } ++ } ++ foreach my $virtpkg ($self->_find_virtual_packages($pkg)) { ++ next if defined $virtpkg->[1] and $virtpkg->[1] ne REL_EQ; ++ ++ if (defined $dep->{relation}) { ++ next if not defined $virtpkg->[2]; ++ return 1 if version_compare_relation($virtpkg->[2], ++ $dep->{relation}, ++ $dep->{version}); ++ } else { ++ return 1; ++ } ++ } ++ return if $lackinfos; ++ return 0; ++} ++ ++=head1 CHANGES ++ ++=head2 Version 1.05 (dpkg 1.17.14) ++ ++New function: Sbuild::Deps::deps_iterate(). ++ ++=head2 Version 1.04 (dpkg 1.17.10) ++ ++New options: Add use_profiles, build_profiles, reduce_profiles and ++reduce_restrictions to Sbuild::Deps::deps_parse(). ++ ++New methods: Add $dep->profile_is_concerned() and $dep->reduce_profiles() ++for all dependency objects. ++ ++=head2 Version 1.03 (dpkg 1.17.0) ++ ++New option: Add build_arch option to Sbuild::Deps::deps_parse(). ++ ++=head2 Version 1.02 (dpkg 1.17.0) ++ ++New function: Sbuild::Deps::deps_concat() ++ ++=head2 Version 1.01 (dpkg 1.16.1) ++ ++New method: Add $dep->reset() for all dependency objects. ++ ++New property: Sbuild::Deps::Simple now recognizes the arch qualifier "any" ++and stores it in the "archqual" property when present. ++ ++New option: Sbuild::Deps::KnownFacts->add_installed_package() now accepts 2 ++supplementary parameters ($arch and $multiarch). ++ ++Deprecated method: Sbuild::Deps::KnownFacts->check_package() is obsolete, ++it should not have been part of the public API. ++ ++=head2 Version 1.00 (dpkg 1.15.6) ++ ++Mark the module as public. ++ ++=cut ++ ++1; +Index: b/lib/Sbuild/Makefile.am +=================================================================== +--- a/lib/Sbuild/Makefile.am ++++ b/lib/Sbuild/Makefile.am +@@ -46,7 +46,10 @@ + LogBase.pm \ + Options.pm \ + OptionsBase.pm \ +- Utility.pm ++ Utility.pm \ ++ Arch.pm \ ++ BuildProfiles.pm \ ++ Deps.pm + + perlmodsbuild_DATA = \ + $(MODULES) \ +Index: b/lib/Sbuild/Makefile.in +=================================================================== +--- a/lib/Sbuild/Makefile.in ++++ b/lib/Sbuild/Makefile.in +@@ -313,7 +313,10 @@ + LogBase.pm \ + Options.pm \ + OptionsBase.pm \ +- Utility.pm ++ Utility.pm \ ++ Arch.pm \ ++ BuildProfiles.pm \ ++ Deps.pm + + perlmodsbuild_DATA = \ + $(MODULES) \ +Index: b/lib/Sbuild/ResolverBase.pm +=================================================================== +--- a/lib/Sbuild/ResolverBase.pm ++++ b/lib/Sbuild/ResolverBase.pm +@@ -28,7 +28,7 @@ + use File::Temp qw(tempdir tempfile); + use File::Copy; + +-use Dpkg::Deps; ++use Sbuild::Deps; + use Sbuild::Base; + use Sbuild qw(isin debug debug2); + +@@ -867,9 +867,9 @@ + # Filter out all but the first alternative except in special + # cases. + if (!$self->get_conf('RESOLVE_ALTERNATIVES')) { +- my $positive_filtered = Dpkg::Deps::AND->new(); ++ my $positive_filtered = Sbuild::Deps::AND->new(); + foreach my $item ($positive->get_deps()) { +- my $alt_filtered = Dpkg::Deps::OR->new(); ++ my $alt_filtered = Sbuild::Deps::OR->new(); + my @alternatives = $item->get_deps(); + my $first = shift @alternatives; + $alt_filtered->add($first) if defined $first; diff -Nru sbuild-0.65.2/debian/patches/copy-dummy-archive.patch sbuild-0.65.2/debian/patches/copy-dummy-archive.patch --- sbuild-0.65.2/debian/patches/copy-dummy-archive.patch 1970-01-01 00:00:00.000000000 +0000 +++ sbuild-0.65.2/debian/patches/copy-dummy-archive.patch 2016-02-18 14:34:45.000000000 +0000 @@ -0,0 +1,26 @@ +Description: Sbuild::ResolverBase: use copy: for dummy archive + We used to use file: URIs for sbuild's dummy archive, but recent versions + of apt put symlinks in /var/lib/apt/lists/ if we do that, which means that + those symlinks become broken as soon as we remove the dummy archive. + sbuild itself is OK with this, but launchpad-buildd tries to read + /var/lib/apt/lists/*_Packages in order to do dep-wait analysis after + failures, and that fails if there are broken symlinks there. It's easy + enough to avoid this problem by using copy: URIs instead, so let's do that. +Origin: backport, https://anonscm.debian.org/cgit/buildd-tools/sbuild.git/commit/?id=e2d63ebc20c8d2ef5d96db83828087505928895f +Last-Update: 2016-02-18 + +Index: b/lib/Sbuild/ResolverBase.pm +=================================================================== +--- a/lib/Sbuild/ResolverBase.pm ++++ b/lib/Sbuild/ResolverBase.pm +@@ -1013,8 +1013,8 @@ + # Write a list file for the dummy archive if one not create yet. + if (! -f $dummy_archive_list_file) { + my ($tmpfh, $tmpfilename) = tempfile(DIR => $session->get('Location') . "/tmp"); +- print $tmpfh 'deb file://' . $session->strip_chroot_path($dummy_archive_dir) . " ./\n"; +- print $tmpfh 'deb-src file://' . $session->strip_chroot_path($dummy_archive_dir) . " ./\n"; ++ print $tmpfh 'deb copy://' . $session->strip_chroot_path($dummy_archive_dir) . " ./\n"; ++ print $tmpfh 'deb-src copy://' . $session->strip_chroot_path($dummy_archive_dir) . " ./\n"; + + for my $repospec (@{$self->get_conf('EXTRA_REPOSITORIES')}) { + print $tmpfh "$repospec\n"; diff -Nru sbuild-0.65.2/debian/patches/fix-build-depends-arch.patch sbuild-0.65.2/debian/patches/fix-build-depends-arch.patch --- sbuild-0.65.2/debian/patches/fix-build-depends-arch.patch 1970-01-01 00:00:00.000000000 +0000 +++ sbuild-0.65.2/debian/patches/fix-build-depends-arch.patch 2016-01-11 12:22:02.000000000 +0000 @@ -0,0 +1,18 @@ +Description: Install Build-Depends-Arch in the correct situations +Origin: upstream, https://anonscm.debian.org/cgit/buildd-tools/sbuild.git/commit/lib/Sbuild/ResolverBase.pm?id=fec82ed70d7efdfe17f676c60e1114bd8bb4a888 +Bug-Ubuntu: https://bugs.launchpad.net/bugs/1516336 +Last-Update: 2016-01-11 + +Index: b/lib/Sbuild/ResolverBase.pm +=================================================================== +--- a/lib/Sbuild/ResolverBase.pm ++++ b/lib/Sbuild/ResolverBase.pm +@@ -806,7 +806,7 @@ + push(@negative, $deps->{'Build Conflicts'}) + if (defined($deps->{'Build Conflicts'}) && + $deps->{'Build Conflicts'} ne ""); +- if ($self->get_conf('BUILD_ARCH_ALL')) { ++ if ($self->get_conf('BUILD_ARCH_ANY')) { + push(@positive_arch, $deps->{'Build Depends Arch'}) + if (defined($deps->{'Build Depends Arch'}) && + $deps->{'Build Depends Arch'} ne ""); diff -Nru sbuild-0.65.2/debian/patches/no-pkg-mangle-deps.patch sbuild-0.65.2/debian/patches/no-pkg-mangle-deps.patch --- sbuild-0.65.2/debian/patches/no-pkg-mangle-deps.patch 2015-04-15 22:44:57.000000000 +0000 +++ sbuild-0.65.2/debian/patches/no-pkg-mangle-deps.patch 2015-07-28 14:12:18.000000000 +0000 @@ -1,8 +1,8 @@ -Index: sbuild-0.65.2/lib/Sbuild/ResolverBase.pm +Index: b/lib/Sbuild/ResolverBase.pm =================================================================== ---- sbuild-0.65.2.orig/lib/Sbuild/ResolverBase.pm -+++ sbuild-0.65.2/lib/Sbuild/ResolverBase.pm -@@ -945,7 +945,7 @@ EOF +--- a/lib/Sbuild/ResolverBase.pm ++++ b/lib/Sbuild/ResolverBase.pm +@@ -925,7 +925,7 @@ #Now build the package: $session->run_command( diff -Nru sbuild-0.65.2/debian/patches/old-dpkg-deps.patch sbuild-0.65.2/debian/patches/old-dpkg-deps.patch --- sbuild-0.65.2/debian/patches/old-dpkg-deps.patch 2015-04-15 18:20:44.000000000 +0000 +++ sbuild-0.65.2/debian/patches/old-dpkg-deps.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,31 +0,0 @@ -Index: sbuild-0.65.2/lib/Sbuild/ResolverBase.pm -=================================================================== ---- sbuild-0.65.2.orig/lib/Sbuild/ResolverBase.pm -+++ sbuild-0.65.2/lib/Sbuild/ResolverBase.pm -@@ -41,6 +41,26 @@ BEGIN { - @EXPORT = qw(); - } - -+sub deps_iterate { -+ my ($deps, $callback_func) = @_; -+ -+ my $visitor_func; -+ $visitor_func = sub { -+ foreach my $dep (@_) { -+ return unless defined $dep; -+ -+ if ($dep->isa('Dpkg::Deps::Simple')) { -+ return unless &{$callback_func}($dep); -+ } else { -+ return unless &{$visitor_func}($dep->get_deps()); -+ } -+ } -+ return 1; -+ }; -+ -+ return &{$visitor_func}($deps); -+} -+ - sub new { - my $class = shift; - my $conf = shift; diff -Nru sbuild-0.65.2/debian/patches/series sbuild-0.65.2/debian/patches/series --- sbuild-0.65.2/debian/patches/series 2015-07-13 13:06:35.000000000 +0000 +++ sbuild-0.65.2/debian/patches/series 2016-02-18 14:37:30.000000000 +0000 @@ -1,6 +1,8 @@ do-not-install-debfoster-into-chroots.patch no-sign-unauthenticated.patch fix-exception-handling.patch -old-dpkg-deps.patch no-pkg-mangle-deps.patch nolog-autoflush-stdout.patch +backport-dpkg-deps.patch +fix-build-depends-arch.patch +copy-dummy-archive.patch