| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 1 | #!/usr/bin/env python3 | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 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 | # | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 31 | __version__ = "0.2.0" | 
 | 32 |  | 
 | 33 | # Python Standard Library modules | 
 | 34 | import os | 
 | 35 | import sys | 
 | 36 | import optparse | 
 | 37 | import logging | 
 | 38 | from distutils import spawn | 
 | 39 |  | 
 | 40 | # External modules | 
 | 41 | scripts_path = os.path.abspath(os.path.dirname(__file__)) | 
 | 42 | lib_path = scripts_path + '/lib' | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 43 | sys.path.insert(0, lib_path) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 44 |  | 
 | 45 | bitbake_exe = spawn.find_executable('bitbake') | 
 | 46 | if bitbake_exe: | 
 | 47 |     bitbake_path = os.path.join(os.path.dirname(bitbake_exe), '../lib') | 
| Patrick Williams | d8c66bc | 2016-06-20 12:57:21 -0500 | [diff] [blame] | 48 |     sys.path.insert(0, bitbake_path) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 49 |     from bb import cookerdata | 
 | 50 |     from bb.main import bitbake_main, BitBakeConfigParameters | 
 | 51 | else: | 
 | 52 |     bitbake_main = None | 
 | 53 |  | 
 | 54 | from wic.utils.oe.misc import get_bitbake_var, BB_VARS | 
 | 55 | from wic.utils.errors import WicError | 
 | 56 | from wic import engine | 
 | 57 | from wic import help as hlp | 
 | 58 |  | 
 | 59 | def 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 |  | 
 | 69 | def 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 |  | 
 | 84 | def 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 Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 116 |     parser.add_option("-m", "--bmap", action="store_true", help="generate .bmap") | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 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: | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 143 |             print("The following build artifacts are not specified:") | 
 | 144 |             print("  " + ", ".join(missed)) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 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: | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 156 |         print("Checking basic build environment...") | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 157 |         if not engine.verify_build_env(): | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 158 |             print("Couldn't verify build environment, exiting\n") | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 159 |             sys.exit(1) | 
 | 160 |         else: | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 161 |             print("Done.\n") | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 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 |  | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 171 |             print("Building rootfs...\n") | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 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: | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 182 |             print("Image name is not specified, exiting. (Use -e/--image-name to specify it)\n") | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 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: | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 190 |             print("No image named %s found, exiting.  (Use 'wic list images' "\ | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 191 |                   "to list available images, or specify a fully-qualified OE "\ | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 192 |                   "kickstart (.wks) filename)\n" % args[0]) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 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): | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 207 |             print("--roofs-dir (-r) not found, exiting\n") | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 208 |             sys.exit(1) | 
 | 209 |         if not os.path.isdir(bootimg_dir): | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 210 |             print("--bootimg-dir (-b) not found, exiting\n") | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 211 |             sys.exit(1) | 
 | 212 |         if not os.path.isdir(kernel_dir): | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 213 |             print("--kernel-dir (-k) not found, exiting\n") | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 214 |             sys.exit(1) | 
 | 215 |         if not os.path.isdir(native_sysroot): | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 216 |             print("--native-sysroot (-n) not found, exiting\n") | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 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?" | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 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)) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 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 |  | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 244 |     print("Creating image(s)...\n") | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 245 |     engine.wic_create(wks_file, rootfs_dir, bootimg_dir, kernel_dir, | 
 | 246 |                       native_sysroot, scripts_path, image_output_dir, | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 247 |                       options.compressor, options.bmap, options.debug) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 248 |  | 
 | 249 |  | 
 | 250 | def 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 |  | 
 | 264 | def 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 |  | 
 | 274 | wic_help_topic_usage = """ | 
 | 275 | """ | 
 | 276 |  | 
 | 277 | subcommands = { | 
 | 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 |  | 
 | 296 | def start_logging(loglevel): | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 297 |     logging.basicConfig(filename='wic.log', filemode='w', level=loglevel) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 298 |  | 
 | 299 |  | 
 | 300 | def 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 |  | 
 | 317 | if __name__ == "__main__": | 
 | 318 |     try: | 
 | 319 |         sys.exit(main(sys.argv[1:])) | 
 | 320 |     except WicError as err: | 
| Patrick Williams | c0f7c04 | 2017-02-23 20:41:17 -0600 | [diff] [blame] | 321 |         print("ERROR:", err, file=sys.stderr) | 
| Patrick Williams | c124f4f | 2015-09-15 14:41:29 -0500 | [diff] [blame] | 322 |         sys.exit(1) | 
 | 323 |  |