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
1=== modified file 'hwpack/testing.py'
2--- hwpack/testing.py 2010-12-08 00:34:09 +0000
3+++ hwpack/testing.py 2010-12-09 20:01:29 +0000
4@@ -161,6 +161,15 @@
5 fixture.setUp()
6 return fixture
7
8+ def createTempFileAsFixture(self, prefix='tmp'):
9+ """Create a temp file and make sure it is removed on tearDown.
10+
11+ :return: The filename of the file created.
12+ """
13+ _, filename = tempfile.mkstemp(prefix=prefix)
14+ self.addCleanup(os.unlink, filename)
15+ return filename
16+
17
18 class ConfigFileFixture(object):
19
20
21=== modified file 'linaro-media-create'
22--- linaro-media-create 2010-12-03 18:55:10 +0000
23+++ linaro-media-create 2010-12-09 20:01:29 +0000
24@@ -438,40 +438,8 @@
25 }
26
27 create_partitions() {
28- if [ "${DEVICE}" ]; then
29- sudo parted -s ${DEVICE} mklabel msdos
30- fi
31-
32- if [ "${IMAGE_FILE}" ]; then
33- partdev=${IMAGE_FILE}
34- else
35- partdev=${DEVICE}
36- fi
37-
38- if [ "$FAT_SIZE" = "32" ]; then
39- PARTITION_TYPE="0x0C"
40- else
41- PARTITION_TYPE="0x0E"
42- fi
43-
44- # Create:
45- # - on mx51evk, a one cylinder partition for fixed-offset bootloader data at
46- # the beginning of the image (size is one cylinder, so 8224768 bytes with
47- # the first sector for MBR),
48- # - a VFAT or FAT16 partition of 9 cylinders (74027520 bytes, ~70 MiB)
49- # and a linux partition of the rest
50- # - a Linux type rootfs for the rest of the space
51- (
52- if [ "$DEVIMAGE" = mx51evk ]; then
53- cat <<EOF
54-,1,0xDA
55-EOF
56- fi
57- cat <<EOF
58-,9,$PARTITION_TYPE,*
59-,,,-
60-EOF
61- ) | sudo sfdisk -D -H $HEADS -S $SECTORS $CYLINDER_ARG $partdev
62+ python -m media_create.create_partitions "${DEVIMAGE}" \
63+ "${DEVICE-$IMAGE_FILE}" "$FAT_SIZE" "$HEADS" "$SECTORS" "$CYLINDER_ARG"
64
65 if [ "${IMAGE_FILE}" ]; then
66 VFATOFFSET=$(($(LC_ALL=C fdisk -l -u "$IMAGE_FILE" | grep FAT | awk '{print $3}')*512))
67@@ -628,6 +596,7 @@
68 fi
69 }
70
71+# XXX: Apparently there's no need to run qemu-img as root.
72 setup_image() {
73 sudo qemu-img create -f raw "$IMAGE_FILE" $IMAGE_SIZE
74 }
75
76=== added file 'media_create/create_partitions.py'
77--- media_create/create_partitions.py 1970-01-01 00:00:00 +0000
78+++ media_create/create_partitions.py 2010-12-09 20:01:29 +0000
79@@ -0,0 +1,87 @@
80+import subprocess
81+import sys
82+
83+from media_create import cmd_runner
84+
85+
86+def run_sfdisk_commands(commands, heads, sectors, cylinders_arg, device,
87+ as_root=True):
88+ """Run the given commands under sfdisk.
89+
90+ :param commands: A string of sfdisk commands; each on a separate line.
91+ :return: A 2-tuple containing the subprocess' stdout and stderr.
92+ """
93+ args = ['sfdisk',
94+ '-D',
95+ '-H', str(heads),
96+ '-S', str(sectors)]
97+ if cylinders_arg:
98+ args.append(cylinders_arg)
99+ args.append(device)
100+ # XXX: There's some stuff duplicated here from cmd_runner.run() but I
101+ # don't see an easy way to consolidate them as a single function, so I'll
102+ # leave it for later.
103+ if as_root:
104+ args = args[:]
105+ args.insert(0, 'sudo')
106+ proc = cmd_runner.Popen(
107+ args, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
108+ stderr=subprocess.PIPE)
109+ return proc.communicate("%s\n" % commands)
110+
111+
112+def create_partitions(board, device, fat_size, heads, sectors, cylinders_arg):
113+ """Partition the given device according to the board requirements.
114+
115+ :param board: A string with the board type (e.g. beagle, panda, etc)
116+ :param device: A string containing the path to the device to partition.
117+ :param fat_size: The type of FATs used in the boot partition (16 or 32).
118+ :param heads: Number of heads to use in the disk geometry of
119+ partitions.
120+ :param sectors: Number of sectors to use in the disk geometry of
121+ partitions.
122+ :param cylinders_arg: A string of the form "-C NN" containing the number
123+ of cylinders to use in the disk geometry of partitions.
124+ """
125+ stdout = []
126+ stderr = []
127+ is_block_device = device.startswith('/dev/')
128+ if is_block_device:
129+ # Overwrite any existing partition tables with a fresh one.
130+ cmd_runner.run(
131+ ['parted', '-s', device, 'mklabel', 'msdos'], as_root=True)
132+
133+ if fat_size == 32:
134+ partition_type = '0x0C'
135+ else:
136+ partition_type = '0x0E'
137+
138+ if board == 'mx51evk':
139+ # Create a one cylinder partition for fixed-offset bootloader data at
140+ # the beginning of the image (size is one cylinder, so 8224768 bytes
141+ # with the first sector for MBR).
142+ out, err = run_sfdisk_commands(
143+ ',1,0xDA', heads, sectors, cylinders_arg, device)
144+ stdout.append(out)
145+ stderr.append(err)
146+
147+ # Create a VFAT or FAT16 partition of 9 cylinders (74027520 bytes, ~70
148+ # MiB), followed by a Linux-type partition containing the rest of the free
149+ # space.
150+ sfdisk_cmd = ',9,%s,*\n,,,-' % partition_type
151+ out, err = run_sfdisk_commands(
152+ sfdisk_cmd, heads, sectors, cylinders_arg, device)
153+ stdout.append(out)
154+ stderr.append(err)
155+ return "\n".join(stdout), "\n".join(stderr)
156+
157+
158+if __name__ == "__main__":
159+ board, device, fat_size, heads, sectors, cylinders_arg = sys.argv[1:]
160+ fat_size = int(fat_size)
161+ heads = int(heads)
162+ sectors = int(sectors)
163+ stdout, stderr = create_partitions(
164+ board, device, fat_size, heads, sectors, cylinders_arg)
165+ print stdout
166+ print stderr
167
168=== modified file 'media_create/tests/fixtures.py'
169--- media_create/tests/fixtures.py 2010-12-09 19:17:14 +0000
170+++ media_create/tests/fixtures.py 2010-12-09 20:01:29 +0000
171@@ -3,6 +3,7 @@
172 import subprocess
173 import tempfile
174
175+from media_create import create_partitions
176 from media_create import cmd_runner
177
178
179@@ -62,17 +63,11 @@
180 setattr(self.obj, self.attr_name, self.orig_attr)
181
182
183-class MockDoRun(object):
184- """A mock for do_run() which just stores the args given to it."""
185+class MockCmdRunnerPopen(object):
186+ """A mock for cmd_runner.Popen() which stores the args given to it."""
187 args = None
188 def __call__(self, args, **kwargs):
189 self.args = args
190- return 0
191-
192-
193-class MockCmdRunnerPopen(object):
194- def __call__(self, args, **kwargs):
195- self.args = args
196 self.returncode = 0
197 return self
198
199@@ -83,7 +78,7 @@
200 class MockCmdRunnerPopenFixture(MockSomethingFixture):
201 """A test fixture which mocks cmd_runner.do_run with the given mock.
202
203- If no mock is given, MockDoRun is used.
204+ If no mock is given, a MockCmdRunnerPopen instance is used.
205 """
206
207 def __init__(self, mock=None):
208@@ -104,3 +99,27 @@
209
210 def tearDown(self):
211 os.chdir(self.orig_cwd)
212+
213+
214+class MockCallableWithPositionalArgs(object):
215+ """A callable mock which just stores the positional args given to it.
216+
217+ Every time an instance of this is "called", it will append a tuple
218+ containing the positional arguments given to it to self.calls.
219+ """
220+ calls = None
221+ return_value = None
222+ def __call__(self, *args):
223+ if self.calls is None:
224+ self.calls = []
225+ self.calls.append(args)
226+ return self.return_value
227+
228+
229+class MockRunSfdiskCommandsFixture(MockSomethingFixture):
230+
231+ def __init__(self):
232+ mock = MockCallableWithPositionalArgs()
233+ mock.return_value = ('', '')
234+ super(MockRunSfdiskCommandsFixture, self).__init__(
235+ create_partitions, 'run_sfdisk_commands', mock)
236
237=== modified file 'media_create/tests/test_media_create.py'
238--- media_create/tests/test_media_create.py 2010-12-09 19:17:14 +0000
239+++ media_create/tests/test_media_create.py 2010-12-09 20:01:29 +0000
240@@ -4,17 +4,19 @@
241 import string
242 import subprocess
243 import sys
244-import tempfile
245
246 from testtools import TestCase
247
248 from hwpack.testing import TestCaseWithFixtures
249
250-from media_create.boot_cmd import create_boot_cmd
251 from media_create import cmd_runner
252 from media_create import ensure_command
253-
254 from media_create import populate_boot
255+from media_create.boot_cmd import create_boot_cmd
256+from media_create.create_partitions import (
257+ create_partitions,
258+ run_sfdisk_commands,
259+ )
260 from media_create.populate_boot import (
261 make_boot_script,
262 make_uImage,
263@@ -31,6 +33,7 @@
264 CreateTarballFixture,
265 MockCmdRunnerPopenFixture,
266 MockSomethingFixture,
267+ MockRunSfdiskCommandsFixture,
268 )
269
270
271@@ -202,7 +205,7 @@
272 def test_get_file_matching(self):
273 prefix = ''.join(
274 random.choice(string.ascii_lowercase) for x in range(5))
275- file1 = self._create_temp_file_as_fixture(prefix)
276+ file1 = self.createTempFileAsFixture(prefix)
277 directory = os.path.dirname(file1)
278 self.assertEqual(
279 file1, _get_file_matching('%s/%s*' % (directory, prefix)))
280@@ -210,8 +213,8 @@
281 def test_get_file_matching_too_many_files_found(self):
282 prefix = ''.join(
283 random.choice(string.ascii_lowercase) for x in range(5))
284- file1 = self._create_temp_file_as_fixture(prefix)
285- file2 = self._create_temp_file_as_fixture(prefix)
286+ file1 = self.createTempFileAsFixture(prefix)
287+ file2 = self.createTempFileAsFixture(prefix)
288 directory = os.path.dirname(file1)
289 self.assertRaises(
290 ValueError, _get_file_matching, '%s/%s*' % (directory, prefix))
291@@ -222,23 +225,79 @@
292
293 def test_run_mkimage(self):
294 # Create a fake boot script.
295- filename = self._create_temp_file_as_fixture()
296+ filename = self.createTempFileAsFixture()
297 f = open(filename, 'w')
298 f.write("setenv bootcmd 'fatload mmc 0:1 0x80000000 uImage;\nboot")
299 f.close()
300
301- img = self._create_temp_file_as_fixture()
302+ img = self.createTempFileAsFixture()
303 # Use that fake boot script to create a boot loader using mkimage.
304 # Send stdout to file as mkimage will print to stdout and we don't
305 # want that.
306 retval = _run_mkimage(
307 'script', '0', '0', 'boot script', filename, img,
308- stdout=open(self._create_temp_file_as_fixture(), 'w'),
309+ stdout=open(self.createTempFileAsFixture(), 'w'),
310 as_root=False)
311
312 self.assertEqual(0, retval)
313
314- def _create_temp_file_as_fixture(self, prefix='tmp'):
315- _, filename = tempfile.mkstemp(prefix=prefix)
316- self.addCleanup(os.unlink, filename)
317- return filename
318+
319+class TestCreatePartitions(TestCaseWithFixtures):
320+
321+ def test_create_partitions_for_mx51evk(self):
322+ # For this board we create a one cylinder partition at the beginning.
323+ popen_fixture = self.useFixture(MockCmdRunnerPopenFixture())
324+ sfdisk_fixture = self.useFixture(MockRunSfdiskCommandsFixture())
325+
326+ create_partitions('mx51evk', '/dev/sdz', 32, 255, 63, '')
327+
328+ self.assertEqual(
329+ ['sudo', 'parted', '-s', '/dev/sdz', 'mklabel', 'msdos'],
330+ popen_fixture.mock.args)
331+ self.assertEqual(
332+ [(',1,0xDA', 255, 63, '', '/dev/sdz'),
333+ (',9,0x0C,*\n,,,-', 255, 63, '', '/dev/sdz')],
334+ sfdisk_fixture.mock.calls)
335+
336+ def test_create_partitions_for_beagle(self):
337+ popen_fixture = self.useFixture(MockCmdRunnerPopenFixture())
338+ sfdisk_fixture = self.useFixture(MockRunSfdiskCommandsFixture())
339+
340+ create_partitions('beagle', '/dev/sdz', 32, 255, 63, '')
341+
342+ self.assertEqual(
343+ ['sudo', 'parted', '-s', '/dev/sdz', 'mklabel', 'msdos'],
344+ popen_fixture.mock.args)
345+ self.assertEqual(
346+ [(',9,0x0C,*\n,,,-', 255, 63, '', '/dev/sdz')],
347+ sfdisk_fixture.mock.calls)
348+
349+ def test_create_partitions_with_img_file(self):
350+ popen_fixture = self.useFixture(MockCmdRunnerPopenFixture())
351+ sfdisk_fixture = self.useFixture(MockRunSfdiskCommandsFixture())
352+
353+ tempfile = self.createTempFileAsFixture()
354+ create_partitions('beagle', tempfile, 32, 255, 63, '')
355+
356+ # popen() was not called as there's no existing partition table for
357+ # us to overwrite on the image file.
358+ self.assertEqual(None, popen_fixture.mock.args)
359+
360+ self.assertEqual(
361+ [(',9,0x0C,*\n,,,-', 255, 63, '', tempfile)],
362+ sfdisk_fixture.mock.calls)
363+
364+ def test_run_sfdisk_commands(self):
365+ tempfile = self.createTempFileAsFixture()
366+ cmd_runner.run(['qemu-img', 'create', '-f', 'raw', tempfile, '10M'],
367+ stdout=subprocess.PIPE)
368+ stdout, stderr = run_sfdisk_commands(
369+ ',1,0xDA', 5, 63, '', tempfile, as_root=False)
370+ self.assertIn('Successfully wrote the new partition table', stdout)
371+
372+ def test_run_sfdisk_commands_raises_on_non_zero_returncode(self):
373+ tempfile = self.createTempFileAsFixture()
374+ self.assertRaises(
375+ cmd_runner.SubcommandNonZeroReturnValue,
376+ run_sfdisk_commands,
377+ ',1,0xDA', 5, 63, '', tempfile, as_root=False)

Subscribers

People subscribed via source and target branches