Colin Watson has proposed merging 
lp:~cjwatson/launchpad-buildd/gather-results-via-backend into 
lp:launchpad-buildd with lp:~cjwatson/launchpad-buildd/fake-backend as a 
prerequisite.

Commit message:
Gather results via the backend abstraction rather than by direct filesystem 
access.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~cjwatson/launchpad-buildd/gather-results-via-backend/+merge/328624

Current exceptions are binarypackage (because sbuild handles its own backend 
access) and sourcepackagerecipe (which needs some further refactoring first).
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of 
lp:~cjwatson/launchpad-buildd/gather-results-via-backend into 
lp:launchpad-buildd.
=== modified file 'lpbuildd/livefs.py'
--- lpbuildd/livefs.py	2017-07-28 13:57:47 +0000
+++ lpbuildd/livefs.py	2017-08-05 09:47:12 +0000
@@ -4,12 +4,10 @@
 __metaclass__ = type
 
 import os
-import shutil
 
 from lpbuildd.debian import (
     DebianBuildManager,
     DebianBuildState,
-    get_build_path,
     )
 
 
@@ -33,11 +31,6 @@
 
     def initiate(self, files, chroot, extra_args):
         """Initiate a build with a given set of files and chroot."""
-        self.build_path = get_build_path(
-            self.home, self._buildid, "chroot-autobuild", "build")
-        if os.path.isdir(self.build_path):
-            shutil.rmtree(self.build_path)
-
         self.subarch = extra_args.get("subarch")
         self.project = extra_args["project"]
         self.subproject = extra_args.get("subproject")
@@ -100,7 +93,8 @@
 
     def gatherResults(self):
         """Gather the results of the build and add them to the file cache."""
-        for entry in sorted(os.listdir(self.build_path)):
-            path = os.path.join(self.build_path, entry)
-            if entry.startswith("livecd.") and not os.path.islink(path):
-                self._slave.addWaitingFile(path)
+        for entry in sorted(self.backend.listdir("/build")):
+            path = os.path.join("/build", entry)
+            if (entry.startswith("livecd.") and
+                    not self.backend.islink(path)):
+                self.addWaitingFileFromBackend(path)

=== modified file 'lpbuildd/slave.py'
--- lpbuildd/slave.py	2017-08-05 09:47:12 +0000
+++ lpbuildd/slave.py	2017-08-05 09:47:12 +0000
@@ -12,6 +12,8 @@
 import hashlib
 import os
 import re
+import shutil
+import tempfile
 import urllib2
 import xmlrpclib
 
@@ -310,6 +312,15 @@
         self._subprocess.ignore = True
         self._subprocess.transport.loseConnection()
 
+    def addWaitingFileFromBackend(self, path):
+        fetched_dir = tempfile.mkdtemp()
+        try:
+            fetched_path = os.path.join(fetched_dir, os.path.basename(path))
+            self.backend.copy_out(path, fetched_path)
+            self._slave.addWaitingFile(fetched_path)
+        finally:
+            shutil.rmtree(fetched_dir)
+
 
 class BuilderStatus:
     """Status values for the builder."""

=== modified file 'lpbuildd/snap.py'
--- lpbuildd/snap.py	2017-04-03 12:30:15 +0000
+++ lpbuildd/snap.py	2017-08-05 09:47:12 +0000
@@ -7,7 +7,6 @@
 
 import json
 import os
-import shutil
 import sys
 
 from lpbuildd.debian import (
@@ -41,11 +40,6 @@
 
     def initiate(self, files, chroot, extra_args):
         """Initiate a build with a given set of files and chroot."""
-        self.build_path = get_build_path(
-            self.home, self._buildid, "chroot-autobuild", "build")
-        if os.path.isdir(self.build_path):
-            shutil.rmtree(self.build_path)
-
         self.name = extra_args["name"]
         self.branch = extra_args.get("branch")
         self.git_repository = extra_args.get("git_repository")
@@ -113,12 +107,12 @@
 
     def gatherResults(self):
         """Gather the results of the build and add them to the file cache."""
-        output_path = os.path.join(self.build_path, self.name)
-        if not os.path.exists(output_path):
+        output_path = os.path.join("/build", self.name)
+        if not self.backend.path_exists(output_path):
             return
-        for entry in sorted(os.listdir(output_path)):
+        for entry in sorted(self.backend.listdir(output_path)):
             path = os.path.join(output_path, entry)
-            if os.path.islink(path):
+            if self.backend.islink(path):
                 continue
             if entry.endswith(".snap") or entry.endswith(".manifest"):
-                self._slave.addWaitingFile(path)
+                self.addWaitingFileFromBackend(path)

=== modified file 'lpbuildd/target/backend.py'
--- lpbuildd/target/backend.py	2017-08-05 09:47:12 +0000
+++ lpbuildd/target/backend.py	2017-08-05 09:47:12 +0000
@@ -49,12 +49,14 @@
         """
         raise NotImplementedError
 
-    def run(self, args, env=None, input_text=None, **kwargs):
+    def run(self, args, env=None, input_text=None, get_output=False,
+            **kwargs):
         """Run a command in the target environment.
 
         :param args: the command and arguments to run.
         :param env: additional environment variables to set.
         :param input_text: input text to pass on the command's stdin.
+        :param get_output: if True, return the output from the command.
         :param kwargs: additional keyword arguments for `subprocess.Popen`.
         """
         raise NotImplementedError
@@ -73,6 +75,57 @@
         """
         raise NotImplementedError
 
+    def copy_out(self, source_path, target_path):
+        """Copy a file out of the target environment.
+
+        The target file will have the same permission mode as the source
+        file.
+
+        :param source_path: the path to the file that should be copied,
+            relative to the target environment's root.
+        :param target_path: the path where the file should be installed in
+            the host system.
+        """
+        raise NotImplementedError
+
+    def path_exists(self, path):
+        """Test whether a path exists in the target environment.
+
+        :param path: the path to the file to test, relative to the target
+            environment's root.
+        """
+        try:
+            self.run(["test", "-e", path])
+            return True
+        except subprocess.CalledProcessError:
+            return False
+
+    def islink(self, path):
+        """Test whether a file is a symbolic link in the target environment.
+
+        :param path: the path to the file to test, relative to the target
+            environment's root.
+        """
+        try:
+            self.run(["test", "-h", path])
+            return True
+        except subprocess.CalledProcessError:
+            return False
+
+    def listdir(self, path):
+        """List a directory in the target environment.
+
+        :param path: the path to the directory to list, relative to the
+            target environment's root.
+        """
+        paths = self.run(
+            ["find", path, "-mindepth", "1", "-maxdepth", "1",
+             "-printf", "%P\\0"],
+            get_output=True).rstrip(b"\0").split(b"\0")
+        # XXX cjwatson 2017-08-04: Use `os.fsdecode` instead once we're on
+        # Python 3.
+        return [path.decode("UTF-8") for path in paths]
+
     def kill_processes(self):
         """Kill any processes left running in the target.
 

=== modified file 'lpbuildd/target/chroot.py'
--- lpbuildd/target/chroot.py	2017-08-05 09:47:12 +0000
+++ lpbuildd/target/chroot.py	2017-08-05 09:47:12 +0000
@@ -52,7 +52,8 @@
         for path in ("/etc/hosts", "/etc/hostname", "/etc/resolv.conf"):
             self.copy_in(path, path)
 
-    def run(self, args, env=None, input_text=None, **kwargs):
+    def run(self, args, env=None, input_text=None, get_output=False,
+            **kwargs):
         """See `Backend`."""
         if env:
             args = ["env"] + [
@@ -61,14 +62,17 @@
         if self.arch is not None:
             args = set_personality(args, self.arch, series=self.series)
         cmd = ["sudo", "/usr/sbin/chroot", self.chroot_path] + args
-        if input_text is None:
+        if input_text is None and not get_output:
             subprocess.check_call(cmd, cwd=self.chroot_path, **kwargs)
         else:
-            proc = subprocess.Popen(
-                cmd, stdin=subprocess.PIPE, universal_newlines=True, **kwargs)
-            proc.communicate(input_text)
+            if get_output:
+                kwargs["stdout"] = subprocess.PIPE
+            proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, **kwargs)
+            output, _ = proc.communicate(input_text)
             if proc.returncode:
                 raise subprocess.CalledProcessError(proc.returncode, cmd)
+            if get_output:
+                return output
 
     def copy_in(self, source_path, target_path):
         """See `Backend`."""
@@ -82,6 +86,14 @@
             ["sudo", "install", "-o", "root", "-g", "root", "-m", "%o" % mode,
              source_path, full_target_path])
 
+    def copy_out(self, source_path, target_path):
+        # We can just use a plain copy here, since the file ownership in the
+        # host system isn't important.
+        full_source_path = os.path.join(
+            self.chroot_path, source_path.lstrip("/"))
+        subprocess.check_call(
+            ["sudo", "cp", "-p", full_source_path, target_path])
+
     def kill_processes(self):
         """See `Backend`."""
         prefix = os.path.realpath(self.chroot_path)

=== modified file 'lpbuildd/target/override_sources_list.py'
--- lpbuildd/target/override_sources_list.py	2017-08-05 09:47:12 +0000
+++ lpbuildd/target/override_sources_list.py	2017-08-05 09:47:12 +0000
@@ -6,6 +6,7 @@
 __metaclass__ = type
 
 import logging
+import os
 import tempfile
 
 from lpbuildd.target.operation import Operation
@@ -31,5 +32,6 @@
             for archive in self.args.archives:
                 print(archive, file=sources_list)
             sources_list.flush()
+            os.fchmod(sources_list.fileno(), 0o644)
             self.backend.copy_in(sources_list.name, "/etc/apt/sources.list")
         return 0

=== modified file 'lpbuildd/target/tests/test_chroot.py'
--- lpbuildd/target/tests/test_chroot.py	2017-08-05 09:47:12 +0000
+++ lpbuildd/target/tests/test_chroot.py	2017-08-05 09:47:12 +0000
@@ -3,6 +3,7 @@
 
 __metaclass__ = type
 
+import io
 import os.path
 import signal
 from textwrap import dedent
@@ -97,6 +98,25 @@
             expected_args,
             [proc._args["args"] for proc in processes_fixture.procs])
 
+    def test_run_get_output(self):
+        self.useFixture(EnvironmentVariable("HOME", "/expected/home"))
+        processes_fixture = self.useFixture(FakeProcesses())
+        processes_fixture.add(
+            lambda _: {"stdout": io.BytesIO(b"hello\n")}, name="sudo")
+        self.assertEqual(
+            "hello\n",
+            Chroot("1", "xenial", "amd64").run(
+                ["echo", "hello"], get_output=True))
+
+        expected_args = [
+            ["sudo", "/usr/sbin/chroot",
+             "/expected/home/build-1/chroot-autobuild",
+             "linux64", "echo", "hello"],
+            ]
+        self.assertEqual(
+            expected_args,
+            [proc._args["args"] for proc in processes_fixture.procs])
+
     def test_copy_in(self):
         self.useFixture(EnvironmentVariable("HOME", "/expected/home"))
         source_dir = self.useFixture(TempDir()).path
@@ -119,6 +139,77 @@
             expected_args,
             [proc._args["args"] for proc in processes_fixture.procs])
 
+    def test_copy_out(self):
+        self.useFixture(EnvironmentVariable("HOME", "/expected/home"))
+        processes_fixture = self.useFixture(FakeProcesses())
+        processes_fixture.add(lambda _: {}, name="sudo")
+        Chroot("1", "xenial", "amd64").copy_out(
+            "/path/to/source", "/path/to/target")
+
+        expected_args = [
+            ["sudo", "cp", "-p",
+             "/expected/home/build-1/chroot-autobuild/path/to/source",
+             "/path/to/target"],
+            ]
+        self.assertEqual(
+            expected_args,
+            [proc._args["args"] for proc in processes_fixture.procs])
+
+    def test_path_exists(self):
+        self.useFixture(EnvironmentVariable("HOME", "/expected/home"))
+        processes_fixture = self.useFixture(FakeProcesses())
+        test_proc_infos = iter([{}, {"returncode": 1}])
+        processes_fixture.add(lambda _: next(test_proc_infos), name="sudo")
+        self.assertTrue(Chroot("1", "xenial", "amd64").path_exists("/present"))
+        self.assertFalse(Chroot("1", "xenial", "amd64").path_exists("/absent"))
+
+        expected_args = [
+            ["sudo", "/usr/sbin/chroot",
+             "/expected/home/build-1/chroot-autobuild",
+             "linux64", "test", "-e", path]
+            for path in ("/present", "/absent")
+            ]
+        self.assertEqual(
+            expected_args,
+            [proc._args["args"] for proc in processes_fixture.procs])
+
+    def test_islink(self):
+        self.useFixture(EnvironmentVariable("HOME", "/expected/home"))
+        processes_fixture = self.useFixture(FakeProcesses())
+        test_proc_infos = iter([{}, {"returncode": 1}])
+        processes_fixture.add(lambda _: next(test_proc_infos), name="sudo")
+        self.assertTrue(Chroot("1", "xenial", "amd64").islink("/link"))
+        self.assertFalse(Chroot("1", "xenial", "amd64").islink("/file"))
+
+        expected_args = [
+            ["sudo", "/usr/sbin/chroot",
+             "/expected/home/build-1/chroot-autobuild",
+             "linux64", "test", "-h", path]
+            for path in ("/link", "/file")
+            ]
+        self.assertEqual(
+            expected_args,
+            [proc._args["args"] for proc in processes_fixture.procs])
+
+    def test_listdir(self):
+        self.useFixture(EnvironmentVariable("HOME", "/expected/home"))
+        processes_fixture = self.useFixture(FakeProcesses())
+        processes_fixture.add(
+            lambda _: {"stdout": io.BytesIO(b"foo\0bar\0baz\0")}, name="sudo")
+        self.assertEqual(
+            ["foo", "bar", "baz"],
+            Chroot("1", "xenial", "amd64").listdir("/path"))
+
+        expected_args = [
+            ["sudo", "/usr/sbin/chroot",
+             "/expected/home/build-1/chroot-autobuild",
+             "linux64", "find", "/path", "-mindepth", "1", "-maxdepth", "1",
+             "-printf", "%P\\0"],
+            ]
+        self.assertEqual(
+            expected_args,
+            [proc._args["args"] for proc in processes_fixture.procs])
+
     def test_kill_processes(self):
         self.useFixture(EnvironmentVariable("HOME", "/expected/home"))
         fs_fixture = self.useFixture(FakeFilesystem())

=== modified file 'lpbuildd/target/tests/test_override_sources_list.py'
--- lpbuildd/target/tests/test_override_sources_list.py	2017-08-05 09:47:12 +0000
+++ lpbuildd/target/tests/test_override_sources_list.py	2017-08-05 09:47:12 +0000
@@ -3,6 +3,7 @@
 
 __metaclass__ = type
 
+import stat
 from textwrap import dedent
 
 from testtools import TestCase
@@ -20,9 +21,9 @@
             ]
         override_sources_list = OverrideSourcesList(args=args)
         self.assertEqual(0, override_sources_list.run())
-        self.assertEqual({
-            "/etc/apt/sources.list": dedent("""\
+        self.assertEqual(
+            (dedent("""\
                 deb http://archive.ubuntu.com/ubuntu xenial main
                 deb http://ppa.launchpad.net/launchpad/ppa/ubuntu xenial main
-                """).encode("UTF-8"),
-            }, override_sources_list.backend.copied_in)
+                """).encode("UTF-8"), stat.S_IFREG | 0o644),
+            override_sources_list.backend.backend_fs["/etc/apt/sources.list"])

=== modified file 'lpbuildd/tests/fakeslave.py'
--- lpbuildd/tests/fakeslave.py	2017-08-05 09:47:12 +0000
+++ lpbuildd/tests/fakeslave.py	2017-08-05 09:47:12 +0000
@@ -10,6 +10,7 @@
 import hashlib
 import os
 import shutil
+import stat
 
 from lpbuildd.target.backend import Backend
 
@@ -117,8 +118,55 @@
             )
         for fake_method in fake_methods:
             setattr(self, fake_method, FakeMethod())
-        self.copied_in = {}
+        self.backend_fs = {}
+
+    def _add_inode(self, path, contents, full_mode):
+        path = os.path.normpath(path)
+        parent = os.path.dirname(path)
+        if parent != path and parent not in self.backend_fs:
+            self.add_dir(parent)
+        self.backend_fs[path] = (contents, full_mode)
+
+    def add_dir(self, path, mode=0o755):
+        self._add_inode(path, None, stat.S_IFDIR | mode)
+
+    def add_file(self, path, contents, mode=0o644):
+        self._add_inode(path, contents, stat.S_IFREG | mode)
+
+    def add_link(self, path, target):
+        self._add_inode(path, target, stat.S_IFLNK | 0o777)
 
     def copy_in(self, source_path, target_path):
         with open(source_path, "rb") as source:
-            self.copied_in[target_path] = source.read()
+            self.add_file(
+                target_path, source.read(), os.fstat(source.fileno()).st_mode)
+
+    def _get_inode(self, path):
+        while True:
+            contents, mode = self.backend_fs[path]
+            if not stat.S_ISLNK(mode):
+                return contents, mode
+            path = os.path.normpath(
+                os.path.join(os.path.dirname(path), contents))
+
+    def copy_out(self, source_path, target_path):
+        contents, mode = self._get_inode(source_path)
+        with open(target_path, "wb") as target:
+            target.write(contents)
+            os.fchmod(target.fileno(), stat.S_IMODE(mode))
+
+    def path_exists(self, path):
+        try:
+            self._get_inode(path)
+            return True
+        except KeyError:
+            return False
+
+    def islink(self, path):
+        _, mode = self.backend_fs.get(path, (b"", 0))
+        return stat.S_ISLNK(mode)
+
+    def listdir(self, path):
+        return [
+            os.path.basename(p) for p in self.backend_fs
+            if os.path.dirname(p) == path]

=== modified file 'lpbuildd/tests/test_livefs.py'
--- lpbuildd/tests/test_livefs.py	2017-08-05 09:47:12 +0000
+++ lpbuildd/tests/test_livefs.py	2017-08-05 09:47:12 +0000
@@ -4,9 +4,11 @@
 __metaclass__ = type
 
 import os
-import shutil
-import tempfile
 
+from fixtures import (
+    EnvironmentVariable,
+    TempDir,
+    )
 from testtools import TestCase
 
 from lpbuildd.livefs import (
@@ -35,19 +37,16 @@
     """Run LiveFilesystemBuildManager through its iteration steps."""
     def setUp(self):
         super(TestLiveFilesystemBuildManagerIteration, self).setUp()
-        self.working_dir = tempfile.mkdtemp()
-        self.addCleanup(lambda: shutil.rmtree(self.working_dir))
+        self.working_dir = self.useFixture(TempDir()).path
         slave_dir = os.path.join(self.working_dir, "slave")
         home_dir = os.path.join(self.working_dir, "home")
         for dir in (slave_dir, home_dir):
             os.mkdir(dir)
+        self.useFixture(EnvironmentVariable("HOME", home_dir))
         self.slave = FakeSlave(slave_dir)
         self.buildid = "123"
         self.buildmanager = MockBuildManager(self.slave, self.buildid)
-        self.buildmanager.home = home_dir
         self.buildmanager._cachepath = self.slave._cachepath
-        self.build_dir = os.path.join(
-            home_dir, "build-%s" % self.buildid, "chroot-autobuild", "build")
 
     def getState(self):
         """Retrieve build manager's state."""
@@ -62,7 +61,10 @@
             "pocket": "release",
             "arch_tag": "i386",
             }
+        original_backend_name = self.buildmanager.backend_name
+        self.buildmanager.backend_name = "fake"
         self.buildmanager.initiate({}, "chroot.tar.gz", extra_args)
+        self.buildmanager.backend_name = original_backend_name
 
         # Skip states that are done in DebianBuildManager to the state
         # directly before BUILD_LIVEFS.
@@ -90,10 +92,8 @@
         with open(log_path, "w") as log:
             log.write("I am a build log.")
 
-        os.makedirs(self.build_dir)
-        manifest_path = os.path.join(self.build_dir, "livecd.ubuntu.manifest")
-        with open(manifest_path, "w") as manifest:
-            manifest.write("I am a manifest file.")
+        self.buildmanager.backend.add_file(
+            "/build/livecd.ubuntu.manifest", b"I am a manifest file.")
 
         # After building the package, reap processes.
         self.buildmanager.iterate(0)
@@ -133,13 +133,10 @@
         with open(log_path, "w") as log:
             log.write("I am a build log.")
 
-        os.makedirs(self.build_dir)
-        target_path = os.path.join(
-            self.build_dir, "livecd.ubuntu.kernel-generic")
-        with open(target_path, "w") as target:
-            target.write("I am a kernel.")
-        link_path = os.path.join(self.build_dir, "livecd.ubuntu.kernel")
-        os.symlink("livecd.ubuntu.kernel-generic", link_path)
+        self.buildmanager.backend.add_file(
+            "/build/livecd.ubuntu.kernel-generic", b"I am a kernel.")
+        self.buildmanager.backend.add_link(
+            "/build/livecd.ubuntu.kernel", "livefs.ubuntu.kernel-generic")
 
         self.buildmanager.iterate(0)
         self.assertThat(self.slave, HasWaitingFiles.byEquality({

=== modified file 'lpbuildd/tests/test_snap.py'
--- lpbuildd/tests/test_snap.py	2017-08-05 09:47:12 +0000
+++ lpbuildd/tests/test_snap.py	2017-08-05 09:47:12 +0000
@@ -4,9 +4,11 @@
 __metaclass__ = type
 
 import os
-import shutil
-import tempfile
 
+from fixtures import (
+    EnvironmentVariable,
+    TempDir,
+    )
 from testtools import TestCase
 
 from lpbuildd.snap import (
@@ -35,19 +37,16 @@
     """Run SnapBuildManager through its iteration steps."""
     def setUp(self):
         super(TestSnapBuildManagerIteration, self).setUp()
-        self.working_dir = tempfile.mkdtemp()
-        self.addCleanup(lambda: shutil.rmtree(self.working_dir))
+        self.working_dir = self.useFixture(TempDir()).path
         slave_dir = os.path.join(self.working_dir, "slave")
         home_dir = os.path.join(self.working_dir, "home")
         for dir in (slave_dir, home_dir):
             os.mkdir(dir)
+        self.useFixture(EnvironmentVariable("HOME", home_dir))
         self.slave = FakeSlave(slave_dir)
         self.buildid = "123"
         self.buildmanager = MockBuildManager(self.slave, self.buildid)
-        self.buildmanager.home = home_dir
         self.buildmanager._cachepath = self.slave._cachepath
-        self.build_dir = os.path.join(
-            home_dir, "build-%s" % self.buildid, "chroot-autobuild", "build")
 
     def getState(self):
         """Retrieve build manager's state."""
@@ -63,7 +62,10 @@
             "git_repository": "https://git.launchpad.dev/~example/+git/snap";,
             "git_path": "master",
             }
+        original_backend_name = self.buildmanager.backend_name
+        self.buildmanager.backend_name = "fake"
         self.buildmanager.initiate({}, "chroot.tar.gz", extra_args)
+        self.buildmanager.backend_name = original_backend_name
 
         # Skip states that are done in DebianBuildManager to the state
         # directly before BUILD_SNAP.
@@ -102,11 +104,8 @@
         with open(log_path, "w") as log:
             log.write("I am a build log.")
 
-        output_dir = os.path.join(self.build_dir, "test-snap")
-        os.makedirs(output_dir)
-        snap_path = os.path.join(output_dir, "test-snap_0_all.snap")
-        with open(snap_path, "w") as snap:
-            snap.write("I am a snap package.")
+        self.buildmanager.backend.add_file(
+            "/build/test-snap/test-snap_0_all.snap", b"I am a snap package.")
 
         # After building the package, reap processes.
         self.buildmanager.iterate(0)
@@ -146,14 +145,10 @@
         with open(log_path, "w") as log:
             log.write("I am a build log.")
 
-        output_dir = os.path.join(self.build_dir, "test-snap")
-        os.makedirs(output_dir)
-        snap_path = os.path.join(output_dir, "test-snap_0_all.snap")
-        with open(snap_path, "w") as snap:
-            snap.write("I am a snap package.")
-        manifest_path = os.path.join(output_dir, "test-snap_0_all.manifest")
-        with open(manifest_path, "w") as manifest:
-            manifest.write("I am a manifest.")
+        self.buildmanager.backend.add_file(
+            "/build/test-snap/test-snap_0_all.snap", b"I am a snap package.")
+        self.buildmanager.backend.add_file(
+            "/build/test-snap/test-snap_0_all.manifest", b"I am a manifest.")
 
         # After building the package, reap processes.
         self.buildmanager.iterate(0)

=== modified file 'lpbuildd/tests/test_translationtemplatesbuildmanager.py'
--- lpbuildd/tests/test_translationtemplatesbuildmanager.py	2017-08-05 09:47:12 +0000
+++ lpbuildd/tests/test_translationtemplatesbuildmanager.py	2017-08-05 09:47:12 +0000
@@ -4,9 +4,11 @@
 __metaclass__ = type
 
 import os
-import shutil
-import tempfile
 
+from fixtures import (
+    EnvironmentVariable,
+    TempDir,
+    )
 from testtools import TestCase
 
 from lpbuildd.tests.fakeslave import FakeSlave
@@ -35,16 +37,15 @@
     """Run TranslationTemplatesBuildManager through its iteration steps."""
     def setUp(self):
         super(TestTranslationTemplatesBuildManagerIteration, self).setUp()
-        self.working_dir = tempfile.mkdtemp()
-        self.addCleanup(lambda: shutil.rmtree(self.working_dir))
+        self.working_dir = self.useFixture(TempDir()).path
         slave_dir = os.path.join(self.working_dir, 'slave')
         home_dir = os.path.join(self.working_dir, 'home')
         for dir in (slave_dir, home_dir):
             os.mkdir(dir)
+        self.useFixture(EnvironmentVariable("HOME", home_dir))
         self.slave = FakeSlave(slave_dir)
         self.buildid = '123'
         self.buildmanager = MockBuildManager(self.slave, self.buildid)
-        self.buildmanager.home = home_dir
         self.chrootdir = os.path.join(
             home_dir, 'build-%s' % self.buildid, 'chroot-autobuild')
 
@@ -57,8 +58,11 @@
         url = 'lp:~my/branch'
         # The build manager's iterate() kicks off the consecutive states
         # after INIT.
+        original_backend_name = self.buildmanager.backend_name
+        self.buildmanager.backend_name = "fake"
         self.buildmanager.initiate(
             {}, 'chroot.tar.gz', {'series': 'xenial', 'branch_url': url})
+        self.buildmanager.backend_name = original_backend_name
 
         # Skip states that are done in DebianBuildManager to the state
         # directly before INSTALL.
@@ -94,12 +98,9 @@
         self.assertFalse(self.slave.wasCalled('chrootFail'))
 
         outfile_path = os.path.join(
-            self.chrootdir, self.buildmanager.home[1:],
-            self.buildmanager._resultname)
-        os.makedirs(os.path.dirname(outfile_path))
-
-        with open(outfile_path, 'w') as outfile:
-            outfile.write("I am a template tarball. Seriously.")
+            self.buildmanager.home, self.buildmanager._resultname)
+        self.buildmanager.backend.add_file(
+            outfile_path, b"I am a template tarball. Seriously.")
 
         # After generating templates, reap processes.
         self.buildmanager.iterate(0)
@@ -166,7 +167,7 @@
         self.buildmanager.initiate(
             {}, 'chroot.tar.gz', {'series': 'xenial', 'branch_url': url})
 
-        # Skip states to the INSTALL state.
+        # Skip states to the GENERATE state.
         self.buildmanager._state = TranslationTemplatesBuildState.GENERATE
 
         # The buildmanager fails and reaps processes.

=== modified file 'lpbuildd/translationtemplates.py'
--- lpbuildd/translationtemplates.py	2015-05-11 05:39:25 +0000
+++ lpbuildd/translationtemplates.py	2017-08-05 09:47:12 +0000
@@ -64,12 +64,9 @@
         """Gather the results of the build and add them to the file cache."""
         # The file is inside the chroot, in the home directory of the buildd
         # user. Should be safe to assume the home dirs are named identically.
-        assert self.home.startswith('/'), "home directory must be absolute."
-
-        path = os.path.join(
-            self._chroot_path, self.home[1:], self._resultname)
-        if os.access(path, os.F_OK):
-            self._slave.addWaitingFile(path)
+        path = os.path.join(self.home, self._resultname)
+        if self.backend.path_exists(path):
+            self.addWaitingFileFromBackend(path)
 
     def iterate_INSTALL(self, success):
         """Installation was done."""

_______________________________________________
Mailing list: https://launchpad.net/~launchpad-reviewers
Post to     : launchpad-reviewers@lists.launchpad.net
Unsubscribe : https://launchpad.net/~launchpad-reviewers
More help   : https://help.launchpad.net/ListHelp

Reply via email to