Merge lp:~salgado/linaro-image-tools/partition-setup into lp:linaro-image-tools/11.11
- partition-setup
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 192 |
Proposed branch: | lp:~salgado/linaro-image-tools/partition-setup |
Merge into: | lp:linaro-image-tools/11.11 |
Diff against target: |
1022 lines (+472/-230) 10 files modified
README (+2/-0) linaro-media-create (+11/-89) media_create/cmd_runner.py (+9/-5) media_create/create_partitions.py (+26/-45) media_create/partition_size.py (+0/-42) media_create/partitions.py (+193/-0) media_create/populate_boot.py (+9/-5) media_create/tests/fixtures.py (+14/-3) media_create/tests/test_media_create.py (+183/-41) tests/integration.txt (+25/-0) |
To merge this branch: | bzr merge lp:~salgado/linaro-image-tools/partition-setup |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Martin Ohlsson (community) | Approve | ||
Review via email: mp+43520@code.launchpad.net |
Commit message
Description of the change
This is a rather large branch with lots of changes that were needed to port
some shell code that was interrelated and thus needed to be ported at once.
- Change cmd_runner.run() to return a Popen instance so that it's more
flexible
- Simplify create_partitions now that it's only called from python code
- Create a new partitions.py module which provides a single function for doing
everything related with partitioning. That's where most of the new code is,
but everything should be self-explanatory (or have comments) there.
- Merge partition_size.py into the above file
- Extend MockCmdRunnerPopen so that it stores the arguments passed in to each
of its invocations; useful when testing functions that run multiple
subprocesses.
- Create a new tests/integrati
tests that are useful but must not be automated.
Martin Ohlsson (martin-ohlson) wrote : | # |
Peter Maydell (pmaydell) wrote : | # |
146 - # Round the size of the raw disk image up to a multiple of 256K
147 - # so it is an exact number of SD card erase blocks in length.
148 - # Otherwise Linux under qemu cannot access the last part of the
149 - # card and is likely to complain that the last partition on the
150 - # disk has been truncated.
151 - IMAGE_SIZE=
So this bug fix has gone from the shell script but I can't find the bit in the Python which implements it. Am I missing something?
Guilherme Salgado (salgado) wrote : | # |
On Mon, 2010-12-13 at 16:25 +0000, Martin Ohlsson wrote:
> > === modified file 'media_
> > --- media_create/
> > +++ media_create/
> >
> > cmd_runner.run(
> > - ['parted', '-s', device, 'mklabel', 'msdos'], as_root=True)
> > + ['parted', '-s', media.path, 'mklabel', 'msdos'], as_root=True)
> > + # It sems to be necessary to sleep a bit here to avoid a race
> > + # condition with the sfdisk commands executed below. Try removing it
> > + # and running the integration tests to see how it fails.
> > + time.sleep(0.5)
>
> Isn't it possible to wait() for the parted command to finish?
Very good catch! Friday I updated a bunch of callsites that were
expecting cmd_runner.run() to wait() for them but forgot this one and
today it didn't occur to me that the race could be a consequence of the
now-missing wait() call. I've updated this and a few other callsites
that I missed to update when I changed cmd_runner.run(). Thanks!
- 193. By Guilherme Salgado
-
Update a few cmd_runner.run() callsites that were not wait()ing
Guilherme Salgado (salgado) wrote : | # |
On Mon, 2010-12-13 at 16:39 +0000, Peter Maydell wrote:
> 146 - # Round the size of the raw disk image up to a multiple of 256K
> 147 - # so it is an exact number of SD card erase blocks in length.
> 148 - # Otherwise Linux under qemu cannot access the last part of the
> 149 - # card and is likely to complain that the last partition on the
> 150 - # disk has been truncated.
> 151 - IMAGE_SIZE=
>
> So this bug fix has gone from the shell script but I can't find the bit in the Python which implements it. Am I missing something
Looks like it was lost in translation indeed. However, qemu was able to
boot an image I generated using the code on this branch. Would the lack
of this fix render the image unusable or should I expect to see other
symptoms? Is there any chance the fix is no longer needed or is needed
only for certain versions of qemu?
Peter Maydell (pmaydell) wrote : | # |
The symptom would be that on bootup fsck complains about the filesystem being larger than the partition. It may well happen only for certain image sizes -- if you happened to get l-m-c to use an image size that's already a multiple of 256K then you wouldn't see any effect.
(We've also had problems reported even with the bugfix, eg https:/
However, I think it would be better to deal with possible improvements to that bug fix elsewhere, not as part of this conversion-
James Westby (james-w) wrote : | # |
Hi,
I haven't read this in the detail that I would like, but I couldn't see any issues.
Could I suggest that your integration tests tell you what the expected result should
be?
Thanks,
James
Martin Ohlsson (martin-ohlson) wrote : | # |
Hi Guilherme,
I read the code a couple of times without noticing anything strange besides my previous comment.
/Martin
Guilherme Salgado (salgado) wrote : | # |
On Mon, 2010-12-13 at 17:37 +0000, Peter Maydell wrote:
> The symptom would be that on bootup fsck complains about the
> filesystem being larger than the partition. It may well happen only
> for certain image sizes -- if you happened to get l-m-c to use an
> image size that's already a multiple of 256K then you wouldn't see any
> effect.
>
> (We've also had problems reported even with the bugfix, eg
> https:/
> still not quite right.)
>
> However, I think it would be better to deal with possible improvements
> to that bug fix elsewhere, not as part of this conversion-
> process.
Agreed, but if I knew how to reproduce I could add that as a comment in
the code to save time when somebody gets to work on those specific bits.
The bug-fix in now present in the python version.
- 194. By Guilherme Salgado
-
A few tweaks a bug fixes suggested by reviewers
Preview Diff
1 | === modified file 'README' | |||
2 | --- README 2010-12-03 13:22:03 +0000 | |||
3 | +++ README 2010-12-14 13:31:33 +0000 | |||
4 | @@ -11,6 +11,8 @@ | |||
5 | 11 | - python-debian >= 0.1.16ubuntu1 | 11 | - python-debian >= 0.1.16ubuntu1 |
6 | 12 | - python-argparse | 12 | - python-argparse |
7 | 13 | - dpkg-dev | 13 | - dpkg-dev |
8 | 14 | - python-parted | ||
9 | 15 | - python-dbus | ||
10 | 14 | 16 | ||
11 | 15 | And run the following command: | 17 | And run the following command: |
12 | 16 | 18 | ||
13 | 17 | 19 | ||
14 | === modified file 'linaro-media-create' | |||
15 | --- linaro-media-create 2010-12-12 20:48:29 +0000 | |||
16 | +++ linaro-media-create 2010-12-14 13:31:33 +0000 | |||
17 | @@ -34,7 +34,7 @@ | |||
18 | 34 | MMC_PART_OFFSET=0 | 34 | MMC_PART_OFFSET=0 |
19 | 35 | BOOTFS_STEP="create_boot_cmd populate_boot" | 35 | BOOTFS_STEP="create_boot_cmd populate_boot" |
20 | 36 | ROOTFS_STEP="populate_rootfs" | 36 | ROOTFS_STEP="populate_rootfs" |
22 | 37 | PARTITION_STEP="create_partitions" | 37 | SHOULD_CREATE_PARTITIONS="yes" |
23 | 38 | mmc_option="0:1" | 38 | mmc_option="0:1" |
24 | 39 | boot_args_options="rootwait ro" | 39 | boot_args_options="rootwait ro" |
25 | 40 | HWPACK_FORCE_YES="no" | 40 | HWPACK_FORCE_YES="no" |
26 | @@ -272,13 +272,13 @@ | |||
27 | 272 | BOOTFS_STEP="" | 272 | BOOTFS_STEP="" |
28 | 273 | ;; | 273 | ;; |
29 | 274 | --no-part) | 274 | --no-part) |
31 | 275 | PARTITION_STEP="" | 275 | SHOULD_CREATE_PARTITIONS="no" |
32 | 276 | ;; | 276 | ;; |
33 | 277 | esac | 277 | esac |
34 | 278 | shift | 278 | shift |
35 | 279 | done | 279 | done |
36 | 280 | 280 | ||
38 | 281 | DEPLOY_STEPS="$PARTITION_STEP prepare_partitions $BOOTFS_STEP $ROOTFS_STEP" | 281 | DEPLOY_STEPS="setup_partitions $BOOTFS_STEP $ROOTFS_STEP" |
39 | 282 | 282 | ||
40 | 283 | python -m media_create.ensure_command mkimage uboot-mkimage | 283 | python -m media_create.ensure_command mkimage uboot-mkimage |
41 | 284 | python -m media_create.ensure_command uuidgen uuid-runtime | 284 | python -m media_create.ensure_command uuidgen uuid-runtime |
42 | @@ -309,33 +309,6 @@ | |||
43 | 309 | 309 | ||
44 | 310 | RFS_UUID=`uuidgen -r` | 310 | RFS_UUID=`uuidgen -r` |
45 | 311 | 311 | ||
46 | 312 | get_device_by_id() { | ||
47 | 313 | if [ ! "${IMAGE_FILE}" ]; then | ||
48 | 314 | for device in /dev/disk/by-id/*; do | ||
49 | 315 | if [ `realpath $device` = $DEVICE ]; then | ||
50 | 316 | case "$device" in | ||
51 | 317 | *-part[0-9]*) | ||
52 | 318 | echo "device $DEVICE must not be a partition part ($device)" >&2 | ||
53 | 319 | exit 1 | ||
54 | 320 | ;; | ||
55 | 321 | esac | ||
56 | 322 | for part_id in `ls "$device-part"*`; do | ||
57 | 323 | part=`realpath $part_id` | ||
58 | 324 | part_no=`echo $part_id | sed -e 's/.*-part//g'` | ||
59 | 325 | # echo "part $part_no found: $part_id" 1>&2 | ||
60 | 326 | # if there is a non-fs-data part (e.g. mx51evk), MMC_PART_OFFSET=1 | ||
61 | 327 | if test "$part_no" = $((1 + $MMC_PART_OFFSET)); then | ||
62 | 328 | BOOTFS=$part | ||
63 | 329 | elif test "$part_no" = $((2 + $MMC_PART_OFFSET)) ; then | ||
64 | 330 | ROOTFS=$part | ||
65 | 331 | fi | ||
66 | 332 | done | ||
67 | 333 | break | ||
68 | 334 | fi | ||
69 | 335 | done | ||
70 | 336 | fi | ||
71 | 337 | } | ||
72 | 338 | |||
73 | 339 | install_hwpack() { | 312 | install_hwpack() { |
74 | 340 | chroot=${DIR}/binary | 313 | chroot=${DIR}/binary |
75 | 341 | # Make sure we unmount /proc in the chroot or else it can't be moved to the | 314 | # Make sure we unmount /proc in the chroot or else it can't be moved to the |
76 | @@ -445,33 +418,22 @@ | |||
77 | 445 | loop_devices="$loop_devices $1" | 418 | loop_devices="$loop_devices $1" |
78 | 446 | } | 419 | } |
79 | 447 | 420 | ||
83 | 448 | create_partitions() { | 421 | setup_partitions() { |
84 | 449 | python -m media_create.create_partitions "${DEVIMAGE}" \ | 422 | boot_and_root_devices=$(python -m media_create.partitions \ |
85 | 450 | "${DEVICE-$IMAGE_FILE}" "$FAT_SIZE" "$HEADS" "$SECTORS" "$CYLINDER_ARG" | 423 | "$DEVIMAGE" "${DEVICE-$IMAGE_FILE}" "$FAT_SIZE" "$IMAGE_SIZE" \ |
86 | 424 | "$SHOULD_CREATE_PARTITIONS") | ||
87 | 425 | eval $boot_and_root_devices | ||
88 | 451 | 426 | ||
89 | 452 | if [ "${IMAGE_FILE}" ]; then | 427 | if [ "${IMAGE_FILE}" ]; then |
90 | 453 | sizes_and_offsets=$(python -m media_create.partition_size "${IMAGE_FILE}") | ||
91 | 454 | eval $sizes_and_offsets | ||
92 | 455 | BOOTFS=$(sudo losetup -f --show "$IMAGE_FILE" --offset $VFATOFFSET \ | ||
93 | 456 | --sizelimit $VFATSIZE) | ||
94 | 457 | register_loopback "$BOOTFS" | 428 | register_loopback "$BOOTFS" |
95 | 458 | ROOTFS=$(sudo losetup -f --show "$IMAGE_FILE" --offset $ROOTOFFSET \ | ||
96 | 459 | --sizelimit $ROOTSIZE) | ||
97 | 460 | register_loopback "$ROOTFS" | 429 | register_loopback "$ROOTFS" |
98 | 461 | fi | 430 | fi |
99 | 431 | |||
100 | 432 | prepare_partitions | ||
101 | 462 | } | 433 | } |
102 | 463 | 434 | ||
103 | 464 | |||
104 | 465 | prepare_partitions() { | 435 | prepare_partitions() { |
105 | 466 | 436 | ||
106 | 467 | # sync and sleep a bit as the partitions may have been created in the | ||
107 | 468 | # previous step. | ||
108 | 469 | echo -n "waiting for partitioning to settle ..." | ||
109 | 470 | sync | ||
110 | 471 | sleep 3 | ||
111 | 472 | echo "done." | ||
112 | 473 | get_device_by_id | ||
113 | 474 | |||
114 | 475 | if [ "$BOOTFS_STEP" ]; then | 437 | if [ "$BOOTFS_STEP" ]; then |
115 | 476 | echo "" | 438 | echo "" |
116 | 477 | echo "Formating Boot Partition" | 439 | echo "Formating Boot Partition" |
117 | @@ -565,6 +527,7 @@ | |||
118 | 565 | echo "Creating /etc/flash-kernel.conf" | 527 | echo "Creating /etc/flash-kernel.conf" |
119 | 566 | echo "" | 528 | echo "" |
120 | 567 | 529 | ||
121 | 530 | TARGET_BOOT_DEV=/dev/mmcblk0p$(( 1 + $MMC_PART_OFFSET )) | ||
122 | 568 | echo "UBOOT_PART=${TARGET_BOOT_DEV}" | sudo tee "${ROOT_DISK}/etc/flash-kernel.conf" >/dev/null | 531 | echo "UBOOT_PART=${TARGET_BOOT_DEV}" | sudo tee "${ROOT_DISK}/etc/flash-kernel.conf" >/dev/null |
123 | 569 | 532 | ||
124 | 570 | sync | 533 | sync |
125 | @@ -572,39 +535,6 @@ | |||
126 | 572 | sudo umount "${ROOT_DISK}" || true | 535 | sudo umount "${ROOT_DISK}" || true |
127 | 573 | } | 536 | } |
128 | 574 | 537 | ||
129 | 575 | calculatesize() { | ||
130 | 576 | IMAGE_SIZE=${IMAGE_SIZE/G/M*1024} | ||
131 | 577 | IMAGE_SIZE=${IMAGE_SIZE/M/K*1024} | ||
132 | 578 | IMAGE_SIZE=${IMAGE_SIZE/K/*1024} | ||
133 | 579 | IMAGE_SIZE=$(($IMAGE_SIZE)) | ||
134 | 580 | } | ||
135 | 581 | |||
136 | 582 | setup_sizes() { | ||
137 | 583 | HEADS=255 | ||
138 | 584 | SECTORS=63 | ||
139 | 585 | SECTORSIZE=512 | ||
140 | 586 | if [ "${IMAGE_FILE}" ]; then | ||
141 | 587 | calculatesize | ||
142 | 588 | CYLINDERSIZE=$(($HEADS*$SECTORS*$SECTORSIZE)) | ||
143 | 589 | CYLINDERS=$(($IMAGE_SIZE/$CYLINDERSIZE)) | ||
144 | 590 | CYLINDER_ARG="-C $CYLINDERS" | ||
145 | 591 | IMAGE_SIZE=$(($CYLINDERS*$CYLINDERSIZE)) | ||
146 | 592 | # Round the size of the raw disk image up to a multiple of 256K | ||
147 | 593 | # so it is an exact number of SD card erase blocks in length. | ||
148 | 594 | # Otherwise Linux under qemu cannot access the last part of the | ||
149 | 595 | # card and is likely to complain that the last partition on the | ||
150 | 596 | # disk has been truncated. | ||
151 | 597 | IMAGE_SIZE=$(((($IMAGE_SIZE-1)/(1024*256)+1)*(1024*256))) | ||
152 | 598 | else | ||
153 | 599 | CYLINDER_ARG="" | ||
154 | 600 | fi | ||
155 | 601 | } | ||
156 | 602 | |||
157 | 603 | # XXX: Apparently there's no need to run qemu-img as root. | ||
158 | 604 | setup_image() { | ||
159 | 605 | sudo qemu-img create -f raw "$IMAGE_FILE" $IMAGE_SIZE | ||
160 | 606 | } | ||
161 | 607 | |||
162 | 608 | remove_image_file() { | 538 | remove_image_file() { |
163 | 609 | if [ -f "$IMAGE_FILE" ]; then | 539 | if [ -f "$IMAGE_FILE" ]; then |
164 | 610 | rm -v $IMAGE_FILE | 540 | rm -v $IMAGE_FILE |
165 | @@ -659,11 +589,6 @@ | |||
166 | 659 | trap cleanup_handler EXIT | 589 | trap cleanup_handler EXIT |
167 | 660 | trap signal_handler INT TERM | 590 | trap signal_handler INT TERM |
168 | 661 | 591 | ||
169 | 662 | setup_sizes | ||
170 | 663 | if [ "${IMAGE_FILE}" ]; then | ||
171 | 664 | setup_image | ||
172 | 665 | fi | ||
173 | 666 | |||
174 | 667 | serial_opts="" | 592 | serial_opts="" |
175 | 668 | if [ "$consoles" ]; then | 593 | if [ "$consoles" ]; then |
176 | 669 | for c in ${consoles}; do | 594 | for c in ${consoles}; do |
177 | @@ -767,9 +692,6 @@ | |||
178 | 767 | fi | 692 | fi |
179 | 768 | fi | 693 | fi |
180 | 769 | 694 | ||
181 | 770 | TARGET_BOOT_DEV=/dev/mmcblk0p$(( 1 + $MMC_PART_OFFSET )) | ||
182 | 771 | TARGET_ROOT_DEV=/dev/mmcblk0p$(( 2 + $MMC_PART_OFFSET )) | ||
183 | 772 | |||
184 | 773 | if [ ! "${DEVICE}" -a ! "${IMAGE_FILE}" ]; then | 695 | if [ ! "${DEVICE}" -a ! "${IMAGE_FILE}" ]; then |
185 | 774 | usage | 696 | usage |
186 | 775 | fi | 697 | fi |
187 | 776 | 698 | ||
188 | === modified file 'media_create/cmd_runner.py' | |||
189 | --- media_create/cmd_runner.py 2010-12-09 19:17:14 +0000 | |||
190 | +++ media_create/cmd_runner.py 2010-12-14 13:31:33 +0000 | |||
191 | @@ -1,13 +1,19 @@ | |||
192 | 1 | import subprocess | 1 | import subprocess |
193 | 2 | 2 | ||
194 | 3 | 3 | ||
196 | 4 | def run(args, as_root=False, stdout=None): | 4 | def run(args, as_root=False, stdin=None, stdout=None, stderr=None): |
197 | 5 | """Run the given command as a sub process. | 5 | """Run the given command as a sub process. |
198 | 6 | 6 | ||
199 | 7 | Return a Popen instance. | ||
200 | 8 | |||
201 | 9 | Callsites must wait() or communicate() with the returned Popen instance. | ||
202 | 10 | |||
203 | 7 | :param command: A list or tuple containing the command to run and the | 11 | :param command: A list or tuple containing the command to run and the |
204 | 8 | arguments that should be passed to it. | 12 | arguments that should be passed to it. |
205 | 9 | :param as_root: Should the given command be run as root (with sudo)? | 13 | :param as_root: Should the given command be run as root (with sudo)? |
207 | 10 | :param stdout: Same as subprocess.Popen(). | 14 | :param stdin: Same as in subprocess.Popen(). |
208 | 15 | :param stdout: Same as in subprocess.Popen(). | ||
209 | 16 | :param stderr: Same as in subprocess.Popen(). | ||
210 | 11 | """ | 17 | """ |
211 | 12 | assert isinstance(args, (list, tuple)), ( | 18 | assert isinstance(args, (list, tuple)), ( |
212 | 13 | "The command to run must be a list or tuple, found: %s" % type(args)) | 19 | "The command to run must be a list or tuple, found: %s" % type(args)) |
213 | @@ -16,9 +22,7 @@ | |||
214 | 16 | if as_root: | 22 | if as_root: |
215 | 17 | args = args[:] | 23 | args = args[:] |
216 | 18 | args.insert(0, 'sudo') | 24 | args.insert(0, 'sudo') |
220 | 19 | proc = Popen(args, stdout=stdout) | 25 | return Popen(args, stdin=stdin, stdout=stdout, stderr=stderr) |
218 | 20 | proc.wait() | ||
219 | 21 | return proc.returncode | ||
221 | 22 | 26 | ||
222 | 23 | 27 | ||
223 | 24 | class Popen(subprocess.Popen): | 28 | class Popen(subprocess.Popen): |
224 | 25 | 29 | ||
225 | === modified file 'media_create/create_partitions.py' | |||
226 | --- media_create/create_partitions.py 2010-12-09 19:58:24 +0000 | |||
227 | +++ media_create/create_partitions.py 2010-12-14 13:31:33 +0000 | |||
228 | @@ -1,11 +1,12 @@ | |||
229 | 1 | import subprocess | 1 | import subprocess |
231 | 2 | import sys | 2 | import time |
232 | 3 | 3 | ||
233 | 4 | from media_create import cmd_runner | 4 | from media_create import cmd_runner |
234 | 5 | 5 | ||
235 | 6 | 6 | ||
238 | 7 | def run_sfdisk_commands(commands, heads, sectors, cylinders_arg, device, | 7 | # TODO: Merge this file with setup_partitions.py. |
239 | 8 | as_root=True): | 8 | def run_sfdisk_commands(commands, heads, sectors, cylinders, device, |
240 | 9 | as_root=True, stderr=None): | ||
241 | 9 | """Run the given commands under sfdisk. | 10 | """Run the given commands under sfdisk. |
242 | 10 | 11 | ||
243 | 11 | :param commands: A string of sfdisk commands; each on a separate line. | 12 | :param commands: A string of sfdisk commands; each on a separate line. |
244 | @@ -15,41 +16,33 @@ | |||
245 | 15 | '-D', | 16 | '-D', |
246 | 16 | '-H', str(heads), | 17 | '-H', str(heads), |
247 | 17 | '-S', str(sectors)] | 18 | '-S', str(sectors)] |
250 | 18 | if cylinders_arg: | 19 | if cylinders is not None: |
251 | 19 | args.append(cylinders_arg) | 20 | args.extend(['-C', str(cylinders)]) |
252 | 20 | args.append(device) | 21 | args.append(device) |
262 | 21 | # XXX: There's some stuff duplicated here from cmd_runner.run() but I | 22 | proc = cmd_runner.run( |
263 | 22 | # don't see an easy way to consolidate them as a single function, so I'll | 23 | args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=stderr, |
264 | 23 | # leave it for later. | 24 | as_root=as_root) |
256 | 24 | if as_root: | ||
257 | 25 | args = args[:] | ||
258 | 26 | args.insert(0, 'sudo') | ||
259 | 27 | proc = cmd_runner.Popen( | ||
260 | 28 | args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, | ||
261 | 29 | stderr=subprocess.PIPE) | ||
265 | 30 | return proc.communicate("%s\n" % commands) | 25 | return proc.communicate("%s\n" % commands) |
266 | 31 | 26 | ||
267 | 32 | 27 | ||
270 | 33 | def create_partitions(board, device, fat_size, heads, sectors, cylinders_arg): | 28 | def create_partitions(board, media, fat_size, heads, sectors, cylinders=None): |
271 | 34 | """Partition the given device according to the board requirements. | 29 | """Partition the given media according to the board requirements. |
272 | 35 | 30 | ||
273 | 36 | :param board: A string with the board type (e.g. beagle, panda, etc) | 31 | :param board: A string with the board type (e.g. beagle, panda, etc) |
275 | 37 | :param device: A string containing the path to the device to partition. | 32 | :param media: A setup_partitions.Media object to partition. |
276 | 38 | :param fat_size: The type of FATs used in the boot partition (16 or 32). | 33 | :param fat_size: The type of FATs used in the boot partition (16 or 32). |
277 | 39 | :param heads: Number of heads to use in the disk geometry of | 34 | :param heads: Number of heads to use in the disk geometry of |
278 | 40 | partitions. | 35 | partitions. |
279 | 41 | :param sectors: Number of sectors to use in the disk geometry of | 36 | :param sectors: Number of sectors to use in the disk geometry of |
280 | 42 | partitions. | 37 | partitions. |
283 | 43 | :param cylinders_arg: A string of the form "-C NN" containing the number | 38 | :param cylinders: The number of cylinders to pass to sfdisk's -C argument. |
284 | 44 | of cylinders to use in the disk geometry of partitions. | 39 | If None the -C argument is not passed. |
285 | 45 | """ | 40 | """ |
290 | 46 | stdout = [] | 41 | if media.is_block_device: |
287 | 47 | stderr = [] | ||
288 | 48 | is_block_device = device.startswith('/dev/') | ||
289 | 49 | if is_block_device: | ||
291 | 50 | # Overwrite any existing partition tables with a fresh one. | 42 | # Overwrite any existing partition tables with a fresh one. |
294 | 51 | cmd_runner.run( | 43 | proc = cmd_runner.run( |
295 | 52 | ['parted', '-s', device, 'mklabel', 'msdos'], as_root=True) | 44 | ['parted', '-s', media.path, 'mklabel', 'msdos'], as_root=True) |
296 | 45 | proc.wait() | ||
297 | 53 | 46 | ||
298 | 54 | if fat_size == 32: | 47 | if fat_size == 32: |
299 | 55 | partition_type = '0x0C' | 48 | partition_type = '0x0C' |
300 | @@ -60,28 +53,16 @@ | |||
301 | 60 | # Create a one cylinder partition for fixed-offset bootloader data at | 53 | # Create a one cylinder partition for fixed-offset bootloader data at |
302 | 61 | # the beginning of the image (size is one cylinder, so 8224768 bytes | 54 | # the beginning of the image (size is one cylinder, so 8224768 bytes |
303 | 62 | # with the first sector for MBR). | 55 | # with the first sector for MBR). |
308 | 63 | out, err = run_sfdisk_commands( | 56 | run_sfdisk_commands(',1,0xDA', heads, sectors, cylinders, media.path) |
305 | 64 | ',1,0xDA', heads, sectors, cylinders_arg, device) | ||
306 | 65 | stdout.append(out) | ||
307 | 66 | stderr.append(err) | ||
309 | 67 | 57 | ||
310 | 68 | # Create a VFAT or FAT16 partition of 9 cylinders (74027520 bytes, ~70 | 58 | # Create a VFAT or FAT16 partition of 9 cylinders (74027520 bytes, ~70 |
311 | 69 | # MiB), followed by a Linux-type partition containing the rest of the free | 59 | # MiB), followed by a Linux-type partition containing the rest of the free |
312 | 70 | # space. | 60 | # space. |
313 | 71 | sfdisk_cmd = ',9,%s,*\n,,,-' % partition_type | 61 | sfdisk_cmd = ',9,%s,*\n,,,-' % partition_type |
330 | 72 | out, err = run_sfdisk_commands( | 62 | run_sfdisk_commands(sfdisk_cmd, heads, sectors, cylinders, media.path) |
331 | 73 | sfdisk_cmd, heads, sectors, cylinders_arg, device) | 63 | |
332 | 74 | stdout.append(out) | 64 | # Sync and sleep to wait for the partition to settle. |
333 | 75 | stderr.append(err) | 65 | cmd_runner.run(['sync']).wait() |
334 | 76 | return "\n".join(stdout), "\n".join(stderr) | 66 | # Sleeping just 1 second seems to be enough here, but if we start getting |
335 | 77 | 67 | # errors because the disk is not partitioned then we should revisit this. | |
336 | 78 | 68 | time.sleep(1) | |
321 | 79 | if __name__ == "__main__": | ||
322 | 80 | board, device, fat_size, heads, sectors, cylinders_arg = sys.argv[1:] | ||
323 | 81 | fat_size = int(fat_size) | ||
324 | 82 | heads = int(heads) | ||
325 | 83 | sectors = int(sectors) | ||
326 | 84 | stdout, stderr = create_partitions( | ||
327 | 85 | board, device, fat_size, heads, sectors, cylinders_arg) | ||
328 | 86 | print stdout | ||
329 | 87 | print stderr | ||
337 | 88 | 69 | ||
338 | === removed file 'media_create/partition_size.py' | |||
339 | --- media_create/partition_size.py 2010-12-08 19:54:08 +0000 | |||
340 | +++ media_create/partition_size.py 1970-01-01 00:00:00 +0000 | |||
341 | @@ -1,42 +0,0 @@ | |||
342 | 1 | import sys | ||
343 | 2 | |||
344 | 3 | from parted import ( | ||
345 | 4 | Device, | ||
346 | 5 | Disk, | ||
347 | 6 | ) | ||
348 | 7 | |||
349 | 8 | |||
350 | 9 | def calculate_partition_size_and_offset(device): | ||
351 | 10 | """Return the size and offset of the boot and root partitions. | ||
352 | 11 | |||
353 | 12 | Both the size and offset are in sectors. | ||
354 | 13 | |||
355 | 14 | :param device: A string containing the path to the device. | ||
356 | 15 | :return: A 4-tuple containing the offset and size of the boot partition | ||
357 | 16 | followed by the offset and size of the root partition. | ||
358 | 17 | """ | ||
359 | 18 | disk = Disk(Device(device)) | ||
360 | 19 | vfat_partition = None | ||
361 | 20 | for partition in disk.partitions: | ||
362 | 21 | if 'boot' in partition.getFlagsAsString(): | ||
363 | 22 | geometry = partition.geometry | ||
364 | 23 | vfat_offset = geometry.start * 512 | ||
365 | 24 | vfat_size = geometry.length * 512 | ||
366 | 25 | vfat_partition = partition | ||
367 | 26 | |||
368 | 27 | assert vfat_partition is not None, ( | ||
369 | 28 | "Couldn't find boot partition on %s" % device) | ||
370 | 29 | linux_partition = vfat_partition.nextPartition() | ||
371 | 30 | geometry = linux_partition.geometry | ||
372 | 31 | linux_offset = geometry.start * 512 | ||
373 | 32 | linux_size = geometry.length * 512 | ||
374 | 33 | return vfat_size, vfat_offset, linux_size, linux_offset | ||
375 | 34 | |||
376 | 35 | |||
377 | 36 | if __name__ == "__main__": | ||
378 | 37 | vsize, voffset, rsize, roffset = calculate_partition_size_and_offset( | ||
379 | 38 | sys.argv[1]) | ||
380 | 39 | # These values need to be assigned to shell variables in our script, so we | ||
381 | 40 | # make its job easier by printing something it can pass on to eval. | ||
382 | 41 | print "VFATSIZE=%s VFATOFFSET=%s ROOTSIZE=%s ROOTOFFSET=%s" % ( | ||
383 | 42 | vsize, voffset, rsize, roffset) | ||
384 | 43 | 0 | ||
385 | === added file 'media_create/partitions.py' | |||
386 | --- media_create/partitions.py 1970-01-01 00:00:00 +0000 | |||
387 | +++ media_create/partitions.py 2010-12-14 13:31:33 +0000 | |||
388 | @@ -0,0 +1,193 @@ | |||
389 | 1 | import subprocess | ||
390 | 2 | import sys | ||
391 | 3 | |||
392 | 4 | import dbus | ||
393 | 5 | from parted import ( | ||
394 | 6 | Device, | ||
395 | 7 | Disk, | ||
396 | 8 | ) | ||
397 | 9 | |||
398 | 10 | from media_create import cmd_runner | ||
399 | 11 | from media_create.create_partitions import create_partitions | ||
400 | 12 | |||
401 | 13 | |||
402 | 14 | HEADS = 255 | ||
403 | 15 | SECTORS = 63 | ||
404 | 16 | SECTOR_SIZE = 512 # bytes | ||
405 | 17 | CYLINDER_SIZE = HEADS * SECTORS * SECTOR_SIZE | ||
406 | 18 | |||
407 | 19 | |||
408 | 20 | # I wonder if it'd make sense to convert this into a small shim which calls | ||
409 | 21 | # the appropriate function for the given type of device? I think it's still | ||
410 | 22 | # small enough that there's not much benefit in doing that, but if it grows we | ||
411 | 23 | # might want to do it. | ||
412 | 24 | def setup_partitions(board, media, fat_size, image_size, | ||
413 | 25 | should_create_partitions): | ||
414 | 26 | """Make sure the given device is partitioned to boot the given board. | ||
415 | 27 | |||
416 | 28 | :param board: The board's name, as a string. | ||
417 | 29 | :param media: The Media we should partition. | ||
418 | 30 | :param fat_size: The FAT size (16 or 32) for the boot partition. | ||
419 | 31 | :param image_size: The size of the image file, in case we're setting up a | ||
420 | 32 | QEMU image. | ||
421 | 33 | :param should_create_partitions: A string with values "yes" or "no", | ||
422 | 34 | specifying whether or not we should erase existing partitions and | ||
423 | 35 | create new ones. | ||
424 | 36 | """ | ||
425 | 37 | cylinders = None | ||
426 | 38 | if not media.is_block_device: | ||
427 | 39 | image_size_in_bytes = convert_size_to_bytes(image_size) | ||
428 | 40 | cylinders = image_size_in_bytes / CYLINDER_SIZE | ||
429 | 41 | image_size_in_bytes = cylinders * CYLINDER_SIZE | ||
430 | 42 | proc = cmd_runner.run( | ||
431 | 43 | ['qemu-img', 'create', '-f', 'raw', media.path, image_size], | ||
432 | 44 | stdout=open('/dev/null', 'w')) | ||
433 | 45 | proc.wait() | ||
434 | 46 | |||
435 | 47 | if should_create_partitions == "yes": | ||
436 | 48 | create_partitions(board, media, fat_size, HEADS, SECTORS, cylinders) | ||
437 | 49 | |||
438 | 50 | if media.is_block_device: | ||
439 | 51 | return get_boot_and_root_partitions_for_media(media) | ||
440 | 52 | else: | ||
441 | 53 | return get_boot_and_root_loopback_devices(media.path) | ||
442 | 54 | |||
443 | 55 | |||
444 | 56 | def get_boot_and_root_loopback_devices(image_file): | ||
445 | 57 | """Return the boot and root loopback devices for the given image file. | ||
446 | 58 | |||
447 | 59 | Register the loopback devices as well. | ||
448 | 60 | """ | ||
449 | 61 | vfat_size, vfat_offset, linux_size, linux_offset = ( | ||
450 | 62 | calculate_partition_size_and_offset(image_file)) | ||
451 | 63 | proc = cmd_runner.run( | ||
452 | 64 | ['losetup', '-f', '--show', image_file, '--offset', | ||
453 | 65 | str(vfat_offset), '--sizelimit', str(vfat_size)], | ||
454 | 66 | stdout=subprocess.PIPE, as_root=True) | ||
455 | 67 | boot_device, _ = proc.communicate() | ||
456 | 68 | proc = cmd_runner.run( | ||
457 | 69 | ['losetup', '-f', '--show', image_file, '--offset', | ||
458 | 70 | str(linux_offset), '--sizelimit', str(linux_size)], | ||
459 | 71 | stdout=subprocess.PIPE, as_root=True) | ||
460 | 72 | root_device, _ = proc.communicate() | ||
461 | 73 | |||
462 | 74 | return boot_device, root_device | ||
463 | 75 | |||
464 | 76 | |||
465 | 77 | def calculate_partition_size_and_offset(image_file): | ||
466 | 78 | """Return the size and offset of the boot and root partitions. | ||
467 | 79 | |||
468 | 80 | Both the size and offset are in sectors. | ||
469 | 81 | |||
470 | 82 | :param image_file: A string containing the path to the image_file. | ||
471 | 83 | :return: A 4-tuple containing the offset and size of the boot partition | ||
472 | 84 | followed by the offset and size of the root partition. | ||
473 | 85 | """ | ||
474 | 86 | # Here we can use parted.Device to read the partitions because we're | ||
475 | 87 | # reading from a regular file rather than a block device. If it was a | ||
476 | 88 | # block device we'd need root rights. | ||
477 | 89 | disk = Disk(Device(image_file)) | ||
478 | 90 | vfat_partition = None | ||
479 | 91 | for partition in disk.partitions: | ||
480 | 92 | if 'boot' in partition.getFlagsAsString(): | ||
481 | 93 | geometry = partition.geometry | ||
482 | 94 | vfat_offset = geometry.start * 512 | ||
483 | 95 | vfat_size = geometry.length * 512 | ||
484 | 96 | vfat_partition = partition | ||
485 | 97 | |||
486 | 98 | assert vfat_partition is not None, ( | ||
487 | 99 | "Couldn't find boot partition on %s" % image_file) | ||
488 | 100 | linux_partition = vfat_partition.nextPartition() | ||
489 | 101 | geometry = linux_partition.geometry | ||
490 | 102 | linux_offset = geometry.start * 512 | ||
491 | 103 | linux_size = geometry.length * 512 | ||
492 | 104 | return vfat_size, vfat_offset, linux_size, linux_offset | ||
493 | 105 | |||
494 | 106 | |||
495 | 107 | def get_boot_and_root_partitions_for_media(media): | ||
496 | 108 | """Return the device files for the boot and root partitions of media. | ||
497 | 109 | |||
498 | 110 | If the given media has 2 partitions, the first is boot and the second is | ||
499 | 111 | root. If there are 3 partitions, the second is boot and third is root. | ||
500 | 112 | |||
501 | 113 | If there are any other number of partitions, ValueError is raised. | ||
502 | 114 | |||
503 | 115 | This function must only be used for block devices. | ||
504 | 116 | """ | ||
505 | 117 | assert media.is_block_device, ( | ||
506 | 118 | "This function must only be used for block devices") | ||
507 | 119 | |||
508 | 120 | partition_count = _get_partition_count(media) | ||
509 | 121 | |||
510 | 122 | if partition_count == 2: | ||
511 | 123 | partition_offset = 0 | ||
512 | 124 | elif partition_count == 3: | ||
513 | 125 | partition_offset = 1 | ||
514 | 126 | else: | ||
515 | 127 | raise ValueError( | ||
516 | 128 | "Unexpected number of partitions on %s: %d" % ( | ||
517 | 129 | media.path, partition_count)) | ||
518 | 130 | |||
519 | 131 | boot_partition = "%s%d" % (media.path, 1 + partition_offset) | ||
520 | 132 | root_partition = "%s%d" % (media.path, 2 + partition_offset) | ||
521 | 133 | return boot_partition, root_partition | ||
522 | 134 | |||
523 | 135 | |||
524 | 136 | def _get_partition_count(media): | ||
525 | 137 | """Return the number of partitions on the given media.""" | ||
526 | 138 | # We could do the same easily using python-parted but it requires root | ||
527 | 139 | # rights to read block devices, so we use UDisks here. | ||
528 | 140 | bus = dbus.SystemBus() | ||
529 | 141 | udisks = dbus.Interface( | ||
530 | 142 | bus.get_object("org.freedesktop.UDisks", "/org/freedesktop/UDisks"), | ||
531 | 143 | 'org.freedesktop.UDisks') | ||
532 | 144 | device_path = udisks.get_dbus_method('FindDeviceByDeviceFile')(media.path) | ||
533 | 145 | device = bus.get_object("org.freedesktop.UDisks", device_path) | ||
534 | 146 | return device.Get( | ||
535 | 147 | device_path, 'partition-table-count', | ||
536 | 148 | dbus_interface='org.freedesktop.DBus.Properties') | ||
537 | 149 | |||
538 | 150 | |||
539 | 151 | def convert_size_to_bytes(size): | ||
540 | 152 | """Convert a size string in Kbytes, Mbytes or Gbytes to bytes.""" | ||
541 | 153 | unit = size[-1].upper() | ||
542 | 154 | real_size = int(size[:-1]) | ||
543 | 155 | if unit == 'K': | ||
544 | 156 | real_size = real_size * 1024 | ||
545 | 157 | elif unit == 'M': | ||
546 | 158 | real_size = real_size * 1024 * 1024 | ||
547 | 159 | elif unit == 'G': | ||
548 | 160 | real_size = real_size * 1024 * 1024 * 1024 | ||
549 | 161 | else: | ||
550 | 162 | raise ValueError("Unknown size format: %s. Use K[bytes], M[bytes] " | ||
551 | 163 | "or G[bytes]" % size) | ||
552 | 164 | |||
553 | 165 | # Round the size of the raw disk image up to a multiple of 256K so it is | ||
554 | 166 | # an exact number of SD card erase blocks in length. Otherwise Linux | ||
555 | 167 | # under qemu cannot access the last part of the card and is likely to | ||
556 | 168 | # complain that the last partition on the disk has been truncated. This | ||
557 | 169 | # doesn't appear to work in all cases, though, as can be seen on | ||
558 | 170 | # https://bugs.launchpad.net/linux-linaro/+bug/673335. | ||
559 | 171 | if real_size % (1024 * 256): | ||
560 | 172 | cylinders = real_size / CYLINDER_SIZE | ||
561 | 173 | real_size = cylinders * CYLINDER_SIZE | ||
562 | 174 | real_size = ((((real_size - 1) / (1024 * 256)) + 1) * (1024 * 256)) | ||
563 | 175 | |||
564 | 176 | return real_size | ||
565 | 177 | |||
566 | 178 | |||
567 | 179 | class Media(object): | ||
568 | 180 | """A representation of the media where Linaro will be installed.""" | ||
569 | 181 | |||
570 | 182 | def __init__(self, path): | ||
571 | 183 | self.path = path | ||
572 | 184 | self.is_block_device = path.startswith('/dev/') | ||
573 | 185 | |||
574 | 186 | |||
575 | 187 | if __name__ == "__main__": | ||
576 | 188 | board, device, fat_size, image_size, should_create_partitions = ( | ||
577 | 189 | sys.argv[1:]) | ||
578 | 190 | fat_size = int(fat_size) | ||
579 | 191 | boot, root = setup_partitions( | ||
580 | 192 | board, Media(device), fat_size, image_size, should_create_partitions) | ||
581 | 193 | print "BOOTFS=%s ROOTFS=%s" % (boot, root) | ||
582 | 0 | 194 | ||
583 | === modified file 'media_create/populate_boot.py' | |||
584 | --- media_create/populate_boot.py 2010-12-08 13:09:27 +0000 | |||
585 | +++ media_create/populate_boot.py 2010-12-14 13:31:33 +0000 | |||
586 | @@ -16,7 +16,9 @@ | |||
587 | 16 | '-n', name, | 16 | '-n', name, |
588 | 17 | '-d', img_data, | 17 | '-d', img_data, |
589 | 18 | img] | 18 | img] |
591 | 19 | return cmd_runner.run(cmd, as_root=as_root, stdout=stdout) | 19 | proc = cmd_runner.run(cmd, as_root=as_root, stdout=stdout) |
592 | 20 | proc.wait() | ||
593 | 21 | return proc.returncode | ||
594 | 20 | 22 | ||
595 | 21 | 23 | ||
596 | 22 | def _get_file_matching(regex): | 24 | def _get_file_matching(regex): |
597 | @@ -58,24 +60,26 @@ | |||
598 | 58 | 60 | ||
599 | 59 | 61 | ||
600 | 60 | def install_mx51evk_boot_loader(imx_file, boot_device_or_file): | 62 | def install_mx51evk_boot_loader(imx_file, boot_device_or_file): |
602 | 61 | cmd_runner.run([ | 63 | proc = cmd_runner.run([ |
603 | 62 | "dd", | 64 | "dd", |
604 | 63 | "if=%s" % imx_file, | 65 | "if=%s" % imx_file, |
605 | 64 | "of=%s" % boot_device_or_file, | 66 | "of=%s" % boot_device_or_file, |
606 | 65 | "bs=1024", | 67 | "bs=1024", |
607 | 66 | "seek=1", | 68 | "seek=1", |
608 | 67 | "conv=notrunc"], as_root=True) | 69 | "conv=notrunc"], as_root=True) |
609 | 70 | proc.wait() | ||
610 | 68 | 71 | ||
611 | 69 | 72 | ||
612 | 70 | def install_omap_boot_loader(mlo_file, boot_disk): | 73 | def install_omap_boot_loader(mlo_file, boot_disk): |
614 | 71 | cmd_runner.run(["cp", "-v", mlo_file, boot_disk], as_root=True) | 74 | cmd_runner.run(["cp", "-v", mlo_file, boot_disk], as_root=True).wait() |
615 | 72 | # XXX: Is this really needed? | 75 | # XXX: Is this really needed? |
617 | 73 | cmd_runner.run(["sync"]) | 76 | cmd_runner.run(["sync"]).wait() |
618 | 74 | 77 | ||
619 | 75 | 78 | ||
620 | 76 | def make_boot_ini(boot_script, boot_disk): | 79 | def make_boot_ini(boot_script, boot_disk): |
622 | 77 | cmd_runner.run( | 80 | proc = cmd_runner.run( |
623 | 78 | ["cp", "-v", boot_script, "%s/boot.ini" % boot_disk], as_root=True) | 81 | ["cp", "-v", boot_script, "%s/boot.ini" % boot_disk], as_root=True) |
624 | 82 | proc.wait() | ||
625 | 79 | 83 | ||
626 | 80 | 84 | ||
627 | 81 | def populate_boot(board, sub_arch, load_addr, uboot_parts_dir, boot_disk, | 85 | def populate_boot(board, sub_arch, load_addr, uboot_parts_dir, boot_disk, |
628 | 82 | 86 | ||
629 | === modified file 'media_create/tests/fixtures.py' | |||
630 | --- media_create/tests/fixtures.py 2010-12-09 19:58:24 +0000 | |||
631 | +++ media_create/tests/fixtures.py 2010-12-14 13:31:33 +0000 | |||
632 | @@ -65,12 +65,23 @@ | |||
633 | 65 | 65 | ||
634 | 66 | class MockCmdRunnerPopen(object): | 66 | class MockCmdRunnerPopen(object): |
635 | 67 | """A mock for cmd_runner.Popen() which stores the args given to it.""" | 67 | """A mock for cmd_runner.Popen() which stores the args given to it.""" |
639 | 68 | args = None | 68 | calls = None |
640 | 69 | def __call__(self, args, **kwargs): | 69 | def __call__(self, cmd, *args, **kwargs): |
641 | 70 | self.args = args | 70 | if self.calls is None: |
642 | 71 | self.calls = [] | ||
643 | 72 | if isinstance(cmd, basestring): | ||
644 | 73 | all_args = [cmd] | ||
645 | 74 | else: | ||
646 | 75 | all_args = cmd | ||
647 | 76 | all_args.extend(args) | ||
648 | 77 | self.calls.append(all_args) | ||
649 | 71 | self.returncode = 0 | 78 | self.returncode = 0 |
650 | 72 | return self | 79 | return self |
651 | 73 | 80 | ||
652 | 81 | def communicate(self, input=None): | ||
653 | 82 | self.wait() | ||
654 | 83 | return '', '' | ||
655 | 84 | |||
656 | 74 | def wait(self): | 85 | def wait(self): |
657 | 75 | return self.returncode | 86 | return self.returncode |
658 | 76 | 87 | ||
659 | 77 | 88 | ||
660 | === modified file 'media_create/tests/test_media_create.py' | |||
661 | --- media_create/tests/test_media_create.py 2010-12-09 20:00:37 +0000 | |||
662 | +++ media_create/tests/test_media_create.py 2010-12-14 13:31:33 +0000 | |||
663 | @@ -4,6 +4,7 @@ | |||
664 | 4 | import string | 4 | import string |
665 | 5 | import subprocess | 5 | import subprocess |
666 | 6 | import sys | 6 | import sys |
667 | 7 | import time | ||
668 | 7 | 8 | ||
669 | 8 | from testtools import TestCase | 9 | from testtools import TestCase |
670 | 9 | 10 | ||
671 | @@ -12,12 +13,20 @@ | |||
672 | 12 | from media_create import cmd_runner | 13 | from media_create import cmd_runner |
673 | 13 | from media_create import ensure_command | 14 | from media_create import ensure_command |
674 | 14 | from media_create import populate_boot | 15 | from media_create import populate_boot |
675 | 16 | from media_create import partitions | ||
676 | 15 | from media_create.boot_cmd import create_boot_cmd | 17 | from media_create.boot_cmd import create_boot_cmd |
677 | 16 | from media_create.create_partitions import ( | 18 | from media_create.create_partitions import ( |
678 | 17 | create_partitions, | 19 | create_partitions, |
679 | 18 | run_sfdisk_commands, | 20 | run_sfdisk_commands, |
680 | 19 | ) | 21 | ) |
682 | 20 | from media_create.partition_size import calculate_partition_size_and_offset | 22 | from media_create.partitions import ( |
683 | 23 | calculate_partition_size_and_offset, | ||
684 | 24 | convert_size_to_bytes, | ||
685 | 25 | get_boot_and_root_loopback_devices, | ||
686 | 26 | get_boot_and_root_partitions_for_media, | ||
687 | 27 | Media, | ||
688 | 28 | setup_partitions, | ||
689 | 29 | ) | ||
690 | 21 | from media_create.populate_boot import ( | 30 | from media_create.populate_boot import ( |
691 | 22 | make_boot_script, | 31 | make_boot_script, |
692 | 23 | make_uImage, | 32 | make_uImage, |
693 | @@ -133,24 +142,28 @@ | |||
694 | 133 | def test_run(self): | 142 | def test_run(self): |
695 | 134 | fixture = MockCmdRunnerPopenFixture() | 143 | fixture = MockCmdRunnerPopenFixture() |
696 | 135 | self.useFixture(fixture) | 144 | self.useFixture(fixture) |
700 | 136 | return_code = cmd_runner.run(['foo', 'bar', 'baz']) | 145 | proc = cmd_runner.run(['foo', 'bar', 'baz']) |
701 | 137 | self.assertEqual(0, return_code) | 146 | self.assertEqual(0, proc.returncode) |
702 | 138 | self.assertEqual(['foo', 'bar', 'baz'], fixture.mock.args) | 147 | self.assertEqual([['foo', 'bar', 'baz']], fixture.mock.calls) |
703 | 139 | 148 | ||
704 | 140 | def test_run_as_root(self): | 149 | def test_run_as_root(self): |
705 | 141 | fixture = MockCmdRunnerPopenFixture() | 150 | fixture = MockCmdRunnerPopenFixture() |
706 | 142 | self.useFixture(fixture) | 151 | self.useFixture(fixture) |
707 | 143 | cmd_runner.run(['foo', 'bar'], as_root=True) | 152 | cmd_runner.run(['foo', 'bar'], as_root=True) |
709 | 144 | self.assertEqual(['sudo', 'foo', 'bar'], fixture.mock.args) | 153 | self.assertEqual([['sudo', 'foo', 'bar']], fixture.mock.calls) |
710 | 145 | 154 | ||
711 | 146 | def test_run_succeeds_on_zero_return_code(self): | 155 | def test_run_succeeds_on_zero_return_code(self): |
714 | 147 | return_code = cmd_runner.run(['true']) | 156 | proc = cmd_runner.run(['true']) |
715 | 148 | self.assertEqual(0, return_code) | 157 | # Need to wait() here as we're using the real Popen. |
716 | 158 | proc.wait() | ||
717 | 159 | self.assertEqual(0, proc.returncode) | ||
718 | 149 | 160 | ||
719 | 150 | def test_run_raises_exception_on_non_zero_return_code(self): | 161 | def test_run_raises_exception_on_non_zero_return_code(self): |
720 | 162 | def run_and_wait(): | ||
721 | 163 | proc = cmd_runner.run(['false']) | ||
722 | 164 | proc.wait() | ||
723 | 151 | self.assertRaises( | 165 | self.assertRaises( |
726 | 152 | cmd_runner.SubcommandNonZeroReturnValue, | 166 | cmd_runner.SubcommandNonZeroReturnValue, run_and_wait) |
725 | 153 | cmd_runner.run, ['false']) | ||
727 | 154 | 167 | ||
728 | 155 | def test_run_must_be_given_list_as_args(self): | 168 | def test_run_must_be_given_list_as_args(self): |
729 | 156 | self.assertRaises(AssertionError, cmd_runner.run, 'true') | 169 | self.assertRaises(AssertionError, cmd_runner.run, 'true') |
730 | @@ -181,7 +194,7 @@ | |||
731 | 181 | 'sudo', 'mkimage', '-A', 'arm', '-O', 'linux', '-T', 'kernel', | 194 | 'sudo', 'mkimage', '-A', 'arm', '-O', 'linux', '-T', 'kernel', |
732 | 182 | '-C', 'none', '-a', 'load_addr', '-e', 'load_addr', '-n', 'Linux', | 195 | '-C', 'none', '-a', 'load_addr', '-e', 'load_addr', '-n', 'Linux', |
733 | 183 | '-d', 'parts_dir/vmlinuz-*-sub_arch', 'boot_disk/uImage'] | 196 | '-d', 'parts_dir/vmlinuz-*-sub_arch', 'boot_disk/uImage'] |
735 | 184 | self.assertEqual(expected, fixture.mock.args) | 197 | self.assertEqual([expected], fixture.mock.calls) |
736 | 185 | 198 | ||
737 | 186 | def test_make_uInitrd(self): | 199 | def test_make_uInitrd(self): |
738 | 187 | self._mock_get_file_matching() | 200 | self._mock_get_file_matching() |
739 | @@ -191,7 +204,7 @@ | |||
740 | 191 | 'sudo', 'mkimage', '-A', 'arm', '-O', 'linux', '-T', 'ramdisk', | 204 | 'sudo', 'mkimage', '-A', 'arm', '-O', 'linux', '-T', 'ramdisk', |
741 | 192 | '-C', 'none', '-a', '0', '-e', '0', '-n', 'initramfs', | 205 | '-C', 'none', '-a', '0', '-e', '0', '-n', 'initramfs', |
742 | 193 | '-d', 'parts_dir/initrd.img-*-sub_arch', 'boot_disk/uInitrd'] | 206 | '-d', 'parts_dir/initrd.img-*-sub_arch', 'boot_disk/uInitrd'] |
744 | 194 | self.assertEqual(expected, fixture.mock.args) | 207 | self.assertEqual([expected], fixture.mock.calls) |
745 | 195 | 208 | ||
746 | 196 | def test_make_boot_script(self): | 209 | def test_make_boot_script(self): |
747 | 197 | self._mock_get_file_matching() | 210 | self._mock_get_file_matching() |
748 | @@ -201,7 +214,7 @@ | |||
749 | 201 | 'sudo', 'mkimage', '-A', 'arm', '-O', 'linux', '-T', 'script', | 214 | 'sudo', 'mkimage', '-A', 'arm', '-O', 'linux', '-T', 'script', |
750 | 202 | '-C', 'none', '-a', '0', '-e', '0', '-n', 'boot script', | 215 | '-C', 'none', '-a', '0', '-e', '0', '-n', 'boot script', |
751 | 203 | '-d', 'tmp_dir/boot.cmd', 'boot_script'] | 216 | '-d', 'tmp_dir/boot.cmd', 'boot_script'] |
753 | 204 | self.assertEqual(expected, fixture.mock.args) | 217 | self.assertEqual([expected], fixture.mock.calls) |
754 | 205 | 218 | ||
755 | 206 | def test_get_file_matching(self): | 219 | def test_get_file_matching(self): |
756 | 207 | prefix = ''.join( | 220 | prefix = ''.join( |
757 | @@ -245,32 +258,46 @@ | |||
758 | 245 | 258 | ||
759 | 246 | class TestCreatePartitions(TestCaseWithFixtures): | 259 | class TestCreatePartitions(TestCaseWithFixtures): |
760 | 247 | 260 | ||
761 | 261 | media = Media('/dev/xdz') | ||
762 | 262 | |||
763 | 263 | def setUp(self): | ||
764 | 264 | super(TestCreatePartitions, self).setUp() | ||
765 | 265 | # Stub time.sleep() as create_partitions() use that. | ||
766 | 266 | self.orig_sleep = time.sleep | ||
767 | 267 | time.sleep = lambda s: None | ||
768 | 268 | |||
769 | 269 | def tearDown(self): | ||
770 | 270 | super(TestCreatePartitions, self).tearDown() | ||
771 | 271 | time.sleep = self.orig_sleep | ||
772 | 272 | |||
773 | 248 | def test_create_partitions_for_mx51evk(self): | 273 | def test_create_partitions_for_mx51evk(self): |
774 | 249 | # For this board we create a one cylinder partition at the beginning. | 274 | # For this board we create a one cylinder partition at the beginning. |
775 | 250 | popen_fixture = self.useFixture(MockCmdRunnerPopenFixture()) | 275 | popen_fixture = self.useFixture(MockCmdRunnerPopenFixture()) |
776 | 251 | sfdisk_fixture = self.useFixture(MockRunSfdiskCommandsFixture()) | 276 | sfdisk_fixture = self.useFixture(MockRunSfdiskCommandsFixture()) |
777 | 252 | 277 | ||
779 | 253 | create_partitions('mx51evk', '/dev/sdz', 32, 255, 63, '') | 278 | create_partitions('mx51evk', self.media, 32, 255, 63, '') |
780 | 254 | 279 | ||
781 | 255 | self.assertEqual( | 280 | self.assertEqual( |
784 | 256 | ['sudo', 'parted', '-s', '/dev/sdz', 'mklabel', 'msdos'], | 281 | [['sudo', 'parted', '-s', self.media.path, 'mklabel', 'msdos'], |
785 | 257 | popen_fixture.mock.args) | 282 | ['sync']], |
786 | 283 | popen_fixture.mock.calls) | ||
787 | 258 | self.assertEqual( | 284 | self.assertEqual( |
790 | 259 | [(',1,0xDA', 255, 63, '', '/dev/sdz'), | 285 | [(',1,0xDA', 255, 63, '', self.media.path), |
791 | 260 | (',9,0x0C,*\n,,,-', 255, 63, '', '/dev/sdz')], | 286 | (',9,0x0C,*\n,,,-', 255, 63, '', self.media.path)], |
792 | 261 | sfdisk_fixture.mock.calls) | 287 | sfdisk_fixture.mock.calls) |
793 | 262 | 288 | ||
794 | 263 | def test_create_partitions_for_beagle(self): | 289 | def test_create_partitions_for_beagle(self): |
795 | 264 | popen_fixture = self.useFixture(MockCmdRunnerPopenFixture()) | 290 | popen_fixture = self.useFixture(MockCmdRunnerPopenFixture()) |
796 | 265 | sfdisk_fixture = self.useFixture(MockRunSfdiskCommandsFixture()) | 291 | sfdisk_fixture = self.useFixture(MockRunSfdiskCommandsFixture()) |
797 | 266 | 292 | ||
799 | 267 | create_partitions('beagle', '/dev/sdz', 32, 255, 63, '') | 293 | create_partitions('beagle', self.media, 32, 255, 63, '') |
800 | 268 | 294 | ||
801 | 269 | self.assertEqual( | 295 | self.assertEqual( |
804 | 270 | ['sudo', 'parted', '-s', '/dev/sdz', 'mklabel', 'msdos'], | 296 | [['sudo', 'parted', '-s', self.media.path, 'mklabel', 'msdos'], |
805 | 271 | popen_fixture.mock.args) | 297 | ['sync']], |
806 | 298 | popen_fixture.mock.calls) | ||
807 | 272 | self.assertEqual( | 299 | self.assertEqual( |
809 | 273 | [(',9,0x0C,*\n,,,-', 255, 63, '', '/dev/sdz')], | 300 | [(',9,0x0C,*\n,,,-', 255, 63, '', self.media.path)], |
810 | 274 | sfdisk_fixture.mock.calls) | 301 | sfdisk_fixture.mock.calls) |
811 | 275 | 302 | ||
812 | 276 | def test_create_partitions_with_img_file(self): | 303 | def test_create_partitions_with_img_file(self): |
813 | @@ -278,11 +305,12 @@ | |||
814 | 278 | sfdisk_fixture = self.useFixture(MockRunSfdiskCommandsFixture()) | 305 | sfdisk_fixture = self.useFixture(MockRunSfdiskCommandsFixture()) |
815 | 279 | 306 | ||
816 | 280 | tempfile = self.createTempFileAsFixture() | 307 | tempfile = self.createTempFileAsFixture() |
818 | 281 | create_partitions('beagle', tempfile, 32, 255, 63, '') | 308 | create_partitions('beagle', Media(tempfile), 32, 255, 63, '') |
819 | 282 | 309 | ||
823 | 283 | # popen() was not called as there's no existing partition table for | 310 | # Unlike the test for partitioning of a regular block device, in this |
824 | 284 | # us to overwrite on the image file. | 311 | # case parted was not called as there's no existing partition table |
825 | 285 | self.assertEqual(None, popen_fixture.mock.args) | 312 | # for us to overwrite on the image file. |
826 | 313 | self.assertEqual([['sync']], popen_fixture.mock.calls) | ||
827 | 286 | 314 | ||
828 | 287 | self.assertEqual( | 315 | self.assertEqual( |
829 | 288 | [(',9,0x0C,*\n,,,-', 255, 63, '', tempfile)], | 316 | [(',9,0x0C,*\n,,,-', 255, 63, '', tempfile)], |
830 | @@ -290,10 +318,13 @@ | |||
831 | 290 | 318 | ||
832 | 291 | def test_run_sfdisk_commands(self): | 319 | def test_run_sfdisk_commands(self): |
833 | 292 | tempfile = self.createTempFileAsFixture() | 320 | tempfile = self.createTempFileAsFixture() |
836 | 293 | cmd_runner.run(['qemu-img', 'create', '-f', 'raw', tempfile, '10M'], | 321 | proc = cmd_runner.run( |
837 | 294 | stdout=subprocess.PIPE) | 322 | ['qemu-img', 'create', '-f', 'raw', tempfile, '10M'], |
838 | 323 | stdout=subprocess.PIPE) | ||
839 | 324 | proc.communicate() | ||
840 | 295 | stdout, stderr = run_sfdisk_commands( | 325 | stdout, stderr = run_sfdisk_commands( |
842 | 296 | ',1,0xDA', 5, 63, '', tempfile, as_root=False) | 326 | ',1,0xDA', 5, 63, '', tempfile, as_root=False, |
843 | 327 | stderr=subprocess.PIPE) | ||
844 | 297 | self.assertIn('Successfully wrote the new partition table', stdout) | 328 | self.assertIn('Successfully wrote the new partition table', stdout) |
845 | 298 | 329 | ||
846 | 299 | def test_run_sfdisk_commands_raises_on_non_zero_returncode(self): | 330 | def test_run_sfdisk_commands_raises_on_non_zero_returncode(self): |
847 | @@ -301,21 +332,132 @@ | |||
848 | 301 | self.assertRaises( | 332 | self.assertRaises( |
849 | 302 | cmd_runner.SubcommandNonZeroReturnValue, | 333 | cmd_runner.SubcommandNonZeroReturnValue, |
850 | 303 | run_sfdisk_commands, | 334 | run_sfdisk_commands, |
864 | 304 | ',1,0xDA', 5, 63, '', tempfile, as_root=False) | 335 | ',1,0xDA', 5, 63, '', tempfile, as_root=False, |
865 | 305 | 336 | stderr=subprocess.PIPE) | |
866 | 306 | 337 | ||
867 | 307 | class TestCalculatePartitionSizeAndOffset(TestCaseWithFixtures): | 338 | |
868 | 308 | 339 | class TestPartitionSetup(TestCaseWithFixtures): | |
869 | 309 | def test_foo(self): | 340 | |
870 | 310 | tempfile = self.createTempFileAsFixture() | 341 | def setUp(self): |
871 | 311 | cmd_runner.run(['qemu-img', 'create', '-f', 'raw', tempfile, '10M'], | 342 | super(TestPartitionSetup, self).setUp() |
872 | 312 | stdout=subprocess.PIPE) | 343 | # Stub time.sleep() as create_partitions() use that. |
873 | 313 | stdout, stderr = run_sfdisk_commands( | 344 | self.orig_sleep = time.sleep |
874 | 314 | ',1,0x0C,*\n,,,-', 5, 63, '', tempfile, as_root=False) | 345 | time.sleep = lambda s: None |
875 | 315 | self.assertIn('Successfully wrote the new partition table', stdout) | 346 | |
876 | 316 | 347 | def tearDown(self): | |
877 | 348 | super(TestPartitionSetup, self).tearDown() | ||
878 | 349 | time.sleep = self.orig_sleep | ||
879 | 350 | |||
880 | 351 | def test_convert_size_in_kbytes_to_bytes(self): | ||
881 | 352 | self.assertEqual(512 * 1024, convert_size_to_bytes('512K')) | ||
882 | 353 | |||
883 | 354 | def test_convert_size_in_mbytes_to_bytes(self): | ||
884 | 355 | self.assertEqual(100 * 1024**2, convert_size_to_bytes('100M')) | ||
885 | 356 | |||
886 | 357 | def test_convert_size_in_gbytes_to_bytes(self): | ||
887 | 358 | self.assertEqual(12 * 1024**3, convert_size_to_bytes('12G')) | ||
888 | 359 | |||
889 | 360 | def test_convert_size_in_kbytes_to_bytes_rounds_to_256k_multiple(self): | ||
890 | 361 | # See comment in convert_size_to_bytes as to why we need to do this. | ||
891 | 362 | self.assertEqual( | ||
892 | 363 | 3891 * (1024 * 256), convert_size_to_bytes('1000537K')) | ||
893 | 364 | |||
894 | 365 | def test_calculate_partition_size_and_offset(self): | ||
895 | 366 | tempfile = self._create_qemu_img_with_partitions(',1,0x0C,*\n,,,-') | ||
896 | 317 | vfat_size, vfat_offset, linux_size, linux_offset = ( | 367 | vfat_size, vfat_offset, linux_size, linux_offset = ( |
897 | 318 | calculate_partition_size_and_offset(tempfile)) | 368 | calculate_partition_size_and_offset(tempfile)) |
898 | 319 | self.assertEqual( | 369 | self.assertEqual( |
899 | 320 | [129024L, 32256L, 10321920L, 161280L], | 370 | [129024L, 32256L, 10321920L, 161280L], |
900 | 321 | [vfat_size, vfat_offset, linux_size, linux_offset]) | 371 | [vfat_size, vfat_offset, linux_size, linux_offset]) |
901 | 372 | |||
902 | 373 | def test_get_boot_and_root_partitions_for_media_with_2_partitions(self): | ||
903 | 374 | self.useFixture(MockSomethingFixture( | ||
904 | 375 | partitions, '_get_partition_count', lambda media: 2)) | ||
905 | 376 | tempfile = self._create_qemu_img_with_partitions(',1,0x0C,*\n,,,-') | ||
906 | 377 | media = Media(tempfile) | ||
907 | 378 | # Pretend the image file is a block device, or else | ||
908 | 379 | # get_boot_and_root_partitions_for_media will choke. | ||
909 | 380 | media.is_block_device = True | ||
910 | 381 | self.assertEqual( | ||
911 | 382 | ("%s%d" % (tempfile, 1), "%s%d" % (tempfile, 2)), | ||
912 | 383 | get_boot_and_root_partitions_for_media(media)) | ||
913 | 384 | |||
914 | 385 | def test_get_boot_and_root_partitions_for_media_with_3_partitions(self): | ||
915 | 386 | self.useFixture(MockSomethingFixture( | ||
916 | 387 | partitions, '_get_partition_count', lambda media: 3)) | ||
917 | 388 | tempfile = self._create_qemu_img_with_partitions( | ||
918 | 389 | ',1,0xDA\n,1,0x0C,*\n,,,-') | ||
919 | 390 | media = Media(tempfile) | ||
920 | 391 | # Pretend the image file is a block device, or else | ||
921 | 392 | # get_boot_and_root_partitions_for_media will choke. | ||
922 | 393 | media.is_block_device = True | ||
923 | 394 | self.assertEqual( | ||
924 | 395 | ("%s%d" % (tempfile, 2), "%s%d" % (tempfile, 3)), | ||
925 | 396 | get_boot_and_root_partitions_for_media(media)) | ||
926 | 397 | |||
927 | 398 | def _create_qemu_img_with_partitions(self, sfdisk_commands): | ||
928 | 399 | tempfile = self.createTempFileAsFixture() | ||
929 | 400 | proc = cmd_runner.run( | ||
930 | 401 | ['qemu-img', 'create', '-f', 'raw', tempfile, '10M'], | ||
931 | 402 | stdout=subprocess.PIPE) | ||
932 | 403 | proc.communicate() | ||
933 | 404 | stdout, stderr = run_sfdisk_commands( | ||
934 | 405 | sfdisk_commands, 5, 63, '', tempfile, as_root=False, | ||
935 | 406 | # Throw away stderr as sfdisk complains a lot when operating on a | ||
936 | 407 | # qemu image. | ||
937 | 408 | stderr=subprocess.PIPE) | ||
938 | 409 | self.assertIn('Successfully wrote the new partition table', stdout) | ||
939 | 410 | return tempfile | ||
940 | 411 | |||
941 | 412 | def test_get_boot_and_root_loopback_devices(self): | ||
942 | 413 | tempfile = self._create_qemu_img_with_partitions(',1,0x0C,*\n,,,-') | ||
943 | 414 | popen_fixture = self.useFixture(MockCmdRunnerPopenFixture()) | ||
944 | 415 | # We can't test the return value of get_boot_and_root_loopback_devices | ||
945 | 416 | # because it'd require running losetup as root, so we just make sure | ||
946 | 417 | # it calls losetup correctly. | ||
947 | 418 | get_boot_and_root_loopback_devices(tempfile) | ||
948 | 419 | self.assertEqual( | ||
949 | 420 | [['sudo', 'losetup', '-f', '--show', tempfile, '--offset', | ||
950 | 421 | '32256', '--sizelimit', '129024'], | ||
951 | 422 | ['sudo', 'losetup', '-f', '--show', tempfile, '--offset', | ||
952 | 423 | '161280', '--sizelimit', '10321920']], | ||
953 | 424 | popen_fixture.mock.calls) | ||
954 | 425 | |||
955 | 426 | def test_setup_partitions_for_image_file(self): | ||
956 | 427 | # In practice we could pass an empty image file to setup_partitions, | ||
957 | 428 | # but here we mock Popen() and thanks to that the image is not setup | ||
958 | 429 | # (via qemu-img) inside setup_partitions. That's why we pass an | ||
959 | 430 | # already setup image file. | ||
960 | 431 | tempfile = self._create_qemu_img_with_partitions(',1,0x0C,*\n,,,-') | ||
961 | 432 | popen_fixture = self.useFixture(MockCmdRunnerPopenFixture()) | ||
962 | 433 | setup_partitions('beagle', Media(tempfile), 32, '2G', 'yes') | ||
963 | 434 | self.assertEqual( | ||
964 | 435 | # This is the call that would create the image file. | ||
965 | 436 | [['qemu-img', 'create', '-f', 'raw', tempfile, '2G'], | ||
966 | 437 | # This call would partition the image file. | ||
967 | 438 | ['sudo', 'sfdisk', '-D', '-H', '255', '-S', '63', '-C', '261', | ||
968 | 439 | tempfile], | ||
969 | 440 | # Make sure changes are written to disk. | ||
970 | 441 | ['sync'], | ||
971 | 442 | # Register boot/root loopback devices so that we can just copy | ||
972 | 443 | # their contents over and have it written to the image file. | ||
973 | 444 | ['sudo', 'losetup', '-f', '--show', tempfile, '--offset', | ||
974 | 445 | '32256', '--sizelimit', '129024'], | ||
975 | 446 | ['sudo', 'losetup', '-f', '--show', tempfile, '--offset', | ||
976 | 447 | '161280', '--sizelimit', '10321920']], | ||
977 | 448 | popen_fixture.mock.calls) | ||
978 | 449 | |||
979 | 450 | def test_setup_partitions_for_block_device(self): | ||
980 | 451 | self.useFixture(MockSomethingFixture( | ||
981 | 452 | partitions, '_get_partition_count', lambda media: 2)) | ||
982 | 453 | tempfile = self._create_qemu_img_with_partitions(',1,0x0C,*\n,,,-') | ||
983 | 454 | media = Media(tempfile) | ||
984 | 455 | # Pretend our tempfile is a block device. | ||
985 | 456 | media.is_block_device = True | ||
986 | 457 | popen_fixture = self.useFixture(MockCmdRunnerPopenFixture()) | ||
987 | 458 | setup_partitions('beagle', media, 32, '2G', 'yes') | ||
988 | 459 | self.assertEqual( | ||
989 | 460 | [['sudo', 'parted', '-s', tempfile, 'mklabel', 'msdos'], | ||
990 | 461 | ['sudo', 'sfdisk', '-D', '-H', '255', '-S', '63', tempfile], | ||
991 | 462 | ['sync']], | ||
992 | 463 | popen_fixture.mock.calls) | ||
993 | 322 | 464 | ||
994 | === added file 'tests/integration.txt' | |||
995 | --- tests/integration.txt 1970-01-01 00:00:00 +0000 | |||
996 | +++ tests/integration.txt 2010-12-14 13:31:33 +0000 | |||
997 | @@ -0,0 +1,25 @@ | |||
998 | 1 | A few integration tests we can run while the migration to python is not | ||
999 | 2 | complete. They probably require root or access to specific block devices so | ||
1000 | 3 | they are not meant to be automated. | ||
1001 | 4 | |||
1002 | 5 | # This should print nothing to stdout but will create a binary/ dir under | ||
1003 | 6 | # the current directory. | ||
1004 | 7 | >>> python -m media_create.unpack_binary_tarball <path-to-binary-tarball> | ||
1005 | 8 | |||
1006 | 9 | # This will remove the binary/ dir created above | ||
1007 | 10 | >>> python -m media_create.remove_binary_dir | ||
1008 | 11 | |||
1009 | 12 | # Partition (for real!) /dev/sdb for a beagle board and return the devices | ||
1010 | 13 | # for the boot and root partitions. | ||
1011 | 14 | >>> python -m media_create.partitions beagle /dev/sdb 32 2G yes | ||
1012 | 15 | Checking that no-one is using this disk right now | ||
1013 | 16 | ... | ||
1014 | 17 | BOOTFS=/dev/sdb1 ROOTFS=/dev/sdb2 | ||
1015 | 18 | |||
1016 | 19 | # Partition /tmp/beagle.img for a beagle board and return the loopback | ||
1017 | 20 | # devices for the boot and root partitions. | ||
1018 | 21 | >>> python -m media_create.partitions beagle /tmp/beagle.img 32 2G yes | ||
1019 | 22 | Warning: /tmp/beagle.img is not a block device | ||
1020 | 23 | ... | ||
1021 | 24 | BOOTFS=/dev/loop0 | ||
1022 | 25 | ROOTFS=/dev/loop1 |
> === modified file 'media_ create/ create_ partitions. py' create_ partitions. py 2010-12-09 19:58:24 +0000 create_ partitions. py 2010-12-13 14:51:10 +0000
> --- media_create/
> +++ media_create/
>
> cmd_runner.run(
> - ['parted', '-s', device, 'mklabel', 'msdos'], as_root=True)
> + ['parted', '-s', media.path, 'mklabel', 'msdos'], as_root=True)
> + # It sems to be necessary to sleep a bit here to avoid a race
> + # condition with the sfdisk commands executed below. Try removing it
> + # and running the integration tests to see how it fails.
> + time.sleep(0.5)
Isn't it possible to wait() for the parted command to finish?
/Martin