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

Proposed by Guilherme Salgado
Status: Merged
Merged at revision: 188
Proposed branch: lp:~salgado/linaro-image-tools/port-create_partitions
Merge into: lp:linaro-image-tools/11.11
Diff against target: 377 lines (+199/-56)
5 files modified
hwpack/testing.py (+9/-0)
linaro-media-create (+3/-34)
media_create/create_partitions.py (+87/-0)
media_create/tests/fixtures.py (+28/-9)
media_create/tests/test_media_create.py (+72/-13)
To merge this branch: bzr merge lp:~salgado/linaro-image-tools/port-create_partitions
Reviewer Review Type Date Requested Status
James Westby (community) Approve
Review via email: mp+43105@code.launchpad.net

Description of the change

Port most of create_partitions to python

To post a comment you must log in.
180. By Guilherme Salgado

merge trunk

Revision history for this message
James Westby (james-w) wrote :

Hi,

Looks fine. I agree sharing more code with do_run would be nice.

The board-specific code in their isn't that nice, but I presume you
are deferring removing that for now?

Thanks,

James

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

I can now use cmd_runner.Popen() here and avoid the duplication. I'll do so after I land that branch.

The board-specific code is going away soon indeed.

Thanks a lot for the review.

181. By Guilherme Salgado

merge trunk

182. By Guilherme Salgado

Use the new cmd_runner.Popen instead of subprocess.Popen

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'hwpack/testing.py'
--- hwpack/testing.py 2010-12-08 00:34:09 +0000
+++ hwpack/testing.py 2010-12-09 20:01:29 +0000
@@ -161,6 +161,15 @@
161 fixture.setUp()161 fixture.setUp()
162 return fixture162 return fixture
163163
164 def createTempFileAsFixture(self, prefix='tmp'):
165 """Create a temp file and make sure it is removed on tearDown.
166
167 :return: The filename of the file created.
168 """
169 _, filename = tempfile.mkstemp(prefix=prefix)
170 self.addCleanup(os.unlink, filename)
171 return filename
172
164173
165class ConfigFileFixture(object):174class ConfigFileFixture(object):
166175
167176
=== modified file 'linaro-media-create'
--- linaro-media-create 2010-12-03 18:55:10 +0000
+++ linaro-media-create 2010-12-09 20:01:29 +0000
@@ -438,40 +438,8 @@
438}438}
439439
440create_partitions() {440create_partitions() {
441 if [ "${DEVICE}" ]; then441 python -m media_create.create_partitions "${DEVIMAGE}" \
442 sudo parted -s ${DEVICE} mklabel msdos442 "${DEVICE-$IMAGE_FILE}" "$FAT_SIZE" "$HEADS" "$SECTORS" "$CYLINDER_ARG"
443 fi
444
445 if [ "${IMAGE_FILE}" ]; then
446 partdev=${IMAGE_FILE}
447 else
448 partdev=${DEVICE}
449 fi
450
451 if [ "$FAT_SIZE" = "32" ]; then
452 PARTITION_TYPE="0x0C"
453 else
454 PARTITION_TYPE="0x0E"
455 fi
456
457 # Create:
458 # - on mx51evk, a one cylinder partition for fixed-offset bootloader data at
459 # the beginning of the image (size is one cylinder, so 8224768 bytes with
460 # the first sector for MBR),
461 # - a VFAT or FAT16 partition of 9 cylinders (74027520 bytes, ~70 MiB)
462 # and a linux partition of the rest
463 # - a Linux type rootfs for the rest of the space
464 (
465 if [ "$DEVIMAGE" = mx51evk ]; then
466 cat <<EOF
467,1,0xDA
468EOF
469 fi
470 cat <<EOF
471,9,$PARTITION_TYPE,*
472,,,-
473EOF
474 ) | sudo sfdisk -D -H $HEADS -S $SECTORS $CYLINDER_ARG $partdev
475443
476 if [ "${IMAGE_FILE}" ]; then444 if [ "${IMAGE_FILE}" ]; then
477 VFATOFFSET=$(($(LC_ALL=C fdisk -l -u "$IMAGE_FILE" | grep FAT | awk '{print $3}')*512))445 VFATOFFSET=$(($(LC_ALL=C fdisk -l -u "$IMAGE_FILE" | grep FAT | awk '{print $3}')*512))
@@ -628,6 +596,7 @@
628 fi596 fi
629}597}
630598
599# XXX: Apparently there's no need to run qemu-img as root.
631setup_image() {600setup_image() {
632 sudo qemu-img create -f raw "$IMAGE_FILE" $IMAGE_SIZE601 sudo qemu-img create -f raw "$IMAGE_FILE" $IMAGE_SIZE
633}602}
634603
=== added file 'media_create/create_partitions.py'
--- media_create/create_partitions.py 1970-01-01 00:00:00 +0000
+++ media_create/create_partitions.py 2010-12-09 20:01:29 +0000
@@ -0,0 +1,87 @@
1import subprocess
2import sys
3
4from media_create import cmd_runner
5
6
7def run_sfdisk_commands(commands, heads, sectors, cylinders_arg, device,
8 as_root=True):
9 """Run the given commands under sfdisk.
10
11 :param commands: A string of sfdisk commands; each on a separate line.
12 :return: A 2-tuple containing the subprocess' stdout and stderr.
13 """
14 args = ['sfdisk',
15 '-D',
16 '-H', str(heads),
17 '-S', str(sectors)]
18 if cylinders_arg:
19 args.append(cylinders_arg)
20 args.append(device)
21 # XXX: There's some stuff duplicated here from cmd_runner.run() but I
22 # don't see an easy way to consolidate them as a single function, so I'll
23 # leave it for later.
24 if as_root:
25 args = args[:]
26 args.insert(0, 'sudo')
27 proc = cmd_runner.Popen(
28 args, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
29 stderr=subprocess.PIPE)
30 return proc.communicate("%s\n" % commands)
31
32
33def create_partitions(board, device, fat_size, heads, sectors, cylinders_arg):
34 """Partition the given device according to the board requirements.
35
36 :param board: A string with the board type (e.g. beagle, panda, etc)
37 :param device: A string containing the path to the device to partition.
38 :param fat_size: The type of FATs used in the boot partition (16 or 32).
39 :param heads: Number of heads to use in the disk geometry of
40 partitions.
41 :param sectors: Number of sectors to use in the disk geometry of
42 partitions.
43 :param cylinders_arg: A string of the form "-C NN" containing the number
44 of cylinders to use in the disk geometry of partitions.
45 """
46 stdout = []
47 stderr = []
48 is_block_device = device.startswith('/dev/')
49 if is_block_device:
50 # Overwrite any existing partition tables with a fresh one.
51 cmd_runner.run(
52 ['parted', '-s', device, 'mklabel', 'msdos'], as_root=True)
53
54 if fat_size == 32:
55 partition_type = '0x0C'
56 else:
57 partition_type = '0x0E'
58
59 if board == 'mx51evk':
60 # Create a one cylinder partition for fixed-offset bootloader data at
61 # the beginning of the image (size is one cylinder, so 8224768 bytes
62 # with the first sector for MBR).
63 out, err = run_sfdisk_commands(
64 ',1,0xDA', heads, sectors, cylinders_arg, device)
65 stdout.append(out)
66 stderr.append(err)
67
68 # Create a VFAT or FAT16 partition of 9 cylinders (74027520 bytes, ~70
69 # MiB), followed by a Linux-type partition containing the rest of the free
70 # space.
71 sfdisk_cmd = ',9,%s,*\n,,,-' % partition_type
72 out, err = run_sfdisk_commands(
73 sfdisk_cmd, heads, sectors, cylinders_arg, device)
74 stdout.append(out)
75 stderr.append(err)
76 return "\n".join(stdout), "\n".join(stderr)
77
78
79if __name__ == "__main__":
80 board, device, fat_size, heads, sectors, cylinders_arg = sys.argv[1:]
81 fat_size = int(fat_size)
82 heads = int(heads)
83 sectors = int(sectors)
84 stdout, stderr = create_partitions(
85 board, device, fat_size, heads, sectors, cylinders_arg)
86 print stdout
87 print stderr
088
=== modified file 'media_create/tests/fixtures.py'
--- media_create/tests/fixtures.py 2010-12-09 19:17:14 +0000
+++ media_create/tests/fixtures.py 2010-12-09 20:01:29 +0000
@@ -3,6 +3,7 @@
3import subprocess3import subprocess
4import tempfile4import tempfile
55
6from media_create import create_partitions
6from media_create import cmd_runner7from media_create import cmd_runner
78
89
@@ -62,17 +63,11 @@
62 setattr(self.obj, self.attr_name, self.orig_attr)63 setattr(self.obj, self.attr_name, self.orig_attr)
6364
6465
65class MockDoRun(object):66class MockCmdRunnerPopen(object):
66 """A mock for do_run() which just stores the args given to it."""67 """A mock for cmd_runner.Popen() which stores the args given to it."""
67 args = None68 args = None
68 def __call__(self, args, **kwargs):69 def __call__(self, args, **kwargs):
69 self.args = args70 self.args = args
70 return 0
71
72
73class MockCmdRunnerPopen(object):
74 def __call__(self, args, **kwargs):
75 self.args = args
76 self.returncode = 071 self.returncode = 0
77 return self72 return self
7873
@@ -83,7 +78,7 @@
83class MockCmdRunnerPopenFixture(MockSomethingFixture):78class MockCmdRunnerPopenFixture(MockSomethingFixture):
84 """A test fixture which mocks cmd_runner.do_run with the given mock.79 """A test fixture which mocks cmd_runner.do_run with the given mock.
8580
86 If no mock is given, MockDoRun is used.81 If no mock is given, a MockCmdRunnerPopen instance is used.
87 """82 """
8883
89 def __init__(self, mock=None):84 def __init__(self, mock=None):
@@ -104,3 +99,27 @@
10499
105 def tearDown(self):100 def tearDown(self):
106 os.chdir(self.orig_cwd)101 os.chdir(self.orig_cwd)
102
103
104class MockCallableWithPositionalArgs(object):
105 """A callable mock which just stores the positional args given to it.
106
107 Every time an instance of this is "called", it will append a tuple
108 containing the positional arguments given to it to self.calls.
109 """
110 calls = None
111 return_value = None
112 def __call__(self, *args):
113 if self.calls is None:
114 self.calls = []
115 self.calls.append(args)
116 return self.return_value
117
118
119class MockRunSfdiskCommandsFixture(MockSomethingFixture):
120
121 def __init__(self):
122 mock = MockCallableWithPositionalArgs()
123 mock.return_value = ('', '')
124 super(MockRunSfdiskCommandsFixture, self).__init__(
125 create_partitions, 'run_sfdisk_commands', mock)
107126
=== modified file 'media_create/tests/test_media_create.py'
--- media_create/tests/test_media_create.py 2010-12-09 19:17:14 +0000
+++ media_create/tests/test_media_create.py 2010-12-09 20:01:29 +0000
@@ -4,17 +4,19 @@
4import string4import string
5import subprocess5import subprocess
6import sys6import sys
7import tempfile
87
9from testtools import TestCase8from testtools import TestCase
109
11from hwpack.testing import TestCaseWithFixtures10from hwpack.testing import TestCaseWithFixtures
1211
13from media_create.boot_cmd import create_boot_cmd
14from media_create import cmd_runner12from media_create import cmd_runner
15from media_create import ensure_command13from media_create import ensure_command
16
17from media_create import populate_boot14from media_create import populate_boot
15from media_create.boot_cmd import create_boot_cmd
16from media_create.create_partitions import (
17 create_partitions,
18 run_sfdisk_commands,
19 )
18from media_create.populate_boot import (20from media_create.populate_boot import (
19 make_boot_script,21 make_boot_script,
20 make_uImage,22 make_uImage,
@@ -31,6 +33,7 @@
31 CreateTarballFixture,33 CreateTarballFixture,
32 MockCmdRunnerPopenFixture,34 MockCmdRunnerPopenFixture,
33 MockSomethingFixture,35 MockSomethingFixture,
36 MockRunSfdiskCommandsFixture,
34 )37 )
3538
3639
@@ -202,7 +205,7 @@
202 def test_get_file_matching(self):205 def test_get_file_matching(self):
203 prefix = ''.join(206 prefix = ''.join(
204 random.choice(string.ascii_lowercase) for x in range(5))207 random.choice(string.ascii_lowercase) for x in range(5))
205 file1 = self._create_temp_file_as_fixture(prefix)208 file1 = self.createTempFileAsFixture(prefix)
206 directory = os.path.dirname(file1)209 directory = os.path.dirname(file1)
207 self.assertEqual(210 self.assertEqual(
208 file1, _get_file_matching('%s/%s*' % (directory, prefix)))211 file1, _get_file_matching('%s/%s*' % (directory, prefix)))
@@ -210,8 +213,8 @@
210 def test_get_file_matching_too_many_files_found(self):213 def test_get_file_matching_too_many_files_found(self):
211 prefix = ''.join(214 prefix = ''.join(
212 random.choice(string.ascii_lowercase) for x in range(5))215 random.choice(string.ascii_lowercase) for x in range(5))
213 file1 = self._create_temp_file_as_fixture(prefix)216 file1 = self.createTempFileAsFixture(prefix)
214 file2 = self._create_temp_file_as_fixture(prefix)217 file2 = self.createTempFileAsFixture(prefix)
215 directory = os.path.dirname(file1)218 directory = os.path.dirname(file1)
216 self.assertRaises(219 self.assertRaises(
217 ValueError, _get_file_matching, '%s/%s*' % (directory, prefix))220 ValueError, _get_file_matching, '%s/%s*' % (directory, prefix))
@@ -222,23 +225,79 @@
222225
223 def test_run_mkimage(self):226 def test_run_mkimage(self):
224 # Create a fake boot script.227 # Create a fake boot script.
225 filename = self._create_temp_file_as_fixture()228 filename = self.createTempFileAsFixture()
226 f = open(filename, 'w')229 f = open(filename, 'w')
227 f.write("setenv bootcmd 'fatload mmc 0:1 0x80000000 uImage;\nboot")230 f.write("setenv bootcmd 'fatload mmc 0:1 0x80000000 uImage;\nboot")
228 f.close()231 f.close()
229232
230 img = self._create_temp_file_as_fixture()233 img = self.createTempFileAsFixture()
231 # Use that fake boot script to create a boot loader using mkimage.234 # Use that fake boot script to create a boot loader using mkimage.
232 # Send stdout to file as mkimage will print to stdout and we don't235 # Send stdout to file as mkimage will print to stdout and we don't
233 # want that.236 # want that.
234 retval = _run_mkimage(237 retval = _run_mkimage(
235 'script', '0', '0', 'boot script', filename, img,238 'script', '0', '0', 'boot script', filename, img,
236 stdout=open(self._create_temp_file_as_fixture(), 'w'),239 stdout=open(self.createTempFileAsFixture(), 'w'),
237 as_root=False)240 as_root=False)
238241
239 self.assertEqual(0, retval)242 self.assertEqual(0, retval)
240243
241 def _create_temp_file_as_fixture(self, prefix='tmp'):244
242 _, filename = tempfile.mkstemp(prefix=prefix)245class TestCreatePartitions(TestCaseWithFixtures):
243 self.addCleanup(os.unlink, filename)246
244 return filename247 def test_create_partitions_for_mx51evk(self):
248 # For this board we create a one cylinder partition at the beginning.
249 popen_fixture = self.useFixture(MockCmdRunnerPopenFixture())
250 sfdisk_fixture = self.useFixture(MockRunSfdiskCommandsFixture())
251
252 create_partitions('mx51evk', '/dev/sdz', 32, 255, 63, '')
253
254 self.assertEqual(
255 ['sudo', 'parted', '-s', '/dev/sdz', 'mklabel', 'msdos'],
256 popen_fixture.mock.args)
257 self.assertEqual(
258 [(',1,0xDA', 255, 63, '', '/dev/sdz'),
259 (',9,0x0C,*\n,,,-', 255, 63, '', '/dev/sdz')],
260 sfdisk_fixture.mock.calls)
261
262 def test_create_partitions_for_beagle(self):
263 popen_fixture = self.useFixture(MockCmdRunnerPopenFixture())
264 sfdisk_fixture = self.useFixture(MockRunSfdiskCommandsFixture())
265
266 create_partitions('beagle', '/dev/sdz', 32, 255, 63, '')
267
268 self.assertEqual(
269 ['sudo', 'parted', '-s', '/dev/sdz', 'mklabel', 'msdos'],
270 popen_fixture.mock.args)
271 self.assertEqual(
272 [(',9,0x0C,*\n,,,-', 255, 63, '', '/dev/sdz')],
273 sfdisk_fixture.mock.calls)
274
275 def test_create_partitions_with_img_file(self):
276 popen_fixture = self.useFixture(MockCmdRunnerPopenFixture())
277 sfdisk_fixture = self.useFixture(MockRunSfdiskCommandsFixture())
278
279 tempfile = self.createTempFileAsFixture()
280 create_partitions('beagle', tempfile, 32, 255, 63, '')
281
282 # popen() was not called as there's no existing partition table for
283 # us to overwrite on the image file.
284 self.assertEqual(None, popen_fixture.mock.args)
285
286 self.assertEqual(
287 [(',9,0x0C,*\n,,,-', 255, 63, '', tempfile)],
288 sfdisk_fixture.mock.calls)
289
290 def test_run_sfdisk_commands(self):
291 tempfile = self.createTempFileAsFixture()
292 cmd_runner.run(['qemu-img', 'create', '-f', 'raw', tempfile, '10M'],
293 stdout=subprocess.PIPE)
294 stdout, stderr = run_sfdisk_commands(
295 ',1,0xDA', 5, 63, '', tempfile, as_root=False)
296 self.assertIn('Successfully wrote the new partition table', stdout)
297
298 def test_run_sfdisk_commands_raises_on_non_zero_returncode(self):
299 tempfile = self.createTempFileAsFixture()
300 self.assertRaises(
301 cmd_runner.SubcommandNonZeroReturnValue,
302 run_sfdisk_commands,
303 ',1,0xDA', 5, 63, '', tempfile, as_root=False)

Subscribers

People subscribed via source and target branches