diff options
Diffstat (limited to 'tools')
-rwxr-xr-x | tools/mic | 394 |
1 files changed, 207 insertions, 187 deletions
@@ -30,213 +30,233 @@ import os import sys import errno -from mic import msger, creator, __version__ as VERSION -from mic.utils import cmdln, misc, errors +from argparse import ArgumentParser, SUPPRESS + +from mic import msger, __version__ as VERSION +from mic.utils import misc, errors from mic.conf import configmgr from mic.plugin import pluginmgr +from mic.helpformat import MICHelpFormatter, subparser + +@subparser +def chroot_parser(parser): + """chroot into an image -def optparser_setup(func): - """Setup optparser for a function""" - if not hasattr(func, "optparser"): - func.optparser = cmdln.SubCmdOptionParser() - func.optparser.disable_interspersed_args() - return func - - -class MicCmd(cmdln.Cmdln): + Examples: + mic chroot platform.img + mic chroot platform.img ls """ - Usage: mic SUBCOMMAND [OPTS] [ARGS...] - - mic Means the Image Creation tool - Try 'mic help SUBCOMMAND' for help on a specific subcommand. - - ${command_list} - global ${option_list} - ${help_list} + parser.add_argument('imagefile', help='Path of image file') + parser.add_argument('-s', '--saveto', action = 'store', dest = 'saveto', default = None, + help = "Save the unpacked image to specified dir") + parser.add_argument('-c', '--cmd', dest = 'cmd', default = None, + help = "command which will be executed in chroot environment") + parser.set_defaults(alias="ch") + return parser + +@subparser +def create_parser(parser): + """create an image + Examples: + $ mic -d -v create auto handset_blackbay.ks + $ mic -d -v cr loop handset_blackbay.ks --logfile=mic.log """ - name = 'mic' - version = VERSION - def print_version(self): + parent_parser = ArgumentParser(add_help=False) + parent_parser.add_argument('ksfile', help='Path of ksfile'); + parent_parser.add_argument('--logfile', dest='logfile', default=None, + help='Path of logfile') + parent_parser.add_argument('-c', '--config', dest='config', default=None, + help='Specify config file for mic') + parent_parser.add_argument('-k', '--cachedir', action='store', + dest='cachedir', default=None, + help='Cache directory to store the downloaded') + parent_parser.add_argument('-o', '--outdir', action='store', dest='outdir', + default=None, help='Output directory') + parent_parser.add_argument('-A', '--arch', dest='arch', default=None, + help='Specify repo architecture') + parent_parser.add_argument('--release', dest='release', default=None, metavar='RID', + help='Generate a release of RID with all necessary' + ' files, when @BUILD_ID@ is contained in ' + 'kickstart file, it will be replaced by RID') + parent_parser.add_argument("--record-pkgs", dest="record_pkgs", default=None, + help='Record the info of installed packages, ' + 'multiple values can be specified which ' + 'joined by ",", valid values: "name", ' + '"content", "license", "vcs"') + parent_parser.add_argument('--pkgmgr', dest='pkgmgr', default=None, + help='Specify backend package manager') + parent_parser.add_argument('--local-pkgs-path', dest='local_pkgs_path', default=None, + help='Path for local pkgs(rpms) to be installed') + parent_parser.add_argument('--runtime', dest='runtime', default=None, + help='Specify runtime mode, avaiable: bootstrap') + # --taring-to is alias to --pack-to + parent_parser.add_argument('--taring-to', dest='pack_to', default=None, + help=SUPPRESS) + parent_parser.add_argument('--pack-to', dest='pack_to', default=None, + help='Pack the images together into the specified' + ' achive, extension supported: .zip, .tar, ' + '.tar.gz, .tar.bz2, etc. by default, .tar ' + 'will be used') + parent_parser.add_argument('--copy-kernel', action='store_true', dest='copy_kernel', + help='Copy kernel files from image /boot directory' + ' to the image output directory.') + parent_parser.add_argument('--install-pkgs', action='store', dest='install_pkgs', default=None, + help='Specify what type of packages to be installed,' + ' valid: source, debuginfo, debugsource') + parent_parser.add_argument('--check-pkgs', action='store', dest='check_pkgs', default=[], + help='Check if given packages would be installed, ' + 'packages should be separated by comma') + parent_parser.add_argument('--tmpfs', action='store_true', dest='enabletmpfs', + help='Setup tmpdir as tmpfs to accelerate, experimental' + ' feature, use it if you have more than 4G memory') + parent_parser.add_argument('--repourl', action='append', dest='repourl', default=[], + help=SUPPRESS) + parent_parser.add_argument('-R', '--repo', action='append', + dest='repo', default=[], + help=SUPPRESS) + parent_parser.add_argument('--ignore-ksrepo', action='store_true', + dest='ignore_ksrepo', default=False, + help=SUPPRESS) + parent_parser.add_argument('--strict-mode', action='store_true', + dest='strict_mode', default=False, + help='Abort creation of image, if there are some errors' + ' during rpm installation. ') + parser.set_defaults(alias="cr") + + subparsers = parser.add_subparsers(title='Subcommands', dest='subcommand') + fs_parser = subparsers.add_parser('fs', parents=[parent_parser], + help='auto detect image type from magic header') + fs_parser.add_argument("--include-src", dest = "include_src",action = "store_true", + default = False, help = "Generate a image with source rpms included") + + auto_parser = subparsers.add_parser('auto', parents=[parent_parser], help='create fs image') + loop_parser = subparsers.add_parser('loop', parents=[parent_parser], help='create loop image') + + loop_parser.add_argument("--compress-disk-image", dest="compress_image", + choices=("gz", "bz2", "lzo"), default=None, + help="Same with --compress-image") + # alias to compress-image for compatibility + loop_parser.add_argument("--compress-image", dest="compress_image", + choices=("gz", "bz2", "lzo"), default=None, + help="Compress all loop images with 'gz' or 'bz2' or 'lzo'," + "Note: if you want to use 'lzo', package 'lzop' is needed to" + "be installed manually.") + loop_parser.add_argument("--shrink", action='store_true', default=False, + help="Whether to shrink loop images to minimal size") + + qcow_parser = subparsers.add_parser('qcow', parents=[parent_parser], help='create qcow image') + + return parser + +def main(argv): + """Script entry point.""" + + def print_version(): """log name, verion, hostname""" - - msger.raw("%s %s (%s)" % (self.name, - self.version, + + name = 'mic' + msger.raw("%s %s (%s)" % (name, + VERSION, misc.get_hostname_distro_str())) - - def get_optparser(self): - optparser = cmdln.CmdlnOptionParser(self, version=self.version) - # hook optparse print_version here - optparser.print_version = self.print_version - optparser.add_option('-d', '--debug', action='store_true', - dest='debug', - help='print debug message') - optparser.add_option('-v', '--verbose', action='store_true', - dest='verbose', - help='verbose information') - optparser.add_option('-i', '--interactive', action='store_true', - dest='interactive', default='True', - help='interactive output') - optparser.add_option('--non-interactive', action='store_false', - dest='interactive', default='True', - help='non-interactive output') - return optparser - - def postoptparse(self): - if self.options.interactive: - msger.enable_interactive() - else: - msger.disable_interactive() - - if self.options.verbose: - msger.set_loglevel('VERBOSE') - - if self.options.debug: - try: - import rpm - rpm.setVerbosity(rpm.RPMLOG_NOTICE) - except ImportError: - pass - - msger.set_loglevel('DEBUG') - - self.print_version() - - def help_create(self): - """Get help info from doc string. - Fill symbols with real parameters + + def has_parameter(arg, arglist): """ - crobj = creator.Creator() - crobj.optparser = crobj.get_optparser() - doc = crobj.__doc__ - doc = crobj.help_reindent(doc) - doc = crobj.help_preprocess(doc, None) - doc = doc.replace(crobj.name, "${cmd_name}", 1) - doc = doc.rstrip() + '\n' - return doc - - @cmdln.alias("cr") - def do_create(self, argv): - """Main for creating image""" - crobj = creator.Creator() - crobj.main(argv[1:]) - - def _root_confirm(self): - """Make sure command is called by root - There are a lot of commands needed to be run during creating images, - some of them must be run with root privilege like mount, kpartx""" - if os.geteuid() != 0: - msger.error('Root permission is required to continue, abort') - - @cmdln.alias("cv") - @cmdln.option("-S", "--shell", - action="store_true", dest="shell", default=False, - help="Launch shell before packaging the converted image") - def do_convert(self, _subcmd, opts, *args): - """${cmd_name}: convert image format - - Usage: - mic convert <imagefile> <destformat> - - ${cmd_option_list} + Helper function. + Check if argument requires parameter by analyzing + its action. Parameter is required only for 'store' and 'append' actions """ - if not args or len(args) != 2: - # print help - handler = self._get_cmd_handler('convert') - if hasattr(handler, "optparser"): - handler.optparser.print_help() - raise errors.Usage("2 arguments and only 2 are required") - - (srcimg, destformat) = args - - if not os.path.exists(srcimg): - raise errors.CreatorError("Cannot find the image: %s" % srcimg) - - self._root_confirm() - - configmgr.convert['shell'] = opts.shell - - srcformat = misc.get_image_type(srcimg) - if srcformat == "ext3fsimg": - srcformat = "loop" - - srcimager = None - destimager = None - for iname, icls in pluginmgr.get_plugins('imager').iteritems(): - if iname == srcformat and hasattr(icls, "do_unpack"): - srcimager = icls - if iname == destformat and hasattr(icls, "do_pack"): - destimager = icls - - if (srcimager and destimager) is None: - raise errors.CreatorError("Can't convert from %s to %s" \ - % (srcformat, destformat)) - maptab = { - "loop": "img", - } - if destformat in maptab: - imgname = os.path.splitext(os.path.basename(srcimg))[0] - dstname = "{0}.{1}".format(imgname, maptab[destformat]) - if os.path.exists(dstname): - if msger.ask("Converted image %s seems existed, " - "remove and continue?" % dstname): - os.unlink(dstname) - else: - raise errors.Abort("Canceled") - - destimager.do_pack(srcimager.do_unpack(srcimg)) - - @cmdln.alias("ch") - @cmdln.option('-s', '--saveto', - action = 'store', dest = 'saveto', default = None, - help = "Save the unpacked image to specified dir") - @optparser_setup - def do_chroot(self, _subcmd, opts, *args): - """${cmd_name}: chroot into an image - - Usage: - mic chroot [options] <imagefile> [command [arg]...] - - ${cmd_option_list} - """ - if not args: - # print help - handler = self._get_cmd_handler('chroot') - if hasattr(handler, "optparser"): - handler.optparser.print_help() - return 1 - - targetimage = args[0] - if not os.path.exists(targetimage): - raise errors.CreatorError("Cannot find the image: %s" - % targetimage) - - self._root_confirm() + if arg.startswith('-'): + for args in arglist: + if arg in (args['short'], args['long']): + if args.get('action') in (None, 'store', 'append'): + return True + return False + + # Create top level parser + epilog = "Try 'mic SUBCOMMAND --help' for help on a specific subcommand." + description = "mic - the Image Creation tool" + parser = ArgumentParser(description=description, epilog=epilog, + formatter_class=MICHelpFormatter) + + # List of global arguments + # The main purpose of this structure is to contain arguments + # of add_argument. This is used to do aliasing properly + # (see code under the comment 'replace aliases with real commands') + global_args = [{'short': '-V', 'long': '--version', 'action': 'version', + 'version': '%(prog)s ' + VERSION}, + {'short': '-d', 'long': '--debug', 'action': 'store_true', + 'help': 'debug output'}, + {'short': '-v', 'long': '--verbose', 'action': 'store_true', + 'help': 'verbose output'}, + {'short': '-i', 'long': '--interactive', 'action': 'store_true', + 'dest': 'interactive', 'default': 'True', 'help': 'interactive output'}, + {'short': '', 'long': '--non-interactive', 'action': 'store_false', + 'dest': 'interactive', 'default': 'True', 'help': 'non-interactive output'}, + ] + + for args in global_args: + parser_kwargs = {} + for key in ('action', 'help', 'version', 'default', 'dest'): + if key in args: + parser_kwargs[key] = args[key] + + if args['short'] is '': + parser.add_argument(args['long'], **parser_kwargs) + else: + parser.add_argument(args['short'], args['long'], **parser_kwargs) + + # hacked by the request of cmdln lovers + parser.format_usage = parser.format_help + + # Create parsers for subcommands + subparsers = parser.add_subparsers(title='subcommands') + + # collect aliases + aliases = {} + for name, obj in globals().iteritems(): + if name.endswith('_parser') and callable(obj): + aliases[obj(subparsers).get_default('alias')] = name.split('_')[0] + + # replace aliases with real commands + for i, arg in enumerate(argv[1:]): + if not arg.startswith('-'): + # argv[i] is previous argument to arg + if not has_parameter(argv[i], global_args) and arg in aliases: + argv[i+1] = aliases[arg] + break + + # Parse arguments + args = parser.parse_args(argv[1:]) - configmgr.chroot['saveto'] = opts.saveto + if args.interactive: + msger.enable_interactive() + else: + msger.disable_interactive() - imagetype = misc.get_image_type(targetimage) - if imagetype in ("ext3fsimg", "ext4fsimg", "btrfsimg"): - imagetype = "loop" + if args.verbose: + msger.set_loglevel('VERBOSE') - chrootclass = None - for pname, pcls in pluginmgr.get_plugins('imager').iteritems(): - if pname == imagetype and hasattr(pcls, "do_chroot"): - chrootclass = pcls - break + if args.debug: + try: + import rpm + rpm.setVerbosity(rpm.RPMLOG_NOTICE) + except ImportError: + pass - if not chrootclass: - raise errors.CreatorError("Cannot support image type: %s" \ - % imagetype) + msger.set_loglevel('DEBUG') - chrootclass.do_chroot(targetimage, args[1:]) + print_version() + # Import target module and call 'main' from it + module = __import__("mic.%s" % args.module, fromlist=[args.module]) + return module.main(parser, args, argv[1:]) + if __name__ == "__main__": try: - MIC = MicCmd() - sys.exit(MIC.main()) + sys.exit(main(sys.argv)) except KeyboardInterrupt: msger.error('\n^C catched, program aborted.') except IOError as ioerr: |