summaryrefslogtreecommitdiff
path: root/morphlib/builder.py
diff options
context:
space:
mode:
Diffstat (limited to 'morphlib/builder.py')
-rw-r--r--morphlib/builder.py304
1 files changed, 152 insertions, 152 deletions
diff --git a/morphlib/builder.py b/morphlib/builder.py
index 1add2835..88a46633 100644
--- a/morphlib/builder.py
+++ b/morphlib/builder.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2011 Codethink Limited
+# Copyright (C) 2011-2012 Codethink Limited
#
# 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
@@ -25,6 +25,35 @@ import urlparse
import morphlib
+def ldconfig(ex, rootdir):
+ '''Run ldconfig for the filesystem below ``rootdir``.
+
+ Essentially, ``rootdir`` specifies the root of a new system.
+ Only directories below it are considered.
+
+ ``etc/ld.so.conf`` below ``rootdir`` is assumed to exist and
+ be populated by the right directories, and should assume
+ the root directory is ``rootdir``. Example: if ``rootdir``
+ is ``/tmp/foo``, then ``/tmp/foo/etc/ld.so.conf`` should
+ contain ``/lib``, not ``/tmp/foo/lib``.
+
+ The ldconfig found via ``$PATH`` is used, not the one in ``rootdir``,
+ since in bootstrap mode that might not yet exist, the various
+ implementations should be compatible enough.
+
+ '''
+
+ conf = os.path.join(rootdir, 'etc', 'ld.so.conf')
+ if os.path.exists(conf):
+ logging.debug('Running ldconfig for %s' % rootdir)
+ cache = os.path.join(rootdir, 'etc', 'ld.so.cache')
+ old_path = ex.env['PATH']
+ ex.env['PATH'] = '%s:/sbin:/usr/sbin:/usr/local/sbin' % old_path
+ ex.runv(['ldconfig', '-f', conf, '-C', cache, '-r', rootdir])
+ ex.env['PATH'] = old_path
+ else:
+ logging.debug('No %s, not running ldconfig' % conf)
+
class BinaryBlob(object):
def __init__(self, morph, repo, ref):
@@ -210,15 +239,16 @@ class Chunk(BinaryBlob):
def create_source_and_tarball(self):
self.msg('Creating source tree and tarball')
- self.build_watch.start('create-source-tarball')
- self.dump_memory_profile('before creating source and tarball for chunk')
- tarball = self.cache_prefix + '.src.tar'
- morphlib.git.export_sources(self.repo, self.ref, tarball)
- self.dump_memory_profile('after exporting sources')
- os.mkdir(self.builddir)
- self.ex.runv(['tar', '-C', self.builddir, '-xf', tarball])
- self.dump_memory_profile('after creating source and tarball for chunk')
- self.build_watch.stop('create-source-tarball')
+ with self.build_watch('create-source-tarball'):
+ self.dump_memory_profile('before creating source and tarball '
+ 'for chunk')
+ tarball = self.cache_prefix + '.src.tar'
+ morphlib.git.export_sources(self.repo, self.ref, tarball)
+ self.dump_memory_profile('after exporting sources')
+ os.mkdir(self.builddir)
+ self.ex.runv(['tar', '-C', self.builddir, '-xf', tarball])
+ self.dump_memory_profile('after creating source and tarball '
+ 'for chunk')
def build_using_buildsystem(self):
bs_name = self.morph.build_system
@@ -227,48 +257,44 @@ class Chunk(BinaryBlob):
self.run_sequentially('configure', bs['configure-commands'])
self.run_in_parallel('build', bs['build-commands'])
self.run_sequentially('test', bs['test-commands'])
- self.run_sequentially('install', bs['install-commands'],
- as_fakeroot=True)
+ self.run_sequentially('install', bs['install-commands'])
def build_using_commands(self):
self.msg('Building using explicit commands')
self.run_sequentially('configure', self.morph.configure_commands)
self.run_in_parallel('build', self.morph.build_commands)
self.run_sequentially('test', self.morph.test_commands)
- self.run_sequentially('install', self.morph.install_commands,
- as_fakeroot=True)
+ self.run_sequentially('install', self.morph.install_commands)
def run_in_parallel(self, what, commands):
self.msg('commands: %s' % what)
- self.build_watch.start(what)
- self.ex.run(commands)
- self.build_watch.stop(what)
+ with self.build_watch(what):
+ self.ex.run(commands)
- def run_sequentially(self, what, commands, as_fakeroot=False, as_root=False):
+ def run_sequentially(self, what, commands):
self.msg ('commands: %s' % what)
- self.build_watch.start(what)
- flags = self.ex.env['MAKEFLAGS']
- self.ex.env['MAKEFLAGS'] = '-j1'
- logging.debug('Setting MAKEFLAGS=%s' % self.ex.env['MAKEFLAGS'])
- self.ex.run(commands, as_fakeroot=as_fakeroot, as_root=as_root)
- self.ex.env['MAKEFLAGS'] = flags
- logging.debug('Restore MAKEFLAGS=%s' % self.ex.env['MAKEFLAGS'])
- self.build_watch.stop(what)
+ with self.build_watch(what):
+ flags = self.ex.env['MAKEFLAGS']
+ self.ex.env['MAKEFLAGS'] = '-j1'
+ logging.debug('Setting MAKEFLAGS=%s' % self.ex.env['MAKEFLAGS'])
+ self.ex.run(commands)
+ self.ex.env['MAKEFLAGS'] = flags
+ logging.debug('Restore MAKEFLAGS=%s' % self.ex.env['MAKEFLAGS'])
def create_chunks(self, chunks):
ret = {}
- self.build_watch.start('create-chunks')
- for chunk_name in chunks:
- self.msg('Creating chunk %s' % chunk_name)
- self.prepare_binary_metadata(chunk_name)
- patterns = chunks[chunk_name]
- patterns += [r'baserock/%s\.' % chunk_name]
- filename = self.filename(chunk_name)
- self.msg('Creating binary for %s' % chunk_name)
- morphlib.bins.create_chunk(self.destdir, filename, patterns,
- self.ex, self.dump_memory_profile)
- ret[chunk_name] = filename
- self.build_watch.stop('create-chunks')
+ with self.build_watch('create-chunks'):
+ for chunk_name in chunks:
+ self.msg('Creating chunk %s' % chunk_name)
+ self.prepare_binary_metadata(chunk_name)
+ patterns = chunks[chunk_name]
+ patterns += [r'baserock/%s\.' % chunk_name]
+ filename = self.filename(chunk_name)
+ self.msg('Creating binary for %s' % chunk_name)
+ morphlib.bins.create_chunk(self.destdir, filename, patterns,
+ self.ex, self.dump_memory_profile)
+ ret[chunk_name] = filename
+
files = os.listdir(self.destdir)
if files:
raise Exception('DESTDIR %s is not empty: %s' %
@@ -294,18 +320,15 @@ class Stratum(BinaryBlob):
def build(self):
os.mkdir(self.destdir)
ex = morphlib.execute.Execute(self.destdir, self.msg)
- self.build_watch.start('unpack-chunks')
- for chunk_name, filename in self.built:
- self.msg('Unpacking chunk %s' % chunk_name)
- morphlib.bins.unpack_binary(filename, self.destdir, ex,
- as_fakeroot=True)
- self.build_watch.stop('unpack-chunks')
- self.prepare_binary_metadata(self.morph.name)
- self.build_watch.start('create-binary')
- self.msg('Creating binary for %s' % self.morph.name)
- filename = self.filename(self.morph.name)
- morphlib.bins.create_stratum(self.destdir, filename, ex)
- self.build_watch.stop('create-binary')
+ with self.build_watch('unpack-chunks'):
+ for chunk_name, filename in self.built:
+ self.msg('Unpacking chunk %s' % chunk_name)
+ morphlib.bins.unpack_binary(filename, self.destdir, ex)
+ with self.build_watch('create-binary'):
+ self.prepare_binary_metadata(self.morph.name)
+ self.msg('Creating binary for %s' % self.morph.name)
+ filename = self.filename(self.morph.name)
+ morphlib.bins.create_stratum(self.destdir, filename, ex)
return { self.morph.name: filename }
@@ -323,118 +346,106 @@ class System(BinaryBlob):
self.ex = morphlib.execute.Execute(self.tempdir.dirname, self.msg)
# Create image.
- self.build_watch.start('create-image')
- image_name = self.tempdir.join('%s.img' % self.morph.name)
- self.ex.runv(['qemu-img', 'create', '-f', 'raw', image_name,
- self.morph.disk_size])
- self.build_watch.stop('create-image')
+ with self.build_watch('create-image'):
+ image_name = self.tempdir.join('%s.img' % self.morph.name)
+ self.ex.runv(['qemu-img', 'create', '-f', 'raw', image_name,
+ self.morph.disk_size])
# Partition it.
- self.build_watch.start('partition-image')
- self.ex.runv(['parted', '-s', image_name, 'mklabel', 'msdos'],
- as_root=True)
- self.ex.runv(['parted', '-s', image_name, 'mkpart', 'primary',
- '0%', '100%'], as_root=True)
- self.ex.runv(['parted', '-s', image_name, 'set', '1', 'boot', 'on'],
- as_root=True)
- self.build_watch.stop('partition-image')
+ with self.build_watch('partition-image'):
+ self.ex.runv(['parted', '-s', image_name, 'mklabel', 'msdos'])
+ self.ex.runv(['parted', '-s', image_name, 'mkpart', 'primary',
+ '0%', '100%'])
+ self.ex.runv(['parted', '-s', image_name, 'set', '1', 'boot', 'on'])
# Install first stage boot loader into MBR.
- self.build_watch.start('install-mbr')
- self.ex.runv(['install-mbr', image_name], as_root=True)
- self.build_watch.stop('install-mbr')
+ with self.build_watch('install-mbr'):
+ self.ex.runv(['install-mbr', image_name])
# Setup device mapper to access the partition.
- self.build_watch.start('setup-device-mapper')
- out = self.ex.runv(['kpartx', '-av', image_name], as_root=True)
- devices = [line.split()[2]
- for line in out.splitlines()
- if line.startswith('add map ')]
- partition = '/dev/mapper/%s' % devices[0]
- self.build_watch.stop('setup-device-mapper')
+ with self.build_watch('setup-device-mapper'):
+ out = self.ex.runv(['kpartx', '-av', image_name])
+ devices = [line.split()[2]
+ for line in out.splitlines()
+ if line.startswith('add map ')]
+ partition = '/dev/mapper/%s' % devices[0]
mount_point = None
try:
# Create filesystem.
- self.build_watch.start('create-filesystem')
- self.ex.runv(['mkfs', '-t', 'ext3', partition], as_root=True)
- self.build_watch.stop('create-filesystem')
+ with self.build_watch('create-filesystem'):
+ self.ex.runv(['mkfs', '-t', 'ext3', partition])
# Mount it.
- self.build_watch.start('mount-filesystem')
- mount_point = self.tempdir.join('mnt')
- os.mkdir(mount_point)
- self.ex.runv(['mount', partition, mount_point], as_root=True)
- self.build_watch.stop('mount-filesystem')
+ with self.build_watch('mount-filesystem'):
+ mount_point = self.tempdir.join('mnt')
+ os.mkdir(mount_point)
+ self.ex.runv(['mount', partition, mount_point])
# Unpack all strata into filesystem.
- self.build_watch.start('unpack-strata')
- for name, filename in self.built:
- self.msg('unpack %s from %s' % (name, filename))
- self.ex.runv(['tar', '-C', mount_point, '-xf', filename],
- as_root=True)
- self.build_watch.stop('unpack-strata')
+ # Also, run ldconfig.
+ with self.build_watch('unpack-strata'):
+ for name, filename in self.built:
+ self.msg('unpack %s from %s' % (name, filename))
+ self.ex.runv(['tar', '-C', mount_point, '-xf', filename])
+ ldconfig(ex, mount_point)
# Create fstab.
- self.build_watch.start('create-fstab')
- fstab = self.tempdir.join('mnt/etc/fstab')
- # sorry about the hack, I wish I knew a better way
- self.ex.runv(['tee', fstab], feed_stdin='''
+ with self.build_watch('create-fstab'):
+ fstab = self.tempdir.join('mnt/etc/fstab')
+ # sorry about the hack, I wish I knew a better way
+ self.ex.runv(['tee', fstab], feed_stdin='''
proc /proc proc defaults 0 0
sysfs /sys sysfs defaults 0 0
/dev/sda1 / ext4 errors=remount-ro 0 1
-''', as_root=True, stdout=open(os.devnull,'w'))
- self.build_watch.stop('create-fstab')
+''', stdout=open(os.devnull,'w'))
# Install extlinux bootloader.
- self.build_watch.start('install-bootloader')
- conf = os.path.join(mount_point, 'extlinux.conf')
- logging.debug('configure extlinux %s' % conf)
- self.ex.runv(['tee', conf], feed_stdin='''
+ with self.build_watch('install-bootloader'):
+ conf = os.path.join(mount_point, 'extlinux.conf')
+ logging.debug('configure extlinux %s' % conf)
+ self.ex.runv(['tee', conf], feed_stdin='''
default linux
timeout 1
label linux
kernel /vmlinuz
append root=/dev/sda1 init=/sbin/init quiet rw
-''', as_root=True, stdout=open(os.devnull, 'w'))
+''', stdout=open(os.devnull, 'w'))
- self.ex.runv(['extlinux', '--install', mount_point], as_root=True)
-
- # Weird hack that makes extlinux work. There is a bug somewhere.
- self.ex.runv(['sync'])
- import time; time.sleep(2)
- self.build_watch.stop('install-bootloader')
+ self.ex.runv(['extlinux', '--install', mount_point])
+
+ # Weird hack that makes extlinux work.
+ # FIXME: There is a bug somewhere.
+ self.ex.runv(['sync'])
+ import time; time.sleep(2)
# Unmount.
- self.build_watch.start('unmount-filesystem')
- self.ex.runv(['umount', mount_point], as_root=True)
- self.build_watch.stop('unmount-filesystem')
+ with self.build_watch('unmount-filesystem'):
+ self.ex.runv(['umount', mount_point])
except BaseException, e:
# Unmount.
if mount_point is not None:
try:
- self.ex.runv(['umount', mount_point], as_root=True)
+ self.ex.runv(['umount', mount_point])
except Exception:
pass
# Undo device mapping.
try:
- self.ex.runv(['kpartx', '-d', image_name], as_root=True)
+ self.ex.runv(['kpartx', '-d', image_name])
except Exception:
pass
raise
# Undo device mapping.
- self.build_watch.start('undo-device-mapper')
- self.ex.runv(['kpartx', '-d', image_name], as_root=True)
- self.build_watch.stop('undo-device-mapper')
+ with self.build_watch('undo-device-mapper'):
+ self.ex.runv(['kpartx', '-d', image_name])
# Move image file to cache.
- self.build_watch.start('cache-image')
- filename = self.filename(self.morph.name)
- self.ex.runv(['mv', image_name, filename])
- self.build_watch.stop('cache-image')
+ with self.build_watch('cache-image'):
+ filename = self.filename(self.morph.name)
+ self.ex.runv(['mv', image_name, filename])
return { self.morph.name: filename }
@@ -451,6 +462,8 @@ class Builder(object):
self.dump_memory_profile = app.dump_memory_profile
self.cachedir = morphlib.cachedir.CacheDir(self.settings['cachedir'])
self.indent = 0
+ self.morph_loader = \
+ morphlib.morphologyloader.MorphologyLoader(self.settings)
def msg(self, text):
spaces = ' ' * self.indent
@@ -468,11 +481,8 @@ class Builder(object):
self.dump_memory_profile('at start of build method')
self.indent_more()
self.msg('build %s|%s|%s' % (repo, ref, filename))
- base_url = self.settings['git-base-url']
- if not base_url.endswith('/'):
- base_url += '/'
- repo = urlparse.urljoin(base_url, repo)
- morph = self.get_morph_from_git(repo, ref, filename)
+ morph = self.morph_loader.load(repo, ref, filename)
+ repo = morph.repo
self.dump_memory_profile('after getting morph from git')
if morph.kind == 'chunk':
@@ -510,24 +520,22 @@ class Builder(object):
self.dump_memory_profile('after installing chunk')
built = builds
else:
- blob.build_watch.start('overall-build')
-
- blob.build_watch.start('build-needed')
- self.build_needed(blob)
- blob.build_watch.stop('build-needed')
- self.dump_memory_profile('after building needed')
-
- self.msg('Building %s %s' % (morph.kind, morph.name))
- self.indent_more()
- built = blob.build()
- self.dump_memory_profile('after building blob')
- self.indent_less()
- for x in built:
- self.msg('%s %s cached at %s' % (morph.kind, x, built[x]))
- self.install_chunk(morph, x, built[x], blob.staging)
- self.dump_memory_profile('after installing chunks')
-
- blob.build_watch.stop('overall-build')
+ with blob.build_watch('overall-build'):
+
+ with blob.build_watch('build-needed'):
+ self.build_needed(blob)
+ self.dump_memory_profile('after building needed')
+
+ self.msg('Building %s %s' % (morph.kind, morph.name))
+ self.indent_more()
+ built = blob.build()
+ self.dump_memory_profile('after building blob')
+ self.indent_less()
+ for x in built:
+ self.msg('%s %s cached at %s' % (morph.kind, x, built[x]))
+ self.install_chunk(morph, x, built[x], blob.staging)
+ self.dump_memory_profile('after installing chunks')
+
blob.save_build_times()
self.indent_less()
@@ -548,26 +556,18 @@ class Builder(object):
if self.settings['bootstrap']:
self.msg('Unpacking chunk %s onto system' % chunk_name)
ex = morphlib.execute.Execute('/', self.msg)
- morphlib.bins.unpack_binary(chunk_filename, '/', ex, as_root=True)
+ morphlib.bins.unpack_binary(chunk_filename, '/', ex)
+ ldconfig(ex, '/')
else:
self.msg('Unpacking chunk %s into staging' % chunk_name)
ex = morphlib.execute.Execute(staging_dir, self.msg)
- morphlib.bins.unpack_binary(chunk_filename, staging_dir, ex,
- as_root=True)
+ morphlib.bins.unpack_binary(chunk_filename, staging_dir, ex)
+ ldconfig(ex, staging_dir)
- def get_morph_from_git(self, repo, ref, filename):
- morph_text = morphlib.git.get_morph_text(repo, ref, filename)
- f = StringIO.StringIO(morph_text)
- scheme, netlock, path, params, query, frag = urlparse.urlparse(repo)
- f.name = os.path.join(path, filename)
- morph = morphlib.morphology.Morphology(f,
- self.settings['git-base-url'])
- return morph
-
def get_cache_id(self, repo, ref, morph_filename):
logging.debug('get_cache_id(%s, %s, %s)' %
(repo, ref, morph_filename))
- morph = self.get_morph_from_git(repo, ref, morph_filename)
+ morph = self.morph_loader.load(repo, ref, morph_filename)
if morph.kind == 'chunk':
kids = []
elif morph.kind == 'stratum':