b6a3dbc9db9a3ec4bc66ba73d88e6e043ffa4148
[tools/mic.git] / tools / mic
1 #!/usr/bin/env python
2 #
3 # Copyright (c) 2011 Intel, Inc.
4 #
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
8 #
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
12 # for more details.
13 #
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.
17
18 import os, sys, errno
19 from mic import msger, creator
20 from mic.utils import cmdln, misc, errors
21 from mic.conf import configmgr
22 from mic.plugin import pluginmgr
23 from mic.__version__ import VERSION
24
25 class MicCmd(cmdln.Cmdln):
26     """
27     Usage: mic SUBCOMMAND [OPTS] [ARGS...]
28
29     mic Means the Image Creation tool
30     Try 'mic help SUBCOMMAND' for help on a specific subcommand.
31
32     ${command_list}
33     global ${option_list}
34     ${help_list}
35     """
36
37     name = 'mic'
38     version = VERSION
39
40     def get_optparser(self):
41         optparser = cmdln.CmdlnOptionParser(self, version=self.version)
42         optparser.add_option('-d', '--debug', action='store_true',
43                              dest='debug',
44                              help='print debug message')
45         optparser.add_option('-v', '--verbose', action='store_true',
46                              dest='verbose',
47                              help='verbose information')
48         return optparser
49
50     def postoptparse(self):
51         if self.options.verbose:
52             msger.set_loglevel('verbose')
53
54         if self.options.debug:
55             try:
56                 import rpm
57                 rpm.setVerbosity(rpm.RPMLOG_NOTICE)
58             except ImportError:
59                 pass
60
61             msger.set_loglevel('debug')
62
63     def help_create(self):
64         cr = creator.Creator()
65         cr.optparser = cr.get_optparser()
66         doc = cr.__doc__
67         doc = cr._help_reindent(doc)
68         doc = cr._help_preprocess(doc, None)
69         doc = doc.replace(cr.name, "${cmd_name}", 1)
70         doc = doc.rstrip() + '\n'
71         return doc
72
73     @cmdln.alias("cr")
74     def do_create(self, argv):
75         try:
76             cr = creator.Creator()
77             cr.main(argv[1:])
78         except:
79             raise
80
81     def _root_confirm(self):
82         if os.geteuid() != 0:
83             msger.error('Root permission is required to continue, abort')
84
85     @cmdln.alias("cv")
86     @cmdln.option("-S", "--shell",
87                   action="store_true", dest="shell", default=False,
88                   help="Launch shell before packaging the converted image")
89     def do_convert(self, subcmd, opts, *args):
90         """${cmd_name}: convert image format
91
92         Usage:
93             mic convert <imagefile> <destformat>
94
95         ${cmd_option_list}
96         """
97
98         if not args:
99             # print help
100             handler = self._get_cmd_handler('convert')
101             if hasattr(handler, "optparser"):
102                 handler.optparser.print_help()
103             return 1
104
105         if len(args) == 1:
106             raise errors.Usage("It need 2 arguments (1 given)")
107         elif len(args) == 2:
108             (srcimg, destformat) = args
109         else:
110             raise errors.Usage("Extra argument given")
111
112         if not os.path.exists(srcimg):
113             raise errors.CreatorError("Cannot find the image: %s" % srcimg)
114
115         self._root_confirm()
116
117         configmgr.convert['shell'] = opts.shell
118
119         srcformat = misc.get_image_type(srcimg)
120         if srcformat == "ext3fsimg":
121             srcformat = "loop"
122
123         srcimager = None
124         destimager = None
125         for iname, icls in pluginmgr.get_plugins('imager').iteritems():
126            if iname == srcformat and hasattr(icls, "do_unpack"):
127                srcimager = icls
128            if iname == destformat and hasattr(icls, "do_pack"):
129                destimager = icls
130
131         if (srcimager and destimager) is None:
132            raise errors.CreatorError("Can't convert from %s to %s" \
133                                      % (srcformat, destformat))
134         else:
135             base_on = srcimager.do_unpack(srcimg)
136             destimager.do_pack(base_on)
137
138     @cmdln.alias("ch")
139     @cmdln.option('-s', '--saveto',
140                   action='store', dest='saveto', default=None,
141                   help="Save the unpacked image to specified dir")
142     def do_chroot(self, subcmd, opts, *args):
143         """${cmd_name}: chroot into an image
144
145         Usage:
146             mic chroot <imagefile>
147
148         ${cmd_option_list}
149         """
150
151         if not args:
152             # print help
153             handler = self._get_cmd_handler('chroot')
154             if hasattr(handler, "optparser"):
155                 handler.optparser.print_help()
156             return 1
157
158         if len(args) == 1:
159             targetimage = args[0]
160         else:
161             raise errors.Usage("Extra argument given")
162
163         if not os.path.exists(targetimage):
164             raise errors.CreatorError("Cannot find the image: %s"
165                                       % targetimage)
166
167         self._root_confirm()
168
169         configmgr.chroot['saveto'] = opts.saveto
170
171         imagetype = misc.get_image_type(targetimage)
172         if imagetype in ("ext3fsimg", "ext4fsimg", "btrfsimg"):
173             imagetype = "loop"
174
175         chrootclass = None
176         for pname, pcls in pluginmgr.get_plugins('imager').iteritems():
177             if pname == imagetype and hasattr(pcls, "do_chroot"):
178                 chrootclass = pcls
179                 break
180
181         if not chrootclass:
182             raise errors.CreatorError("Cannot support image type: %s" \
183                                       % imagetype)
184
185         chrootclass.do_chroot(targetimage)
186
187 if __name__ == "__main__":
188     try:
189         mic = MicCmd()
190         sys.exit(mic.main())
191
192     except KeyboardInterrupt:
193         msger.error('\n^C catched, program aborted.')
194
195     # catch 'no space left' exception, etc
196     except IOError, e:
197         if e.errno == errno.ENOSPC:
198             msger.error('\nNo space left on device')
199         raise
200
201     except errors.Usage, usage:
202         msger.error(str(usage))
203
204     except errors.Abort, msg:
205         msger.info(str(msg))
206
207     except errors.CreatorError, err:
208         if msger.get_loglevel() == 'debug':
209             import traceback
210             msger.error(traceback.format_exc())
211         else:
212             msger.error('\n'+str(err))