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

Proposed by Guilherme Salgado
Status: Merged
Merged at revision: 182
Proposed branch: lp:~salgado/linaro-image-tools/port-populate_boot
Merge into: lp:linaro-image-tools/11.11
Diff against target: 468 lines (+252/-92)
4 files modified
linaro-media-create (+21/-88)
media_create/cmd_runner.py (+5/-4)
media_create/populate_boot.py (+128/-0)
media_create/tests/test_media_create.py (+98/-0)
To merge this branch: bzr merge lp:~salgado/linaro-image-tools/port-populate_boot
Reviewer Review Type Date Requested Status
Michael Hudson-Doyle (community) Approve
Review via email: mp+42670@code.launchpad.net

Description of the change

This branch ports the meat of populate_boot to python.

There are a few things left to port in that function, but this branch is
already quite big.

It can be reviewed as one big diff or two incremental ones:

  r175 refactors populate_boot into smaller shell functions
  r178 ports that to python, and even makes a few improvements

To post a comment you must log in.
Revision history for this message
Martin Ohlsson (martin-ohlson) wrote :

>=== modified file 'media_create/cmd_runner.py'
>--- media_create/cmd_runner.py 2010-12-01 19:08:25 +0000
>+++ media_create/cmd_runner.py 2010-12-03 19:01:21 +0000
>@@ -1,12 +1,13 @@
> import subprocess
>
>-def run(args, as_root=False):
>+def run(args, as_root=False, stdout=None):

Would it be possible to add stdin as a parameter to this function so the output from one command can be connected to the input of another? E.g. check_device() connects several commands using a pipe.

This implies also that stdout of the subprocess is returned in some way.

/Martin

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

On Fri, 2010-12-03 at 19:57 +0000, Martin Ohlsson wrote:
> >=== modified file 'media_create/cmd_runner.py'
> >--- media_create/cmd_runner.py 2010-12-01 19:08:25 +0000
> >+++ media_create/cmd_runner.py 2010-12-03 19:01:21 +0000
> >@@ -1,12 +1,13 @@
> > import subprocess
> >
> >-def run(args, as_root=False):
> >+def run(args, as_root=False, stdout=None):
>
> Would it be possible to add stdin as a parameter to this function so the output from one command can be connected to the input of another? E.g. check_device() connects several commands using a pipe.

I suppose that's possible, but I wonder if there is a real advantage in
running each of the commands individually and pipe their stdin/stdout in
Python, or would this be a case we'd be better off by letting the shell
do that (i.e. run them all as a single subprocess.call(...,
shell=True))?

>
> This implies also that stdout of the subprocess is returned in some way.

I'm not sure I understand what you mean here.

Revision history for this message
Martin Ohlsson (martin-ohlson) wrote :

You're right, it would probably mess up the simplicity of the cmd_runner to make it handle everything. More complex cases might be better handled locally for those rare situations.

Revision history for this message
Michael Hudson-Doyle (mwhudson) wrote :

I haven't checked every last detail for correctness, but I approve of the overall structure. Let me know if you want me to check all the arguments to each invocation of mkImage -- it can be done, but is probably a paper and pencil job.

I wonder if it would be easier to read if populate_boot took --options rather than positional arguments. I guess it depends how you see the code developing.

Thanks for working on this, linaro-media-create just makes me want to cry and this helps :-)

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

On Mon, 2010-12-06 at 22:21 +0000, Michael Hudson-Doyle wrote:
> Review: Approve
> I haven't checked every last detail for correctness, but I approve of
> the overall structure. Let me know if you want me to check all the
> arguments to each invocation of mkImage -- it can be done, but is
> probably a paper and pencil job.

I don't think that's necessary; I've checked it many times myself.

>
> I wonder if it would be easier to read if populate_boot took --options
> rather than positional arguments. I guess it depends how you see the
> code developing.

It'd probably be more readable, but soon enough we won't need any of
that as everything will be python, so I'd rather stick with whatever is
simpler until we get there.

>
> Thanks for working on this, linaro-media-create just makes me want to
> cry and this helps :-)

You're certainly not alone there.

Thanks for the review!

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'linaro-media-create'
2--- linaro-media-create 2010-11-30 12:35:27 +0000
3+++ linaro-media-create 2010-12-03 19:01:21 +0000
4@@ -535,9 +535,9 @@
5 echo ""
6
7 if [ "$IS_LIVE" -eq 1 ]; then
8- parts_dir=casper
9+ parts_dir="${DIR}/binary/casper"
10 else
11- parts_dir=boot
12+ parts_dir="${DIR}/binary/boot"
13 fi
14
15 mkdir -p "${BOOT_DISK}"
16@@ -548,92 +548,9 @@
17 "${BOOT_DISK}"
18 fi
19
20- case "$DEVIMAGE" in
21- beagle|igep)
22- if [ "$DEVIMAGE" = "beagle" ]; then
23- sudo cp -v binary/usr/lib/x-loader-omap/MLO "${BOOT_DISK}"
24- fi
25- sync
26- echo "done"
27-
28- sudo mkimage -A arm -O linux -T kernel -C none -a 0x80008000 \
29- -e 0x80008000 -n Linux \
30- -d "${DIR}/binary/${parts_dir}"/vmlinuz-*-linaro-omap \
31- "${BOOT_DISK}/uImage"
32- sudo mkimage -A arm -O linux -T ramdisk -C none -a 0 \
33- -e 0 -n initramfs \
34- -d "${DIR}/binary/${parts_dir}"/initrd.img-*-linaro-omap \
35- "${BOOT_DISK}/uInitrd"
36- sudo mkimage -A arm -O linux -T script -C none -a 0 \
37- -e 0 -n "boot script" -d "${TMP_DIR}/boot.cmd" \
38- "${BOOT_DISK}/boot.scr"
39- sudo cp -v "${BOOT_DISK}/boot.scr" "${BOOT_DISK}/boot.ini"
40- ;;
41-
42- panda)
43- sudo cp -v binary/usr/lib/x-loader-omap4/MLO "${BOOT_DISK}"
44- sync
45- echo "done"
46-
47- sudo mkimage -A arm -O linux -T kernel -C none -a 0x80008000 \
48- -e 0x80008000 -n Linux \
49- -d "${DIR}/binary/${parts_dir}"/vmlinuz-*-omap4 \
50- "${BOOT_DISK}/uImage"
51- sudo mkimage -A arm -O linux -T ramdisk -C none -a 0 \
52- -e 0 -n initramfs \
53- -d "${DIR}/binary/${parts_dir}"/initrd.img-*-omap4 \
54- "${BOOT_DISK}/uInitrd"
55- sudo mkimage -A arm -O linux -T script -C none -a 0 \
56- -e 0 -n "boot script" -d "${TMP_DIR}/boot.cmd" \
57- "${BOOT_DISK}/boot.scr"
58- sudo cp -v "${BOOT_DISK}/boot.scr" "${BOOT_DISK}/boot.ini"
59- ;;
60-
61- ux500)
62- sudo mkimage -A arm -O linux -T kernel -C none -a 0x00008000 \
63- -e 0x00008000 -n Linux \
64- -d "${DIR}/binary/${parts_dir}"/vmlinuz-*-ux500 \
65- "${BOOT_DISK}/uImage"
66- sudo mkimage -A arm -O linux -T ramdisk -C none -a 0 \
67- -e 0 -n initramfs \
68- -d "${DIR}/binary/${parts_dir}"/initrd.img-*-ux500 \
69- "${BOOT_DISK}/uInitrd"
70- sudo mkimage -A arm -O linux -T script -C none -a 0 \
71- -e 0 -n "boot script" -d "${TMP_DIR}/boot.cmd" \
72- "${BOOT_DISK}/flash.scr"
73- ;;
74-
75- vexpress)
76- sudo mkimage -A arm -O linux -T kernel -C none -a "$KERNEL_ADDR" \
77- -e "$KERNEL_ADDR" -n Linux \
78- -d "${DIR}/binary/${parts_dir}"/vmlinuz-*-linaro-vexpress \
79- "${BOOT_DISK}/uImage"
80- sudo mkimage -A arm -O linux -T ramdisk -C none -a "$INITRD_ADDR" \
81- -e "$INITRD_ADDR" -n initramfs \
82- -d "${DIR}/binary/${parts_dir}"/initrd.img-*-linaro-vexpress \
83- "${BOOT_DISK}/uInitrd"
84- ;;
85-
86- mx51evk)
87- sudo dd if=binary/usr/lib/u-boot/mx51evk/u-boot.imx of="${DEVICE:-$IMAGE_FILE}" \
88- bs=1024 seek=1 conv=notrunc
89- sudo mkimage -A arm -O linux -T kernel -C none -a 0x90008000 \
90- -e 0x90008000 -n Linux \
91- -d "${DIR}/binary/${parts_dir}"/vmlinuz-*-linaro-mx51 \
92- "${BOOT_DISK}/uImage"
93- sudo mkimage -A arm -O linux -T ramdisk -C none -a 0 \
94- -e 0 -n initramfs \
95- -d "${DIR}/binary/${parts_dir}"/initrd.img-*-linaro-mx51 \
96- "${BOOT_DISK}/uInitrd"
97- sudo mkimage -A arm -O linux -T script -C none -a 0 \
98- -e 0 -n "boot script" -d "${TMP_DIR}/boot.cmd" \
99- "${BOOT_DISK}/boot.scr"
100- ;;
101- *)
102- echo "Internal error; missing support for $DEVIMAGE" >&2
103- exit 1
104- ;;
105- esac
106+ python -m media_create.populate_boot "$DEVIMAGE" "$SUB_ARCH" "$LOAD_ADDR" \
107+ "$parts_dir" "$BOOT_DISK" "$TMP_DIR" "$BOOT_SCRIPT" \
108+ "${DEVICE:-$IMAGE_FILE}"
109
110 sync
111 sync
112@@ -798,6 +715,8 @@
113 ;;
114 esac
115
116+# This whole thing will be moved into config files that will be specific for
117+# each board.
118 if [ "$DEVIMAGE" ]; then
119 case "$DEVIMAGE" in
120 beagle|igep)
121@@ -807,6 +726,9 @@
122 fi
123 KERNEL_ADDR="0x80000000"
124 INITRD_ADDR="0x81600000"
125+ LOAD_ADDR="0x80008000"
126+ SUB_ARCH="linaro-omap"
127+ BOOT_SCRIPT="boot.scr"
128 boot_args_options="$boot_args_options earlyprintk fixrtc nocompcache vram=12M omapfb.debug=y omapfb.mode=dvi:1280x720MR-16@60"
129 ;;
130 panda)
131@@ -816,6 +738,9 @@
132 fi
133 KERNEL_ADDR="0x80200000"
134 INITRD_ADDR="0x81600000"
135+ LOAD_ADDR="0x80008000"
136+ SUB_ARCH="omap4"
137+ BOOT_SCRIPT="boot.scr"
138 boot_args_options="$boot_args_options earlyprintk fixrtc nocompcache vram=32M omapfb.debug=y omapfb.vram=0:8M mem=463M ip=none"
139 ;;
140 ux500)
141@@ -825,6 +750,9 @@
142 fi
143 KERNEL_ADDR="0x00100000"
144 INITRD_ADDR="0x08000000"
145+ LOAD_ADDR="0x00008000"
146+ SUB_ARCH="ux500"
147+ BOOT_SCRIPT="flash.scr"
148 boot_args_options="$boot_args_options earlyprintk rootdelay=1 fixrtc nocompcache"
149 boot_args_options="$boot_args_options mem=96M@0 mem_modem=32M@96M mem=44M@128M pmem=22M@172M mem=30M@194M mem_mali=32M@224M pmem_hwb=54M@256M hwmem=48M@302M mem=152M@360M"
150 mmc_option="1:1"
151@@ -836,6 +764,9 @@
152 fi
153 KERNEL_ADDR="0x90000000"
154 INITRD_ADDR="0x90800000"
155+ LOAD_ADDR="0x90008000"
156+ SUB_ARCH="linaro-mx51"
157+ BOOT_SCRIPT="boot.scr"
158 MMC_PART_OFFSET=1
159 mmc_option="0:2"
160 ;;
161@@ -846,6 +777,8 @@
162 fi
163 KERNEL_ADDR="0x60008000"
164 INITRD_ADDR="0x81000000"
165+ LOAD_ADDR=$KERNEL_ADDR
166+ SUB_ARCH="linaro-vexpress"
167 # ARM Boot Monitor is used to load u-boot, uImage etc. into flash and
168 # only allows for FAT16
169 FAT_SIZE=16
170
171=== modified file 'media_create/cmd_runner.py'
172--- media_create/cmd_runner.py 2010-12-01 19:08:25 +0000
173+++ media_create/cmd_runner.py 2010-12-03 19:01:21 +0000
174@@ -1,12 +1,13 @@
175 import subprocess
176
177
178-def run(args, as_root=False):
179+def run(args, as_root=False, stdout=None):
180 """Run the given command as a sub process.
181
182 :param command: A list or tuple containing the command to run and the
183 arguments that should be passed to it.
184 :param as_root: Should the given command be run as root (with sudo)?
185+ :param stdout: Same as subprocess.Popen().
186 """
187 assert isinstance(args, (list, tuple)), (
188 "The command to run must be a list or tuple, found: %s" % type(args))
189@@ -15,15 +16,15 @@
190 if as_root:
191 args = args[:]
192 args.insert(0, 'sudo')
193- return_value = do_run(args)
194+ return_value = do_run(args, stdout=stdout)
195 if return_value != 0:
196 raise SubcommandNonZeroReturnValue(args, return_value)
197 return return_value
198
199
200-def do_run(args):
201+def do_run(args, stdout=None):
202 """A wrapper around subprocess.call() to make testing easier."""
203- return subprocess.call(args)
204+ return subprocess.call(args, stdout=stdout)
205
206
207 class SubcommandNonZeroReturnValue(Exception):
208
209=== added file 'media_create/populate_boot.py'
210--- media_create/populate_boot.py 1970-01-01 00:00:00 +0000
211+++ media_create/populate_boot.py 2010-12-03 19:01:21 +0000
212@@ -0,0 +1,128 @@
213+import glob
214+import sys
215+
216+from media_create import cmd_runner
217+
218+
219+def _run_mkimage(img_type, load_addr, entry_point, name, img_data, img,
220+ stdout=None):
221+ cmd = ['mkimage',
222+ '-A', 'arm',
223+ '-O', 'linux',
224+ '-T', img_type,
225+ '-C', 'none',
226+ '-a', load_addr,
227+ '-e', load_addr,
228+ '-n', name,
229+ '-d', img_data,
230+ img]
231+ return cmd_runner.run(cmd, as_root=True, stdout=stdout)
232+
233+
234+def _get_file_matching(regex):
235+ """Return a file whose path matches the given regex.
236+
237+ If zero or more than one files match, raise a ValueError.
238+ """
239+ files = glob.glob(regex)
240+ if len(files) == 1:
241+ return files[0]
242+ elif len(files) == 0:
243+ raise ValueError(
244+ "No files found matching '%s'; can't continue" % regex)
245+ else:
246+ # TODO: Could ask the user to chosse which file to use instead of
247+ # raising an exception.
248+ raise ValueError("Too many files matching '%s' found." % regex)
249+
250+
251+def make_uImage(load_addr, uboot_parts_dir, sub_arch, boot_disk):
252+ img_data = _get_file_matching(
253+ '%s/vmlinuz-*-%s' % (uboot_parts_dir, sub_arch))
254+ img = '%s/uImage' % boot_disk
255+ return _run_mkimage(
256+ 'kernel', load_addr, load_addr, 'Linux', img_data, img)
257+
258+
259+def make_uInitrd(uboot_parts_dir, sub_arch, boot_disk):
260+ img_data = _get_file_matching(
261+ '%s/initrd.img-*-%s' % (uboot_parts_dir, sub_arch))
262+ img = '%s/uInitrd' % boot_disk
263+ return _run_mkimage('ramdisk', '0', '0', 'initramfs', img_data, img)
264+
265+
266+def make_boot_script(boot_script, tmp_dir):
267+ img_data = '%s/boot.cmd' % tmp_dir
268+ return _run_mkimage(
269+ 'script', '0', '0', 'boot script', img_data, boot_script)
270+
271+
272+def install_mx51evk_boot_loader(imx_file, boot_device_or_file):
273+ cmd_runner.run([
274+ "dd",
275+ "if=%s" % imx_file,
276+ "of=%s" % boot_device_or_file,
277+ "bs=1024",
278+ "seek=1",
279+ "conv=notrunc"], as_root=True)
280+
281+
282+def install_omap_boot_loader(mlo_file, boot_disk):
283+ cmd_runner.run(["cp", "-v", mlo_file, boot_disk], as_root=True)
284+ # XXX: Is this really needed?
285+ cmd_runner.run(["sync"])
286+
287+
288+def make_boot_ini(boot_script, boot_disk):
289+ cmd_runner.run(
290+ ["cp", "-v", boot_script, "%s/boot.ini" % boot_disk], as_root=True)
291+
292+
293+def populate_boot(board, sub_arch, load_addr, uboot_parts_dir, boot_disk,
294+ tmp_dir, boot_script_name, boot_device_or_file):
295+
296+ boot_script = "%(boot_disk)s/%(boot_script_name)s" % (
297+ dict(boot_disk=boot_disk, boot_script_name=boot_script_name))
298+
299+ # TODO: Once linaro-media-create is fully ported to python, we should
300+ # split this into several board-specific functions that are defined
301+ # somewhere else and just called here.
302+ if board in ["beagle", "panda"]:
303+ mlo_file = "binary/usr/lib/x-loader-omap/MLO"
304+ if board == "panda":
305+ mlo_file = "binary/usr/lib/x-loader-omap4/MLO"
306+ install_omap_boot_loader(mlo_file, boot_disk)
307+ make_uImage(load_addr, uboot_parts_dir, sub_arch, boot_disk)
308+ make_uInitrd(uboot_parts_dir, sub_arch, boot_disk)
309+ make_boot_script(boot_script, tmp_dir)
310+ make_boot_ini(boot_script, boot_disk)
311+
312+ elif board == "igep":
313+ make_uImage(load_addr, uboot_parts_dir, sub_arch, boot_disk)
314+ make_uInitrd(uboot_parts_dir, sub_arch, boot_disk)
315+ make_boot_script(boot_script, tmp_dir)
316+ make_boot_ini(boot_script, boot_disk)
317+
318+ elif board == "ux500":
319+ make_uImage(load_addr, uboot_parts_dir, sub_arch, boot_disk)
320+ make_uInitrd(uboot_parts_dir, sub_arch, boot_disk)
321+ make_boot_script(boot_script, tmp_dir)
322+
323+ elif board == "vexpress":
324+ make_uImage(load_addr, uboot_parts_dir, sub_arch, boot_disk)
325+ make_uInitrd(uboot_parts_dir, sub_arch, boot_disk)
326+
327+ elif board == "mx51evk":
328+ install_mx51evk_boot_loader(
329+ "binary/usr/lib/u-boot/mx51evk/u-boot.imx", boot_device_or_file)
330+ make_uImage(load_addr, uboot_parts_dir, sub_arch, boot_disk)
331+ make_uInitrd(uboot_parts_dir, sub_arch, boot_disk)
332+ make_boot_script(boot_script, tmp_dir)
333+
334+ else:
335+ raise AssertionError(
336+ "Internal error; missing support for board: %s" % board)
337+
338+
339+if __name__ == "__main__":
340+ sys.exit(populate_boot(*sys.argv[1:]))
341
342=== modified file 'media_create/tests/test_media_create.py'
343--- media_create/tests/test_media_create.py 2010-12-03 18:48:55 +0000
344+++ media_create/tests/test_media_create.py 2010-12-03 19:01:21 +0000
345@@ -1,7 +1,10 @@
346 from contextlib import contextmanager
347 import os
348+import random
349+import string
350 import subprocess
351 import sys
352+import tempfile
353
354 from testtools import TestCase
355
356@@ -11,6 +14,14 @@
357 from media_create import cmd_runner
358 from media_create import ensure_command
359
360+from media_create import populate_boot
361+from media_create.populate_boot import (
362+ make_boot_script,
363+ make_uImage,
364+ make_uInitrd,
365+ _get_file_matching,
366+ _run_mkimage,
367+ )
368 from media_create.remove_binary_dir import remove_binary_dir
369 from media_create.unpack_binary_tarball import unpack_binary_tarball
370
371@@ -18,6 +29,7 @@
372 CreateTempDirFixture,
373 CreateTarballFixture,
374 MockDoRunFixture,
375+ MockSomethingFixture,
376 )
377
378
379@@ -135,3 +147,89 @@
380 def test_do_run(self):
381 return_code = cmd_runner.do_run('true')
382 self.assertEqual(0, return_code)
383+
384+
385+class TestPopulateBoot(TestCaseWithFixtures):
386+
387+ def _mock_get_file_matching(self):
388+ self.useFixture(MockSomethingFixture(
389+ populate_boot, '_get_file_matching',
390+ lambda regex: regex))
391+
392+ def _mock_do_run(self):
393+ fixture = MockDoRunFixture()
394+ self.useFixture(fixture)
395+ return fixture
396+
397+ def test_make_uImage(self):
398+ self._mock_get_file_matching()
399+ fixture = self._mock_do_run()
400+ make_uImage('load_addr', 'parts_dir', 'sub_arch', 'boot_disk')
401+ expected = [
402+ 'sudo', 'mkimage', '-A', 'arm', '-O', 'linux', '-T', 'kernel',
403+ '-C', 'none', '-a', 'load_addr', '-e', 'load_addr', '-n', 'Linux',
404+ '-d', 'parts_dir/vmlinuz-*-sub_arch', 'boot_disk/uImage']
405+ self.assertEqual(expected, fixture.mock.args)
406+
407+ def test_make_uInitrd(self):
408+ self._mock_get_file_matching()
409+ fixture = self._mock_do_run()
410+ make_uInitrd('parts_dir', 'sub_arch', 'boot_disk')
411+ expected = [
412+ 'sudo', 'mkimage', '-A', 'arm', '-O', 'linux', '-T', 'ramdisk',
413+ '-C', 'none', '-a', '0', '-e', '0', '-n', 'initramfs',
414+ '-d', 'parts_dir/initrd.img-*-sub_arch', 'boot_disk/uInitrd']
415+ self.assertEqual(expected, fixture.mock.args)
416+
417+ def test_make_boot_script(self):
418+ self._mock_get_file_matching()
419+ fixture = self._mock_do_run()
420+ make_boot_script('boot_script', 'tmp_dir')
421+ expected = [
422+ 'sudo', 'mkimage', '-A', 'arm', '-O', 'linux', '-T', 'script',
423+ '-C', 'none', '-a', '0', '-e', '0', '-n', 'boot script',
424+ '-d', 'tmp_dir/boot.cmd', 'boot_script']
425+ self.assertEqual(expected, fixture.mock.args)
426+
427+ def test_get_file_matching(self):
428+ prefix = ''.join(
429+ random.choice(string.ascii_lowercase) for x in range(5))
430+ file1 = self._create_temp_file_as_fixture(prefix)
431+ directory = os.path.dirname(file1)
432+ self.assertEqual(
433+ file1, _get_file_matching('%s/%s*' % (directory, prefix)))
434+
435+ def test_get_file_matching_too_many_files_found(self):
436+ prefix = ''.join(
437+ random.choice(string.ascii_lowercase) for x in range(5))
438+ file1 = self._create_temp_file_as_fixture(prefix)
439+ file2 = self._create_temp_file_as_fixture(prefix)
440+ directory = os.path.dirname(file1)
441+ self.assertRaises(
442+ ValueError, _get_file_matching, '%s/%s*' % (directory, prefix))
443+
444+ def test_get_file_matching_no_files_found(self):
445+ self.assertRaises(
446+ ValueError, _get_file_matching, '/foo/bar/baz/*non-existent')
447+
448+ def test_run_mkimage(self):
449+ # Create a fake boot script.
450+ filename = self._create_temp_file_as_fixture()
451+ f = open(filename, 'w')
452+ f.write("setenv bootcmd 'fatload mmc 0:1 0x80000000 uImage;\nboot")
453+ f.close()
454+
455+ img = self._create_temp_file_as_fixture()
456+ # Use that fake boot script to create a boot loader using mkimage.
457+ # Send stdout to file as mkimage will print to stdout and we don't
458+ # want that.
459+ retval = _run_mkimage(
460+ 'script', '0', '0', 'boot script', filename, img,
461+ stdout=open(self._create_temp_file_as_fixture(), 'w'))
462+
463+ self.assertEqual(0, retval)
464+
465+ def _create_temp_file_as_fixture(self, prefix='tmp'):
466+ _, filename = tempfile.mkstemp(prefix=prefix)
467+ self.addCleanup(os.unlink, filename)
468+ return filename

Subscribers

People subscribed via source and target branches