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