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')
136 parser.set_defaults(alias="cr")
138 subparsers = parser.add_subparsers(title='Subcommands', dest='subcommand')
139 auto_parser = subparsers.add_parser('auto', parents=[parent_parser], help='auto detect image type from magic header')
141 fs_parser = subparsers.add_parser('fs', parents=[parent_parser],
142 help='create fs image')
143 fs_parser.add_argument("--include-src", dest = "include_src",action = "store_true",
144 default = False, help = "Generate a image with source rpms included")
146 loop_parser = subparsers.add_parser('loop', parents=[parent_parser], help='create loop image')
148 loop_parser.add_argument("--compress-disk-image", dest="compress_image",
149 choices=("gz", "bz2"), default=None,
150 help="Same with --compress-image")
151 # alias to compress-image for compatibility
152 loop_parser.add_argument("--compress-image", dest="compress_image",
153 choices=("gz", "bz2"), default=None,
154 help="Compress all loop images with 'gz' or 'bz2'")
155 loop_parser.add_argument("--shrink", action='store_true', default=False,
156 help="Whether to shrink loop images to minimal size")
158 qcow_parser = subparsers.add_parser('qcow', parents=[parent_parser], help='create qcow image')
160 raw_parser = subparsers.add_parser('raw', parents=[parent_parser], help='create raw image')
162 raw_parser.add_argument("--compress-disk-image", dest="compress_image",
163 choices=("gz", "bz2"), default=None,
164 help="Same with --compress-image")
165 raw_parser.add_argument("--compress-image", dest="compress_image",
166 choices=("gz", "bz2"), default = None,
167 help="Compress all raw images before package")
168 raw_parser.add_argument("--generate-bmap", action="store_true", default = None,
169 help="also generate the block map file")
170 raw_parser.add_argument("--fstab-entry", dest="fstab_entry", choices=("name", "uuid"), default="uuid",
171 help="Set fstab entry, 'name' means using device names, "
172 "'uuid' means using filesystem uuid")
176 """Script entry point."""
179 """log name, verion, hostname"""
182 msger.raw("%s %s (%s)" % (name,
184 misc.get_hostname_distro_str()))
186 def has_parameter(arg, arglist):
189 Check if argument requires parameter by analyzing
190 its action. Parameter is required only for 'store' and 'append' actions
192 if arg.startswith('-'):
194 if arg in (args['short'], args['long']):
195 if args.get('action') in (None, 'store', 'append'):
199 def sigterm_handler(signal, frame):
200 raise errors.Abort('\nSIGTERM catched, program aborted.')
202 # Add SIGTERM handler for exit gracefully
203 signal.signal(signal.SIGTERM, sigterm_handler)
205 # Create top level parser
206 epilog = "Try 'mic SUBCOMMAND --help' for help on a specific subcommand."
207 description = "mic - the Image Creation tool"
208 parser = ArgumentParser(description=description, epilog=epilog,
209 formatter_class=MICHelpFormatter)
211 # List of global arguments
212 # The main purpose of this structure is to contain arguments
213 # of add_argument. This is used to do aliasing properly
214 # (see code under the comment 'replace aliases with real commands')
215 global_args = [{'short': '-V', 'long': '--version', 'action': 'version',
216 'version': '%(prog)s ' + VERSION},
217 {'short': '-d', 'long': '--debug', 'action': 'store_true',
218 'help': 'debug output'},
219 {'short': '-v', 'long': '--verbose', 'action': 'store_true',
220 'help': 'verbose output'},
221 {'short': '-i', 'long': '--interactive', 'action': 'store_true',
222 'dest': 'interactive', 'default': 'True', 'help': 'interactive output'},
223 {'short': '', 'long': '--non-interactive', 'action': 'store_false',
224 'dest': 'interactive', 'default': 'True', 'help': 'non-interactive output'},
227 for args in global_args:
229 for key in ('action', 'help', 'version', 'default', 'dest'):
231 parser_kwargs[key] = args[key]
233 if args['short'] is '':
234 parser.add_argument(args['long'], **parser_kwargs)
236 parser.add_argument(args['short'], args['long'], **parser_kwargs)
238 # hacked by the request of cmdln lovers
239 parser.format_usage = parser.format_help
241 # Create parsers for subcommands
242 subparsers = parser.add_subparsers(title='subcommands')
246 for name, obj in globals().iteritems():
247 if name.endswith('_parser') and callable(obj):
248 aliases[obj(subparsers).get_default('alias')] = name.split('_')[0]
250 # replace aliases with real commands
251 for i, arg in enumerate(argv[1:]):
252 if not arg.startswith('-'):
253 # argv[i] is previous argument to arg
254 if not has_parameter(argv[i], global_args) and arg in aliases:
255 argv[i+1] = aliases[arg]
259 args = parser.parse_args(argv[1:])
262 msger.enable_interactive()
264 msger.disable_interactive()
267 msger.set_loglevel('VERBOSE')
272 rpm.setVerbosity(rpm.RPMLOG_DEBUG)
276 msger.set_loglevel('DEBUG')
280 # Import target module and call 'main' from it
281 module = __import__("mic.%s" % args.module, fromlist=[args.module])
282 return module.main(parser, args, argv[1:])
285 if __name__ == "__main__":
287 sys.exit(main(sys.argv))
288 except KeyboardInterrupt:
289 msger.error('\n^C catched, program aborted.')
290 except IOError as ioerr:
291 # catch 'no space left' exception, etc
292 if ioerr.errno == errno.ENOSPC:
293 msger.error('\nNo space left on device')
295 except errors.Usage as usage:
296 msger.error(str(usage))
297 except errors.Abort as msg:
299 except errors.CreatorError as err:
300 if msger.get_loglevel() == 'DEBUG':
302 msger.error(traceback.format_exc())
304 msger.error(str(err))