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. ')
127 parent_parser.add_argument('--use-mic-in-bootstrap', action='store_true',
128 dest='use_mic_in_bootstrap', default=False,
129 help='This option works in bootstrap runtime mode,'
130 ' Use mic in bootstrap to create image.'
131 ' By default, copy host mic to bootstrap and use it.')
133 parent_parser.add_argument('-d', '--debug', action='store_true',
135 parent_parser.add_argument('-v', '--verbose', action='store_true',
136 help='verbose output')
137 parent_parser.add_argument('-i', '--interactive', action='store_true',
138 dest='interactive', default=True,
139 help='interactive output')
140 parent_parser.add_argument('--run_script', action='store', dest='run_script',
141 default=None, help='Run script on local PC after image created')
142 parent_parser.add_argument('--tpk_install', action='store', dest='tpk_install',
143 default=None, help='Copy tpk file to /usr/apps/.preload-tpk')
144 parent_parser.add_argument('--rpm-debug', action='store_true', dest='rpm_debug', help='Set debug mode for rpm install')
146 parser.set_defaults(alias="cr")
148 subparsers = parser.add_subparsers(title='Subcommands', dest='subcommand')
149 auto_parser = subparsers.add_parser('auto', parents=[parent_parser], help='auto detect image type from magic header')
151 fs_parser = subparsers.add_parser('fs', parents=[parent_parser],
152 help='create fs image')
153 fs_parser.add_argument("--include-src", dest = "include_src",action = "store_true",
154 default = False, help = "Generate a image with source rpms included")
156 loop_parser = subparsers.add_parser('loop', parents=[parent_parser], help='create loop image')
158 loop_parser.add_argument("--compress-disk-image", dest="compress_image",
159 choices=("gz", "bz2"), default=None,
160 help="Same with --compress-image")
161 # alias to compress-image for compatibility
162 loop_parser.add_argument("--compress-image", dest="compress_image",
163 choices=("gz", "bz2"), default=None,
164 help="Compress all loop images with 'gz' or 'bz2'")
165 loop_parser.add_argument("--shrink", action='store_true', default=False,
166 help="Whether to shrink loop images to minimal size")
168 qcow_parser = subparsers.add_parser('qcow', parents=[parent_parser], help='create qcow image')
170 raw_parser = subparsers.add_parser('raw', parents=[parent_parser], help='create raw image')
172 raw_parser.add_argument("--compress-disk-image", dest="compress_image",
173 choices=("gz", "bz2"), default=None,
174 help="Same with --compress-image")
175 raw_parser.add_argument("--compress-image", dest="compress_image",
176 choices=("gz", "bz2"), default = None,
177 help="Compress all raw images before package")
178 raw_parser.add_argument("--generate-bmap", action="store_true", default = None,
179 help="also generate the block map file")
180 raw_parser.add_argument("--fstab-entry", dest="fstab_entry", choices=("name", "uuid"), default="uuid",
181 help="Set fstab entry, 'name' means using device names, "
182 "'uuid' means using filesystem uuid")
186 """Script entry point."""
189 """log name, verion, hostname"""
192 msger.raw("%s %s (%s)" % (name,
194 misc.get_hostname_distro_str()))
196 def has_parameter(arg, arglist):
199 Check if argument requires parameter by analyzing
200 its action. Parameter is required only for 'store' and 'append' actions
202 if arg.startswith('-'):
204 if arg in (args['short'], args['long']):
205 if args.get('action') in (None, 'store', 'append'):
209 def sigterm_handler(signal, frame):
210 raise errors.Abort('\nSIGTERM catched, program aborted.')
212 # Add SIGTERM handler for exit gracefully
213 signal.signal(signal.SIGTERM, sigterm_handler)
215 # Create top level parser
216 epilog = "Try 'mic SUBCOMMAND --help' for help on a specific subcommand."
217 description = "mic - the Image Creation tool"
218 parser = ArgumentParser(description=description, epilog=epilog,
219 formatter_class=MICHelpFormatter)
221 # List of global arguments
222 # The main purpose of this structure is to contain arguments
223 # of add_argument. This is used to do aliasing properly
224 # (see code under the comment 'replace aliases with real commands')
225 global_args = [{'short': '-V', 'long': '--version', 'action': 'version',
226 'version': '%(prog)s ' + VERSION},
227 {'short': '-d', 'long': '--debug', 'action': 'store_true',
228 'help': 'debug output'},
229 {'short': '-v', 'long': '--verbose', 'action': 'store_true',
230 'help': 'verbose output'},
231 {'short': '-i', 'long': '--interactive', 'action': 'store_true',
232 'dest': 'interactive', 'default': 'True', 'help': 'interactive output'},
233 {'short': '', 'long': '--non-interactive', 'action': 'store_false',
234 'dest': 'interactive', 'default': 'True', 'help': 'non-interactive output'},
237 for args in global_args:
239 for key in ('action', 'help', 'version', 'default', 'dest'):
241 parser_kwargs[key] = args[key]
243 if args['short'] is '':
244 parser.add_argument(args['long'], **parser_kwargs)
246 parser.add_argument(args['short'], args['long'], **parser_kwargs)
248 # hacked by the request of cmdln lovers
249 parser.format_usage = parser.format_help
251 # Create parsers for subcommands
252 subparsers = parser.add_subparsers(title='subcommands')
256 for name, obj in globals().iteritems():
257 if name.endswith('_parser') and callable(obj):
258 aliases[obj(subparsers).get_default('alias')] = name.split('_')[0]
260 # replace aliases with real commands
261 for i, arg in enumerate(argv[1:]):
262 if not arg.startswith('-'):
263 # argv[i] is previous argument to arg
264 if not has_parameter(argv[i], global_args) and arg in aliases:
265 argv[i+1] = aliases[arg]
269 args = parser.parse_args(argv[1:])
272 msger.enable_interactive()
274 msger.disable_interactive()
277 msger.set_loglevel('VERBOSE')
282 rpm.setVerbosity(rpm.RPMLOG_DEBUG)
286 msger.set_loglevel('DEBUG')
290 # Import target module and call 'main' from it
291 module = __import__("mic.%s" % args.module, fromlist=[args.module])
292 return module.main(parser, args, argv[1:])
295 if __name__ == "__main__":
297 sys.exit(main(sys.argv))
298 except KeyboardInterrupt:
299 msger.error('\n^C catched, program aborted.')
300 except IOError as ioerr:
301 # catch 'no space left' exception, etc
302 if ioerr.errno == errno.ENOSPC:
303 msger.error('\nNo space left on device')
305 except errors.Usage as usage:
306 msger.error(str(usage))
307 except errors.Abort as msg:
309 except errors.CreatorError as err:
310 if msger.get_loglevel() == 'DEBUG':
312 msger.error(traceback.format_exc())
314 msger.error(str(err))