3 #Copyright (c) 2011 Intel, Inc.
5 #This program is free software; you can redistribute it and/or modify it
6 #under the terms of the GNU General Public License as published by the Free
7 #Software Foundation; version 2 of the License
9 #This program is distributed in the hope that it will be useful, but
10 #WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 # You should have received a copy of the GNU General Public License along
15 # with this program; if not, write to the Free Software Foundation, Inc., 59
16 # Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 # pylint: disable-msg=E0611, E1101, R0201
19 # E0611: no name in module, some attributes are set during running, so ignore it
20 # E1101: %s %r has no %r member, some attributes are set during running,
22 # R0201: Method could be a function
25 This mudule is entry for mic.
26 It defines a class named MicCmd inheriting Cmdln, and supplies interfaces like
27 'create, chroot, convert' and also some parameters for command 'mic'.
34 from argparse import ArgumentParser, SUPPRESS
36 from mic import msger, __version__ as VERSION
37 from mic.utils import misc, errors
38 from mic.conf import configmgr
39 from mic.plugin import pluginmgr
40 from mic.helpformat import MICHelpFormatter, subparser
44 def chroot_parser(parser):
45 """chroot into an image
48 mic chroot platform.img
49 mic chroot platform.img ls
51 parser.add_argument('imagefile', help='Path of image file')
52 parser.add_argument('-s', '--saveto', action = 'store', dest = 'saveto', default = None,
53 help = "Save the unpacked image to specified dir")
54 parser.add_argument('-c', '--cmd', dest = 'cmd', default = None,
55 help = "command which will be executed in chroot environment")
56 parser.set_defaults(alias="ch")
60 def create_parser(parser):
63 $ mic -d -v create auto handset_blackbay.ks
64 $ mic -d -v cr loop handset_blackbay.ks --logfile=mic.log
67 parent_parser = ArgumentParser(add_help=False)
68 parent_parser.add_argument('ksfile', help='Path of ksfile')
69 parent_parser.add_argument('--logfile', dest='logfile', default=None,
70 help='Path of logfile')
71 parent_parser.add_argument('-c', '--config', dest='config', default=None,
72 help='Specify config file for mic')
73 parent_parser.add_argument('-k', '--cachedir', action='store',
74 dest='cachedir', default=None,
75 help='Cache directory to store the downloaded')
76 parent_parser.add_argument('-o', '--outdir', action='store', dest='outdir',
77 default=None, help='Output directory')
78 parent_parser.add_argument('-A', '--arch', dest='arch', default=None,
79 help='Specify repo architecture')
80 parent_parser.add_argument('--release', dest='release', default=None, metavar='RID',
81 help='Generate a release of RID with all necessary'
82 ' files, when @BUILD_ID@ is contained in '
83 'kickstart file, it will be replaced by RID')
84 parent_parser.add_argument("--record-pkgs", dest="record_pkgs", default=None,
85 help='Record the info of installed packages, '
86 'multiple values can be specified which '
87 'joined by ",", valid values: "name", '
88 '"content", "license", "vcs"')
89 parent_parser.add_argument('--pkgmgr', dest='pkgmgr', default=None,
90 help='Specify backend package manager')
91 parent_parser.add_argument('--local-pkgs-path', dest='local_pkgs_path', default=None,
92 help='Path for local pkgs(rpms) to be installed')
93 parent_parser.add_argument('--runtime', dest='runtime', default=None,
94 help='Specify runtime mode, avaiable: bootstrap')
95 # --taring-to is alias to --pack-to
96 parent_parser.add_argument('--taring-to', dest='pack_to', default=None,
98 parent_parser.add_argument('--pack-to', dest='pack_to', default=None,
99 help='Pack the images together into the specified'
100 ' achive, extension supported: .zip, .tar, '
101 '.tar.gz, .tar.bz2, etc. by default, .tar '
103 parent_parser.add_argument('--copy-kernel', action='store_true', dest='copy_kernel',
104 help='Copy kernel files from image /boot directory'
105 ' to the image output directory.')
106 parent_parser.add_argument('--install-pkgs', action='store', dest='install_pkgs', default=None,
107 help='Specify what type of packages to be installed,'
108 ' valid: source, debuginfo, debugsource')
109 parent_parser.add_argument('--check-pkgs', action='store', dest='check_pkgs', default=[],
110 help='Check if given packages would be installed, '
111 'packages should be separated by comma')
112 parent_parser.add_argument('--tmpfs', action='store_true', dest='enabletmpfs',
113 help='Setup tmpdir as tmpfs to accelerate, experimental'
114 ' feature, use it if you have more than 4G memory')
115 parent_parser.add_argument('--repourl', action='append', dest='repourl', default=[],
117 parent_parser.add_argument('-R', '--repo', action='append',
118 dest='repo', default=[],
120 parent_parser.add_argument('--ignore-ksrepo', action='store_true',
121 dest='ignore_ksrepo', default=False,
123 parent_parser.add_argument('--strict-mode', action='store_true',
124 dest='strict_mode', default=False,
125 help='Abort creation of image, if there are some errors'
126 ' during rpm installation. ')
128 parent_parser.add_argument('-d', '--debug', action='store_true',
130 parent_parser.add_argument('-v', '--verbose', action='store_true',
131 help='verbose output')
132 parent_parser.add_argument('-i', '--interactive', action='store_true',
133 dest='interactive', default=True,
134 help='interactive output')
135 parent_parser.add_argument('--run_script', action='store', dest='run_script',
136 default=None, help='Run script on local PC after image created')
138 parser.set_defaults(alias="cr")
140 subparsers = parser.add_subparsers(title='Subcommands', dest='subcommand')
141 auto_parser = subparsers.add_parser('auto', parents=[parent_parser], help='auto detect image type from magic header')
143 fs_parser = subparsers.add_parser('fs', parents=[parent_parser],
144 help='create fs image')
145 fs_parser.add_argument("--include-src", dest = "include_src",action = "store_true",
146 default = False, help = "Generate a image with source rpms included")
148 loop_parser = subparsers.add_parser('loop', parents=[parent_parser], help='create loop image')
150 loop_parser.add_argument("--compress-disk-image", dest="compress_image",
151 choices=("gz", "bz2"), default=None,
152 help="Same with --compress-image")
153 # alias to compress-image for compatibility
154 loop_parser.add_argument("--compress-image", dest="compress_image",
155 choices=("gz", "bz2"), default=None,
156 help="Compress all loop images with 'gz' or 'bz2'")
157 loop_parser.add_argument("--shrink", action='store_true', default=False,
158 help="Whether to shrink loop images to minimal size")
160 qcow_parser = subparsers.add_parser('qcow', parents=[parent_parser], help='create qcow image')
162 raw_parser = subparsers.add_parser('raw', parents=[parent_parser], help='create raw image')
164 raw_parser.add_argument("--compress-disk-image", dest="compress_image",
165 choices=("gz", "bz2"), default=None,
166 help="Same with --compress-image")
167 raw_parser.add_argument("--compress-image", dest="compress_image",
168 choices=("gz", "bz2"), default = None,
169 help="Compress all raw images before package")
170 raw_parser.add_argument("--generate-bmap", action="store_true", default = None,
171 help="also generate the block map file")
172 raw_parser.add_argument("--fstab-entry", dest="fstab_entry", choices=("name", "uuid"), default="uuid",
173 help="Set fstab entry, 'name' means using device names, "
174 "'uuid' means using filesystem uuid")
178 """Script entry point."""
181 """log name, verion, hostname"""
184 msger.raw("%s %s (%s)" % (name,
186 misc.get_hostname_distro_str()))
188 def has_parameter(arg, arglist):
191 Check if argument requires parameter by analyzing
192 its action. Parameter is required only for 'store' and 'append' actions
194 if arg.startswith('-'):
196 if arg in (args['short'], args['long']):
197 if args.get('action') in (None, 'store', 'append'):
201 def sigterm_handler(signal, frame):
202 raise errors.Abort('\nSIGTERM catched, program aborted.')
204 # Add SIGTERM handler for exit gracefully
205 signal.signal(signal.SIGTERM, sigterm_handler)
207 # Create top level parser
208 epilog = "Try 'mic SUBCOMMAND --help' for help on a specific subcommand."
209 description = "mic - the Image Creation tool"
210 parser = ArgumentParser(description=description, epilog=epilog,
211 formatter_class=MICHelpFormatter)
213 # List of global arguments
214 # The main purpose of this structure is to contain arguments
215 # of add_argument. This is used to do aliasing properly
216 # (see code under the comment 'replace aliases with real commands')
217 global_args = [{'short': '-V', 'long': '--version', 'action': 'version',
218 'version': '%(prog)s ' + VERSION},
219 {'short': '-d', 'long': '--debug', 'action': 'store_true',
220 'help': 'debug output'},
221 {'short': '-v', 'long': '--verbose', 'action': 'store_true',
222 'help': 'verbose output'},
223 {'short': '-i', 'long': '--interactive', 'action': 'store_true',
224 'dest': 'interactive', 'default': 'True', 'help': 'interactive output'},
225 {'short': '', 'long': '--non-interactive', 'action': 'store_false',
226 'dest': 'interactive', 'default': 'True', 'help': 'non-interactive output'},
229 for args in global_args:
231 for key in ('action', 'help', 'version', 'default', 'dest'):
233 parser_kwargs[key] = args[key]
235 if args['short'] is '':
236 parser.add_argument(args['long'], **parser_kwargs)
238 parser.add_argument(args['short'], args['long'], **parser_kwargs)
240 # hacked by the request of cmdln lovers
241 parser.format_usage = parser.format_help
243 # Create parsers for subcommands
244 subparsers = parser.add_subparsers(title='subcommands')
248 for name, obj in globals().iteritems():
249 if name.endswith('_parser') and callable(obj):
250 aliases[obj(subparsers).get_default('alias')] = name.split('_')[0]
252 # replace aliases with real commands
253 for i, arg in enumerate(argv[1:]):
254 if not arg.startswith('-'):
255 # argv[i] is previous argument to arg
256 if not has_parameter(argv[i], global_args) and arg in aliases:
257 argv[i+1] = aliases[arg]
261 args = parser.parse_args(argv[1:])
264 msger.enable_interactive()
266 msger.disable_interactive()
269 msger.set_loglevel('VERBOSE')
274 rpm.setVerbosity(rpm.RPMLOG_DEBUG)
278 msger.set_loglevel('DEBUG')
282 # Import target module and call 'main' from it
283 module = __import__("mic.%s" % args.module, fromlist=[args.module])
284 return module.main(parser, args, argv[1:])
287 if __name__ == "__main__":
289 sys.exit(main(sys.argv))
290 except KeyboardInterrupt:
291 msger.error('\n^C catched, program aborted.')
292 except IOError as ioerr:
293 # catch 'no space left' exception, etc
294 if ioerr.errno == errno.ENOSPC:
295 msger.error('\nNo space left on device')
297 except errors.Usage as usage:
298 msger.error(str(usage))
299 except errors.Abort as msg:
301 except errors.CreatorError as err:
302 if msger.get_loglevel() == 'DEBUG':
304 msger.error(traceback.format_exc())
306 msger.error(str(err))