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
1=== modified file 'linaro-media-create'
2--- linaro-media-create 2011-01-05 15:52:33 +0000
3+++ linaro-media-create 2011-01-05 16:55:11 +0000
4@@ -269,66 +269,8 @@
5 RFS_UUID=`uuidgen -r`
6
7 install_hwpacks () {
8- chroot=${DIR}/binary
9- # Make sure we unmount /proc in the chroot or else it can't be moved to the
10- # rootfs.
11-
12- LINARO_HWPACK_INSTALL=$(which linaro-hwpack-install)
13-
14- sudo mv -f "${chroot}/etc/resolv.conf" ${TMP_DIR}/resolv.conf.orig
15- sudo cp /etc/resolv.conf "${chroot}/etc/resolv.conf"
16-
17- sudo mv -f "${chroot}/etc/hosts" ${TMP_DIR}/hosts.orig
18- sudo cp /etc/hosts "${chroot}/etc/hosts"
19-
20- local arch_is_arm=no
21- case `uname -m` in
22- arm*)
23- arch_is_arm=yes
24- ;;
25- *)
26- python -m media_create.ensure_command qemu-arm-static qemu-arm-static
27- python -m media_create.ensure_command qemu-img qemu-kvm
28- sudo cp /usr/bin/qemu-arm-static "${chroot}/usr/bin"
29- ;;
30- esac
31- sudo cp "$LINARO_HWPACK_INSTALL" "${chroot}/usr/bin"
32-
33- # Actually install the hwpack.
34- sudo mount proc "${chroot}/proc" -t proc
35- cleanup_chroot() {
36- sudo umount -v "$chroot/proc"
37- }
38-
39- for HWPACK_FILE in "${HWPACK_FILES[@]}"; do
40-
41- sudo cp "$HWPACK_FILE" "$chroot"
42- echo ""
43- echo "---------------------------------------------------"
44- echo "Installing (apt-get) $HWPACK_FILE in target rootfs."
45- echo ""
46- if [ "$HWPACK_FORCE_YES" = "yes" ]; then
47- sudo LC_ALL=C chroot "$chroot" linaro-hwpack-install --force-yes /"$(basename "$HWPACK_FILE")"
48- else
49- sudo LC_ALL=C chroot "$chroot" linaro-hwpack-install /"$(basename "$HWPACK_FILE")"
50- fi
51- echo "---------------------------------------------------"
52- echo ""
53- sudo rm -f "${chroot}/$(basename "$HWPACK_FILE")"
54-
55- done
56-
57- # Revert some changes we did to the rootfs as we don't want them in the
58- # image.
59- sudo umount "${chroot}/proc"
60- cleanup_chroot() { :; }
61-
62- sudo mv -f ${TMP_DIR}/resolv.conf.orig "${chroot}/etc/resolv.conf"
63- sudo mv -f ${TMP_DIR}/hosts.orig "${chroot}/etc/hosts"
64- if [ "arch_is_arm" = no ]; then
65- sudo rm -f "${chroot}/usr/bin/qemu-arm-static"
66- fi
67- sudo rm -f "${chroot}/usr/bin/linaro-hwpack-install"
68+ python -m media_create.hwpack "${DIR}/binary" "$HWPACK_FORCE_YES" \
69+ "${HWPACK_FILES[@]}"
70 }
71
72 unpack_binary_tarball() {
73@@ -444,10 +386,6 @@
74 exit 2
75 }
76
77-# Initially, no action is needed to clean up mounts in the chroot.
78-# install_hwpack will temporarily define this function when needed.
79-cleanup_chroot() { :; }
80-
81 cleanup_handler() {
82 status=$?
83
84@@ -463,7 +401,6 @@
85 echo "Performing cleanup..."
86 echo
87
88- cleanup_chroot
89 cleanup_sd
90 cleanup_mountpoints
91 cleanup_tempfiles
92
93=== modified file 'media_create/cmd_runner.py'
94--- media_create/cmd_runner.py 2010-12-17 07:03:34 +0000
95+++ media_create/cmd_runner.py 2011-01-05 16:55:11 +0000
96@@ -26,10 +26,6 @@
97 return Popen(args, stdin=stdin, stdout=stdout, stderr=stderr)
98
99
100-def get_extended_env(ext):
101- return os.environ.update(ext)
102-
103-
104 class Popen(subprocess.Popen):
105 """A version of Popen which raises an error on non-zero returncode.
106
107@@ -37,9 +33,12 @@
108 SubcommandNonZeroReturnValue if it's non-zero.
109 """
110
111- def __init__(self, args, **kwargs):
112+ def __init__(self, args, env=None, **kwargs):
113 self._my_args = args
114- super(Popen, self).__init__(args, **kwargs)
115+ if env is None:
116+ env = os.environ.copy()
117+ env['LC_ALL'] = 'C'
118+ super(Popen, self).__init__(args, env=env, **kwargs)
119
120 def wait(self):
121 returncode = super(Popen, self).wait()
122
123=== added file 'media_create/hwpack.py'
124--- media_create/hwpack.py 1970-01-01 00:00:00 +0000
125+++ media_create/hwpack.py 2011-01-05 16:55:11 +0000
126@@ -0,0 +1,120 @@
127+import atexit
128+import os
129+import platform
130+import shutil
131+import sys
132+import tempfile
133+
134+from media_create import cmd_runner
135+from media_create.ensure_command import ensure_command
136+
137+
138+def install_hwpacks(chroot_dir, tmp_dir, hwpack_force_yes, *hwpack_files):
139+ """Install the given hwpacks onto the given chroot."""
140+
141+ chroot_etc = os.path.join(chroot_dir, 'etc')
142+ temporarily_overwrite_file_on_dir('/etc/resolv.conf', chroot_etc, tmp_dir)
143+ temporarily_overwrite_file_on_dir('/etc/hosts', chroot_etc, tmp_dir)
144+
145+ if not platform.machine().startswith('arm'):
146+ ensure_command('qemu-arm-static', 'qemu-arm-static')
147+ ensure_command('qemu-img', 'qemu-kvm')
148+ copy_file('/usr/bin/qemu-arm-static',
149+ os.path.join(chroot_dir, 'usr', 'bin'))
150+
151+ # FIXME: This is an ugly hack to make sure we use the l-h-i script from
152+ # the current development tree when possible.
153+ here = os.path.dirname(__file__)
154+ linaro_hwpack_install_path = os.path.join(
155+ here, '..', 'linaro-hwpack-install')
156+ if not os.path.exists(linaro_hwpack_install_path):
157+ linaro_hwpack_install_path = '/usr/bin/linaro-hwpack-install'
158+ copy_file(linaro_hwpack_install_path,
159+ os.path.join(chroot_dir, 'usr', 'bin'))
160+
161+ mount_chroot_proc(chroot_dir)
162+
163+ for hwpack_file in hwpack_files:
164+ install_hwpack(chroot_dir, hwpack_file, hwpack_force_yes)
165+
166+
167+def install_hwpack(chroot_dir, hwpack_file, hwpack_force_yes):
168+ """Install an hwpack on the given chroot.
169+
170+ Copy the hwpack file to the chroot and run linaro-hwpack-install passing
171+ that hwpack file to it. If hwpack_force_yes is True, also pass
172+ --force-yes to linaro-hwpack-install.
173+ """
174+ hwpack_basename = os.path.basename(hwpack_file)
175+ copy_file(hwpack_file, chroot_dir)
176+ print "-" * 60
177+ print "Installing (apt-get) %s in target rootfs." % hwpack_basename
178+ args = ['chroot', chroot_dir, 'linaro-hwpack-install']
179+ if hwpack_force_yes:
180+ args.append('--force-yes')
181+ args.append('/%s' % hwpack_basename)
182+ cmd_runner.run(args, as_root=True).wait()
183+ print "-" * 60
184+
185+
186+def mount_chroot_proc(chroot_dir):
187+ """Mount a /proc filesystem on the given chroot.
188+
189+ Also register an atexit function to unmount that /proc filesystem.
190+ """
191+ chroot_proc = os.path.join(chroot_dir, 'proc')
192+ proc = cmd_runner.run(
193+ ['mount', 'proc', chroot_proc, '-t', 'proc'], as_root=True)
194+ proc.wait()
195+ def umount_chroot_proc():
196+ cmd_runner.run(['umount', '-v', chroot_proc], as_root=True).wait()
197+ atexit.register(umount_chroot_proc)
198+
199+
200+def copy_file(filepath, directory):
201+ """Copy the given file to the given directory.
202+
203+ The copying of the file is done in a subprocess and run using sudo.
204+
205+ We also register an atexit function to remove the file from the given
206+ directory.
207+ """
208+ cmd_runner.run(['cp', filepath, directory], as_root=True).wait()
209+
210+ def undo():
211+ new_path = os.path.join(directory, os.path.basename(filepath))
212+ cmd_runner.run(['rm', '-f', new_path], as_root=True).wait()
213+ atexit.register(undo)
214+
215+
216+def temporarily_overwrite_file_on_dir(filepath, directory, tmp_dir):
217+ """Temporarily replace a file on the given directory.
218+
219+ We'll move the existing file on the given directory to a temp dir, then
220+ copy over the given file to that directory and register an atexit function
221+ to move the orig file back to the given directory.
222+ """
223+ basename = os.path.basename(filepath)
224+ path_to_orig = os.path.join(tmp_dir, basename)
225+ # Move the existing file from the given directory to the temp dir.
226+ cmd_runner.run(
227+ ['mv', '-f', os.path.join(directory, basename), path_to_orig],
228+ as_root=True).wait()
229+ # Now copy the given file onto the given directory.
230+ cmd_runner.run(['cp', filepath, directory], as_root=True).wait()
231+
232+ def undo():
233+ cmd_runner.run(
234+ ['mv', '-f', path_to_orig, directory], as_root=True).wait()
235+ atexit.register(undo)
236+
237+
238+if __name__ == '__main__':
239+ tmp_dir = tempfile.mkdtemp()
240+ atexit.register(shutil.rmtree, tmp_dir)
241+ chroot_dir, hwpack_force_yes = sys.argv[1:3]
242+ hwpack_force_yes = False
243+ if hwpack_force_yes == "yes":
244+ hwpack_force_yes = True
245+ hwpacks = sys.argv[3:]
246+ install_hwpacks(chroot_dir, tmp_dir, hwpack_force_yes, *hwpacks)
247
248=== modified file 'media_create/tests/test_media_create.py'
249--- media_create/tests/test_media_create.py 2010-12-20 10:00:07 +0000
250+++ media_create/tests/test_media_create.py 2011-01-05 16:55:11 +0000
251@@ -1,4 +1,5 @@
252 from contextlib import contextmanager
253+import atexit
254 import os
255 import random
256 import string
257@@ -17,6 +18,13 @@
258 from media_create import partitions
259 from media_create import rootfs
260 from media_create.boot_cmd import create_boot_cmd
261+from media_create.hwpack import (
262+ copy_file,
263+ install_hwpack,
264+ install_hwpacks,
265+ mount_chroot_proc,
266+ temporarily_overwrite_file_on_dir,
267+ )
268 from media_create.partitions import (
269 calculate_partition_size_and_offset,
270 convert_size_to_bytes,
271@@ -639,3 +647,116 @@
272 def test_check_device_not_found(self):
273 self._mock_does_device_exist_false()
274 self.assertFalse(check_device.check_device(None))
275+
276+
277+class AtExitRegister(object):
278+ funcs = None
279+ def __call__(self, func, *args, **kwargs):
280+ if self.funcs is None:
281+ self.funcs = []
282+ self.funcs.append((func, args, kwargs))
283+
284+
285+class TestInstallHWPack(TestCaseWithFixtures):
286+
287+ def test_temporarily_overwrite_file_on_dir(self):
288+ fixture = self.useFixture(MockCmdRunnerPopenFixture())
289+ temporarily_overwrite_file_on_dir('/path/to/file', '/dir', '/tmp/dir')
290+ self.assertEquals(
291+ [['sudo', 'mv', '-f', '/dir/file', '/tmp/dir/file'],
292+ ['sudo', 'cp', '/path/to/file', '/dir']],
293+ fixture.mock.calls)
294+
295+ fixture.mock.calls = []
296+ self._run_registered_atexit_functions()
297+ self.assertEquals(
298+ [['sudo', 'mv', '-f', '/tmp/dir/file', '/dir']],
299+ fixture.mock.calls)
300+
301+ def test_copy_file(self):
302+ fixture = self.useFixture(MockCmdRunnerPopenFixture())
303+ copy_file('/path/to/file', '/dir')
304+ self.assertEquals(
305+ [['sudo', 'cp', '/path/to/file', '/dir']],
306+ fixture.mock.calls)
307+
308+ fixture.mock.calls = []
309+ self._run_registered_atexit_functions()
310+ self.assertEquals(
311+ [['sudo', 'rm', '-f', '/dir/file']], fixture.mock.calls)
312+
313+ def test_mount_chroot_proc(self):
314+ fixture = self.useFixture(MockCmdRunnerPopenFixture())
315+ mount_chroot_proc('chroot')
316+ self.assertEquals(
317+ [['sudo', 'mount', 'proc', 'chroot/proc', '-t', 'proc']],
318+ fixture.mock.calls)
319+
320+ fixture.mock.calls = []
321+ self._run_registered_atexit_functions()
322+ self.assertEquals(
323+ [['sudo', 'umount', '-v', 'chroot/proc']], fixture.mock.calls)
324+
325+ def test_install_hwpack(self):
326+ self.useFixture(MockSomethingFixture(
327+ sys, 'stdout', open('/dev/null', 'w')))
328+ fixture = self.useFixture(MockCmdRunnerPopenFixture())
329+ force_yes = False
330+ install_hwpack('chroot', 'hwpack.tgz', force_yes)
331+ self.assertEquals(
332+ [['sudo', 'cp', 'hwpack.tgz', 'chroot'],
333+ ['sudo', 'chroot', 'chroot', 'linaro-hwpack-install',
334+ '/hwpack.tgz']],
335+ fixture.mock.calls)
336+
337+ fixture.mock.calls = []
338+ self._run_registered_atexit_functions()
339+ self.assertEquals(
340+ [['sudo', 'rm', '-f', 'chroot/hwpack.tgz']], fixture.mock.calls)
341+
342+ def test_install_hwpacks(self):
343+ self.useFixture(MockSomethingFixture(
344+ sys, 'stdout', open('/dev/null', 'w')))
345+ fixture = self.useFixture(MockCmdRunnerPopenFixture())
346+ force_yes = True
347+ install_hwpacks(
348+ 'chroot', '/tmp/dir', force_yes, 'hwpack1.tgz', 'hwpack2.tgz')
349+ self.assertEquals(
350+ [['sudo', 'mv', '-f', 'chroot/etc/resolv.conf',
351+ '/tmp/dir/resolv.conf'],
352+ ['sudo', 'cp', '/etc/resolv.conf', 'chroot/etc'],
353+ ['sudo', 'mv', '-f', 'chroot/etc/hosts', '/tmp/dir/hosts'],
354+ ['sudo', 'cp', '/etc/hosts', 'chroot/etc'],
355+ ['sudo', 'cp', '/usr/bin/qemu-arm-static', 'chroot/usr/bin'],
356+ ['sudo', 'cp', 'media_create/../linaro-hwpack-install',
357+ 'chroot/usr/bin'],
358+ ['sudo', 'mount', 'proc', 'chroot/proc', '-t', 'proc'],
359+ ['sudo', 'cp', 'hwpack1.tgz', 'chroot'],
360+ ['sudo', 'chroot', 'chroot', 'linaro-hwpack-install',
361+ '--force-yes', '/hwpack1.tgz'],
362+ ['sudo', 'cp', 'hwpack2.tgz', 'chroot'],
363+ ['sudo', 'chroot', 'chroot', 'linaro-hwpack-install',
364+ '--force-yes', '/hwpack2.tgz']],
365+ fixture.mock.calls)
366+
367+ fixture.mock.calls = []
368+ self._run_registered_atexit_functions()
369+ self.assertEquals(
370+ [['sudo', 'mv', '-f', '/tmp/dir/resolv.conf', 'chroot/etc'],
371+ ['sudo', 'mv', '-f', '/tmp/dir/hosts', 'chroot/etc'],
372+ ['sudo', 'rm', '-f', 'chroot/usr/bin/qemu-arm-static'],
373+ ['sudo', 'rm', '-f', 'chroot/usr/bin/linaro-hwpack-install'],
374+ ['sudo', 'umount', '-v', 'chroot/proc'],
375+ ['sudo', 'rm', '-f', 'chroot/hwpack1.tgz'],
376+ ['sudo', 'rm', '-f', 'chroot/hwpack2.tgz']],
377+ fixture.mock.calls)
378+
379+ def _run_registered_atexit_functions(self):
380+ for func, args, kwargs in self.atexit_fixture.mock.funcs:
381+ func(*args, **kwargs)
382+
383+ def setUp(self):
384+ super(TestInstallHWPack, self).setUp()
385+ self.atexit_fixture = self.useFixture(MockSomethingFixture(
386+ atexit, 'register', AtExitRegister()))
387+

Subscribers

People subscribed via source and target branches