blob: 2286f20a96e0af4c9af6723e4c47a6206527771b [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#!/usr/bin/env python
2# ex:ts=4:sw=4:sts=4:et
3# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
4#
5# Copyright (c) 2013, Intel Corporation.
6# All rights reserved.
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License version 2 as
10# published by the Free Software Foundation.
11#
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16#
17# You should have received a copy of the GNU General Public License along
18# with this program; if not, write to the Free Software Foundation, Inc.,
19# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20#
21# DESCRIPTION 'wic' is the OpenEmbedded Image Creator that users can
22# use to generate bootable images. Invoking it without any arguments
23# will display help screens for the 'wic' command and list the
24# available 'wic' subcommands. Invoking a subcommand without any
25# arguments will likewise display help screens for the specified
26# subcommand. Please use that interface for detailed help.
27#
28# AUTHORS
29# Tom Zanussi <tom.zanussi (at] linux.intel.com>
30#
31
32__version__ = "0.2.0"
33
34# Python Standard Library modules
35import os
36import sys
37import optparse
38import logging
39from distutils import spawn
40
41# External modules
42scripts_path = os.path.abspath(os.path.dirname(__file__))
43lib_path = scripts_path + '/lib'
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050044sys.path.insert(0, lib_path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050045
46bitbake_exe = spawn.find_executable('bitbake')
47if bitbake_exe:
48 bitbake_path = os.path.join(os.path.dirname(bitbake_exe), '../lib')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050049 sys.path.insert(0, bitbake_path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050050 from bb import cookerdata
51 from bb.main import bitbake_main, BitBakeConfigParameters
52else:
53 bitbake_main = None
54
55from wic.utils.oe.misc import get_bitbake_var, BB_VARS
56from wic.utils.errors import WicError
57from wic import engine
58from wic import help as hlp
59
60def rootfs_dir_to_args(krootfs_dir):
61 """
62 Get a rootfs_dir dict and serialize to string
63 """
64 rootfs_dir = ''
65 for key, val in krootfs_dir.items():
66 rootfs_dir += ' '
67 rootfs_dir += '='.join([key, val])
68 return rootfs_dir.strip()
69
70def callback_rootfs_dir(option, opt, value, parser):
71 """
72 Build a dict using --rootfs_dir connection=dir
73 """
74 if not type(parser.values.rootfs_dir) is dict:
75 parser.values.rootfs_dir = dict()
76
77 if '=' in value:
78 (key, rootfs_dir) = value.split('=')
79 else:
80 key = 'ROOTFS_DIR'
81 rootfs_dir = value
82
83 parser.values.rootfs_dir[key] = rootfs_dir
84
85def wic_create_subcommand(args, usage_str):
86 """
87 Command-line handling for image creation. The real work is done
88 by image.engine.wic_create()
89 """
90 parser = optparse.OptionParser(usage=usage_str)
91
92 parser.add_option("-o", "--outdir", dest="outdir",
93 help="name of directory to create image in")
94 parser.add_option("-e", "--image-name", dest="image_name",
95 help="name of the image to use the artifacts from "
96 "e.g. core-image-sato")
97 parser.add_option("-r", "--rootfs-dir", dest="rootfs_dir", type="string",
98 action="callback", callback=callback_rootfs_dir,
99 help="path to the /rootfs dir to use as the "
100 ".wks rootfs source")
101 parser.add_option("-b", "--bootimg-dir", dest="bootimg_dir",
102 help="path to the dir containing the boot artifacts "
103 "(e.g. /EFI or /syslinux dirs) to use as the "
104 ".wks bootimg source")
105 parser.add_option("-k", "--kernel-dir", dest="kernel_dir",
106 help="path to the dir containing the kernel to use "
107 "in the .wks bootimg")
108 parser.add_option("-n", "--native-sysroot", dest="native_sysroot",
109 help="path to the native sysroot containing the tools "
110 "to use to build the image")
111 parser.add_option("-p", "--skip-build-check", dest="build_check",
112 action="store_false", default=True, help="skip the build check")
113 parser.add_option("-f", "--build-rootfs", action="store_true", help="build rootfs")
114 parser.add_option("-c", "--compress-with", choices=("gzip", "bzip2", "xz"),
115 dest='compressor',
116 help="compress image with specified compressor")
117 parser.add_option("-v", "--vars", dest='vars_dir',
118 help="directory with <image>.env files that store "
119 "bitbake variables")
120 parser.add_option("-D", "--debug", dest="debug", action="store_true",
121 default=False, help="output debug information")
122
123 (options, args) = parser.parse_args(args)
124
125 if len(args) != 1:
126 logging.error("Wrong number of arguments, exiting\n")
127 parser.print_help()
128 sys.exit(1)
129
130 if options.build_rootfs and not bitbake_main:
131 logging.error("Can't build roofs as bitbake is not in the $PATH")
132 sys.exit(1)
133
134 if not options.image_name:
135 missed = []
136 for val, opt in [(options.rootfs_dir, 'rootfs-dir'),
137 (options.bootimg_dir, 'bootimg-dir'),
138 (options.kernel_dir, 'kernel-dir'),
139 (options.native_sysroot, 'native-sysroot')]:
140 if not val:
141 missed.append(opt)
142 if missed:
143 print "The following build artifacts are not specified:"
144 print " " + ", ".join(missed)
145 sys.exit(1)
146
147 if options.image_name:
148 BB_VARS.default_image = options.image_name
149 else:
150 options.build_check = False
151
152 if options.vars_dir:
153 BB_VARS.vars_dir = options.vars_dir
154
155 if options.build_check:
156 print "Checking basic build environment..."
157 if not engine.verify_build_env():
158 print "Couldn't verify build environment, exiting\n"
159 sys.exit(1)
160 else:
161 print "Done.\n"
162
163 bootimg_dir = ""
164
165 if options.image_name:
166 if options.build_rootfs:
167 argv = ["bitbake", options.image_name]
168 if options.debug:
169 argv.append("--debug")
170
171 print "Building rootfs...\n"
172 if bitbake_main(BitBakeConfigParameters(argv),
173 cookerdata.CookerConfiguration()):
174 sys.exit(1)
175
176 rootfs_dir = get_bitbake_var("IMAGE_ROOTFS", options.image_name)
177 kernel_dir = get_bitbake_var("DEPLOY_DIR_IMAGE", options.image_name)
178 native_sysroot = get_bitbake_var("STAGING_DIR_NATIVE",
179 options.image_name)
180 else:
181 if options.build_rootfs:
182 print "Image name is not specified, exiting. (Use -e/--image-name to specify it)\n"
183 sys.exit(1)
184
185 wks_file = args[0]
186
187 if not wks_file.endswith(".wks"):
188 wks_file = engine.find_canned_image(scripts_path, wks_file)
189 if not wks_file:
190 print "No image named %s found, exiting. (Use 'wic list images' "\
191 "to list available images, or specify a fully-qualified OE "\
192 "kickstart (.wks) filename)\n" % args[0]
193 sys.exit(1)
194
195 image_output_dir = ""
196 if options.outdir:
197 image_output_dir = options.outdir
198
199 if not options.image_name:
200 rootfs_dir = ''
201 if 'ROOTFS_DIR' in options.rootfs_dir:
202 rootfs_dir = options.rootfs_dir['ROOTFS_DIR']
203 bootimg_dir = options.bootimg_dir
204 kernel_dir = options.kernel_dir
205 native_sysroot = options.native_sysroot
206 if rootfs_dir and not os.path.isdir(rootfs_dir):
207 print "--roofs-dir (-r) not found, exiting\n"
208 sys.exit(1)
209 if not os.path.isdir(bootimg_dir):
210 print "--bootimg-dir (-b) not found, exiting\n"
211 sys.exit(1)
212 if not os.path.isdir(kernel_dir):
213 print "--kernel-dir (-k) not found, exiting\n"
214 sys.exit(1)
215 if not os.path.isdir(native_sysroot):
216 print "--native-sysroot (-n) not found, exiting\n"
217 sys.exit(1)
218 else:
219 not_found = not_found_dir = ""
220 if not os.path.isdir(rootfs_dir):
221 (not_found, not_found_dir) = ("rootfs-dir", rootfs_dir)
222 elif not os.path.isdir(kernel_dir):
223 (not_found, not_found_dir) = ("kernel-dir", kernel_dir)
224 elif not os.path.isdir(native_sysroot):
225 (not_found, not_found_dir) = ("native-sysroot", native_sysroot)
226 if not_found:
227 if not not_found_dir:
228 not_found_dir = "Completely missing artifact - wrong image (.wks) used?"
229 print "Build artifacts not found, exiting."
230 print " (Please check that the build artifacts for the machine"
231 print " selected in local.conf actually exist and that they"
232 print " are the correct artifacts for the image (.wks file)).\n"
233 print "The artifact that couldn't be found was %s:\n %s" % \
234 (not_found, not_found_dir)
235 sys.exit(1)
236
237 krootfs_dir = options.rootfs_dir
238 if krootfs_dir is None:
239 krootfs_dir = {}
240 krootfs_dir['ROOTFS_DIR'] = rootfs_dir
241
242 rootfs_dir = rootfs_dir_to_args(krootfs_dir)
243
244 print "Creating image(s)...\n"
245 engine.wic_create(wks_file, rootfs_dir, bootimg_dir, kernel_dir,
246 native_sysroot, scripts_path, image_output_dir,
247 options.compressor, options.debug)
248
249
250def wic_list_subcommand(args, usage_str):
251 """
252 Command-line handling for listing available images.
253 The real work is done by image.engine.wic_list()
254 """
255 parser = optparse.OptionParser(usage=usage_str)
256 args = parser.parse_args(args)[1]
257
258 if not engine.wic_list(args, scripts_path):
259 logging.error("Bad list arguments, exiting\n")
260 parser.print_help()
261 sys.exit(1)
262
263
264def wic_help_topic_subcommand(args, usage_str):
265 """
266 Command-line handling for help-only 'subcommands'. This is
267 essentially a dummy command that doesn nothing but allow users to
268 use the existing subcommand infrastructure to display help on a
269 particular topic not attached to any particular subcommand.
270 """
271 pass
272
273
274wic_help_topic_usage = """
275"""
276
277subcommands = {
278 "create": [wic_create_subcommand,
279 hlp.wic_create_usage,
280 hlp.wic_create_help],
281 "list": [wic_list_subcommand,
282 hlp.wic_list_usage,
283 hlp.wic_list_help],
284 "plugins": [wic_help_topic_subcommand,
285 wic_help_topic_usage,
286 hlp.get_wic_plugins_help],
287 "overview": [wic_help_topic_subcommand,
288 wic_help_topic_usage,
289 hlp.wic_overview_help],
290 "kickstart": [wic_help_topic_subcommand,
291 wic_help_topic_usage,
292 hlp.wic_kickstart_help],
293}
294
295
296def start_logging(loglevel):
297 logging.basicConfig(filname='wic.log', filemode='w', level=loglevel)
298
299
300def main(argv):
301 parser = optparse.OptionParser(version="wic version %s" % __version__,
302 usage=hlp.wic_usage)
303
304 parser.disable_interspersed_args()
305
306 args = parser.parse_args(argv)[1]
307
308 if len(args):
309 if args[0] == "help":
310 if len(args) == 1:
311 parser.print_help()
312 sys.exit(1)
313
314 return hlp.invoke_subcommand(args, parser, hlp.wic_help_usage, subcommands)
315
316
317if __name__ == "__main__":
318 try:
319 sys.exit(main(sys.argv[1:]))
320 except WicError as err:
321 print >> sys.stderr, "ERROR:", err
322 sys.exit(1)
323