=== modified file 'linaro-media-create'
@@ -28,7 +28,10 @@
from linaro_image_tools.media_create.boards import board_configs
from linaro_image_tools.media_create.check_device import (
confirm_device_selection_and_ensure_it_is_ready)
-from linaro_image_tools.media_create.hwpack import install_hwpacks
+from linaro_image_tools.media_create.chroot_utils import (
+ install_hwpacks,
+ install_packages,
+ )
from linaro_image_tools.media_create.partitions import (
Media,
setup_partitions,
@@ -78,10 +81,10 @@
if not is_arm_host():
required_commands.append('qemu-arm-static')
required_commands.append('qemu-img')
- if args.rootfs in ['ext2', 'ext3', 'ext4']:
+ if args.rootfs in ['btrfs', 'ext2', 'ext3', 'ext4']:
required_commands.append('mkfs.%s' % args.rootfs)
else:
- required_commands.append('mkfs.btrfs')
+ raise AssertionError('Unsupported rootfs type %s' % args.rootfs)
for command in required_commands:
ensure_command(command)
@@ -122,6 +125,9 @@
install_hwpacks(
ROOTFS_DIR, TMP_DIR, lmc_dir, args.hwpack_force_yes, *hwpacks)
+ if args.rootfs == 'btrfs':
+ install_packages(ROOTFS_DIR, TMP_DIR, "btrfs-tools")
+
boot_partition, root_partition = setup_partitions(
board_config, media, args.image_size, args.boot_label, args.rfs_label,
args.rootfs, args.should_create_partitions, args.should_format_bootfs,
=== modified file 'linaro_image_tools/cmd_runner.py'
@@ -22,6 +22,7 @@
DEFAULT_PATH = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
+CHROOT_ARGS = ['chroot']
SUDO_ARGS = ['sudo', '-E']
@@ -34,7 +35,8 @@
env['PATH'] = os.pathsep.join(dirs)
-def run(args, as_root=False, stdin=None, stdout=None, stderr=None):
+def run(args, as_root=False, chroot=None, stdin=None, stdout=None,
+ stderr=None):
"""Run the given command as a sub process.
Return a Popen instance.
@@ -44,6 +46,7 @@
:param command: A list or tuple containing the command to run and the
arguments that should be passed to it.
:param as_root: Should the given command be run as root (with sudo)?
+ :param chroot: A directory to chroot into (implies as_root).
:param stdin: Same as in subprocess.Popen().
:param stdout: Same as in subprocess.Popen().
:param stderr: Same as in subprocess.Popen().
@@ -52,6 +55,9 @@
"The command to run must be a list or tuple, found: %s" % type(args))
if isinstance(args, tuple):
args = list(args)
+ if chroot is not None:
+ args = CHROOT_ARGS + [chroot] + args
+ as_root = True
if as_root and os.getuid() != 0:
args = SUDO_ARGS + args
return Popen(args, stdin=stdin, stdout=stdout, stderr=stderr)
=== renamed file 'linaro_image_tools/media_create/hwpack.py' => 'linaro_image_tools/media_create/chroot_utils.py'
@@ -32,10 +32,8 @@
# functions would only be called after l-m-c.py exits.
local_atexit = []
-def install_hwpacks(
- chroot_dir, tmp_dir, tools_dir, hwpack_force_yes, *hwpack_files):
- """Install the given hwpacks onto the given chroot."""
-
+def prepare_chroot(chroot_dir, tmp_dir):
+ """Prepares a chroot to run commands in it (networking and QEMU setup)."""
chroot_etc = os.path.join(chroot_dir, 'etc')
temporarily_overwrite_file_on_dir('/etc/resolv.conf', chroot_etc, tmp_dir)
temporarily_overwrite_file_on_dir('/etc/hosts', chroot_etc, tmp_dir)
@@ -44,6 +42,11 @@
copy_file('/usr/bin/qemu-arm-static',
os.path.join(chroot_dir, 'usr', 'bin'))
+def install_hwpacks(
+ chroot_dir, tmp_dir, tools_dir, hwpack_force_yes, *hwpack_files):
+ """Install the given hwpacks onto the given chroot."""
+ prepare_chroot(chroot_dir, tmp_dir)
+
linaro_hwpack_install_path = find_command(
'linaro-hwpack-install', prefer_dir=tools_dir)
# FIXME: shouldn't use chroot/usr/bin as this might conflict with installed
@@ -70,15 +73,36 @@
hwpack_basename = os.path.basename(hwpack_file)
copy_file(hwpack_file, chroot_dir)
print "-" * 60
- print "Installing (apt-get) %s in target rootfs." % hwpack_basename
- args = ['chroot', chroot_dir, 'linaro-hwpack-install']
+ print "Installing (linaro-hwpack-install) %s in target rootfs." % (
+ hwpack_basename)
+ args = ['linaro-hwpack-install']
if hwpack_force_yes:
args.append('--force-yes')
args.append('/%s' % hwpack_basename)
- cmd_runner.run(args, as_root=True).wait()
+ cmd_runner.run(args, as_root=True, chroot=chroot_dir).wait()
print "-" * 60
+def install_packages(chroot_dir, tmp_dir, *packages):
+ """Install packages in the given chroot.
+
+ This does not run apt-get update before hand."""
+ prepare_chroot(chroot_dir, tmp_dir)
+
+ try:
+ mount_chroot_proc(chroot_dir)
+ print "-" * 60
+ print "Installing (apt-get) %s in target rootfs." % " ".join(packages)
+ args = ("apt-get", "--yes", "install") + packages
+ cmd_runner.run(args, as_root=True, chroot=chroot_dir).wait()
+ print "Cleaning up downloaded packages."
+ args = ("apt-get", "clean")
+ cmd_runner.run(args, as_root=True, chroot=chroot_dir).wait()
+ print "-" * 60
+ finally:
+ run_local_atexit_funcs()
+
+
def mount_chroot_proc(chroot_dir):
"""Mount a /proc filesystem on the given chroot.
=== modified file 'linaro_image_tools/media_create/rootfs.py'
@@ -24,6 +24,15 @@
from linaro_image_tools import cmd_runner
+def rootfs_mount_options(rootfs_type):
+ """Return mount options for the specific rootfs type."""
+ if rootfs_type == "btrfs":
+ return "defaults"
+ if rootfs_type in ('ext2', 'ext3', 'ext4'):
+ return "errors=remount-ro"
+ raise ValueError('Unsupported rootfs type')
+
+
def populate_rootfs(content_dir, root_disk, partition, rootfs_type,
rootfs_uuid, should_create_swap, swap_size,
partition_offset):
@@ -47,8 +56,9 @@
move_contents(content_dir, root_disk)
- fstab_additions = ["UUID=%s / %s errors=remount-ro 0 1 " % (
- rootfs_uuid, rootfs_type)]
+ mount_options = rootfs_mount_options(rootfs_type)
+ fstab_additions = ["UUID=%s / %s %s 0 1" % (
+ rootfs_uuid, rootfs_type, mount_options)]
if should_create_swap:
print "\nCreating SWAP File\n"
if has_space_left_for_swap(root_disk, swap_size):
@@ -115,7 +125,7 @@
def append_to_fstab(root_disk, fstab_additions):
fstab = os.path.join(root_disk, 'etc', 'fstab')
- data = open(fstab).read() + '\n' + '\n'.join(fstab_additions)
+ data = open(fstab).read() + '\n' + '\n'.join(fstab_additions) + '\n'
write_data_to_protected_file(fstab, data)
=== modified file 'linaro_image_tools/media_create/tests/test_media_create.py'
@@ -54,11 +54,13 @@
_get_mlo_file,
_run_mkimage,
)
-from linaro_image_tools.media_create.hwpack import (
+from linaro_image_tools.media_create.chroot_utils import (
copy_file,
install_hwpack,
install_hwpacks,
+ install_packages,
mount_chroot_proc,
+ prepare_chroot,
run_local_atexit_funcs,
temporarily_overwrite_file_on_dir,
)
@@ -78,10 +80,12 @@
_parse_blkid_output,
)
from linaro_image_tools.media_create.rootfs import (
+ append_to_fstab,
create_flash_kernel_config,
has_space_left_for_swap,
move_contents,
populate_rootfs,
+ rootfs_mount_options,
write_data_to_protected_file,
)
from linaro_image_tools.media_create.tests.fixtures import (
@@ -100,6 +104,7 @@
from linaro_image_tools.utils import find_command, preferred_tools_dir
+chroot_args = " ".join(cmd_runner.CHROOT_ARGS)
sudo_args = " ".join(cmd_runner.SUDO_ARGS)
@@ -1035,7 +1040,7 @@
swap_size=100, partition_offset=0)
self.assertEqual(
- ['UUID=uuid / ext3 errors=remount-ro 0 1 ',
+ ['UUID=uuid / ext3 errors=remount-ro 0 1',
'/SWAP.swap none swap sw 0 0'],
self.lines_added_to_fstab)
self.assertEqual(True, self.create_flash_kernel_config_called)
@@ -1111,6 +1116,27 @@
fixture.mock.commands_executed)
self.assertEqual(data, open(tmpfile).read())
+ def test_rootfs_mount_options_for_btrfs(self):
+ self.assertEqual("defaults", rootfs_mount_options('btrfs'))
+
+ def test_rootfs_mount_options_for_ext4(self):
+ self.assertEqual("errors=remount-ro", rootfs_mount_options('ext4'))
+
+ def test_rootfs_mount_options_for_unknown(self):
+ self.assertRaises(ValueError, rootfs_mount_options, 'unknown')
+
+ def test_append_to_fstab(self):
+ tempdir = self.useFixture(CreateTempDirFixture()).get_temp_dir()
+ etc = os.path.join(tempdir, 'etc')
+ os.mkdir(etc)
+ fstab = os.path.join(etc, 'fstab')
+ open(fstab, "w").close()
+ append_to_fstab(tempdir, ['foo', 'bar'])
+ f = open(fstab)
+ contents = f.read()
+ f.close()
+ self.assertEquals("\nfoo\nbar\n", contents)
+
class TestCheckDevice(TestCaseWithFixtures):
@@ -1191,6 +1217,13 @@
class TestInstallHWPack(TestCaseWithFixtures):
+ def mock_prepare_chroot(self, chroot_dir, tmp_dir):
+ def fake_prepare_chroot(chroot_dir, tmp_dir):
+ cmd_runner.run(['prepare_chroot %s %s' % (chroot_dir, tmp_dir)],
+ as_root=True).wait()
+ self.useFixture(MockSomethingFixture(
+ linaro_image_tools.media_create.chroot_utils, 'prepare_chroot',
+ fake_prepare_chroot))
def test_temporarily_overwrite_file_on_dir(self):
fixture = self.useFixture(MockCmdRunnerPopenFixture())
@@ -1236,49 +1269,92 @@
self.useFixture(MockSomethingFixture(
sys, 'stdout', open('/dev/null', 'w')))
fixture = self.useFixture(MockCmdRunnerPopenFixture())
+ chroot_dir = 'chroot_dir'
force_yes = False
- install_hwpack('chroot', 'hwpack.tgz', force_yes)
+ install_hwpack(chroot_dir, 'hwpack.tgz', force_yes)
self.assertEquals(
- ['%s cp hwpack.tgz chroot' % sudo_args,
- '%s chroot chroot linaro-hwpack-install /hwpack.tgz'
- % sudo_args],
+ ['%s cp hwpack.tgz %s' % (sudo_args, chroot_dir),
+ '%s %s %s linaro-hwpack-install /hwpack.tgz'
+ % (sudo_args, chroot_args, chroot_dir)],
fixture.mock.commands_executed)
fixture.mock.calls = []
run_local_atexit_funcs()
self.assertEquals(
- ['%s rm -f chroot/hwpack.tgz' % sudo_args],
+ ['%s rm -f %s/hwpack.tgz' % (sudo_args, chroot_dir)],
fixture.mock.commands_executed)
def test_install_hwpacks(self):
self.useFixture(MockSomethingFixture(
sys, 'stdout', open('/dev/null', 'w')))
fixture = self.useFixture(MockCmdRunnerPopenFixture())
+ chroot_dir = 'chroot_dir'
+ tmp_dir = 'tmp_dir'
+ self.mock_prepare_chroot(chroot_dir, tmp_dir)
force_yes = True
prefer_dir = preferred_tools_dir()
install_hwpacks(
- 'chroot', '/tmp/dir', prefer_dir, force_yes, 'hwpack1.tgz',
+ chroot_dir, tmp_dir, prefer_dir, force_yes, 'hwpack1.tgz',
'hwpack2.tgz')
linaro_hwpack_install = find_command(
'linaro-hwpack-install', prefer_dir=prefer_dir)
expected = [
+ 'prepare_chroot %(chroot_dir)s %(tmp_dir)s',
+ 'cp %(linaro_hwpack_install)s %(chroot_dir)s/usr/bin',
+ 'mount proc %(chroot_dir)s/proc -t proc',
+ 'cp hwpack1.tgz %(chroot_dir)s',
+ ('%(chroot_args)s %(chroot_dir)s linaro-hwpack-install '
+ '--force-yes /hwpack1.tgz'),
+ 'cp hwpack2.tgz %(chroot_dir)s',
+ ('%(chroot_args)s %(chroot_dir)s linaro-hwpack-install '
+ '--force-yes /hwpack2.tgz'),
+ 'rm -f %(chroot_dir)s/hwpack2.tgz',
+ 'rm -f %(chroot_dir)s/hwpack1.tgz',
+ 'umount -v %(chroot_dir)s/proc',
+ 'rm -f %(chroot_dir)s/usr/bin/linaro-hwpack-install']
+ keywords = dict(
+ chroot_dir=chroot_dir, tmp_dir=tmp_dir, chroot_args=chroot_args,
+ linaro_hwpack_install=linaro_hwpack_install)
+ expected = [
+ "%s %s" % (sudo_args, line % keywords) for line in expected]
+ self.assertEquals(expected, fixture.mock.commands_executed)
+
+ def test_install_packages(self):
+ self.useFixture(MockSomethingFixture(
+ sys, 'stdout', open('/dev/null', 'w')))
+ fixture = self.useFixture(MockCmdRunnerPopenFixture())
+ chroot_dir = 'chroot_dir'
+ tmp_dir = 'tmp_dir'
+ self.mock_prepare_chroot(chroot_dir, tmp_dir)
+
+ install_packages(chroot_dir, tmp_dir, 'pkg1', 'pkg2')
+ expected = [
+ 'prepare_chroot %(chroot_dir)s %(tmp_dir)s',
+ 'mount proc %(chroot_dir)s/proc -t proc',
+ '%(chroot_args)s %(chroot_dir)s apt-get --yes install pkg1 pkg2',
+ '%(chroot_args)s %(chroot_dir)s apt-get clean',
+ 'umount -v %(chroot_dir)s/proc']
+ keywords = dict(
+ chroot_dir=chroot_dir, tmp_dir=tmp_dir, chroot_args=chroot_args)
+ expected = [
+ "%s %s" % (sudo_args, line % keywords) for line in expected]
+ self.assertEquals(expected, fixture.mock.commands_executed)
+
+ def test_prepare_chroot(self):
+ self.useFixture(MockSomethingFixture(
+ sys, 'stdout', open('/dev/null', 'w')))
+ fixture = self.useFixture(MockCmdRunnerPopenFixture())
+
+ prepare_chroot('chroot', '/tmp/dir')
+ run_local_atexit_funcs()
+ expected = [
'mv -f chroot/etc/resolv.conf /tmp/dir/resolv.conf',
'cp /etc/resolv.conf chroot/etc',
'mv -f chroot/etc/hosts /tmp/dir/hosts',
'cp /etc/hosts chroot/etc',
'cp /usr/bin/qemu-arm-static chroot/usr/bin',
- 'cp %s chroot/usr/bin' % linaro_hwpack_install,
- 'mount proc chroot/proc -t proc',
- 'cp hwpack1.tgz chroot',
- 'chroot chroot linaro-hwpack-install --force-yes /hwpack1.tgz',
- 'cp hwpack2.tgz chroot',
- 'chroot chroot linaro-hwpack-install --force-yes /hwpack2.tgz',
- 'rm -f chroot/hwpack2.tgz',
- 'rm -f chroot/hwpack1.tgz',
- 'umount -v chroot/proc',
- 'rm -f chroot/usr/bin/linaro-hwpack-install',
'rm -f chroot/usr/bin/qemu-arm-static',
'mv -f /tmp/dir/hosts chroot/etc',
'mv -f /tmp/dir/resolv.conf chroot/etc']
@@ -1301,13 +1377,12 @@
# run_local_atexit_funcs() runs the atexit handlers in LIFO order, but
# even though the first function called (raising_func) will raise
# an exception, the second one will still be called after it.
- linaro_image_tools.media_create.hwpack.local_atexit = [
+ linaro_image_tools.media_create.chroot_utils.local_atexit = [
behaving_func, raising_func]
# run_local_atexit_funcs() also propagates the last exception raised
# by one of the functions.
- self.assertRaises(
- TestException,
- linaro_image_tools.media_create.hwpack.run_local_atexit_funcs)
+ chroot_utils = linaro_image_tools.media_create.chroot_utils
+ self.assertRaises(TestException, chroot_utils.run_local_atexit_funcs)
self.assertEquals(
['raising_func', 'behaving_func'], self.call_order)
@@ -1324,10 +1399,11 @@
sys, 'stdout', open('/dev/null', 'w')))
self.useFixture(MockCmdRunnerPopenFixture())
self.useFixture(MockSomethingFixture(
- linaro_image_tools.media_create.hwpack, 'install_hwpack',
+ linaro_image_tools.media_create.chroot_utils, 'install_hwpack',
mock_install_hwpack))
self.useFixture(MockSomethingFixture(
- linaro_image_tools.media_create.hwpack, 'run_local_atexit_funcs',
+ linaro_image_tools.media_create.chroot_utils,
+ 'run_local_atexit_funcs',
mock_run_local_atexit_functions))
force_yes = True
@@ -1346,5 +1422,5 @@
# Ensure the list of cleanup functions gets cleared to make sure tests
# don't interfere with one another.
def clear_atexits():
- linaro_image_tools.media_create.hwpack.local_atexit = []
+ linaro_image_tools.media_create.chroot_utils.local_atexit = []
self.addCleanup(clear_atexits)
=== modified file 'linaro_image_tools/tests/fixtures.py'
@@ -69,6 +69,10 @@
child_finished = True
def __call__(self, cmd, *args, **kwargs):
+ if not self.child_finished:
+ raise AssertionError(
+ "You should call wait() or communicate() to ensure "
+ "the subprocess is finished before proceeding.")
self.child_finished = False
if self.calls is None:
self.calls = []
=== modified file 'linaro_image_tools/tests/test_cmd_runner.py'
@@ -28,6 +28,7 @@
sudo_args = " ".join(cmd_runner.SUDO_ARGS)
+chroot_args = " ".join(cmd_runner.CHROOT_ARGS)
class TestSanitizePath(TestCaseWithFixtures):
@@ -82,6 +83,13 @@
self.assertEqual(
['%s foo bar' % sudo_args], fixture.mock.commands_executed)
+ def test_chrooted(self):
+ fixture = self.useFixture(MockCmdRunnerPopenFixture())
+ cmd_runner.run(['foo', 'bar'], chroot='chroot_dir').wait()
+ self.assertEqual(
+ ['%s %s chroot_dir foo bar' % (sudo_args, chroot_args)],
+ fixture.mock.commands_executed)
+
def test_run_succeeds_on_zero_return_code(self):
proc = cmd_runner.run(['true'])
# Need to wait() here as we're using the real Popen.