blob: fe2c33f0e7b25c41aebee8c597f5541e81cc6e60 [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)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050044
45bitbake_exe = spawn.find_executable('bitbake')
46if bitbake_exe:
47 bitbake_path = os.path.join(os.path.dirname(bitbake_exe), '../lib')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050048 sys.path.insert(0, bitbake_path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050049 from bb import cookerdata
50 from bb.main import bitbake_main, BitBakeConfigParameters
51else:
52 bitbake_main = None
53
54from wic.utils.oe.misc import get_bitbake_var, BB_VARS
55from wic.utils.errors import WicError
56from wic import engine
57from wic import help as hlp
58
59def rootfs_dir_to_args(krootfs_dir):
60 """
61 Get a rootfs_dir dict and serialize to string
62 """
63 rootfs_dir = ''
64 for key, val in krootfs_dir.items():
65 rootfs_dir += ' '
66 rootfs_dir += '='.join([key, val])
67 return rootfs_dir.strip()
68
69def callback_rootfs_dir(option, opt, value, parser):
70 """
71 Build a dict using --rootfs_dir connection=dir
72 """
73 if not type(parser.values.rootfs_dir) is dict:
74 parser.values.rootfs_dir = dict()
75
76 if '=' in value:
77 (key, rootfs_dir) = value.split('=')
78 else:
79 key = 'ROOTFS_DIR'
80 rootfs_dir = value
81
82 parser.values.rootfs_dir[key] = rootfs_dir
83
84def wic_create_subcommand(args, usage_str):
85 """
86 Command-line handling for image creation. The real work is done
87 by image.engine.wic_create()
88 """
89 parser = optparse.OptionParser(usage=usage_str)
90
91 parser.add_option("-o", "--outdir", dest="outdir",
92 help="name of directory to create image in")
93 parser.add_option("-e", "--image-name", dest="image_name",
94 help="name of the image to use the artifacts from "
95 "e.g. core-image-sato")
96 parser.add_option("-r", "--rootfs-dir", dest="rootfs_dir", type="string",
97 action="callback", callback=callback_rootfs_dir,
98 help="path to the /rootfs dir to use as the "
99 ".wks rootfs source")
100 parser.add_option("-b", "--bootimg-dir", dest="bootimg_dir",
101 help="path to the dir containing the boot artifacts "
102 "(e.g. /EFI or /syslinux dirs) to use as the "
103 ".wks bootimg source")
104 parser.add_option("-k", "--kernel-dir", dest="kernel_dir",
105 help="path to the dir containing the kernel to use "
106 "in the .wks bootimg")
107 parser.add_option("-n", "--native-sysroot", dest="native_sysroot",
108 help="path to the native sysroot containing the tools "
109 "to use to build the image")
110 parser.add_option("-p", "--skip-build-check", dest="build_check",
111 action="store_false", default=True, help="skip the build check")
112 parser.add_option("-f", "--build-rootfs", action="store_true", help="build rootfs")
113 parser.add_option("-c", "--compress-with", choices=("gzip", "bzip2", "xz"),
114 dest='compressor',
115 help="compress image with specified compressor")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600116 parser.add_option("-m", "--bmap", action="store_true", help="generate .bmap")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500117 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:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600143 print("The following build artifacts are not specified:")
144 print(" " + ", ".join(missed))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500145 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:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600156 print("Checking basic build environment...")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500157 if not engine.verify_build_env():
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600158 print("Couldn't verify build environment, exiting\n")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500159 sys.exit(1)
160 else:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600161 print("Done.\n")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500162
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
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600171 print("Building rootfs...\n")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500172 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:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600182 print("Image name is not specified, exiting. (Use -e/--image-name to specify it)\n")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500183 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:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600190 print("No image named %s found, exiting. (Use 'wic list images' "\
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500191 "to list available images, or specify a fully-qualified OE "\
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600192 "kickstart (.wks) filename)\n" % args[0])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500193 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):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600207 print("--roofs-dir (-r) not found, exiting\n")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500208 sys.exit(1)
209 if not os.path.isdir(bootimg_dir):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600210 print("--bootimg-dir (-b) not found, exiting\n")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500211 sys.exit(1)
212 if not os.path.isdir(kernel_dir):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600213 print("--kernel-dir (-k) not found, exiting\n")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500214 sys.exit(1)
215 if not os.path.isdir(native_sysroot):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600216 print("--native-sysroot (-n) not found, exiting\n")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500217 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?"
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600229 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))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500235 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
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600244 print("Creating image(s)...\n")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500245 engine.wic_create(wks_file, rootfs_dir, bootimg_dir, kernel_dir,
246 native_sysroot, scripts_path, image_output_dir,
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600247 options.compressor, options.bmap, options.debug)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500248
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):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600297 logging.basicConfig(filename='wic.log', filemode='w', level=loglevel)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500298
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:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600321 print("ERROR:", err, file=sys.stderr)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500322 sys.exit(1)
323