1*4882a593Smuzhiyun#!/usr/bin/env python3 2*4882a593Smuzhiyun# 3*4882a593Smuzhiyun# Copyright (c) 2013, Intel Corporation. 4*4882a593Smuzhiyun# 5*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only 6*4882a593Smuzhiyun# 7*4882a593Smuzhiyun# DESCRIPTION 'wic' is the OpenEmbedded Image Creator that users can 8*4882a593Smuzhiyun# use to generate bootable images. Invoking it without any arguments 9*4882a593Smuzhiyun# will display help screens for the 'wic' command and list the 10*4882a593Smuzhiyun# available 'wic' subcommands. Invoking a subcommand without any 11*4882a593Smuzhiyun# arguments will likewise display help screens for the specified 12*4882a593Smuzhiyun# subcommand. Please use that interface for detailed help. 13*4882a593Smuzhiyun# 14*4882a593Smuzhiyun# AUTHORS 15*4882a593Smuzhiyun# Tom Zanussi <tom.zanussi (at] linux.intel.com> 16*4882a593Smuzhiyun# 17*4882a593Smuzhiyun__version__ = "0.2.0" 18*4882a593Smuzhiyun 19*4882a593Smuzhiyun# Python Standard Library modules 20*4882a593Smuzhiyunimport os 21*4882a593Smuzhiyunimport sys 22*4882a593Smuzhiyunimport argparse 23*4882a593Smuzhiyunimport logging 24*4882a593Smuzhiyunimport subprocess 25*4882a593Smuzhiyunimport shutil 26*4882a593Smuzhiyun 27*4882a593Smuzhiyunfrom collections import namedtuple 28*4882a593Smuzhiyun 29*4882a593Smuzhiyun# External modules 30*4882a593Smuzhiyunscripts_path = os.path.dirname(os.path.realpath(__file__)) 31*4882a593Smuzhiyunlib_path = scripts_path + '/lib' 32*4882a593Smuzhiyunsys.path.insert(0, lib_path) 33*4882a593Smuzhiyunimport scriptpath 34*4882a593Smuzhiyunscriptpath.add_oe_lib_path() 35*4882a593Smuzhiyun 36*4882a593Smuzhiyun# Check whether wic is running within eSDK environment 37*4882a593Smuzhiyunsdkroot = scripts_path 38*4882a593Smuzhiyunif os.environ.get('SDKTARGETSYSROOT'): 39*4882a593Smuzhiyun while sdkroot != '' and sdkroot != os.sep: 40*4882a593Smuzhiyun if os.path.exists(os.path.join(sdkroot, '.devtoolbase')): 41*4882a593Smuzhiyun # Set BUILDDIR for wic to work within eSDK 42*4882a593Smuzhiyun os.environ['BUILDDIR'] = sdkroot 43*4882a593Smuzhiyun # .devtoolbase only exists within eSDK 44*4882a593Smuzhiyun # If found, initialize bitbake path for eSDK environment and append to PATH 45*4882a593Smuzhiyun sdkroot = os.path.join(os.path.dirname(scripts_path), 'bitbake', 'bin') 46*4882a593Smuzhiyun os.environ['PATH'] += ":" + sdkroot 47*4882a593Smuzhiyun break 48*4882a593Smuzhiyun sdkroot = os.path.dirname(sdkroot) 49*4882a593Smuzhiyun 50*4882a593Smuzhiyunbitbake_exe = shutil.which('bitbake') 51*4882a593Smuzhiyunif bitbake_exe: 52*4882a593Smuzhiyun bitbake_path = scriptpath.add_bitbake_lib_path() 53*4882a593Smuzhiyun import bb 54*4882a593Smuzhiyun 55*4882a593Smuzhiyunfrom wic import WicError 56*4882a593Smuzhiyunfrom wic.misc import get_bitbake_var, BB_VARS 57*4882a593Smuzhiyunfrom wic import engine 58*4882a593Smuzhiyunfrom wic import help as hlp 59*4882a593Smuzhiyun 60*4882a593Smuzhiyun 61*4882a593Smuzhiyundef wic_logger(): 62*4882a593Smuzhiyun """Create and convfigure wic logger.""" 63*4882a593Smuzhiyun logger = logging.getLogger('wic') 64*4882a593Smuzhiyun logger.setLevel(logging.INFO) 65*4882a593Smuzhiyun 66*4882a593Smuzhiyun handler = logging.StreamHandler() 67*4882a593Smuzhiyun 68*4882a593Smuzhiyun formatter = logging.Formatter('%(levelname)s: %(message)s') 69*4882a593Smuzhiyun handler.setFormatter(formatter) 70*4882a593Smuzhiyun 71*4882a593Smuzhiyun logger.addHandler(handler) 72*4882a593Smuzhiyun 73*4882a593Smuzhiyun return logger 74*4882a593Smuzhiyun 75*4882a593Smuzhiyunlogger = wic_logger() 76*4882a593Smuzhiyun 77*4882a593Smuzhiyundef rootfs_dir_to_args(krootfs_dir): 78*4882a593Smuzhiyun """ 79*4882a593Smuzhiyun Get a rootfs_dir dict and serialize to string 80*4882a593Smuzhiyun """ 81*4882a593Smuzhiyun rootfs_dir = '' 82*4882a593Smuzhiyun for key, val in krootfs_dir.items(): 83*4882a593Smuzhiyun rootfs_dir += ' ' 84*4882a593Smuzhiyun rootfs_dir += '='.join([key, val]) 85*4882a593Smuzhiyun return rootfs_dir.strip() 86*4882a593Smuzhiyun 87*4882a593Smuzhiyun 88*4882a593Smuzhiyunclass RootfsArgAction(argparse.Action): 89*4882a593Smuzhiyun def __init__(self, **kwargs): 90*4882a593Smuzhiyun super().__init__(**kwargs) 91*4882a593Smuzhiyun 92*4882a593Smuzhiyun def __call__(self, parser, namespace, value, option_string=None): 93*4882a593Smuzhiyun if not "rootfs_dir" in vars(namespace) or \ 94*4882a593Smuzhiyun not type(namespace.__dict__['rootfs_dir']) is dict: 95*4882a593Smuzhiyun namespace.__dict__['rootfs_dir'] = {} 96*4882a593Smuzhiyun 97*4882a593Smuzhiyun if '=' in value: 98*4882a593Smuzhiyun (key, rootfs_dir) = value.split('=') 99*4882a593Smuzhiyun else: 100*4882a593Smuzhiyun key = 'ROOTFS_DIR' 101*4882a593Smuzhiyun rootfs_dir = value 102*4882a593Smuzhiyun 103*4882a593Smuzhiyun namespace.__dict__['rootfs_dir'][key] = rootfs_dir 104*4882a593Smuzhiyun 105*4882a593Smuzhiyun 106*4882a593Smuzhiyundef wic_create_subcommand(options, usage_str): 107*4882a593Smuzhiyun """ 108*4882a593Smuzhiyun Command-line handling for image creation. The real work is done 109*4882a593Smuzhiyun by image.engine.wic_create() 110*4882a593Smuzhiyun """ 111*4882a593Smuzhiyun if options.build_rootfs and not bitbake_exe: 112*4882a593Smuzhiyun raise WicError("Can't build rootfs as bitbake is not in the $PATH") 113*4882a593Smuzhiyun 114*4882a593Smuzhiyun if not options.image_name: 115*4882a593Smuzhiyun missed = [] 116*4882a593Smuzhiyun for val, opt in [(options.rootfs_dir, 'rootfs-dir'), 117*4882a593Smuzhiyun (options.bootimg_dir, 'bootimg-dir'), 118*4882a593Smuzhiyun (options.kernel_dir, 'kernel-dir'), 119*4882a593Smuzhiyun (options.native_sysroot, 'native-sysroot')]: 120*4882a593Smuzhiyun if not val: 121*4882a593Smuzhiyun missed.append(opt) 122*4882a593Smuzhiyun if missed: 123*4882a593Smuzhiyun raise WicError("The following build artifacts are not specified: %s" % 124*4882a593Smuzhiyun ", ".join(missed)) 125*4882a593Smuzhiyun 126*4882a593Smuzhiyun if options.image_name: 127*4882a593Smuzhiyun BB_VARS.default_image = options.image_name 128*4882a593Smuzhiyun else: 129*4882a593Smuzhiyun options.build_check = False 130*4882a593Smuzhiyun 131*4882a593Smuzhiyun if options.vars_dir: 132*4882a593Smuzhiyun BB_VARS.vars_dir = options.vars_dir 133*4882a593Smuzhiyun 134*4882a593Smuzhiyun if options.build_check and not engine.verify_build_env(): 135*4882a593Smuzhiyun raise WicError("Couldn't verify build environment, exiting") 136*4882a593Smuzhiyun 137*4882a593Smuzhiyun if options.debug: 138*4882a593Smuzhiyun logger.setLevel(logging.DEBUG) 139*4882a593Smuzhiyun 140*4882a593Smuzhiyun if options.image_name: 141*4882a593Smuzhiyun if options.build_rootfs: 142*4882a593Smuzhiyun argv = ["bitbake", options.image_name] 143*4882a593Smuzhiyun if options.debug: 144*4882a593Smuzhiyun argv.append("--debug") 145*4882a593Smuzhiyun 146*4882a593Smuzhiyun logger.info("Building rootfs...\n") 147*4882a593Smuzhiyun subprocess.check_call(argv) 148*4882a593Smuzhiyun 149*4882a593Smuzhiyun rootfs_dir = get_bitbake_var("IMAGE_ROOTFS", options.image_name) 150*4882a593Smuzhiyun kernel_dir = get_bitbake_var("DEPLOY_DIR_IMAGE", options.image_name) 151*4882a593Smuzhiyun bootimg_dir = get_bitbake_var("STAGING_DATADIR", options.image_name) 152*4882a593Smuzhiyun 153*4882a593Smuzhiyun native_sysroot = options.native_sysroot 154*4882a593Smuzhiyun if options.vars_dir and not native_sysroot: 155*4882a593Smuzhiyun native_sysroot = get_bitbake_var("RECIPE_SYSROOT_NATIVE", options.image_name) 156*4882a593Smuzhiyun else: 157*4882a593Smuzhiyun if options.build_rootfs: 158*4882a593Smuzhiyun raise WicError("Image name is not specified, exiting. " 159*4882a593Smuzhiyun "(Use -e/--image-name to specify it)") 160*4882a593Smuzhiyun native_sysroot = options.native_sysroot 161*4882a593Smuzhiyun 162*4882a593Smuzhiyun if options.kernel_dir: 163*4882a593Smuzhiyun kernel_dir = options.kernel_dir 164*4882a593Smuzhiyun 165*4882a593Smuzhiyun if not options.vars_dir and (not native_sysroot or not os.path.isdir(native_sysroot)): 166*4882a593Smuzhiyun logger.info("Building wic-tools...\n") 167*4882a593Smuzhiyun subprocess.check_call(["bitbake", "wic-tools"]) 168*4882a593Smuzhiyun native_sysroot = get_bitbake_var("RECIPE_SYSROOT_NATIVE", "wic-tools") 169*4882a593Smuzhiyun 170*4882a593Smuzhiyun if not native_sysroot: 171*4882a593Smuzhiyun raise WicError("Unable to find the location of the native tools sysroot") 172*4882a593Smuzhiyun 173*4882a593Smuzhiyun wks_file = options.wks_file 174*4882a593Smuzhiyun 175*4882a593Smuzhiyun if not wks_file.endswith(".wks"): 176*4882a593Smuzhiyun wks_file = engine.find_canned_image(scripts_path, wks_file) 177*4882a593Smuzhiyun if not wks_file: 178*4882a593Smuzhiyun raise WicError("No image named %s found, exiting. (Use 'wic list images' " 179*4882a593Smuzhiyun "to list available images, or specify a fully-qualified OE " 180*4882a593Smuzhiyun "kickstart (.wks) filename)" % options.wks_file) 181*4882a593Smuzhiyun 182*4882a593Smuzhiyun if not options.image_name: 183*4882a593Smuzhiyun rootfs_dir = '' 184*4882a593Smuzhiyun if 'ROOTFS_DIR' in options.rootfs_dir: 185*4882a593Smuzhiyun rootfs_dir = options.rootfs_dir['ROOTFS_DIR'] 186*4882a593Smuzhiyun bootimg_dir = options.bootimg_dir 187*4882a593Smuzhiyun kernel_dir = options.kernel_dir 188*4882a593Smuzhiyun native_sysroot = options.native_sysroot 189*4882a593Smuzhiyun if rootfs_dir and not os.path.isdir(rootfs_dir): 190*4882a593Smuzhiyun raise WicError("--rootfs-dir (-r) not found, exiting") 191*4882a593Smuzhiyun if not os.path.isdir(bootimg_dir): 192*4882a593Smuzhiyun raise WicError("--bootimg-dir (-b) not found, exiting") 193*4882a593Smuzhiyun if not os.path.isdir(kernel_dir): 194*4882a593Smuzhiyun raise WicError("--kernel-dir (-k) not found, exiting") 195*4882a593Smuzhiyun if not os.path.isdir(native_sysroot): 196*4882a593Smuzhiyun raise WicError("--native-sysroot (-n) not found, exiting") 197*4882a593Smuzhiyun else: 198*4882a593Smuzhiyun not_found = not_found_dir = "" 199*4882a593Smuzhiyun if not os.path.isdir(rootfs_dir): 200*4882a593Smuzhiyun (not_found, not_found_dir) = ("rootfs-dir", rootfs_dir) 201*4882a593Smuzhiyun elif not os.path.isdir(kernel_dir): 202*4882a593Smuzhiyun (not_found, not_found_dir) = ("kernel-dir", kernel_dir) 203*4882a593Smuzhiyun elif not os.path.isdir(native_sysroot): 204*4882a593Smuzhiyun (not_found, not_found_dir) = ("native-sysroot", native_sysroot) 205*4882a593Smuzhiyun if not_found: 206*4882a593Smuzhiyun if not not_found_dir: 207*4882a593Smuzhiyun not_found_dir = "Completely missing artifact - wrong image (.wks) used?" 208*4882a593Smuzhiyun logger.info("Build artifacts not found, exiting.") 209*4882a593Smuzhiyun logger.info(" (Please check that the build artifacts for the machine") 210*4882a593Smuzhiyun logger.info(" selected in local.conf actually exist and that they") 211*4882a593Smuzhiyun logger.info(" are the correct artifacts for the image (.wks file)).\n") 212*4882a593Smuzhiyun raise WicError("The artifact that couldn't be found was %s:\n %s" % (not_found, not_found_dir)) 213*4882a593Smuzhiyun 214*4882a593Smuzhiyun krootfs_dir = options.rootfs_dir 215*4882a593Smuzhiyun if krootfs_dir is None: 216*4882a593Smuzhiyun krootfs_dir = {} 217*4882a593Smuzhiyun krootfs_dir['ROOTFS_DIR'] = rootfs_dir 218*4882a593Smuzhiyun 219*4882a593Smuzhiyun rootfs_dir = rootfs_dir_to_args(krootfs_dir) 220*4882a593Smuzhiyun 221*4882a593Smuzhiyun logger.info("Creating image(s)...\n") 222*4882a593Smuzhiyun engine.wic_create(wks_file, rootfs_dir, bootimg_dir, kernel_dir, 223*4882a593Smuzhiyun native_sysroot, options) 224*4882a593Smuzhiyun 225*4882a593Smuzhiyun 226*4882a593Smuzhiyundef wic_list_subcommand(args, usage_str): 227*4882a593Smuzhiyun """ 228*4882a593Smuzhiyun Command-line handling for listing available images. 229*4882a593Smuzhiyun The real work is done by image.engine.wic_list() 230*4882a593Smuzhiyun """ 231*4882a593Smuzhiyun if not engine.wic_list(args, scripts_path): 232*4882a593Smuzhiyun raise WicError("Bad list arguments, exiting") 233*4882a593Smuzhiyun 234*4882a593Smuzhiyun 235*4882a593Smuzhiyundef wic_ls_subcommand(args, usage_str): 236*4882a593Smuzhiyun """ 237*4882a593Smuzhiyun Command-line handling for list content of images. 238*4882a593Smuzhiyun The real work is done by engine.wic_ls() 239*4882a593Smuzhiyun """ 240*4882a593Smuzhiyun engine.wic_ls(args, args.native_sysroot) 241*4882a593Smuzhiyun 242*4882a593Smuzhiyundef wic_cp_subcommand(args, usage_str): 243*4882a593Smuzhiyun """ 244*4882a593Smuzhiyun Command-line handling for copying files/dirs to images. 245*4882a593Smuzhiyun The real work is done by engine.wic_cp() 246*4882a593Smuzhiyun """ 247*4882a593Smuzhiyun engine.wic_cp(args, args.native_sysroot) 248*4882a593Smuzhiyun 249*4882a593Smuzhiyundef wic_rm_subcommand(args, usage_str): 250*4882a593Smuzhiyun """ 251*4882a593Smuzhiyun Command-line handling for removing files/dirs from images. 252*4882a593Smuzhiyun The real work is done by engine.wic_rm() 253*4882a593Smuzhiyun """ 254*4882a593Smuzhiyun engine.wic_rm(args, args.native_sysroot) 255*4882a593Smuzhiyun 256*4882a593Smuzhiyundef wic_write_subcommand(args, usage_str): 257*4882a593Smuzhiyun """ 258*4882a593Smuzhiyun Command-line handling for writing images. 259*4882a593Smuzhiyun The real work is done by engine.wic_write() 260*4882a593Smuzhiyun """ 261*4882a593Smuzhiyun engine.wic_write(args, args.native_sysroot) 262*4882a593Smuzhiyun 263*4882a593Smuzhiyundef wic_help_subcommand(args, usage_str): 264*4882a593Smuzhiyun """ 265*4882a593Smuzhiyun Command-line handling for help subcommand to keep the current 266*4882a593Smuzhiyun structure of the function definitions. 267*4882a593Smuzhiyun """ 268*4882a593Smuzhiyun pass 269*4882a593Smuzhiyun 270*4882a593Smuzhiyun 271*4882a593Smuzhiyundef wic_help_topic_subcommand(usage_str, help_str): 272*4882a593Smuzhiyun """ 273*4882a593Smuzhiyun Display function for help 'sub-subcommands'. 274*4882a593Smuzhiyun """ 275*4882a593Smuzhiyun print(help_str) 276*4882a593Smuzhiyun return 277*4882a593Smuzhiyun 278*4882a593Smuzhiyun 279*4882a593Smuzhiyunwic_help_topic_usage = """ 280*4882a593Smuzhiyun""" 281*4882a593Smuzhiyun 282*4882a593Smuzhiyunhelptopics = { 283*4882a593Smuzhiyun "plugins": [wic_help_topic_subcommand, 284*4882a593Smuzhiyun wic_help_topic_usage, 285*4882a593Smuzhiyun hlp.wic_plugins_help], 286*4882a593Smuzhiyun "overview": [wic_help_topic_subcommand, 287*4882a593Smuzhiyun wic_help_topic_usage, 288*4882a593Smuzhiyun hlp.wic_overview_help], 289*4882a593Smuzhiyun "kickstart": [wic_help_topic_subcommand, 290*4882a593Smuzhiyun wic_help_topic_usage, 291*4882a593Smuzhiyun hlp.wic_kickstart_help], 292*4882a593Smuzhiyun "create": [wic_help_topic_subcommand, 293*4882a593Smuzhiyun wic_help_topic_usage, 294*4882a593Smuzhiyun hlp.wic_create_help], 295*4882a593Smuzhiyun "ls": [wic_help_topic_subcommand, 296*4882a593Smuzhiyun wic_help_topic_usage, 297*4882a593Smuzhiyun hlp.wic_ls_help], 298*4882a593Smuzhiyun "cp": [wic_help_topic_subcommand, 299*4882a593Smuzhiyun wic_help_topic_usage, 300*4882a593Smuzhiyun hlp.wic_cp_help], 301*4882a593Smuzhiyun "rm": [wic_help_topic_subcommand, 302*4882a593Smuzhiyun wic_help_topic_usage, 303*4882a593Smuzhiyun hlp.wic_rm_help], 304*4882a593Smuzhiyun "write": [wic_help_topic_subcommand, 305*4882a593Smuzhiyun wic_help_topic_usage, 306*4882a593Smuzhiyun hlp.wic_write_help], 307*4882a593Smuzhiyun "list": [wic_help_topic_subcommand, 308*4882a593Smuzhiyun wic_help_topic_usage, 309*4882a593Smuzhiyun hlp.wic_list_help] 310*4882a593Smuzhiyun} 311*4882a593Smuzhiyun 312*4882a593Smuzhiyun 313*4882a593Smuzhiyundef wic_init_parser_create(subparser): 314*4882a593Smuzhiyun subparser.add_argument("wks_file") 315*4882a593Smuzhiyun 316*4882a593Smuzhiyun subparser.add_argument("-o", "--outdir", dest="outdir", default='.', 317*4882a593Smuzhiyun help="name of directory to create image in") 318*4882a593Smuzhiyun subparser.add_argument("-w", "--workdir", 319*4882a593Smuzhiyun help="temporary workdir to use for intermediate files") 320*4882a593Smuzhiyun subparser.add_argument("-e", "--image-name", dest="image_name", 321*4882a593Smuzhiyun help="name of the image to use the artifacts from " 322*4882a593Smuzhiyun "e.g. core-image-sato") 323*4882a593Smuzhiyun subparser.add_argument("-r", "--rootfs-dir", action=RootfsArgAction, 324*4882a593Smuzhiyun help="path to the /rootfs dir to use as the " 325*4882a593Smuzhiyun ".wks rootfs source") 326*4882a593Smuzhiyun subparser.add_argument("-b", "--bootimg-dir", dest="bootimg_dir", 327*4882a593Smuzhiyun help="path to the dir containing the boot artifacts " 328*4882a593Smuzhiyun "(e.g. /EFI or /syslinux dirs) to use as the " 329*4882a593Smuzhiyun ".wks bootimg source") 330*4882a593Smuzhiyun subparser.add_argument("-k", "--kernel-dir", dest="kernel_dir", 331*4882a593Smuzhiyun help="path to the dir containing the kernel to use " 332*4882a593Smuzhiyun "in the .wks bootimg") 333*4882a593Smuzhiyun subparser.add_argument("-n", "--native-sysroot", dest="native_sysroot", 334*4882a593Smuzhiyun help="path to the native sysroot containing the tools " 335*4882a593Smuzhiyun "to use to build the image") 336*4882a593Smuzhiyun subparser.add_argument("-s", "--skip-build-check", dest="build_check", 337*4882a593Smuzhiyun action="store_false", default=True, help="skip the build check") 338*4882a593Smuzhiyun subparser.add_argument("-f", "--build-rootfs", action="store_true", help="build rootfs") 339*4882a593Smuzhiyun subparser.add_argument("-c", "--compress-with", choices=("gzip", "bzip2", "xz"), 340*4882a593Smuzhiyun dest='compressor', 341*4882a593Smuzhiyun help="compress image with specified compressor") 342*4882a593Smuzhiyun subparser.add_argument("-m", "--bmap", action="store_true", help="generate .bmap") 343*4882a593Smuzhiyun subparser.add_argument("--no-fstab-update" ,action="store_true", 344*4882a593Smuzhiyun help="Do not change fstab file.") 345*4882a593Smuzhiyun subparser.add_argument("-v", "--vars", dest='vars_dir', 346*4882a593Smuzhiyun help="directory with <image>.env files that store " 347*4882a593Smuzhiyun "bitbake variables") 348*4882a593Smuzhiyun subparser.add_argument("-D", "--debug", dest="debug", action="store_true", 349*4882a593Smuzhiyun default=False, help="output debug information") 350*4882a593Smuzhiyun subparser.add_argument("-i", "--imager", dest="imager", 351*4882a593Smuzhiyun default="direct", help="the wic imager plugin") 352*4882a593Smuzhiyun subparser.add_argument("--extra-space", type=int, dest="extra_space", 353*4882a593Smuzhiyun default=0, help="additional free disk space to add to the image") 354*4882a593Smuzhiyun return 355*4882a593Smuzhiyun 356*4882a593Smuzhiyun 357*4882a593Smuzhiyundef wic_init_parser_list(subparser): 358*4882a593Smuzhiyun subparser.add_argument("list_type", 359*4882a593Smuzhiyun help="can be 'images' or 'source-plugins' " 360*4882a593Smuzhiyun "to obtain a list. " 361*4882a593Smuzhiyun "If value is a valid .wks image file") 362*4882a593Smuzhiyun subparser.add_argument("help_for", default=[], nargs='*', 363*4882a593Smuzhiyun help="If 'list_type' is a valid .wks image file " 364*4882a593Smuzhiyun "this value can be 'help' to show the help information " 365*4882a593Smuzhiyun "defined inside the .wks file") 366*4882a593Smuzhiyun return 367*4882a593Smuzhiyun 368*4882a593Smuzhiyundef imgtype(arg): 369*4882a593Smuzhiyun """ 370*4882a593Smuzhiyun Custom type for ArgumentParser 371*4882a593Smuzhiyun Converts path spec to named tuple: (image, partition, path) 372*4882a593Smuzhiyun """ 373*4882a593Smuzhiyun image = arg 374*4882a593Smuzhiyun part = path = None 375*4882a593Smuzhiyun if ':' in image: 376*4882a593Smuzhiyun image, part = image.split(':') 377*4882a593Smuzhiyun if '/' in part: 378*4882a593Smuzhiyun part, path = part.split('/', 1) 379*4882a593Smuzhiyun if not path: 380*4882a593Smuzhiyun path = '/' 381*4882a593Smuzhiyun 382*4882a593Smuzhiyun if not os.path.isfile(image): 383*4882a593Smuzhiyun err = "%s is not a regular file or symlink" % image 384*4882a593Smuzhiyun raise argparse.ArgumentTypeError(err) 385*4882a593Smuzhiyun 386*4882a593Smuzhiyun return namedtuple('ImgType', 'image part path')(image, part, path) 387*4882a593Smuzhiyun 388*4882a593Smuzhiyundef wic_init_parser_ls(subparser): 389*4882a593Smuzhiyun subparser.add_argument("path", type=imgtype, 390*4882a593Smuzhiyun help="image spec: <image>[:<vfat partition>[<path>]]") 391*4882a593Smuzhiyun subparser.add_argument("-n", "--native-sysroot", 392*4882a593Smuzhiyun help="path to the native sysroot containing the tools") 393*4882a593Smuzhiyun 394*4882a593Smuzhiyundef imgpathtype(arg): 395*4882a593Smuzhiyun img = imgtype(arg) 396*4882a593Smuzhiyun if img.part is None: 397*4882a593Smuzhiyun raise argparse.ArgumentTypeError("partition number is not specified") 398*4882a593Smuzhiyun return img 399*4882a593Smuzhiyun 400*4882a593Smuzhiyundef wic_init_parser_cp(subparser): 401*4882a593Smuzhiyun subparser.add_argument("src", 402*4882a593Smuzhiyun help="image spec: <image>:<vfat partition>[<path>] or <file>") 403*4882a593Smuzhiyun subparser.add_argument("dest", 404*4882a593Smuzhiyun help="image spec: <image>:<vfat partition>[<path>] or <file>") 405*4882a593Smuzhiyun subparser.add_argument("-n", "--native-sysroot", 406*4882a593Smuzhiyun help="path to the native sysroot containing the tools") 407*4882a593Smuzhiyun 408*4882a593Smuzhiyundef wic_init_parser_rm(subparser): 409*4882a593Smuzhiyun subparser.add_argument("path", type=imgpathtype, 410*4882a593Smuzhiyun help="path: <image>:<vfat partition><path>") 411*4882a593Smuzhiyun subparser.add_argument("-n", "--native-sysroot", 412*4882a593Smuzhiyun help="path to the native sysroot containing the tools") 413*4882a593Smuzhiyun subparser.add_argument("-r", dest="recursive_delete", action="store_true", default=False, 414*4882a593Smuzhiyun help="remove directories and their contents recursively, " 415*4882a593Smuzhiyun " this only applies to ext* partition") 416*4882a593Smuzhiyun 417*4882a593Smuzhiyundef expandtype(rules): 418*4882a593Smuzhiyun """ 419*4882a593Smuzhiyun Custom type for ArgumentParser 420*4882a593Smuzhiyun Converts expand rules to the dictionary {<partition>: size} 421*4882a593Smuzhiyun """ 422*4882a593Smuzhiyun if rules == 'auto': 423*4882a593Smuzhiyun return {} 424*4882a593Smuzhiyun result = {} 425*4882a593Smuzhiyun for rule in rules.split(','): 426*4882a593Smuzhiyun try: 427*4882a593Smuzhiyun part, size = rule.split(':') 428*4882a593Smuzhiyun except ValueError: 429*4882a593Smuzhiyun raise argparse.ArgumentTypeError("Incorrect rule format: %s" % rule) 430*4882a593Smuzhiyun 431*4882a593Smuzhiyun if not part.isdigit(): 432*4882a593Smuzhiyun raise argparse.ArgumentTypeError("Rule '%s': partition number must be integer" % rule) 433*4882a593Smuzhiyun 434*4882a593Smuzhiyun # validate size 435*4882a593Smuzhiyun multiplier = 1 436*4882a593Smuzhiyun for suffix, mult in [('K', 1024), ('M', 1024 * 1024), ('G', 1024 * 1024 * 1024)]: 437*4882a593Smuzhiyun if size.upper().endswith(suffix): 438*4882a593Smuzhiyun multiplier = mult 439*4882a593Smuzhiyun size = size[:-1] 440*4882a593Smuzhiyun break 441*4882a593Smuzhiyun if not size.isdigit(): 442*4882a593Smuzhiyun raise argparse.ArgumentTypeError("Rule '%s': size must be integer" % rule) 443*4882a593Smuzhiyun 444*4882a593Smuzhiyun result[int(part)] = int(size) * multiplier 445*4882a593Smuzhiyun 446*4882a593Smuzhiyun return result 447*4882a593Smuzhiyun 448*4882a593Smuzhiyundef wic_init_parser_write(subparser): 449*4882a593Smuzhiyun subparser.add_argument("image", 450*4882a593Smuzhiyun help="path to the wic image") 451*4882a593Smuzhiyun subparser.add_argument("target", 452*4882a593Smuzhiyun help="target file or device") 453*4882a593Smuzhiyun subparser.add_argument("-e", "--expand", type=expandtype, 454*4882a593Smuzhiyun help="expand rules: auto or <partition>:<size>[,<partition>:<size>]") 455*4882a593Smuzhiyun subparser.add_argument("-n", "--native-sysroot", 456*4882a593Smuzhiyun help="path to the native sysroot containing the tools") 457*4882a593Smuzhiyun 458*4882a593Smuzhiyundef wic_init_parser_help(subparser): 459*4882a593Smuzhiyun helpparsers = subparser.add_subparsers(dest='help_topic', help=hlp.wic_usage) 460*4882a593Smuzhiyun for helptopic in helptopics: 461*4882a593Smuzhiyun helpparsers.add_parser(helptopic, help=helptopics[helptopic][2]) 462*4882a593Smuzhiyun return 463*4882a593Smuzhiyun 464*4882a593Smuzhiyun 465*4882a593Smuzhiyunsubcommands = { 466*4882a593Smuzhiyun "create": [wic_create_subcommand, 467*4882a593Smuzhiyun hlp.wic_create_usage, 468*4882a593Smuzhiyun hlp.wic_create_help, 469*4882a593Smuzhiyun wic_init_parser_create], 470*4882a593Smuzhiyun "list": [wic_list_subcommand, 471*4882a593Smuzhiyun hlp.wic_list_usage, 472*4882a593Smuzhiyun hlp.wic_list_help, 473*4882a593Smuzhiyun wic_init_parser_list], 474*4882a593Smuzhiyun "ls": [wic_ls_subcommand, 475*4882a593Smuzhiyun hlp.wic_ls_usage, 476*4882a593Smuzhiyun hlp.wic_ls_help, 477*4882a593Smuzhiyun wic_init_parser_ls], 478*4882a593Smuzhiyun "cp": [wic_cp_subcommand, 479*4882a593Smuzhiyun hlp.wic_cp_usage, 480*4882a593Smuzhiyun hlp.wic_cp_help, 481*4882a593Smuzhiyun wic_init_parser_cp], 482*4882a593Smuzhiyun "rm": [wic_rm_subcommand, 483*4882a593Smuzhiyun hlp.wic_rm_usage, 484*4882a593Smuzhiyun hlp.wic_rm_help, 485*4882a593Smuzhiyun wic_init_parser_rm], 486*4882a593Smuzhiyun "write": [wic_write_subcommand, 487*4882a593Smuzhiyun hlp.wic_write_usage, 488*4882a593Smuzhiyun hlp.wic_write_help, 489*4882a593Smuzhiyun wic_init_parser_write], 490*4882a593Smuzhiyun "help": [wic_help_subcommand, 491*4882a593Smuzhiyun wic_help_topic_usage, 492*4882a593Smuzhiyun hlp.wic_help_help, 493*4882a593Smuzhiyun wic_init_parser_help] 494*4882a593Smuzhiyun} 495*4882a593Smuzhiyun 496*4882a593Smuzhiyun 497*4882a593Smuzhiyundef init_parser(parser): 498*4882a593Smuzhiyun parser.add_argument("--version", action="version", 499*4882a593Smuzhiyun version="%(prog)s {version}".format(version=__version__)) 500*4882a593Smuzhiyun parser.add_argument("-D", "--debug", dest="debug", action="store_true", 501*4882a593Smuzhiyun default=False, help="output debug information") 502*4882a593Smuzhiyun 503*4882a593Smuzhiyun subparsers = parser.add_subparsers(dest='command', help=hlp.wic_usage) 504*4882a593Smuzhiyun for subcmd in subcommands: 505*4882a593Smuzhiyun subparser = subparsers.add_parser(subcmd, help=subcommands[subcmd][2]) 506*4882a593Smuzhiyun subcommands[subcmd][3](subparser) 507*4882a593Smuzhiyun 508*4882a593Smuzhiyunclass WicArgumentParser(argparse.ArgumentParser): 509*4882a593Smuzhiyun def format_help(self): 510*4882a593Smuzhiyun return hlp.wic_help 511*4882a593Smuzhiyun 512*4882a593Smuzhiyundef main(argv): 513*4882a593Smuzhiyun parser = WicArgumentParser( 514*4882a593Smuzhiyun description="wic version %s" % __version__) 515*4882a593Smuzhiyun 516*4882a593Smuzhiyun init_parser(parser) 517*4882a593Smuzhiyun 518*4882a593Smuzhiyun args = parser.parse_args(argv) 519*4882a593Smuzhiyun 520*4882a593Smuzhiyun if args.debug: 521*4882a593Smuzhiyun logger.setLevel(logging.DEBUG) 522*4882a593Smuzhiyun 523*4882a593Smuzhiyun if "command" in vars(args): 524*4882a593Smuzhiyun if args.command == "help": 525*4882a593Smuzhiyun if args.help_topic is None: 526*4882a593Smuzhiyun parser.print_help() 527*4882a593Smuzhiyun elif args.help_topic in helptopics: 528*4882a593Smuzhiyun hlpt = helptopics[args.help_topic] 529*4882a593Smuzhiyun hlpt[0](hlpt[1], hlpt[2]) 530*4882a593Smuzhiyun return 0 531*4882a593Smuzhiyun 532*4882a593Smuzhiyun # validate wic cp src and dest parameter to identify which one of it is 533*4882a593Smuzhiyun # image and cast it into imgtype 534*4882a593Smuzhiyun if args.command == "cp": 535*4882a593Smuzhiyun if ":" in args.dest: 536*4882a593Smuzhiyun args.dest = imgtype(args.dest) 537*4882a593Smuzhiyun elif ":" in args.src: 538*4882a593Smuzhiyun args.src = imgtype(args.src) 539*4882a593Smuzhiyun else: 540*4882a593Smuzhiyun raise argparse.ArgumentTypeError("no image or partition number specified.") 541*4882a593Smuzhiyun 542*4882a593Smuzhiyun return hlp.invoke_subcommand(args, parser, hlp.wic_help_usage, subcommands) 543*4882a593Smuzhiyun 544*4882a593Smuzhiyun 545*4882a593Smuzhiyunif __name__ == "__main__": 546*4882a593Smuzhiyun try: 547*4882a593Smuzhiyun sys.exit(main(sys.argv[1:])) 548*4882a593Smuzhiyun except WicError as err: 549*4882a593Smuzhiyun print() 550*4882a593Smuzhiyun logger.error(err) 551*4882a593Smuzhiyun sys.exit(1) 552