summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rwxr-xr-xtools/mic394
1 files changed, 207 insertions, 187 deletions
diff --git a/tools/mic b/tools/mic
index 871f9bd..7785bec 100755
--- a/tools/mic
+++ b/tools/mic
@@ -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: