blob: a5f2dbfc6f2f20e5e6415b0c260cc34ffff97e96 [file] [log] [blame]
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001#!/usr/bin/env python3
Patrick Williamsc124f4f2015-09-15 14:41:29 -05002# 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#
Patrick Williamsc124f4f2015-09-15 14:41:29 -050031__version__ = "0.2.0"
32
33# Python Standard Library modules
34import os
35import sys
36import optparse
37import logging
38from distutils import spawn
39
40# External modules
41scripts_path = os.path.abspath(os.path.dirname(__file__))
42lib_path = scripts_path + '/lib'
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050043sys.path.insert(0, lib_path)
Brad Bishop6e60e8b2018-02-01 10:27:11 -050044oe_lib_path = os.path.join(os.path.dirname(scripts_path), 'meta', 'lib')
45sys.path.insert(0, oe_lib_path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050046
47bitbake_exe = spawn.find_executable('bitbake')
48if bitbake_exe:
49 bitbake_path = os.path.join(os.path.dirname(bitbake_exe), '../lib')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050050 sys.path.insert(0, bitbake_path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050051 from bb import cookerdata
52 from bb.main import bitbake_main, BitBakeConfigParameters
53else:
54 bitbake_main = None
55
Brad Bishop6e60e8b2018-02-01 10:27:11 -050056from wic import WicError
57from wic.utils.misc import get_bitbake_var, BB_VARS
Patrick Williamsc124f4f2015-09-15 14:41:29 -050058from wic import engine
59from wic import help as hlp
60
Brad Bishop6e60e8b2018-02-01 10:27:11 -050061
62def wic_logger():
63 """Create and convfigure wic logger."""
64 logger = logging.getLogger('wic')
65 logger.setLevel(logging.INFO)
66
67 handler = logging.StreamHandler()
68
69 formatter = logging.Formatter('%(levelname)s: %(message)s')
70 handler.setFormatter(formatter)
71
72 logger.addHandler(handler)
73
74 return logger
75
76logger = wic_logger()
77
Patrick Williamsc124f4f2015-09-15 14:41:29 -050078def rootfs_dir_to_args(krootfs_dir):
79 """
80 Get a rootfs_dir dict and serialize to string
81 """
82 rootfs_dir = ''
83 for key, val in krootfs_dir.items():
84 rootfs_dir += ' '
85 rootfs_dir += '='.join([key, val])
86 return rootfs_dir.strip()
87
88def callback_rootfs_dir(option, opt, value, parser):
89 """
90 Build a dict using --rootfs_dir connection=dir
91 """
92 if not type(parser.values.rootfs_dir) is dict:
93 parser.values.rootfs_dir = dict()
94
95 if '=' in value:
96 (key, rootfs_dir) = value.split('=')
97 else:
98 key = 'ROOTFS_DIR'
99 rootfs_dir = value
100
101 parser.values.rootfs_dir[key] = rootfs_dir
102
103def wic_create_subcommand(args, usage_str):
104 """
105 Command-line handling for image creation. The real work is done
106 by image.engine.wic_create()
107 """
108 parser = optparse.OptionParser(usage=usage_str)
109
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500110 parser.add_option("-o", "--outdir", dest="outdir", default='.',
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500111 help="name of directory to create image in")
112 parser.add_option("-e", "--image-name", dest="image_name",
113 help="name of the image to use the artifacts from "
114 "e.g. core-image-sato")
115 parser.add_option("-r", "--rootfs-dir", dest="rootfs_dir", type="string",
116 action="callback", callback=callback_rootfs_dir,
117 help="path to the /rootfs dir to use as the "
118 ".wks rootfs source")
119 parser.add_option("-b", "--bootimg-dir", dest="bootimg_dir",
120 help="path to the dir containing the boot artifacts "
121 "(e.g. /EFI or /syslinux dirs) to use as the "
122 ".wks bootimg source")
123 parser.add_option("-k", "--kernel-dir", dest="kernel_dir",
124 help="path to the dir containing the kernel to use "
125 "in the .wks bootimg")
126 parser.add_option("-n", "--native-sysroot", dest="native_sysroot",
127 help="path to the native sysroot containing the tools "
128 "to use to build the image")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500129 parser.add_option("-s", "--skip-build-check", dest="build_check",
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500130 action="store_false", default=True, help="skip the build check")
131 parser.add_option("-f", "--build-rootfs", action="store_true", help="build rootfs")
132 parser.add_option("-c", "--compress-with", choices=("gzip", "bzip2", "xz"),
133 dest='compressor',
134 help="compress image with specified compressor")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600135 parser.add_option("-m", "--bmap", action="store_true", help="generate .bmap")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500136 parser.add_option("-v", "--vars", dest='vars_dir',
137 help="directory with <image>.env files that store "
138 "bitbake variables")
139 parser.add_option("-D", "--debug", dest="debug", action="store_true",
140 default=False, help="output debug information")
141
142 (options, args) = parser.parse_args(args)
143
144 if len(args) != 1:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500145 parser.print_help()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500146 raise WicError("Wrong number of arguments, exiting")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500147
148 if options.build_rootfs and not bitbake_main:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500149 raise WicError("Can't build rootfs as bitbake is not in the $PATH")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500150
151 if not options.image_name:
152 missed = []
153 for val, opt in [(options.rootfs_dir, 'rootfs-dir'),
154 (options.bootimg_dir, 'bootimg-dir'),
155 (options.kernel_dir, 'kernel-dir'),
156 (options.native_sysroot, 'native-sysroot')]:
157 if not val:
158 missed.append(opt)
159 if missed:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500160 raise WicError("The following build artifacts are not specified: %s" %
161 ", ".join(missed))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500162
163 if options.image_name:
164 BB_VARS.default_image = options.image_name
165 else:
166 options.build_check = False
167
168 if options.vars_dir:
169 BB_VARS.vars_dir = options.vars_dir
170
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500171 if options.build_check and not engine.verify_build_env():
172 raise WicError("Couldn't verify build environment, exiting")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500173
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500174 if options.debug:
175 logger.setLevel(logging.DEBUG)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500176
177 if options.image_name:
178 if options.build_rootfs:
179 argv = ["bitbake", options.image_name]
180 if options.debug:
181 argv.append("--debug")
182
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500183 logger.info("Building rootfs...\n")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500184 if bitbake_main(BitBakeConfigParameters(argv),
185 cookerdata.CookerConfiguration()):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500186 raise WicError("bitbake exited with error")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500187
188 rootfs_dir = get_bitbake_var("IMAGE_ROOTFS", options.image_name)
189 kernel_dir = get_bitbake_var("DEPLOY_DIR_IMAGE", options.image_name)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500190 bootimg_dir = get_bitbake_var("STAGING_DATADIR", options.image_name)
191 native_sysroot = get_bitbake_var("RECIPE_SYSROOT_NATIVE",
192 options.image_name) #, cache=False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500193 else:
194 if options.build_rootfs:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500195 raise WicError("Image name is not specified, exiting. "
196 "(Use -e/--image-name to specify it)")
197 native_sysroot = options.native_sysroot
198
199 if not native_sysroot or not os.path.isdir(native_sysroot):
200 logger.info("Building wic-tools...\n")
201 if bitbake_main(BitBakeConfigParameters("bitbake wic-tools".split()),
202 cookerdata.CookerConfiguration()):
203 raise WicError("bitbake wic-tools failed")
204 native_sysroot = get_bitbake_var("RECIPE_SYSROOT_NATIVE", "wic-tools")
205 if not native_sysroot:
206 raise WicError("Unable to find the location of the native "
207 "tools sysroot to use")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500208
209 wks_file = args[0]
210
211 if not wks_file.endswith(".wks"):
212 wks_file = engine.find_canned_image(scripts_path, wks_file)
213 if not wks_file:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500214 raise WicError("No image named %s found, exiting. (Use 'wic list images' "
215 "to list available images, or specify a fully-qualified OE "
216 "kickstart (.wks) filename)" % args[0])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500217
218 if not options.image_name:
219 rootfs_dir = ''
220 if 'ROOTFS_DIR' in options.rootfs_dir:
221 rootfs_dir = options.rootfs_dir['ROOTFS_DIR']
222 bootimg_dir = options.bootimg_dir
223 kernel_dir = options.kernel_dir
224 native_sysroot = options.native_sysroot
225 if rootfs_dir and not os.path.isdir(rootfs_dir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500226 raise WicError("--rootfs-dir (-r) not found, exiting")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500227 if not os.path.isdir(bootimg_dir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500228 raise WicError("--bootimg-dir (-b) not found, exiting")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500229 if not os.path.isdir(kernel_dir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500230 raise WicError("--kernel-dir (-k) not found, exiting")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500231 if not os.path.isdir(native_sysroot):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500232 raise WicError("--native-sysroot (-n) not found, exiting")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500233 else:
234 not_found = not_found_dir = ""
235 if not os.path.isdir(rootfs_dir):
236 (not_found, not_found_dir) = ("rootfs-dir", rootfs_dir)
237 elif not os.path.isdir(kernel_dir):
238 (not_found, not_found_dir) = ("kernel-dir", kernel_dir)
239 elif not os.path.isdir(native_sysroot):
240 (not_found, not_found_dir) = ("native-sysroot", native_sysroot)
241 if not_found:
242 if not not_found_dir:
243 not_found_dir = "Completely missing artifact - wrong image (.wks) used?"
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500244 logger.info("Build artifacts not found, exiting.")
245 logger.info(" (Please check that the build artifacts for the machine")
246 logger.info(" selected in local.conf actually exist and that they")
247 logger.info(" are the correct artifacts for the image (.wks file)).\n")
248 raise WicError("The artifact that couldn't be found was %s:\n %s", not_found, not_found_dir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500249
250 krootfs_dir = options.rootfs_dir
251 if krootfs_dir is None:
252 krootfs_dir = {}
253 krootfs_dir['ROOTFS_DIR'] = rootfs_dir
254
255 rootfs_dir = rootfs_dir_to_args(krootfs_dir)
256
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500257 logger.info("Creating image(s)...\n")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500258 engine.wic_create(wks_file, rootfs_dir, bootimg_dir, kernel_dir,
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500259 native_sysroot, options)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500260
261
262def wic_list_subcommand(args, usage_str):
263 """
264 Command-line handling for listing available images.
265 The real work is done by image.engine.wic_list()
266 """
267 parser = optparse.OptionParser(usage=usage_str)
268 args = parser.parse_args(args)[1]
269
270 if not engine.wic_list(args, scripts_path):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500271 parser.print_help()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500272 raise WicError("Bad list arguments, exiting")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500273
274
275def wic_help_topic_subcommand(args, usage_str):
276 """
277 Command-line handling for help-only 'subcommands'. This is
278 essentially a dummy command that doesn nothing but allow users to
279 use the existing subcommand infrastructure to display help on a
280 particular topic not attached to any particular subcommand.
281 """
282 pass
283
284
285wic_help_topic_usage = """
286"""
287
288subcommands = {
289 "create": [wic_create_subcommand,
290 hlp.wic_create_usage,
291 hlp.wic_create_help],
292 "list": [wic_list_subcommand,
293 hlp.wic_list_usage,
294 hlp.wic_list_help],
295 "plugins": [wic_help_topic_subcommand,
296 wic_help_topic_usage,
297 hlp.get_wic_plugins_help],
298 "overview": [wic_help_topic_subcommand,
299 wic_help_topic_usage,
300 hlp.wic_overview_help],
301 "kickstart": [wic_help_topic_subcommand,
302 wic_help_topic_usage,
303 hlp.wic_kickstart_help],
304}
305
306
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500307def main(argv):
308 parser = optparse.OptionParser(version="wic version %s" % __version__,
309 usage=hlp.wic_usage)
310
311 parser.disable_interspersed_args()
312
313 args = parser.parse_args(argv)[1]
314
315 if len(args):
316 if args[0] == "help":
317 if len(args) == 1:
318 parser.print_help()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500319 raise WicError("help command requires parameter")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500320
321 return hlp.invoke_subcommand(args, parser, hlp.wic_help_usage, subcommands)
322
323
324if __name__ == "__main__":
325 try:
326 sys.exit(main(sys.argv[1:]))
327 except WicError as err:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500328 print()
329 logger.error(err)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500330 sys.exit(1)