From c58c9cb5de2c24ee8d92e1e711d3a741dd785459 Mon Sep 17 00:00:00 2001 From: Joe Burmeister Date: Wed, 28 Nov 2012 17:58:28 +0000 Subject: Hardlinked chroot done with linux-user-chroot The patch gives two things. Improves morph build time by reusing decompressed files of chunks/stage-fillers with hardlinks from the chroot. Rather than decompressing each time into each chroot. Original: real 5h 17m 47s Hardlink: real 2h 52m 27s It uses linux-user-chroot to create the chroot and make all but the basics readonly. --- morphlib/stagingarea.py | 57 ++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 3 deletions(-) (limited to 'morphlib/stagingarea.py') diff --git a/morphlib/stagingarea.py b/morphlib/stagingarea.py index a87b45c3..31fb8410 100644 --- a/morphlib/stagingarea.py +++ b/morphlib/stagingarea.py @@ -40,6 +40,8 @@ class StagingArea(object): self._app = app self.dirname = dirname self.tempdir = tempdir + self.builddirname = None + self.destdirname = None # Wrapper to be overridden by unit tests. def _mkdir(self, dirname): # pragma: no cover @@ -90,7 +92,17 @@ class StagingArea(object): logging.debug('Installing artifact %s' % getattr(handle, 'name', 'unknown name')) - morphlib.bins.unpack_binary_from_file(handle, self.dirname) + + decompressed_artifact = os.path.join(self._app.settings['cachedir'],'artifacts',os.path.basename(handle.name) + '.d') + if not os.path.exists(decompressed_artifact): + self._mkdir(decompressed_artifact) + morphlib.bins.unpack_binary_from_file(handle, decompressed_artifact + "/") + + if not os.path.exists(self.dirname): + self._mkdir(self.dirname) + + self._app.runcmd(["cp -al " + decompressed_artifact+"/* " + self.dirname+"/"],shell=True) + def remove(self): '''Remove the entire staging area. @@ -103,6 +115,27 @@ class StagingArea(object): shutil.rmtree(self.dirname) + def chroot_open(self, source): + # After setup, and before it's use as a chroot + + assert self.builddirname == None and self.destdirname == None + + builddir = self.builddir(source) + destdir = self.destdir(source) + self.builddirname = self.relative(builddir).lstrip('/') + self.destdirname = self.relative(destdir).lstrip('/') + + for mount_point in ['proc','dev/shm']: + path = os.path.join(self.dirname, mount_point) + if not os.path.exists(path): + os.makedirs(path) + + return builddir, destdir + + def chroot_close(self): + # After it's use as a chroot is complete. + pass + def runcmd(self, argv, **kwargs): # pragma: no cover '''Run a command in a chroot in the staging area.''' cwd = kwargs.get('cwd') or '/' @@ -111,6 +144,24 @@ class StagingArea(object): del kwargs['cwd'] else: cwd = '/' - real_argv = ['chroot', self.dirname, 'sh', '-c', - 'cd "$1" && shift && exec "$@"', '--', cwd] + argv + + entries = os.listdir(self.dirname) + + for friend in [self.builddirname,self.destdirname,'dev','proc','tmp']: + try: + entries.remove(friend) + except: + pass + + real_argv = ['linux-user-chroot'] + + for entry in entries: + real_argv += ['--mount-readonly',"/"+entry] + + real_argv += ['--mount-proc','/proc'] + real_argv += ['--mount-bind','/dev/shm','/dev/shm'] + real_argv += [self.dirname, 'sh', '-c', + 'cd "$1" && shift && exec "$@"', '--', cwd] + real_argv += argv + return self._app.runcmd(real_argv, **kwargs) -- cgit v1.2.1