xref: /OK3568_Linux_fs/yocto/poky/scripts/wic (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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