Merge lp:~salgado/linaro-image-tools/port-install_hwpacks into lp:linaro-image-tools/11.11

Proposed by Guilherme Salgado
Status: Merged
Merged at revision: 230
Proposed branch: lp:~salgado/linaro-image-tools/port-install_hwpacks
Merge into: lp:linaro-image-tools/11.11
Diff against target: 387 lines (+248/-71)
4 files modified
linaro-media-create (+2/-65)
media_create/cmd_runner.py (+5/-6)
media_create/hwpack.py (+120/-0)
media_create/tests/test_media_create.py (+121/-0)
To merge this branch: bzr merge lp:~salgado/linaro-image-tools/port-install_hwpacks
Reviewer Review Type Date Requested Status
James Westby (community) Approve
Review via email: mp+45264@code.launchpad.net

Description of the change

Port install_hwpacks to python

To post a comment you must log in.
Revision history for this message
James Westby (james-w) wrote :

Looks good, thanks.

I'm interested in why you chose to use atexit rather than finally
blocks etc?

Thanks,

James

review: Approve
Revision history for this message
Guilherme Salgado (salgado) wrote :

Hi James,

Thanks for the review!

The reason why I went with atexit is that most of the functions here are
just setting things up in the chroot so that install_hwpack[s] can run,
and we want these things to be undone only after install_hwpack[s] has
finished. To achieve that using try/finally blocks I'd need to have
most of this code in a single function, which is not nice.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'linaro-media-create'
--- linaro-media-create 2011-01-05 15:52:33 +0000
+++ linaro-media-create 2011-01-05 16:55:11 +0000
@@ -269,66 +269,8 @@
269RFS_UUID=`uuidgen -r`269RFS_UUID=`uuidgen -r`
270270
271install_hwpacks () {271install_hwpacks () {
272 chroot=${DIR}/binary272 python -m media_create.hwpack "${DIR}/binary" "$HWPACK_FORCE_YES" \
273 # Make sure we unmount /proc in the chroot or else it can't be moved to the273 "${HWPACK_FILES[@]}"
274 # rootfs.
275
276 LINARO_HWPACK_INSTALL=$(which linaro-hwpack-install)
277
278 sudo mv -f "${chroot}/etc/resolv.conf" ${TMP_DIR}/resolv.conf.orig
279 sudo cp /etc/resolv.conf "${chroot}/etc/resolv.conf"
280
281 sudo mv -f "${chroot}/etc/hosts" ${TMP_DIR}/hosts.orig
282 sudo cp /etc/hosts "${chroot}/etc/hosts"
283
284 local arch_is_arm=no
285 case `uname -m` in
286 arm*)
287 arch_is_arm=yes
288 ;;
289 *)
290 python -m media_create.ensure_command qemu-arm-static qemu-arm-static
291 python -m media_create.ensure_command qemu-img qemu-kvm
292 sudo cp /usr/bin/qemu-arm-static "${chroot}/usr/bin"
293 ;;
294 esac
295 sudo cp "$LINARO_HWPACK_INSTALL" "${chroot}/usr/bin"
296
297 # Actually install the hwpack.
298 sudo mount proc "${chroot}/proc" -t proc
299 cleanup_chroot() {
300 sudo umount -v "$chroot/proc"
301 }
302
303 for HWPACK_FILE in "${HWPACK_FILES[@]}"; do
304
305 sudo cp "$HWPACK_FILE" "$chroot"
306 echo ""
307 echo "---------------------------------------------------"
308 echo "Installing (apt-get) $HWPACK_FILE in target rootfs."
309 echo ""
310 if [ "$HWPACK_FORCE_YES" = "yes" ]; then
311 sudo LC_ALL=C chroot "$chroot" linaro-hwpack-install --force-yes /"$(basename "$HWPACK_FILE")"
312 else
313 sudo LC_ALL=C chroot "$chroot" linaro-hwpack-install /"$(basename "$HWPACK_FILE")"
314 fi
315 echo "---------------------------------------------------"
316 echo ""
317 sudo rm -f "${chroot}/$(basename "$HWPACK_FILE")"
318
319 done
320
321 # Revert some changes we did to the rootfs as we don't want them in the
322 # image.
323 sudo umount "${chroot}/proc"
324 cleanup_chroot() { :; }
325
326 sudo mv -f ${TMP_DIR}/resolv.conf.orig "${chroot}/etc/resolv.conf"
327 sudo mv -f ${TMP_DIR}/hosts.orig "${chroot}/etc/hosts"
328 if [ "arch_is_arm" = no ]; then
329 sudo rm -f "${chroot}/usr/bin/qemu-arm-static"
330 fi
331 sudo rm -f "${chroot}/usr/bin/linaro-hwpack-install"
332}274}
333275
334unpack_binary_tarball() {276unpack_binary_tarball() {
@@ -444,10 +386,6 @@
444 exit 2386 exit 2
445}387}
446388
447# Initially, no action is needed to clean up mounts in the chroot.
448# install_hwpack will temporarily define this function when needed.
449cleanup_chroot() { :; }
450
451cleanup_handler() {389cleanup_handler() {
452 status=$?390 status=$?
453391
@@ -463,7 +401,6 @@
463 echo "Performing cleanup..."401 echo "Performing cleanup..."
464 echo402 echo
465403
466 cleanup_chroot
467 cleanup_sd404 cleanup_sd
468 cleanup_mountpoints405 cleanup_mountpoints
469 cleanup_tempfiles406 cleanup_tempfiles
470407
=== modified file 'media_create/cmd_runner.py'
--- media_create/cmd_runner.py 2010-12-17 07:03:34 +0000
+++ media_create/cmd_runner.py 2011-01-05 16:55:11 +0000
@@ -26,10 +26,6 @@
26 return Popen(args, stdin=stdin, stdout=stdout, stderr=stderr)26 return Popen(args, stdin=stdin, stdout=stdout, stderr=stderr)
2727
2828
29def get_extended_env(ext):
30 return os.environ.update(ext)
31
32
33class Popen(subprocess.Popen):29class Popen(subprocess.Popen):
34 """A version of Popen which raises an error on non-zero returncode.30 """A version of Popen which raises an error on non-zero returncode.
3531
@@ -37,9 +33,12 @@
37 SubcommandNonZeroReturnValue if it's non-zero.33 SubcommandNonZeroReturnValue if it's non-zero.
38 """34 """
3935
40 def __init__(self, args, **kwargs):36 def __init__(self, args, env=None, **kwargs):
41 self._my_args = args37 self._my_args = args
42 super(Popen, self).__init__(args, **kwargs)38 if env is None:
39 env = os.environ.copy()
40 env['LC_ALL'] = 'C'
41 super(Popen, self).__init__(args, env=env, **kwargs)
4342
44 def wait(self):43 def wait(self):
45 returncode = super(Popen, self).wait()44 returncode = super(Popen, self).wait()
4645
=== added file 'media_create/hwpack.py'
--- media_create/hwpack.py 1970-01-01 00:00:00 +0000
+++ media_create/hwpack.py 2011-01-05 16:55:11 +0000
@@ -0,0 +1,120 @@
1import atexit
2import os
3import platform
4import shutil
5import sys
6import tempfile
7
8from media_create import cmd_runner
9from media_create.ensure_command import ensure_command
10
11
12def install_hwpacks(chroot_dir, tmp_dir, hwpack_force_yes, *hwpack_files):
13 """Install the given hwpacks onto the given chroot."""
14
15 chroot_etc = os.path.join(chroot_dir, 'etc')
16 temporarily_overwrite_file_on_dir('/etc/resolv.conf', chroot_etc, tmp_dir)
17 temporarily_overwrite_file_on_dir('/etc/hosts', chroot_etc, tmp_dir)
18
19 if not platform.machine().startswith('arm'):
20 ensure_command('qemu-arm-static', 'qemu-arm-static')
21 ensure_command('qemu-img', 'qemu-kvm')
22 copy_file('/usr/bin/qemu-arm-static',
23 os.path.join(chroot_dir, 'usr', 'bin'))
24
25 # FIXME: This is an ugly hack to make sure we use the l-h-i script from
26 # the current development tree when possible.
27 here = os.path.dirname(__file__)
28 linaro_hwpack_install_path = os.path.join(
29 here, '..', 'linaro-hwpack-install')
30 if not os.path.exists(linaro_hwpack_install_path):
31 linaro_hwpack_install_path = '/usr/bin/linaro-hwpack-install'
32 copy_file(linaro_hwpack_install_path,
33 os.path.join(chroot_dir, 'usr', 'bin'))
34
35 mount_chroot_proc(chroot_dir)
36
37 for hwpack_file in hwpack_files:
38 install_hwpack(chroot_dir, hwpack_file, hwpack_force_yes)
39
40
41def install_hwpack(chroot_dir, hwpack_file, hwpack_force_yes):
42 """Install an hwpack on the given chroot.
43
44 Copy the hwpack file to the chroot and run linaro-hwpack-install passing
45 that hwpack file to it. If hwpack_force_yes is True, also pass
46 --force-yes to linaro-hwpack-install.
47 """
48 hwpack_basename = os.path.basename(hwpack_file)
49 copy_file(hwpack_file, chroot_dir)
50 print "-" * 60
51 print "Installing (apt-get) %s in target rootfs." % hwpack_basename
52 args = ['chroot', chroot_dir, 'linaro-hwpack-install']
53 if hwpack_force_yes:
54 args.append('--force-yes')
55 args.append('/%s' % hwpack_basename)
56 cmd_runner.run(args, as_root=True).wait()
57 print "-" * 60
58
59
60def mount_chroot_proc(chroot_dir):
61 """Mount a /proc filesystem on the given chroot.
62
63 Also register an atexit function to unmount that /proc filesystem.
64 """
65 chroot_proc = os.path.join(chroot_dir, 'proc')
66 proc = cmd_runner.run(
67 ['mount', 'proc', chroot_proc, '-t', 'proc'], as_root=True)
68 proc.wait()
69 def umount_chroot_proc():
70 cmd_runner.run(['umount', '-v', chroot_proc], as_root=True).wait()
71 atexit.register(umount_chroot_proc)
72
73
74def copy_file(filepath, directory):
75 """Copy the given file to the given directory.
76
77 The copying of the file is done in a subprocess and run using sudo.
78
79 We also register an atexit function to remove the file from the given
80 directory.
81 """
82 cmd_runner.run(['cp', filepath, directory], as_root=True).wait()
83
84 def undo():
85 new_path = os.path.join(directory, os.path.basename(filepath))
86 cmd_runner.run(['rm', '-f', new_path], as_root=True).wait()
87 atexit.register(undo)
88
89
90def temporarily_overwrite_file_on_dir(filepath, directory, tmp_dir):
91 """Temporarily replace a file on the given directory.
92
93 We'll move the existing file on the given directory to a temp dir, then
94 copy over the given file to that directory and register an atexit function
95 to move the orig file back to the given directory.
96 """
97 basename = os.path.basename(filepath)
98 path_to_orig = os.path.join(tmp_dir, basename)
99 # Move the existing file from the given directory to the temp dir.
100 cmd_runner.run(
101 ['mv', '-f', os.path.join(directory, basename), path_to_orig],
102 as_root=True).wait()
103 # Now copy the given file onto the given directory.
104 cmd_runner.run(['cp', filepath, directory], as_root=True).wait()
105
106 def undo():
107 cmd_runner.run(
108 ['mv', '-f', path_to_orig, directory], as_root=True).wait()
109 atexit.register(undo)
110
111
112if __name__ == '__main__':
113 tmp_dir = tempfile.mkdtemp()
114 atexit.register(shutil.rmtree, tmp_dir)
115 chroot_dir, hwpack_force_yes = sys.argv[1:3]
116 hwpack_force_yes = False
117 if hwpack_force_yes == "yes":
118 hwpack_force_yes = True
119 hwpacks = sys.argv[3:]
120 install_hwpacks(chroot_dir, tmp_dir, hwpack_force_yes, *hwpacks)
0121
=== modified file 'media_create/tests/test_media_create.py'
--- media_create/tests/test_media_create.py 2010-12-20 10:00:07 +0000
+++ media_create/tests/test_media_create.py 2011-01-05 16:55:11 +0000
@@ -1,4 +1,5 @@
1from contextlib import contextmanager1from contextlib import contextmanager
2import atexit
2import os3import os
3import random4import random
4import string5import string
@@ -17,6 +18,13 @@
17from media_create import partitions18from media_create import partitions
18from media_create import rootfs19from media_create import rootfs
19from media_create.boot_cmd import create_boot_cmd20from media_create.boot_cmd import create_boot_cmd
21from media_create.hwpack import (
22 copy_file,
23 install_hwpack,
24 install_hwpacks,
25 mount_chroot_proc,
26 temporarily_overwrite_file_on_dir,
27 )
20from media_create.partitions import (28from media_create.partitions import (
21 calculate_partition_size_and_offset,29 calculate_partition_size_and_offset,
22 convert_size_to_bytes,30 convert_size_to_bytes,
@@ -639,3 +647,116 @@
639 def test_check_device_not_found(self):647 def test_check_device_not_found(self):
640 self._mock_does_device_exist_false()648 self._mock_does_device_exist_false()
641 self.assertFalse(check_device.check_device(None))649 self.assertFalse(check_device.check_device(None))
650
651
652class AtExitRegister(object):
653 funcs = None
654 def __call__(self, func, *args, **kwargs):
655 if self.funcs is None:
656 self.funcs = []
657 self.funcs.append((func, args, kwargs))
658
659
660class TestInstallHWPack(TestCaseWithFixtures):
661
662 def test_temporarily_overwrite_file_on_dir(self):
663 fixture = self.useFixture(MockCmdRunnerPopenFixture())
664 temporarily_overwrite_file_on_dir('/path/to/file', '/dir', '/tmp/dir')
665 self.assertEquals(
666 [['sudo', 'mv', '-f', '/dir/file', '/tmp/dir/file'],
667 ['sudo', 'cp', '/path/to/file', '/dir']],
668 fixture.mock.calls)
669
670 fixture.mock.calls = []
671 self._run_registered_atexit_functions()
672 self.assertEquals(
673 [['sudo', 'mv', '-f', '/tmp/dir/file', '/dir']],
674 fixture.mock.calls)
675
676 def test_copy_file(self):
677 fixture = self.useFixture(MockCmdRunnerPopenFixture())
678 copy_file('/path/to/file', '/dir')
679 self.assertEquals(
680 [['sudo', 'cp', '/path/to/file', '/dir']],
681 fixture.mock.calls)
682
683 fixture.mock.calls = []
684 self._run_registered_atexit_functions()
685 self.assertEquals(
686 [['sudo', 'rm', '-f', '/dir/file']], fixture.mock.calls)
687
688 def test_mount_chroot_proc(self):
689 fixture = self.useFixture(MockCmdRunnerPopenFixture())
690 mount_chroot_proc('chroot')
691 self.assertEquals(
692 [['sudo', 'mount', 'proc', 'chroot/proc', '-t', 'proc']],
693 fixture.mock.calls)
694
695 fixture.mock.calls = []
696 self._run_registered_atexit_functions()
697 self.assertEquals(
698 [['sudo', 'umount', '-v', 'chroot/proc']], fixture.mock.calls)
699
700 def test_install_hwpack(self):
701 self.useFixture(MockSomethingFixture(
702 sys, 'stdout', open('/dev/null', 'w')))
703 fixture = self.useFixture(MockCmdRunnerPopenFixture())
704 force_yes = False
705 install_hwpack('chroot', 'hwpack.tgz', force_yes)
706 self.assertEquals(
707 [['sudo', 'cp', 'hwpack.tgz', 'chroot'],
708 ['sudo', 'chroot', 'chroot', 'linaro-hwpack-install',
709 '/hwpack.tgz']],
710 fixture.mock.calls)
711
712 fixture.mock.calls = []
713 self._run_registered_atexit_functions()
714 self.assertEquals(
715 [['sudo', 'rm', '-f', 'chroot/hwpack.tgz']], fixture.mock.calls)
716
717 def test_install_hwpacks(self):
718 self.useFixture(MockSomethingFixture(
719 sys, 'stdout', open('/dev/null', 'w')))
720 fixture = self.useFixture(MockCmdRunnerPopenFixture())
721 force_yes = True
722 install_hwpacks(
723 'chroot', '/tmp/dir', force_yes, 'hwpack1.tgz', 'hwpack2.tgz')
724 self.assertEquals(
725 [['sudo', 'mv', '-f', 'chroot/etc/resolv.conf',
726 '/tmp/dir/resolv.conf'],
727 ['sudo', 'cp', '/etc/resolv.conf', 'chroot/etc'],
728 ['sudo', 'mv', '-f', 'chroot/etc/hosts', '/tmp/dir/hosts'],
729 ['sudo', 'cp', '/etc/hosts', 'chroot/etc'],
730 ['sudo', 'cp', '/usr/bin/qemu-arm-static', 'chroot/usr/bin'],
731 ['sudo', 'cp', 'media_create/../linaro-hwpack-install',
732 'chroot/usr/bin'],
733 ['sudo', 'mount', 'proc', 'chroot/proc', '-t', 'proc'],
734 ['sudo', 'cp', 'hwpack1.tgz', 'chroot'],
735 ['sudo', 'chroot', 'chroot', 'linaro-hwpack-install',
736 '--force-yes', '/hwpack1.tgz'],
737 ['sudo', 'cp', 'hwpack2.tgz', 'chroot'],
738 ['sudo', 'chroot', 'chroot', 'linaro-hwpack-install',
739 '--force-yes', '/hwpack2.tgz']],
740 fixture.mock.calls)
741
742 fixture.mock.calls = []
743 self._run_registered_atexit_functions()
744 self.assertEquals(
745 [['sudo', 'mv', '-f', '/tmp/dir/resolv.conf', 'chroot/etc'],
746 ['sudo', 'mv', '-f', '/tmp/dir/hosts', 'chroot/etc'],
747 ['sudo', 'rm', '-f', 'chroot/usr/bin/qemu-arm-static'],
748 ['sudo', 'rm', '-f', 'chroot/usr/bin/linaro-hwpack-install'],
749 ['sudo', 'umount', '-v', 'chroot/proc'],
750 ['sudo', 'rm', '-f', 'chroot/hwpack1.tgz'],
751 ['sudo', 'rm', '-f', 'chroot/hwpack2.tgz']],
752 fixture.mock.calls)
753
754 def _run_registered_atexit_functions(self):
755 for func, args, kwargs in self.atexit_fixture.mock.funcs:
756 func(*args, **kwargs)
757
758 def setUp(self):
759 super(TestInstallHWPack, self).setUp()
760 self.atexit_fixture = self.useFixture(MockSomethingFixture(
761 atexit, 'register', AtExitRegister()))
762

Subscribers

People subscribed via source and target branches