Merge lp:~dooferlad/linaro-image-tools/add-directory-option into lp:linaro-image-tools/11.11

Proposed by James Tunnicliffe
Status: Merged
Merged at revision: 508
Proposed branch: lp:~dooferlad/linaro-image-tools/add-directory-option
Merge into: lp:linaro-image-tools/11.11
Diff against target: 287 lines (+156/-32)
5 files modified
linaro-media-create (+37/-25)
linaro_image_tools/media_create/__init__.py (+11/-6)
linaro_image_tools/media_create/boards.py (+28/-0)
linaro_image_tools/tests/test_utils.py (+44/-1)
linaro_image_tools/utils.py (+36/-0)
To merge this branch: bzr merge lp:~dooferlad/linaro-image-tools/add-directory-option
Reviewer Review Type Date Requested Status
Loïc Minier (community) Approve
Review via email: mp+102518@code.launchpad.net

This proposal supersedes a proposal from 2012-04-17.

Description of the change

Slightly modified patch from https://bugs.launchpad.net/linaro-image-tools/+bug/962147

Updated:
--directory can now be specified at the same time as --image-file. If --directory and --image-file are combined, a file, whose name is specified by --image-file, will be created in --directory. If --image-file is not specified, a sensible default file name will be used and printed for the user to see.

--directory and --mmc are incompatable.

--directory and specifying a full path to a file with --image-file are incompatable.

Updated(2):
Fixed spelling of IncompatibleOptions.
Renamed --directory option to --output-directory. Set default file name for an image to sd.img.
Moved defaulting of args.device into ArgumentParser set up.
Moved additional option checks into their own function (additional_option_checks).

I am unable to move more argument processing into media_create/__init__.py get_args_parser() because ArgumentParser can't cope with the complexity of the logic. I have split it out into another function though, so it is clear what is happening.

To post a comment you must log in.
Revision history for this message
Loïc Minier (lool) wrote : Posted in a previous version of this proposal

On Mon, Apr 16, 2012, James Tunnicliffe wrote:
[...]
> + if args.directory is not None:
> + if not board_config.outputs_directory:
> + raise BoardAbilityNotMet("The board '%s' does not support the"
> + "--directory option." % args.board)

 I find the per board attribute kinda ugly and I'm not sure we want to
 suffer from supporting both a single file output or a directory with
 multiple files as output.

 How about we just default to always outputting to a directory, default
 to ./ as the target directory, and allow overriding that, but keep the
 --image-file as the default filename for the main image? We could
 document for each boardconfig what it outputs as to display it at the
 end of the build or in the help output.

 There are alternate approaches such as output a zip/tgz file with all
 the assets and naming that after --image-file, but that's probably a
 bit heavy. We could also abuse --image-file by outputting a warning
 and creating a directory there instead (e.g. --image-file foo.img would
 create ./foo.img/ and output the assets below that).

--
Loïc Minier

Revision history for this message
James Tunnicliffe (dooferlad) wrote : Posted in a previous version of this proposal

On 16 April 2012 17:40, Loïc Minier <email address hidden> wrote:
> On Mon, Apr 16, 2012, James Tunnicliffe wrote:
> [...]
>> +    if args.directory is not None:
>> +        if not board_config.outputs_directory:
>> +            raise BoardAbilityNotMet("The board '%s' does not support the"
>> +                                     "--directory option." % args.board)
>
>  I find the per board attribute kinda ugly and I'm not sure we want to
>  suffer from supporting both a single file output or a directory with
>  multiple files as output.
>
>  How about we just default to always outputting to a directory, default
>  to ./ as the target directory, and allow overriding that, but keep the
>  --image-file as the default filename for the main image?  We could
>  document for each boardconfig what it outputs as to display it at the
>  end of the build or in the help output.

I like this approach since it gracefully reverts back to the old
behaviour. Will make some changes.

--
James Tunnicliffe

Revision history for this message
James Tunnicliffe (dooferlad) wrote : Posted in a previous version of this proposal

Oops, forgot to delete the outputs_directory flag. Hang on...

Revision history for this message
James Tunnicliffe (dooferlad) wrote : Posted in a previous version of this proposal

OK. Done.

Revision history for this message
Loïc Minier (lool) wrote : Posted in a previous version of this proposal

On Tue, Apr 17, 2012, James Tunnicliffe wrote:
> + IncompatableOptions,

 IncompatibleOptions

> + parser.add_argument(
> + '--directory', dest='directory',
> + help='Directory where image and accessories should be written to.')

 --output-directory?

> + outputs_directory = False

 not too nice as property; perhaps outputs_multiple_artifacts = False?
 Or expected_artifacts = 1?

> +def prep_media_path(args, board_config):
> +
> + # If args.device isn't set, generate a sensible default file name and
> + # tell the user
> + if not args.device:
> + args.device = board_config.board + ".img"
> + print "Setting destination file name to", args.device

 I think it would be more stable to just call it mmc.img or sd.img.

> + if args.directory is not None:
> + # If args.device is a path to a device (/dev/) then this is an error
> + if "--mmc" in sys.argv:
> + raise IncompatableOptions("--directory option incompatable with "
> + "option --mmc")
> +
> + # If directory is used as well as having a full path (rather than just
> + # a file name or relative path) in args.device, this is an error.
> + if re.search(r"^/", args.device):
> + raise IncompatableOptions("--directory option incompatable with "

 IncompatibleOptions + "incompatible"

 We could actually support absolute --image-file with --directory and
 just output the image where the user wants it, but I don't really care
 strongly about the behavior in that particular use case.

 Generally ok with the design apart of the minor comments here, but
 I have one objection: I think the argument validation / mangling should
 happen when parsing the cmdline rather than in boards code.

 Could you just include prep_media_path logic as part of the cmdline
 args validation? This would also remove the need for a special
 exception down the road.

 Otherwise good, thanks!

--
Loïc Minier

Revision history for this message
Ricardo Salveti (rsalveti) wrote : Posted in a previous version of this proposal

On Tue, Apr 17, 2012 at 3:37 PM, Loïc Minier <email address hidden> wrote:
>> +def prep_media_path(args, board_config):
>> +
>> +    # If args.device isn't set, generate a sensible default file name and
>> +    # tell the user
>> +    if not args.device:
>> +        args.device = board_config.board + ".img"
>> +        print "Setting destination file name to", args.device
>
>  I think it would be more stable to just call it mmc.img or sd.img.

+1, that would help scripting the output later on.

>> +    if args.directory is not None:
>> +        # If args.device is a path to a device (/dev/) then this is an error
>> +        if "--mmc" in sys.argv:
>> +            raise IncompatableOptions("--directory option incompatable with "
>> +                                      "option --mmc")
>> +
>> +        # If directory is used as well as having a full path (rather than just
>> +        # a file name or relative path) in args.device, this is an error.
>> +        if re.search(r"^/", args.device):
>> +            raise IncompatableOptions("--directory option incompatable with "
>
>  IncompatibleOptions + "incompatible"
>
>  We could actually support absolute --image-file with --directory and
>  just output the image where the user wants it, but I don't really care
>  strongly about the behavior in that particular use case.
>
>  Generally ok with the design apart of the minor comments here, but
>  I have one objection: I think the argument validation / mangling should
>  happen when parsing the cmdline rather than in boards code.

+1

>  Otherwise good, thanks!

+1

516. By James Tunnicliffe

remove .idea ignore

Revision history for this message
Loïc Minier (lool) wrote :

 review approve

 Seems almost good to go except minor points below:

On Wed, Apr 18, 2012, James Tunnicliffe wrote:
> + try:
> + additional_option_checks(args)

 I would just include the logic here rather than adding a separate
 function + Exception, but up to you

> === modified file 'linaro_image_tools/media_create/partitions.py'
> --- linaro_image_tools/media_create/partitions.py 2012-01-17 14:19:19 +0000
> +++ linaro_image_tools/media_create/partitions.py 2012-04-18 13:29:21 +0000
> @@ -590,4 +590,5 @@
>
> def __init__(self, path):
> self.path = path
> + self.directory = None
> self.is_block_device = path.startswith('/dev/')

 Hmm shouldn't you take directory in __init__?

> +class Args():
> + def __init__(self, directory, device, board):
> + self.directory = directory
> + self.device = device
> + self.board = board

 Don't think board is needed anymore, but you shouldn't you just use a
 Media() instance?

--
Loïc Minier

review: Approve
517. By James Tunnicliffe

Removed unused directory variable.

Revision history for this message
James Tunnicliffe (dooferlad) wrote :

On 18 April 2012 14:55, Loïc Minier <email address hidden> wrote:
> Review: Approve
>
>  review approve
>
>  Seems almost good to go except minor points below:
>
> On Wed, Apr 18, 2012, James Tunnicliffe wrote:
>> +    try:
>> +        additional_option_checks(args)
>
>  I would just include the logic here rather than adding a separate
>  function + Exception, but up to you

I just got to write tests for it this way.

>> === modified file 'linaro_image_tools/media_create/partitions.py'
>> --- linaro_image_tools/media_create/partitions.py     2012-01-17 14:19:19 +0000
>> +++ linaro_image_tools/media_create/partitions.py     2012-04-18 13:29:21 +0000
>> @@ -590,4 +590,5 @@
>>
>>      def __init__(self, path):
>>          self.path = path
>> +        self.directory = None
>>          self.is_block_device = path.startswith('/dev/')
>
>  Hmm shouldn't you take directory in __init__?

Actually, I can't find anywhere it is used. Deleted.

>> +class Args():
>> +    def __init__(self, directory, device, board):
>> +        self.directory = directory
>> +        self.device = device
>> +        self.board = board
>
>  Don't think board is needed anymore, but you shouldn't you just use a
>  Media() instance?

It is needed as a fake version of what comes out of the arguments
parser. It isn't the same as Media.

--
James Tunnicliffe

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 2012-01-17 14:50:47 +0000
3+++ linaro-media-create 2012-04-18 14:21:19 +0000
4@@ -48,6 +48,9 @@
5 is_arm_host,
6 check_file_integrity_and_log_errors,
7 path_in_tarfile_exists,
8+ IncompatibleOptions,
9+ prep_media_path,
10+ additional_option_checks,
11 )
12
13 # Just define the global variables
14@@ -97,6 +100,37 @@
15 parser = get_args_parser()
16 args = parser.parse_args()
17
18+ try:
19+ additional_option_checks(args)
20+ except IncompatibleOptions as e:
21+ parser.print_help()
22+ print >> sys.stderr, "\nError:", e.value
23+ sys.exit(1)
24+
25+ board_config = board_configs[args.board]
26+ board_config.set_metadata(args.hwpacks)
27+ board_config.set_board(args.board)
28+ board_config.add_boot_args(args.extra_boot_args)
29+ board_config.add_boot_args_from_file(args.extra_boot_args_file)
30+
31+ media = Media(prep_media_path(args))
32+
33+ if media.is_block_device:
34+ if not board_config.supports_writing_to_mmc:
35+ print "The board '%s' does not support the --mmc option. Please use "\
36+ "--image_file to create an image file for this board." % args.board
37+ sys.exit(1)
38+ if not confirm_device_selection_and_ensure_it_is_ready(args.device,
39+ args.nocheck_mmc):
40+ sys.exit(1)
41+ elif not args.should_format_rootfs or not args.should_format_bootfs:
42+ print ("Do not use --no-boot or --no-part in conjunction with "
43+ "--image_file.")
44+ sys.exit(1)
45+ else:
46+ # All good, move on.
47+ pass
48+
49 ch = logging.StreamHandler()
50 ch.setLevel(logging.INFO)
51 formatter = logging.Formatter("%(message)s")
52@@ -116,12 +150,6 @@
53 BOOT_DISK = os.path.join(TMP_DIR, 'boot-disc')
54 ROOT_DISK = os.path.join(TMP_DIR, 'root-disc')
55
56- board_config = board_configs[args.board]
57- board_config.set_metadata(args.hwpacks)
58- board_config.set_board(args.board)
59- board_config.add_boot_args(args.extra_boot_args)
60- board_config.add_boot_args_from_file(args.extra_boot_args_file)
61-
62 ensure_required_commands(args)
63
64 sig_file_list = args.hwpacksigs[:]
65@@ -134,24 +162,8 @@
66 sig_file_list, args.binary, args.hwpacks)
67 if not files_ok:
68 sys.exit(1)
69-
70+
71 atexit.register(cleanup_tempdir)
72- media = Media(args.device)
73- if media.is_block_device:
74- if not board_config.supports_writing_to_mmc:
75- print "The board '%s' does not support the --mmc option. Please use " \
76- "--image_file to create an image file for this board." % args.board
77- sys.exit(1)
78- if not confirm_device_selection_and_ensure_it_is_ready(args.device,
79- args.nocheck_mmc):
80- sys.exit(1)
81- elif not args.should_format_rootfs or not args.should_format_bootfs:
82- print ("Do not use --no-boot or --no-part in conjunction with "
83- "--image_file.")
84- sys.exit(1)
85- else:
86- # All good, move on.
87- pass
88
89 unpack_binary_tarball(args.binary, TMP_DIR)
90
91@@ -174,7 +186,7 @@
92
93 if args.should_format_bootfs:
94 board_config.populate_boot(
95- ROOTFS_DIR, rootfs_uuid, boot_partition, BOOT_DISK, args.device,
96+ ROOTFS_DIR, rootfs_uuid, boot_partition, BOOT_DISK, media.path,
97 args.is_live, args.is_lowmem, args.consoles)
98
99 if args.should_format_rootfs:
100@@ -185,4 +197,4 @@
101 rootfs_uuid, create_swap, str(args.swap_file),
102 board_config.mmc_part_offset, board_config)
103
104- print "Done creating Linaro image on %s" % args.device
105+ print "Done creating Linaro image on %s" % media.path
106
107=== modified file 'linaro_image_tools/media_create/__init__.py'
108--- linaro_image_tools/media_create/__init__.py 2012-01-19 06:31:50 +0000
109+++ linaro_image_tools/media_create/__init__.py 2012-04-18 14:21:19 +0000
110@@ -77,12 +77,17 @@
111 def get_args_parser():
112 """Get the ArgumentParser for the arguments given on the command line."""
113 parser = argparse.ArgumentParser(version='%(prog)s ' + get_version())
114- group = parser.add_mutually_exclusive_group(required=True)
115- group.add_argument(
116- '--mmc', dest='device', help='The storage device to use.')
117- group.add_argument(
118- '--image-file', '--image_file', dest='device',
119- help='File where we should write the QEMU image.')
120+ group = parser.add_mutually_exclusive_group()
121+ group.add_argument(
122+ '--mmc', dest='device', default="sd.img",
123+ help='The storage device to use.')
124+ group.add_argument(
125+ '--image-file', '--image_file', dest='device', default="sd.img",
126+ help='File where we should write an image file (defaults to sd.img '
127+ 'if neither --image-file or --mmc are specified.)')
128+ parser.add_argument(
129+ '--output-directory', dest='directory',
130+ help='Directory where image and accessories should be written to.')
131 parser.add_argument(
132 '--dev', required=True, dest='board', choices=KNOWN_BOARDS,
133 help='Generate an SD card or image for the given board.')
134
135=== modified file 'linaro_image_tools/media_create/boards.py'
136--- linaro_image_tools/media_create/boards.py 2012-04-17 16:22:09 +0000
137+++ linaro_image_tools/media_create/boards.py 2012-04-18 14:21:19 +0000
138@@ -1337,6 +1337,33 @@
139 pass
140
141
142+class FastModelConfig(BoardConfig):
143+ supports_writing_to_mmc = False
144+
145+ @classmethod
146+ def _get_bootcmd(cls, d_img_data):
147+ """Get the bootcmd for FastModel.
148+
149+ We override this as we don't do uboot.
150+ """
151+ return ""
152+
153+ @classmethod
154+ def _make_boot_files_v2(cls, boot_env, chroot_dir, boot_dir,
155+ boot_device_or_file, k_img_data, i_img_data,
156+ d_img_data):
157+ logger = logging.getLogger("linaro_image_tools")
158+ logger.info("WTF=%s." % boot_device_or_file )
159+ output_dir=os.path.dirname(boot_device_or_file)
160+ cmd = [ "cp", "-v", _get_file_matching("%s/boot/img.axf" % chroot_dir), output_dir ]
161+ proc = cmd_runner.run(cmd, as_root=True)
162+ proc.wait()
163+ cmd = [ "cp", "-v", k_img_data, i_img_data, d_img_data, output_dir ]
164+ proc = cmd_runner.run(cmd, as_root=True)
165+ proc.wait()
166+ return
167+
168+
169 class SamsungConfig(BoardConfig):
170 @classproperty
171 def extra_serial_opts(cls):
172@@ -1542,6 +1569,7 @@
173 'panda': PandaConfig,
174 'vexpress': VexpressConfig,
175 'vexpress-a9': VexpressA9Config,
176+ 'fastmodel': FastModelConfig,
177 'ux500': Ux500Config,
178 'snowball_sd': SnowballSdConfig,
179 'snowball_emmc': SnowballEmmcConfig,
180
181=== modified file 'linaro_image_tools/tests/test_utils.py'
182--- linaro_image_tools/tests/test_utils.py 2011-10-12 09:54:29 +0000
183+++ linaro_image_tools/tests/test_utils.py 2012-04-18 14:21:19 +0000
184@@ -41,9 +41,11 @@
185 verify_file_integrity,
186 check_file_integrity_and_log_errors,
187 path_in_tarfile_exists,
188+ IncompatibleOptions,
189+ prep_media_path,
190+ additional_option_checks,
191 )
192
193-
194 sudo_args = " ".join(cmd_runner.SUDO_ARGS)
195
196
197@@ -260,3 +262,44 @@
198 UnableToFindPackageProvidingCommand,
199 install_package_providing, 'mkfs.lean')
200
201+
202+class Args():
203+ def __init__(self, directory, device, board):
204+ self.directory = directory
205+ self.device = device
206+ self.board = board
207+
208+
209+class TestPrepMediaPath(TestCaseWithFixtures):
210+
211+ def test_prep_media_path(self):
212+ self.useFixture(MockSomethingFixture(os.path, 'abspath', lambda x: x))
213+ self.useFixture(MockSomethingFixture(os, "makedirs", lambda x: x))
214+
215+ self.assertEqual("testdevice",
216+ prep_media_path(Args(directory=None,
217+ device="testdevice",
218+ board="testboard")))
219+
220+ self.assertEqual("/foo/bar/testdevice",
221+ prep_media_path(Args(directory="/foo/bar",
222+ device="testdevice",
223+ board="testboard")))
224+
225+class TestPrepMediaPath(TestCaseWithFixtures):
226+
227+ def test_additional_option_checks(self):
228+ self.useFixture(MockSomethingFixture(os.path, 'abspath', lambda x: x))
229+ self.useFixture(MockSomethingFixture(os, "makedirs", lambda x: x))
230+
231+ self.assertRaises(IncompatibleOptions, additional_option_checks,
232+ Args(directory="/foo/bar",
233+ device="/testdevice",
234+ board="testboard"))
235+
236+ sys.argv.append("--mmc")
237+ self.assertRaises(IncompatibleOptions, additional_option_checks,
238+ Args(directory="/foo/bar",
239+ device="testdevice",
240+ board="testboard"))
241+ sys.argv.remove("--mmc")
242
243=== modified file 'linaro_image_tools/utils.py'
244--- linaro_image_tools/utils.py 2011-11-28 12:49:14 +0000
245+++ linaro_image_tools/utils.py 2012-04-18 14:21:19 +0000
246@@ -247,5 +247,41 @@
247 return prefer_dir
248
249
250+def prep_media_path(args):
251+ if args.directory is not None:
252+ loc = os.path.abspath(args.directory)
253+ try:
254+ os.makedirs(loc)
255+ except OSError:
256+ pass # Directory exists.
257+
258+ path = os.path.join(loc, args.device)
259+ else:
260+ path = args.device
261+
262+ return path
263+
264+
265 class UnableToFindPackageProvidingCommand(Exception):
266 """We can't find a package which provides the given command."""
267+
268+
269+class IncompatibleOptions(Exception):
270+ def __init__(self, value):
271+ self.value = value
272+
273+ def __str__(self):
274+ return repr(self.value)
275+
276+def additional_option_checks(args):
277+ if args.directory is not None:
278+ # If args.device is a path to a device (/dev/) then this is an error
279+ if "--mmc" in sys.argv:
280+ raise IncompatibleOptions("--directory option incompatable with "
281+ "option --mmc")
282+
283+ # If directory is used as well as having a full path (rather than just
284+ # a file name or relative path) in args.device, this is an error.
285+ if re.search(r"^/", args.device):
286+ raise IncompatibleOptions("--directory option incompatable with "
287+ "a full path in --image-file")

Subscribers

People subscribed via source and target branches