Package: sbuild
Version: 0.64.0-1
Severity: wishlist
Tags: patch

When building related set of packages most people resort to set up a local
archive to enable the newly built packages to depend on locally built
dependencies for which the needed version has not hit the main archive yet.

Since sbuild already sets up a dummy archive for build dependencies, it could
also allow users to specify a list of packages that should be pushed there.

To do so I've added an --add-extra-package option that accepts a debfile and
can be used multiple times. It already allowed me to locally build packages
which depend on stuff not yet in the archive without any additional setup.

The git repo (`add-extra-package` branch) with the patches is at
http://cgit.collabora.com/git/user/em/sbuild/log/?h=add-extra-package

I also took the chance to refactor a bit the dummy archive handling and split
it out of the ResolverBase class. Even if not strictly needed it allowed me to
have a clear idea of the involved pieces and I think that the result is a bit
easier to understand and more flexible.

Comments and suggestions welcome, I'm not very proficient in Perl. :)



-- System Information:
Debian Release: jessie/sid
  APT prefers unstable
  APT policy: (500, 'unstable'), (500, 'testing'), (500, 'stable'), (500, 
'oldstable'), (1, 'experimental')
Architecture: amd64 (x86_64)
Foreign Architectures: i386

Kernel: Linux 3.10-rc5-amd64 (SMP w/4 CPU cores)
Locale: LANG=it_IT.utf8, LC_CTYPE=it_IT.utf8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages sbuild depends on:
ii  adduser         3.113+nmu3
ii  apt-utils       0.9.8.2
ii  libsbuild-perl  0.64.0-1
ii  perl            5.14.2-21
ii  perl-modules    5.14.2-21

Versions of packages sbuild recommends:
ii  debootstrap  1.0.52
ii  fakeroot     1.19-2

Versions of packages sbuild suggests:
pn  deborphan  <none>
ii  wget       1.14-2

-- no debconf information
>From 3746120a509778eb263ff9565ddf1de54bcedc2a Mon Sep 17 00:00:00 2001
From: Emanuele Aina <emanuele.a...@collabora.com>
Date: Fri, 31 May 2013 20:05:09 +0200
Subject: [PATCH 1/3] Sbuild::ResolverBase: Move the build-deps package
 building in its own method

---
 lib/Sbuild/ResolverBase.pm | 168 ++++++++++++++++++++++++++-------------------
 1 file changed, 99 insertions(+), 69 deletions(-)

diff --git a/lib/Sbuild/ResolverBase.pm b/lib/Sbuild/ResolverBase.pm
index efa6d9d..8048f16 100644
--- a/lib/Sbuild/ResolverBase.pm
+++ b/lib/Sbuild/ResolverBase.pm
@@ -607,79 +607,17 @@ sub get_dpkg_status {
     return \%result;
 }
 
-# Create an apt archive. Add to it if one exists.
-sub setup_apt_archive {
+sub build_dummy_package {
     my $self = shift;
+
     my $dummy_pkg_name = shift;
+    my $dummy_pkg_dir = shift;
+    my $dummy_deb = shift;
+    my $dummy_dsc = shift;
     my @pkgs = @_;
 
     my $session = $self->get('Session');
 
-    #Prepare a path to build a dummy package containing our deps:
-    if (! defined $self->get('Dummy package path')) {
-        $self->set('Dummy package path',
-		   tempdir('resolver' . '-XXXXXX',
-			   DIR => $self->get('Chroot Build Dir')));
-    }
-    $session->run_command(
-	{ COMMAND => ['chown', $self->get_conf('BUILD_USER') . ':sbuild',
-		      $session->strip_chroot_path($self->get('Dummy package path'))],
-	  USER => 'root',
-	  DIR => '/' });
-    if ($?) {
-	$self->log_error("E: Failed to set " . $self->get_conf('BUILD_USER') .
-			 ":sbuild ownership on dummy package dir\n");
-	return 0;
-    }
-    $session->run_command(
-	{ COMMAND => ['chmod', '0770', $session->strip_chroot_path($self->get('Dummy package path'))],
-	  USER => 'root',
-	  DIR => '/' });
-    if ($?) {
-	$self->log_error("E: Failed to set 0770 permissions on dummy package dir\n");
-	return 0;
-    }
-    my $dummy_dir = $self->get('Dummy package path');
-    my $dummy_gpghome = $dummy_dir . '/gpg';
-    my $dummy_archive_dir = $dummy_dir . '/apt_archive';
-    my $dummy_release_file = $dummy_archive_dir . '/Release';
-    my $dummy_archive_seckey = $dummy_archive_dir . '/sbuild-key.sec';
-    my $dummy_archive_pubkey = $dummy_archive_dir . '/sbuild-key.pub';
-
-    $self->set('Dummy archive directory', $dummy_archive_dir);
-    $self->set('Dummy Release file', $dummy_release_file);
-    my $dummy_archive_list_file = $self->get('Dummy archive list file');
-
-    if (! -d $dummy_dir) {
-        $self->log_warning('Could not create build-depends dummy dir ' . $dummy_dir . ': ' . $!);
-        $self->cleanup_apt_archive();
-        return 0;
-    }
-    if (!(-d $dummy_gpghome || mkdir $dummy_gpghome, 0700)) {
-        $self->log_warning('Could not create build-depends dummy gpg home dir ' . $dummy_gpghome . ': ' . $!);
-        $self->cleanup_apt_archive();
-        return 0;
-    }
-    $session->run_command(
-	{ COMMAND => ['chown', $self->get_conf('BUILD_USER') . ':sbuild',
-		      $session->strip_chroot_path($dummy_gpghome)],
-	  USER => 'root',
-	  DIR => '/' });
-    if ($?) {
-	$self->log_error("E: Failed to set " . $self->get_conf('BUILD_USER') .
-			 ":sbuild ownership on $dummy_gpghome\n");
-	return 0;
-    }
-    if (!(-d $dummy_archive_dir || mkdir $dummy_archive_dir, 0775)) {
-        $self->log_warning('Could not create build-depends dummy archive dir ' . $dummy_archive_dir . ': ' . $!);
-        $self->cleanup_apt_archive();
-        return 0;
-    }
-
-    my $dummy_pkg_dir = $dummy_dir . '/' . $dummy_pkg_name;
-    my $dummy_deb = $dummy_archive_dir . '/' . $dummy_pkg_name . '.deb';
-    my $dummy_dsc = $dummy_archive_dir . '/' . $dummy_pkg_name . '.dsc';
-
     if (!(mkdir($dummy_pkg_dir) && mkdir($dummy_pkg_dir . '/DEBIAN'))) {
 	$self->log_warning('Could not create build-depends dummy dir ' . $dummy_pkg_dir . '/DEBIAN: ' . $!);
         $self->cleanup_apt_archive();
@@ -795,8 +733,7 @@ EOF
 
     foreach my $path ($dummy_pkg_dir . '/DEBIAN/control',
 		      $dummy_pkg_dir . '/DEBIAN',
-		      $dummy_pkg_dir,
-		      $dummy_archive_dir) {
+		      $dummy_pkg_dir) {
 	$session->run_command(
 	    { COMMAND => ['chown', $self->get_conf('BUILD_USER') . ':sbuild',
 			  $session->strip_chroot_path($path)],
@@ -857,6 +794,99 @@ EOF
     print $dummy_dsc_fh "\n";
     close $dummy_dsc_fh;
 
+    return 1;
+}
+
+# Create an apt archive. Add to it if one exists.
+sub setup_apt_archive {
+    my $self = shift;
+    my $dummy_pkg_name = shift;
+    my @pkgs = @_;
+
+    my $session = $self->get('Session');
+
+    #Prepare a path to build a dummy package containing our deps:
+    if (! defined $self->get('Dummy package path')) {
+        $self->set('Dummy package path',
+		   tempdir('resolver' . '-XXXXXX',
+			   DIR => $self->get('Chroot Build Dir')));
+    }
+    $session->run_command(
+	{ COMMAND => ['chown', $self->get_conf('BUILD_USER') . ':sbuild',
+		      $session->strip_chroot_path($self->get('Dummy package path'))],
+	  USER => 'root',
+	  DIR => '/' });
+    if ($?) {
+	$self->log_error("E: Failed to set " . $self->get_conf('BUILD_USER') .
+			 ":sbuild ownership on dummy package dir\n");
+	return 0;
+    }
+    $session->run_command(
+	{ COMMAND => ['chmod', '0770', $session->strip_chroot_path($self->get('Dummy package path'))],
+	  USER => 'root',
+	  DIR => '/' });
+    if ($?) {
+	$self->log_error("E: Failed to set 0770 permissions on dummy package dir\n");
+	return 0;
+    }
+    my $dummy_dir = $self->get('Dummy package path');
+    my $dummy_gpghome = $dummy_dir . '/gpg';
+    my $dummy_archive_dir = $dummy_dir . '/apt_archive';
+    my $dummy_release_file = $dummy_archive_dir . '/Release';
+    my $dummy_archive_seckey = $dummy_archive_dir . '/sbuild-key.sec';
+    my $dummy_archive_pubkey = $dummy_archive_dir . '/sbuild-key.pub';
+
+    $self->set('Dummy archive directory', $dummy_archive_dir);
+    $self->set('Dummy Release file', $dummy_release_file);
+    my $dummy_archive_list_file = $self->get('Dummy archive list file');
+
+    if (! -d $dummy_dir) {
+        $self->log_warning('Could not create build-depends dummy dir ' . $dummy_dir . ': ' . $!);
+        $self->cleanup_apt_archive();
+        return 0;
+    }
+    if (!(-d $dummy_gpghome || mkdir $dummy_gpghome, 0700)) {
+        $self->log_warning('Could not create build-depends dummy gpg home dir ' . $dummy_gpghome . ': ' . $!);
+        $self->cleanup_apt_archive();
+        return 0;
+    }
+    $session->run_command(
+	{ COMMAND => ['chown', $self->get_conf('BUILD_USER') . ':sbuild',
+		      $session->strip_chroot_path($dummy_gpghome)],
+	  USER => 'root',
+	  DIR => '/' });
+    if ($?) {
+	$self->log_error("E: Failed to set " . $self->get_conf('BUILD_USER') .
+			 ":sbuild ownership on $dummy_gpghome\n");
+	return 0;
+    }
+    if (!(-d $dummy_archive_dir || mkdir $dummy_archive_dir, 0775)) {
+        $self->log_warning('Could not create build-depends dummy archive dir ' . $dummy_archive_dir . ': ' . $!);
+        $self->cleanup_apt_archive();
+        return 0;
+    }
+
+    $session->run_command(
+        { COMMAND => ['chown', $self->get_conf('BUILD_USER') . ':sbuild',
+                      $session->strip_chroot_path($dummy_archive_dir)],
+          USER => 'root',
+          DIR => '/' });
+    if ($?) {
+        $self->log_error("E: Failed to set " . $self->get_conf('BUILD_USER')
+                       . ":sbuild ownership on $dummy_archive_dir\n");
+        return 0;
+    }
+
+    my $dummy_pkg_dir = $dummy_dir . '/' . $dummy_pkg_name;
+    my $dummy_deb = $dummy_archive_dir . '/' . $dummy_pkg_name . '.deb';
+    my $dummy_dsc = $dummy_archive_dir . '/' . $dummy_pkg_name . '.dsc';
+
+    if (!$self->build_dummy_package ($dummy_pkg_name, $dummy_pkg_dir, $dummy_deb, $dummy_dsc, @pkgs)) {
+        $self->log("Failed to create build-depends dummy package.\n");
+        $self->cleanup_apt_archive();
+        return 0;
+    }
+
     # Do code to run apt-ftparchive
     if (!$self->run_apt_ftparchive()) {
         $self->log("Failed to run apt-ftparchive.\n");
-- 
1.8.3.1


>From da51ee83b51d89c17c2b874fcc95767f368a03a4 Mon Sep 17 00:00:00 2001
From: Emanuele Aina <emanuele.a...@collabora.com>
Date: Fri, 31 May 2013 20:09:05 +0200
Subject: [PATCH 2/3] Sbuild::DummyArchive: Move dummy archive management in
 its own class

---
 lib/Sbuild/DummyArchive.pm | 554 +++++++++++++++++++++++++++++++++++++++++++++
 lib/Sbuild/Makefile.am     |   1 +
 lib/Sbuild/ResolverBase.pm | 334 ++++-----------------------
 3 files changed, 602 insertions(+), 287 deletions(-)
 create mode 100644 lib/Sbuild/DummyArchive.pm

diff --git a/lib/Sbuild/DummyArchive.pm b/lib/Sbuild/DummyArchive.pm
new file mode 100644
index 0000000..afe2bc7
--- /dev/null
+++ b/lib/Sbuild/DummyArchive.pm
@@ -0,0 +1,554 @@
+# DummyArchive.pm: build library for sbuild
+# Copyright © 2005      Ryan Murray <rmur...@debian.org>
+# Copyright © 2005-2010 Roger Leigh <rle...@debian.org>
+# Copyright © 2008      Simon McVittie <s...@debian.org>
+# Copyright © 2013      Emanuele Aina <emanuele.a...@collabora.com>
+#
+# 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 Sbuild::DummyArchive;
+
+use strict;
+use warnings;
+use POSIX;
+use Fcntl;
+use File::Temp qw(tempdir tempfile);
+use File::Copy;
+
+use Dpkg::Deps;
+use Sbuild::Base;
+use Sbuild qw(isin debug debug2);
+
+BEGIN {
+    use Exporter ();
+    our (@ISA, @EXPORT);
+
+    @ISA = qw(Exporter Sbuild::Base);
+
+    @EXPORT = qw();
+}
+
+sub new {
+    my $class = shift;
+    my $conf = shift;
+    my $session = shift;
+    my $host = shift;
+    my $archive_shortname = shift;
+    my $archive_name = shift;
+    my $secret_key_file = shift;
+    my $public_key_file = shift;
+
+    my $self = $class->SUPER::new($conf);
+    bless($self, $class);
+
+    $self->set('Session', $session);
+    $self->set('Host', $host);
+    $self->set('Split', $self->get_conf('CHROOT_SPLIT'));
+    # Typically set by Sbuild::Build, but not outside a build context.
+    $self->set('Host Arch', $self->get_conf('HOST_ARCH'));
+    $self->set('Build Arch', $self->get_conf('BUILD_ARCH'));
+
+    $self->set('Shortname', $archive_shortname);
+    $self->set('Name', $archive_name);
+    $self->set('Dummy archive secret key file', $secret_key_file);
+    $self->set('Dummy archive public key file', $public_key_file);
+    $self->set('Debs', []);
+    $self->set('Dscs', []);
+
+    my $dummy_archive_list_file = $session->get('Location') .
+        "/etc/apt/sources.list.d/sbuild-${archive_shortname}-archive.list";
+    $self->set('Dummy archive list file', $dummy_archive_list_file);
+
+    return $self;
+}
+
+sub force_update_archive_list {
+    my $self = shift;
+
+	# Example archive list names:
+	#_tmp_resolver-XXXXXX_apt%5farchive_._Packages
+	#_tmp_resolver-XXXXXX_apt%5farchive_._Release
+	#_tmp_resolver-XXXXXX_apt%5farchive_._Release.gpg
+	#_tmp_resolver-XXXXXX_apt%5farchive_._Sources
+
+	# Update lists directly; only updates local archive
+
+	# Filename quoting for safety taken from apt URItoFileName and
+	# QuoteString.
+	my $session = $self->get('Session');
+	my $dummy_dir = $self->get('Dummy archive path');
+	my $dummy_archive_dir = $session->strip_chroot_path($dummy_dir.'/apt_archive/./');
+	my @chars = split('', $dummy_archive_dir);
+
+	foreach(@chars) {
+	    if (index('\\|{}[]<>"^~_=!@#$%^&*', $_) != -1 || # "Bad" characters
+		!m/[[:print:]]/ || # Not printable
+		ord($_) == 0x25 || # Percent '%' char
+		ord($_) <= 0x20 || # Control chars
+		ord($_) >= 0x7f) { # Control chars
+		$_ = sprintf("%%%02x", ord($_));
+	    }
+	}
+
+	my $uri = join('', @chars);
+	$uri =~ s;/;_;g; # Escape slashes
+
+	foreach my $file ("Packages", "Release", "Release.gpg", "Sources") {
+	    $session->run_command(
+		{ COMMAND => ['cp', $dummy_archive_dir . '/' . $file,
+			      '/var/lib/apt/lists/' . $uri . $file],
+		  USER => 'root',
+		  PRIORITY => 0 });
+		if ($?) {
+			$self->log("Failed to copy file from dummy archive to apt lists.\n");
+			return 1;
+		}
+	}
+
+	$self->run_apt_command(
+	    { COMMAND => [$self->get_conf('APT_CACHE'), 'gencaches'],
+	      ENV => {'DEBIAN_FRONTEND' => 'noninteractive'},
+	      USER => 'root',
+	      DIR => '/' });
+	return $?;
+}
+
+sub add_deb {
+    my $self = shift;
+    my $deb = shift;
+
+    my @debs = @{$self->get('Debs')};
+    push (@debs, $deb);
+    $self->set('Debs', \@debs);
+}
+
+sub add_dsc {
+    my $self = shift;
+    my $dsc = shift;
+
+    my @dscs = @{$self->get('Dscs')};
+    push (@dscs, $dsc);
+    $self->set('Dscs', \@dscs);
+}
+
+sub run_apt {
+    my $self = shift;
+    my $mode = shift;
+    my $inst_ret = shift;
+    my $rem_ret = shift;
+    my $action = shift;
+    my @packages = @_;
+    my( $msgs, $status, $pkgs, $rpkgs );
+
+    $msgs = "";
+    # redirection of stdin from /dev/null so that conffile question
+    # are treated as if RETURN was pressed.
+    # dpkg since 1.4.1.18 issues an error on the conffile question if
+    # it reads EOF -- hardwire the new --force-confold option to avoid
+    # the questions.
+    my @apt_command = ($self->get_conf('APT_GET'), '--purge',
+	'-o', 'DPkg::Options::=--force-confold',
+	'-o', 'DPkg::Options::=--refuse-remove-essential',
+	'-o', 'APT::Install-Recommends=false',
+	'-q');
+    push @apt_command, '--allow-unauthenticated' if
+	($self->get_conf('APT_ALLOW_UNAUTHENTICATED'));
+    push @apt_command, "$mode", $action, @packages;
+    my $pipe =
+	$self->pipe_apt_command(
+	    { COMMAND => \@apt_command,
+	      ENV => {'DEBIAN_FRONTEND' => 'noninteractive'},
+	      USER => 'root',
+	      PRIORITY => 0,
+	      DIR => '/' });
+    if (!$pipe) {
+	$self->log("Can't open pipe to apt-get: $!\n");
+	return 0;
+    }
+
+    while(<$pipe>) {
+	$msgs .= $_;
+	$self->log($_) if $mode ne "-s" || debug($_);
+    }
+    close($pipe);
+    $status = $?;
+
+    $pkgs = $rpkgs = "";
+    if ($msgs =~ /NEW packages will be installed:\n((^[ 	].*\n)*)/mi) {
+	($pkgs = $1) =~ s/^[ 	]*((.|\n)*)\s*$/$1/m;
+	$pkgs =~ s/\*//g;
+    }
+    if ($msgs =~ /packages will be REMOVED:\n((^[ 	].*\n)*)/mi) {
+	($rpkgs = $1) =~ s/^[ 	]*((.|\n)*)\s*$/$1/m;
+	$rpkgs =~ s/\*//g;
+    }
+    @$inst_ret = split( /\s+/, $pkgs );
+    @$rem_ret = split( /\s+/, $rpkgs );
+
+    $self->log("apt-get failed.\n") if $status && $mode ne "-s";
+    return $mode eq "-s" || $status == 0;
+}
+
+# Create an apt archive. Add to it if one exists.
+sub setup {
+    my $self = shift;
+
+    my $shortname = $self->get('Shortname');
+    my $session = $self->get('Session');
+
+    if (! defined $self->get('Dummy archive path')) {
+        my $archive_shortname = $self->get('Shortname');
+        $self->set('Dummy archive path',
+		   tempdir('dummy-archive-' . $shortname. '-XXXXXX',
+			   DIR => $self->get('Chroot Build Dir')));
+    }
+    $session->run_command(
+	{ COMMAND => ['chown', $self->get_conf('BUILD_USER') . ':sbuild',
+		      $session->strip_chroot_path($self->get('Dummy archive path'))],
+	  USER => 'root',
+	  DIR => '/' });
+    if ($?) {
+	$self->log_error("E: Failed to set " . $self->get_conf('BUILD_USER') .
+			 ":sbuild ownership on dummy archive dir\n");
+	return 0;
+    }
+    $session->run_command(
+	{ COMMAND => ['chmod', '0770', $session->strip_chroot_path($self->get('Dummy archive path'))],
+	  USER => 'root',
+	  DIR => '/' });
+    if ($?) {
+	$self->log_error("E: Failed to set 0770 permissions on dummy archive dir\n");
+	return 0;
+    }
+    my $dummy_dir = $self->get('Dummy archive path');
+    my $dummy_gpghome = $dummy_dir . '/gpg';
+    my $dummy_archive_dir = $dummy_dir . '/apt_archive';
+    my $dummy_release_file = $dummy_archive_dir . '/Release';
+
+    $self->set('Dummy archive directory', $dummy_archive_dir);
+    $self->set('Dummy Release file', $dummy_release_file);
+    $self->set('Dummy GPG home', $dummy_gpghome);
+
+    if (!(-d $dummy_gpghome || mkdir $dummy_gpghome, 0700)) {
+        $self->log_warning('Could not create gpg home dir ' . $dummy_gpghome .
+                           ' for dummy archive ' . $shortname . ': ' . $!);
+        $self->cleanup();
+        return 0;
+    }
+    $session->run_command(
+	{ COMMAND => ['chown', $self->get_conf('BUILD_USER') . ':sbuild',
+		      $session->strip_chroot_path($dummy_gpghome)],
+	  USER => 'root',
+	  DIR => '/' });
+    if ($?) {
+	$self->log_error("E: Failed to set " . $self->get_conf('BUILD_USER') .
+			 ":sbuild ownership on $dummy_gpghome\n");
+	return 0;
+    }
+    if (!(-d $dummy_archive_dir || mkdir $dummy_archive_dir, 0775)) {
+        $self->log_warning('Could not create archive dir ' . $dummy_archive_dir .
+                           ' for dummy archive ' . $shortname . ': ' . $!);
+        $self->cleanup();
+        return 0;
+    }
+    return 1;
+}
+
+# Push files in the archive and add it to the APT sources
+sub populate {
+    my $self = shift;
+
+    my @debs = @{$self->get('Debs')};
+    my @dscs = @{$self->get('Dscs')};
+    my $dummy_archive_dir = $self->get('Dummy archive directory');
+    my $dummy_archive_list_file = $self->get('Dummy archive list file');
+    my $dummy_release_file= $self->get('Dummy Release file');
+    my $session = $self->get('Session');
+    my $dummy_gpghome = $self->get('Dummy GPG home');
+
+    my $dummy_archive_seckey = $dummy_archive_dir . '/sbuild-key.sec';
+    my $dummy_archive_pubkey = $dummy_archive_dir . '/sbuild-key.pub';
+
+    foreach my $file (@debs, @dscs) {
+        copy($file, $dummy_archive_dir);
+        if ($?) {
+            $self->log("Failed to copy ${file} to the dummy archive.\n");
+            $self->cleanup();
+            return 0;
+        }
+    }
+
+    # Do code to run apt-ftparchive
+    if (!$self->run_apt_ftparchive()) {
+        $self->log("Failed to run apt-ftparchive.\n");
+        $self->cleanup();
+        return 0;
+    }
+
+    if (! -f $dummy_archive_seckey) {
+        my $secret_key = $self->get('Dummy archive secret key file');
+        copy($secret_key, $dummy_archive_seckey);
+        if ($?) {
+            $self->log("Failed to copy the secret key ${secret_key} to the dummy archive.\n");
+            $self->cleanup();
+            return 0;
+        }
+    }
+
+    if (! -f $dummy_archive_pubkey) {
+        my $public_key = $self->get('Dummy archive public key file');
+        copy($public_key, $dummy_archive_pubkey);
+        if ($?) {
+            $self->log("Failed to copy the public key ${public_key} to the dummy archive.\n");
+            $self->cleanup();
+            return 0;
+        }
+    }
+
+    # Sign the release file
+    my @gpg_command = ('gpg', '--yes', '--no-default-keyring',
+                       '--homedir',
+                       $session->strip_chroot_path($dummy_gpghome),
+                       '--secret-keyring',
+                       $session->strip_chroot_path($dummy_archive_seckey),
+                       '--keyring',
+                       $session->strip_chroot_path($dummy_archive_pubkey),
+                       '--default-key', 'Sbuild Signer', '-abs',
+                       '-o', $session->strip_chroot_path($dummy_release_file) . '.gpg',
+                       $session->strip_chroot_path($dummy_release_file));
+    $session->run_command(
+	{ COMMAND => \@gpg_command,
+	  USER => $self->get_conf('BUILD_USER'),
+	  PRIORITY => 0});
+    if ($?) {
+	$self->log("Failed to sign dummy archive Release file.\n");
+        $self->cleanup();
+	return 0;
+    }
+
+    # 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";
+        close($tmpfh);
+        # List file needs to be moved with root.
+        $session->run_command(
+            { COMMAND => ['chmod', '0644', $session->strip_chroot_path($tmpfilename)],
+              USER => 'root',
+              PRIORITY => 0});
+        if ($?) {
+            $self->log("Failed to create apt list file for dummy archive.\n");
+            $self->cleanup();
+            return 0;
+        }
+        $session->run_command(
+            { COMMAND => ['mv', $session->strip_chroot_path($tmpfilename),
+                          $session->strip_chroot_path($dummy_archive_list_file)],
+              USER => 'root',
+              PRIORITY => 0});
+        if ($?) {
+            $self->log("Failed to create apt list file for dummy archive.\n");
+            $self->cleanup();
+            return 0;
+        }
+    }
+
+    # Add the generated key
+    $session->run_command(
+        { COMMAND => ['apt-key', 'add', $session->strip_chroot_path($dummy_archive_pubkey)],
+          USER => 'root',
+          PRIORITY => 0});
+    if ($?) {
+        $self->log("Failed to add dummy archive key.\n");
+        $self->cleanup();
+        return 0;
+    }
+
+    return 1;
+}
+
+sub cleanup {
+    my $self = shift;
+
+    my $session = $self->get('Session');
+
+    if (defined $self->get('Dummy archive path')) {
+	$session->run_command(
+	    { COMMAND => ['rm', '-fr', $session->strip_chroot_path($self->get('Dummy archive path'))],
+	      USER => $self->get_conf('BUILD_USER'),
+	      DIR => '/' });
+    }
+
+    $session->run_command(
+	{ COMMAND => ['rm', '-f', $session->strip_chroot_path($self->get('Dummy archive list file'))],
+	  USER => 'root',
+	  DIR => '/',
+	  PRIORITY => 0});
+    $self->set('Dummy archive path', undef);
+    $self->set('Dummy archive directory', undef);
+    $self->set('Dummy Release file', undef);
+}
+
+# Function that runs apt-ftparchive
+sub run_apt_ftparchive {
+    my $self = shift;
+
+    my $session = $self->get('Session');
+    my $host = $self->get('Host');
+
+    my ($tmpfh, $tmpfilename) = tempfile();
+    my $dummy_archive_shortname = $self->get('Shortname');
+    my $dummy_archive_name = $self->get('Name');
+    my $dummy_archive_dir = $self->get('Dummy archive directory');
+
+    # Write the conf file.
+    print $tmpfh <<"EOF";
+Dir {
+ ArchiveDir "$dummy_archive_dir";
+};
+
+Default {
+ Packages::Compress ". gzip";
+ Sources::Compress ". gzip";
+};
+
+BinDirectory "$dummy_archive_dir" {
+ Packages "Packages";
+ Sources "Sources";
+};
+
+APT::FTPArchive::Release::Origin "sbuild-$dummy_archive_shortname-archive";
+APT::FTPArchive::Release::Label "sbuild-$dummy_archive_shortname-archive";
+APT::FTPArchive::Release::Suite "invalid";
+APT::FTPArchive::Release::Codename "invalid";
+APT::FTPArchive::Release::Description "Sbuild $dummy_archive_name Temporary Archive";
+EOF
+    close $tmpfh;
+
+    # Remove APT_CONFIG environment variable here, restore it later.
+    my $env = $self->get('Session')->get('Defaults')->{'ENV'};
+    my $apt_config_value = $env->{'APT_CONFIG'};
+    delete $env->{'APT_CONFIG'};
+
+    # Run apt-ftparchive to generate Packages and Sources files.
+    $host->run_command(
+        { COMMAND => ['apt-ftparchive', '-q=2', 'generate', $tmpfilename],
+          USER => $self->get_conf('USERNAME'),
+          PRIORITY => 0,
+          DIR => '/'});
+    if ($?) {
+        $env->{'APT_CONFIG'} = $apt_config_value;
+	unlink $tmpfilename;
+        return 0;
+    }
+
+    # Get output for Release file
+    my $pipe = $host->pipe_command(
+        { COMMAND => ['apt-ftparchive', '-q=2', '-c', $tmpfilename, 'release', $dummy_archive_dir],
+          USER => $self->get_conf('USERNAME'),
+          PRIORITY => 0,
+          DIR => '/'});
+    if (!defined($pipe)) {
+        $env->{'APT_CONFIG'} = $apt_config_value;
+	unlink $tmpfilename;
+        return 0;
+    }
+    $env->{'APT_CONFIG'} = $apt_config_value;
+
+
+    # Write output to Release file path.
+    my ($releasefh);
+    if (!open($releasefh, '>', $self->get('Dummy Release file'))) {
+        close $pipe;
+	unlink $tmpfilename;
+        return 0;
+    }
+
+    while (<$pipe>) {
+        print $releasefh $_;
+    }
+    close $releasefh;
+    close $pipe;
+
+    # Remove config file.  Note also removed on failure paths above.
+    unlink $tmpfilename;
+
+    return 1;
+}
+
+sub get_apt_command_internal {
+    my $self = shift;
+    my $options = shift;
+
+    my $command = $options->{'COMMAND'};
+    my $apt_options = $self->get('APT Options');
+
+    debug2("APT Options: ", join(" ", @$apt_options), "\n")
+	if defined($apt_options);
+
+    my @aptcommand = ();
+    if (defined($apt_options)) {
+	push(@aptcommand, @{$command}[0]);
+	push(@aptcommand, @$apt_options);
+	if ($#$command > 0) {
+	    push(@aptcommand, @{$command}[1 .. $#$command]);
+	}
+    } else {
+	@aptcommand = @$command;
+    }
+
+    debug2("APT Command: ", join(" ", @aptcommand), "\n");
+
+    $options->{'INTCOMMAND'} = \@aptcommand;
+}
+
+sub run_apt_command {
+    my $self = shift;
+    my $options = shift;
+
+    my $session = $self->get('Session');
+    my $host = $self->get('Host');
+
+    # Set modfied command
+    $self->get_apt_command_internal($options);
+
+    if ($self->get('Split')) {
+	return $host->run_command_internal($options);
+    } else {
+	return $session->run_command_internal($options);
+    }
+}
+
+sub pipe_apt_command {
+    my $self = shift;
+    my $options = shift;
+
+    my $session = $self->get('Session');
+    my $host = $self->get('Host');
+
+    # Set modfied command
+    $self->get_apt_command_internal($options);
+
+    if ($self->get('Split')) {
+	return $host->pipe_command_internal($options);
+    } else {
+	return $session->pipe_command_internal($options);
+    }
+}
+
+1;
diff --git a/lib/Sbuild/Makefile.am b/lib/Sbuild/Makefile.am
index 945645c..5897657 100644
--- a/lib/Sbuild/Makefile.am
+++ b/lib/Sbuild/Makefile.am
@@ -35,6 +35,7 @@ MODULES =			\
 	ChrootInfo.pm		\
 	ChrootInfoSchroot.pm	\
 	ChrootInfoSudo.pm	\
+	DummyArchive.pm		\
 	Exception.pm		\
 	ResolverBase.pm		\
 	AptitudeResolver.pm	\
diff --git a/lib/Sbuild/ResolverBase.pm b/lib/Sbuild/ResolverBase.pm
index 8048f16..c1dd9c3 100644
--- a/lib/Sbuild/ResolverBase.pm
+++ b/lib/Sbuild/ResolverBase.pm
@@ -30,6 +30,7 @@ use File::Copy;
 
 use Dpkg::Deps;
 use Sbuild::Base;
+use Sbuild::DummyArchive;
 use Sbuild qw(isin debug debug2);
 
 BEGIN {
@@ -59,10 +60,17 @@ sub new {
     $self->set('Host Arch', $self->get_conf('HOST_ARCH'));
     $self->set('Build Arch', $self->get_conf('BUILD_ARCH'));
 
-    my $dummy_archive_list_file = $session->get('Location') .
-        '/etc/apt/sources.list.d/sbuild-build-depends-archive.list';
-    $self->set('Dummy archive list file', $dummy_archive_list_file);
+    if (!$self->generate_keys()) {
+        $self->log("Failed to generate archive keys.\n");
+        $self->cleanup_apt_archive();
+        return 0;
+    }
 
+    my $dummy_archive = Sbuild::DummyArchive->new($conf, $session, $host,
+                                                  'build-depends', 'Build Dependencies',
+                                                  $self->get_conf('SBUILD_BUILD_DEPENDS_SECRET_KEY'),
+                                                  $self->get_conf('SBUILD_BUILD_DEPENDS_PUBLIC_KEY'));
+    $self->set('Dummy archive', $dummy_archive);
 
     return $self;
 }
@@ -188,52 +196,8 @@ sub update_archive {
 	      DIR => '/' });
 	return $?;
     } else {
-	# Example archive list names:
-	#_tmp_resolver-XXXXXX_apt%5farchive_._Packages
-	#_tmp_resolver-XXXXXX_apt%5farchive_._Release
-	#_tmp_resolver-XXXXXX_apt%5farchive_._Release.gpg
-	#_tmp_resolver-XXXXXX_apt%5farchive_._Sources
-
-	# Update lists directly; only updates local archive
-
-	# Filename quoting for safety taken from apt URItoFileName and
-	# QuoteString.
-	my $session = $self->get('Session');
-	my $dummy_dir = $self->get('Dummy package path');
-	my $dummy_archive_dir = $session->strip_chroot_path($dummy_dir.'/apt_archive/./');
-	my @chars = split('', $dummy_archive_dir);
-
-	foreach(@chars) {
-	    if (index('\\|{}[]<>"^~_=!@#$%^&*', $_) != -1 || # "Bad" characters
-		!m/[[:print:]]/ || # Not printable
-		ord($_) == 0x25 || # Percent '%' char
-		ord($_) <= 0x20 || # Control chars
-		ord($_) >= 0x7f) { # Control chars
-		$_ = sprintf("%%%02x", ord($_));
-	    }
-	}
-
-	my $uri = join('', @chars);
-	$uri =~ s;/;_;g; # Escape slashes
-
-	foreach my $file ("Packages", "Release", "Release.gpg", "Sources") {
-	    $session->run_command(
-		{ COMMAND => ['cp', $dummy_archive_dir . '/' . $file,
-			      '/var/lib/apt/lists/' . $uri . $file],
-		  USER => 'root',
-		  PRIORITY => 0 });
-		if ($?) {
-			$self->log("Failed to copy file from dummy archive to apt lists.\n");
-			return 1;
-		}
-	}
-
-	$self->run_apt_command(
-	    { COMMAND => [$self->get_conf('APT_CACHE'), 'gencaches'],
-	      ENV => {'DEBIAN_FRONTEND' => 'noninteractive'},
-	      USER => 'root',
-	      DIR => '/' });
-	return $?;
+        my $dummy_archive = $self->get('Dummy archive');
+        $dummy_archive->force_update_archive_list();
     }
 }
 
@@ -797,7 +761,27 @@ EOF
     return 1;
 }
 
-# Create an apt archive. Add to it if one exists.
+# Generate a key pair if not already done.
+sub generate_keys {
+    my $self = shift;
+
+    if ((-f $self->get_conf('SBUILD_BUILD_DEPENDS_SECRET_KEY')) &&
+        (-f $self->get_conf('SBUILD_BUILD_DEPENDS_PUBLIC_KEY'))) {
+        return 1;
+    }
+
+    $self->log_error("Local archive GPG signing key not found\n");
+    $self->log_info("Please generate a key with 'sbuild-update --keygen'\n");
+    $self->log_info("Note that on machines with scarce entropy, you may wish ".
+		    "to generate the key with this command on another machine ".
+		    "and copy the public and private keypair to '" .
+		    $self->get_conf('SBUILD_BUILD_DEPENDS_PUBLIC_KEY')
+		    ."' and '".
+		    $self->get_conf('SBUILD_BUILD_DEPENDS_SECRET_KEY') ."'\n");
+    return 0;
+}
+
+# Create an apt archive with the dummy build-depends package.
 sub setup_apt_archive {
     my $self = shift;
     my $dummy_pkg_name = shift;
@@ -805,6 +789,9 @@ sub setup_apt_archive {
 
     my $session = $self->get('Session');
 
+    my $dummy_archive = $self->get('Dummy archive');
+    $dummy_archive->set('Chroot Build Dir', $self->get('Chroot Build Dir'));
+
     #Prepare a path to build a dummy package containing our deps:
     if (! defined $self->get('Dummy package path')) {
         $self->set('Dummy package path',
@@ -830,56 +817,9 @@ sub setup_apt_archive {
 	return 0;
     }
     my $dummy_dir = $self->get('Dummy package path');
-    my $dummy_gpghome = $dummy_dir . '/gpg';
-    my $dummy_archive_dir = $dummy_dir . '/apt_archive';
-    my $dummy_release_file = $dummy_archive_dir . '/Release';
-    my $dummy_archive_seckey = $dummy_archive_dir . '/sbuild-key.sec';
-    my $dummy_archive_pubkey = $dummy_archive_dir . '/sbuild-key.pub';
-
-    $self->set('Dummy archive directory', $dummy_archive_dir);
-    $self->set('Dummy Release file', $dummy_release_file);
-    my $dummy_archive_list_file = $self->get('Dummy archive list file');
-
-    if (! -d $dummy_dir) {
-        $self->log_warning('Could not create build-depends dummy dir ' . $dummy_dir . ': ' . $!);
-        $self->cleanup_apt_archive();
-        return 0;
-    }
-    if (!(-d $dummy_gpghome || mkdir $dummy_gpghome, 0700)) {
-        $self->log_warning('Could not create build-depends dummy gpg home dir ' . $dummy_gpghome . ': ' . $!);
-        $self->cleanup_apt_archive();
-        return 0;
-    }
-    $session->run_command(
-	{ COMMAND => ['chown', $self->get_conf('BUILD_USER') . ':sbuild',
-		      $session->strip_chroot_path($dummy_gpghome)],
-	  USER => 'root',
-	  DIR => '/' });
-    if ($?) {
-	$self->log_error("E: Failed to set " . $self->get_conf('BUILD_USER') .
-			 ":sbuild ownership on $dummy_gpghome\n");
-	return 0;
-    }
-    if (!(-d $dummy_archive_dir || mkdir $dummy_archive_dir, 0775)) {
-        $self->log_warning('Could not create build-depends dummy archive dir ' . $dummy_archive_dir . ': ' . $!);
-        $self->cleanup_apt_archive();
-        return 0;
-    }
-
-    $session->run_command(
-        { COMMAND => ['chown', $self->get_conf('BUILD_USER') . ':sbuild',
-                      $session->strip_chroot_path($dummy_archive_dir)],
-          USER => 'root',
-          DIR => '/' });
-    if ($?) {
-        $self->log_error("E: Failed to set " . $self->get_conf('BUILD_USER')
-                       . ":sbuild ownership on $dummy_archive_dir\n");
-        return 0;
-    }
-
     my $dummy_pkg_dir = $dummy_dir . '/' . $dummy_pkg_name;
-    my $dummy_deb = $dummy_archive_dir . '/' . $dummy_pkg_name . '.deb';
-    my $dummy_dsc = $dummy_archive_dir . '/' . $dummy_pkg_name . '.dsc';
+    my $dummy_deb = $dummy_dir . '/' . $dummy_pkg_name . '.deb';
+    my $dummy_dsc = $dummy_dir . '/' . $dummy_pkg_name . '.dsc';
 
     if (!$self->build_dummy_package ($dummy_pkg_name, $dummy_pkg_dir, $dummy_deb, $dummy_dsc, @pkgs)) {
         $self->log("Failed to create build-depends dummy package.\n");
@@ -887,78 +827,17 @@ sub setup_apt_archive {
         return 0;
     }
 
-    # Do code to run apt-ftparchive
-    if (!$self->run_apt_ftparchive()) {
-        $self->log("Failed to run apt-ftparchive.\n");
+    if (!$dummy_archive->setup()) {
+        $self->log("Failed to setup build-depends dummy archive.\n");
         $self->cleanup_apt_archive();
         return 0;
     }
 
-    # Sign the release file
-    if (!$self->generate_keys()) {
-        $self->log("Failed to generate archive keys.\n");
-        $self->cleanup_apt_archive();
-        return 0;
-    }
-    copy($self->get_conf('SBUILD_BUILD_DEPENDS_SECRET_KEY'), $dummy_archive_seckey) unless
-        (-f $dummy_archive_seckey);
-    copy($self->get_conf('SBUILD_BUILD_DEPENDS_PUBLIC_KEY'), $dummy_archive_pubkey) unless
-        (-f $dummy_archive_pubkey);
-    my @gpg_command = ('gpg', '--yes', '--no-default-keyring',
-                       '--homedir',
-                       $session->strip_chroot_path($dummy_gpghome),
-                       '--secret-keyring',
-                       $session->strip_chroot_path($dummy_archive_seckey),
-                       '--keyring',
-                       $session->strip_chroot_path($dummy_archive_pubkey),
-                       '--default-key', 'Sbuild Signer', '-abs',
-                       '-o', $session->strip_chroot_path($dummy_release_file) . '.gpg',
-                       $session->strip_chroot_path($dummy_release_file));
-    $session->run_command(
-	{ COMMAND => \@gpg_command,
-	  USER => $self->get_conf('BUILD_USER'),
-	  PRIORITY => 0});
-    if ($?) {
-	$self->log("Failed to sign dummy archive Release file.\n");
-        $self->cleanup_apt_archive();
-	return 0;
-    }
+    $dummy_archive->add_deb ($dummy_deb);
+    $dummy_archive->add_dsc ($dummy_dsc);
 
-    # 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";
-        close($tmpfh);
-        # List file needs to be moved with root.
-        $session->run_command(
-            { COMMAND => ['chmod', '0644', $session->strip_chroot_path($tmpfilename)],
-              USER => 'root',
-              PRIORITY => 0});
-        if ($?) {
-            $self->log("Failed to create apt list file for dummy archive.\n");
-            $self->cleanup_apt_archive();
-            return 0;
-        }
-        $session->run_command(
-            { COMMAND => ['mv', $session->strip_chroot_path($tmpfilename),
-                          $session->strip_chroot_path($dummy_archive_list_file)],
-              USER => 'root',
-              PRIORITY => 0});
-        if ($?) {
-            $self->log("Failed to create apt list file for dummy archive.\n");
-            $self->cleanup_apt_archive();
-            return 0;
-        }
-    }
-
-    # Add the generated key
-    $session->run_command(
-        { COMMAND => ['apt-key', 'add', $session->strip_chroot_path($dummy_archive_pubkey)],
-          USER => 'root',
-          PRIORITY => 0});
-    if ($?) {
-        $self->log("Failed to add dummy archive key.\n");
+    if (!$dummy_archive->populate()) {
+        $self->log("Failed to populate build-depends dummy archive.\n");
         $self->cleanup_apt_archive();
         return 0;
     }
@@ -970,129 +849,10 @@ sub setup_apt_archive {
 sub cleanup_apt_archive {
     my $self = shift;
 
-    my $session = $self->get('Session');
-
-    if (defined $self->get('Dummy package path')) {
-	$session->run_command(
-	    { COMMAND => ['rm', '-fr', $session->strip_chroot_path($self->get('Dummy package path'))],
-	      USER => $self->get_conf('BUILD_USER'),
-	      DIR => '/' });
-    }
-
-    $session->run_command(
-	{ COMMAND => ['rm', '-f', $session->strip_chroot_path($self->get('Dummy archive list file'))],
-	  USER => 'root',
-	  DIR => '/',
-	  PRIORITY => 0});
-    $self->set('Dummy package path', undef);
-    $self->set('Dummy archive directory', undef);
-    $self->set('Dummy Release file', undef);
+    my $dummy_archive = $self->get('Dummy archive');
+    $dummy_archive->cleanup();
 }
 
-# Generate a key pair if not already done.
-sub generate_keys {
-    my $self = shift;
-
-    if ((-f $self->get_conf('SBUILD_BUILD_DEPENDS_SECRET_KEY')) &&
-        (-f $self->get_conf('SBUILD_BUILD_DEPENDS_PUBLIC_KEY'))) {
-        return 1;
-    }
-
-    $self->log_error("Local archive GPG signing key not found\n");
-    $self->log_info("Please generate a key with 'sbuild-update --keygen'\n");
-    $self->log_info("Note that on machines with scarce entropy, you may wish ".
-		    "to generate the key with this command on another machine ".
-		    "and copy the public and private keypair to '" .
-		    $self->get_conf('SBUILD_BUILD_DEPENDS_PUBLIC_KEY')
-		    ."' and '".
-		    $self->get_conf('SBUILD_BUILD_DEPENDS_SECRET_KEY') ."'\n");
-    return 0;
-}
-
-# Function that runs apt-ftparchive
-sub run_apt_ftparchive {
-    my $self = shift;
-
-    my $session = $self->get('Session');
-    my $host = $self->get('Host');
-
-    my ($tmpfh, $tmpfilename) = tempfile();
-    my $dummy_archive_dir = $self->get('Dummy archive directory');
-
-    # Write the conf file.
-    print $tmpfh <<"EOF";
-Dir {
- ArchiveDir "$dummy_archive_dir";
-};
-
-Default {
- Packages::Compress ". gzip";
- Sources::Compress ". gzip";
-};
-
-BinDirectory "$dummy_archive_dir" {
- Packages "Packages";
- Sources "Sources";
-};
-
-APT::FTPArchive::Release::Origin "sbuild-build-depends-archive";
-APT::FTPArchive::Release::Label "sbuild-build-depends-archive";
-APT::FTPArchive::Release::Suite "invalid";
-APT::FTPArchive::Release::Codename "invalid";
-APT::FTPArchive::Release::Description "Sbuild Build Dependency Temporary Archive";
-EOF
-    close $tmpfh;
-
-    # Remove APT_CONFIG environment variable here, restore it later.
-    my $env = $self->get('Session')->get('Defaults')->{'ENV'};
-    my $apt_config_value = $env->{'APT_CONFIG'};
-    delete $env->{'APT_CONFIG'};
-
-    # Run apt-ftparchive to generate Packages and Sources files.
-    $host->run_command(
-        { COMMAND => ['apt-ftparchive', '-q=2', 'generate', $tmpfilename],
-          USER => $self->get_conf('USERNAME'),
-          PRIORITY => 0,
-          DIR => '/'});
-    if ($?) {
-        $env->{'APT_CONFIG'} = $apt_config_value;
-	unlink $tmpfilename;
-        return 0;
-    }
-
-    # Get output for Release file
-    my $pipe = $host->pipe_command(
-        { COMMAND => ['apt-ftparchive', '-q=2', '-c', $tmpfilename, 'release', $dummy_archive_dir],
-          USER => $self->get_conf('USERNAME'),
-          PRIORITY => 0,
-          DIR => '/'});
-    if (!defined($pipe)) {
-        $env->{'APT_CONFIG'} = $apt_config_value;
-	unlink $tmpfilename;
-        return 0;
-    }
-    $env->{'APT_CONFIG'} = $apt_config_value;
-
-
-    # Write output to Release file path.
-    my ($releasefh);
-    if (!open($releasefh, '>', $self->get('Dummy Release file'))) {
-        close $pipe;
-	unlink $tmpfilename;
-        return 0;
-    }
-
-    while (<$pipe>) {
-        print $releasefh $_;
-    }
-    close $releasefh;
-    close $pipe;
-
-    # Remove config file.  Note also removed on failure paths above.
-    unlink $tmpfilename;
-
-    return 1;
-}
 
 sub get_apt_command_internal {
     my $self = shift;
-- 
1.8.3.1


>From cccdc7803b8e0c8755b9bfbe9e60b8787ce524e9 Mon Sep 17 00:00:00 2001
From: Emanuele Aina <emanuele.a...@collabora.com>
Date: Mon, 3 Jun 2013 11:09:36 +0200
Subject: [PATCH 3/3] Sbuild::ResolverBase: Let users add custom packages to
 the build-deps archive

By letting users add custom packages to the dummy build-depends archive
with the --add-extra-package flags it should be easier to build packages
without waiting for their build dependencies to enter the main archive
and without going through the hassle of maintaining a local archive.
---
 lib/Sbuild/Build.pm        |  3 +++
 lib/Sbuild/Conf.pm         |  6 ++++++
 lib/Sbuild/Options.pm      |  3 +++
 lib/Sbuild/ResolverBase.pm | 14 ++++++++++++++
 man/sbuild.1.in            |  6 ++++++
 5 files changed, 32 insertions(+)

diff --git a/lib/Sbuild/Build.pm b/lib/Sbuild/Build.pm
index 0b2985c..fa8f749 100644
--- a/lib/Sbuild/Build.pm
+++ b/lib/Sbuild/Build.pm
@@ -659,6 +659,9 @@ sub run_fetch_install_packages {
 				    $self->get('Build Conflicts Arch'),
 				    $self->get('Build Conflicts Indep'));
 
+	$resolver->add_extra_packages(
+				    $self->get_conf('EXTRA_PACKAGES'));
+
 	my @build_deps;
 	if ($self->get('Host Arch') eq $self->get('Build Arch')) {
 	    @build_deps = ('ESSENTIAL', 'GCC_SNAPSHOT', 'MANUAL',
diff --git a/lib/Sbuild/Conf.pm b/lib/Sbuild/Conf.pm
index 27b035c..2b87484 100644
--- a/lib/Sbuild/Conf.pm
+++ b/lib/Sbuild/Conf.pm
@@ -803,6 +803,12 @@ sub setup ($) {
 	    DEFAULT => [],
 	    HELP => 'Additional per-build dependencies.  Do not set by hand.'
 	},
+	'EXTRA_PACKAGES'			=> {
+	    TYPE => 'ARRAY:STRING',
+	    GROUP => '__INTERNAL',
+	    DEFAULT => [],
+	    HELP => 'Extra packages to be made available for dependency resolution.'
+	},
 	'CROSSBUILD_CORE_DEPENDS'				=> {
 	    TYPE => 'HASH:ARRAY:STRING',
 	    VARNAME => 'crossbuild_core_depends',
diff --git a/lib/Sbuild/Options.pm b/lib/Sbuild/Options.pm
index 4a232bf..dcfb946 100644
--- a/lib/Sbuild/Options.pm
+++ b/lib/Sbuild/Options.pm
@@ -140,6 +140,9 @@ sub set_options {
 		       "e|uploader=s" => sub {
 			   $self->set_conf('UPLOADER_NAME', $_[1]);
 		       },
+		       "add-extra-package=s" => sub {
+			   push(@{$self->get_conf('EXTRA_PACKAGES')}, $_[1]);
+		       },
 		       "debbuildopts=s" => sub {
 			   push(@{$self->get_conf('DPKG_BUILDPACKAGE_USER_OPTIONS')},
 				split(/\s+/, $_[1]));
diff --git a/lib/Sbuild/ResolverBase.pm b/lib/Sbuild/ResolverBase.pm
index c1dd9c3..9be5b69 100644
--- a/lib/Sbuild/ResolverBase.pm
+++ b/lib/Sbuild/ResolverBase.pm
@@ -55,6 +55,7 @@ sub new {
     $self->set('Host', $host);
     $self->set('Changes', {});
     $self->set('AptDependencies', {});
+    $self->set('ExtraPackages', []);
     $self->set('Split', $self->get_conf('CHROOT_SPLIT'));
     # Typically set by Sbuild::Build, but not outside a build context.
     $self->set('Host Arch', $self->get_conf('HOST_ARCH'));
@@ -285,6 +286,14 @@ sub add_dependencies {
     $self->get('AptDependencies')->{$pkg} = $deps;
 }
 
+sub add_extra_packages {
+    my $self = shift;
+    my $pkgs = shift;
+    my @pkgs = @$pkgs;
+
+    $self->set('ExtraPackages', \@pkgs);
+}
+
 sub install_core_deps {
     my $self = shift;
     my $name = shift;
@@ -836,6 +845,11 @@ sub setup_apt_archive {
     $dummy_archive->add_deb ($dummy_deb);
     $dummy_archive->add_dsc ($dummy_dsc);
 
+    my @extra_debs = @{$self->get('ExtraPackages')};
+    foreach my $extra_deb (@extra_debs) {
+        $dummy_archive->add_deb ($extra_deb);
+    }
+
     if (!$dummy_archive->populate()) {
         $self->log("Failed to populate build-depends dummy archive.\n");
         $self->cleanup_apt_archive();
diff --git a/man/sbuild.1.in b/man/sbuild.1.in
index a91a064..f87f32c 100644
--- a/man/sbuild.1.in
+++ b/man/sbuild.1.in
@@ -42,6 +42,7 @@ sbuild \- build debian packages from source
 .RB [ \-\-add-conflicts\-arch=\fIdependency\fP ]
 .RB [ \-\-add-depends\-indep=\fIdependency\fP ]
 .RB [ \-\-add-conflicts\-indep=\fIdependency\fP ]
+.RB [ \-\-add-extra-package=\fIdebfile\fP ]
 .RB [ \-m \[or] \-\-maintainer=\fImaintainer\fP ]
 .RB [ \-e \[or] \-\-uploader=\fIuploader\fP ]
 .RB [ \-k \[or] \-\-keyid=\fIkey-id\fP ]
@@ -145,6 +146,11 @@ and Build-Conflicts-Indep dependencies, respectively.  The options may be used
 any number of times to add multiple dependencies.  The format is identical to
 the format used in debian/control.
 .TP
+.BR \-\-add-extra-package=\fIdebfile\fP
+Inject additional packages into the build dependencies dummy archive.  This can
+be useful to build related packages before the depended-on ones hit the main
+archive.  The option may be used any number of times to add multiple packages.
+.TP
 .BR "\-\-arch=\fIarchitecture\fP"
 Build using the architecture specified.  A chroot named
 \fI$distribution\-$arch-sbuild\fP or \fI$distribution\-arch\fP is searched for,
-- 
1.8.3.1

Reply via email to