summaryrefslogtreecommitdiffstats
path: root/scripts/lib/mic/creator.py
diff options
context:
space:
mode:
authorTom Zanussi <tom.zanussi@linux.intel.com>2013-08-24 15:31:34 +0000
committerRichard Purdie <richard.purdie@linuxfoundation.org>2013-10-01 22:56:03 +0100
commit9fc88f96d40b17c90bac53b90045a87b2d2cff84 (patch)
tree63010e5aabf895697655baf89bd668d6752b3f97 /scripts/lib/mic/creator.py
parent53a1d9a788fd9f970af980da2ab975cca60685c4 (diff)
downloadpoky-9fc88f96d40b17c90bac53b90045a87b2d2cff84.tar.gz
wic: Add mic w/pykickstart
This is the starting point for the implemention described in [YOCTO 3847] which came to the conclusion that it would make sense to use kickstart syntax to implement image creation in OpenEmbedded. I subsequently realized that there was an existing tool that already implemented image creation using kickstart syntax, the Tizen/Meego mic tool. As such, it made sense to use that as a starting point - this commit essentially just copies the relevant Python code from the MIC tool to the scripts/lib dir, where it can be accessed by the previously created wic tool. Most of this will be removed or renamed by later commits, since we're initially focusing on partitioning only. Care should be taken so that we can easily add back any additional functionality should we decide later to expand the tool, though (we may also want to contribute our local changes to the mic tool to the Tizen project if it makes sense, and therefore should avoid gratuitous changes to the original code if possible). Added the /mic subdir from Tizen mic repo as a starting point: git clone git://review.tizen.org/tools/mic.git For reference, the top commit: commit 20164175ddc234a17b8a12c33d04b012347b1530 Author: Gui Chen <gui.chen@intel.com> Date: Sun Jun 30 22:32:16 2013 -0400 bump up to 0.19.2 Also added the /plugins subdir, moved to under the /mic subdir (to match the default plugin_dir location in mic.conf.in, which was renamed to yocto-image.conf (moved and renamed by later patches) and put into /scripts. (From OE-Core rev: 31f0360f1fd4ebc9dfcaed42d1c50d2448b4632e) Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com> Signed-off-by: Saul Wold <sgw@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'scripts/lib/mic/creator.py')
-rw-r--r--scripts/lib/mic/creator.py354
1 files changed, 354 insertions, 0 deletions
diff --git a/scripts/lib/mic/creator.py b/scripts/lib/mic/creator.py
new file mode 100644
index 0000000000..af5fb82a1e
--- /dev/null
+++ b/scripts/lib/mic/creator.py
@@ -0,0 +1,354 @@
1#!/usr/bin/python -tt
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
18import os, sys, re
19from optparse import SUPPRESS_HELP
20
21from mic import msger, rt_util
22from mic.utils import cmdln, errors, rpmmisc
23from mic.conf import configmgr
24from mic.plugin import pluginmgr
25
26
27class Creator(cmdln.Cmdln):
28 """${name}: create an image
29
30 Usage:
31 ${name} SUBCOMMAND <ksfile> [OPTS]
32
33 ${command_list}
34 ${option_list}
35 """
36
37 name = 'mic create(cr)'
38
39 def __init__(self, *args, **kwargs):
40 cmdln.Cmdln.__init__(self, *args, **kwargs)
41 self._subcmds = []
42
43 # get cmds from pluginmgr
44 # mix-in do_subcmd interface
45 for subcmd, klass in pluginmgr.get_plugins('imager').iteritems():
46 if not hasattr(klass, 'do_create'):
47 msger.warning("Unsurpport subcmd: %s" % subcmd)
48 continue
49
50 func = getattr(klass, 'do_create')
51 setattr(self.__class__, "do_"+subcmd, func)
52 self._subcmds.append(subcmd)
53
54 def get_optparser(self):
55 optparser = cmdln.CmdlnOptionParser(self)
56 optparser.add_option('-d', '--debug', action='store_true',
57 dest='debug',
58 help=SUPPRESS_HELP)
59 optparser.add_option('-v', '--verbose', action='store_true',
60 dest='verbose',
61 help=SUPPRESS_HELP)
62 optparser.add_option('', '--logfile', type='string', dest='logfile',
63 default=None,
64 help='Path of logfile')
65 optparser.add_option('-c', '--config', type='string', dest='config',
66 default=None,
67 help='Specify config file for mic')
68 optparser.add_option('-k', '--cachedir', type='string', action='store',
69 dest='cachedir', default=None,
70 help='Cache directory to store the downloaded')
71 optparser.add_option('-o', '--outdir', type='string', action='store',
72 dest='outdir', default=None,
73 help='Output directory')
74 optparser.add_option('-A', '--arch', type='string', dest='arch',
75 default=None,
76 help='Specify repo architecture')
77 optparser.add_option('', '--release', type='string', dest='release',
78 default=None, metavar='RID',
79 help='Generate a release of RID with all necessary'
80 ' files, when @BUILD_ID@ is contained in '
81 'kickstart file, it will be replaced by RID')
82 optparser.add_option("", "--record-pkgs", type="string",
83 dest="record_pkgs", default=None,
84 help='Record the info of installed packages, '
85 'multiple values can be specified which '
86 'joined by ",", valid values: "name", '
87 '"content", "license", "vcs"')
88 optparser.add_option('', '--pkgmgr', type='string', dest='pkgmgr',
89 default=None,
90 help='Specify backend package manager')
91 optparser.add_option('', '--local-pkgs-path', type='string',
92 dest='local_pkgs_path', default=None,
93 help='Path for local pkgs(rpms) to be installed')
94 optparser.add_option('', '--runtime', type='string',
95 dest='runtime', default=None,
96 help='Specify runtime mode, avaiable: bootstrap, native')
97 # --taring-to is alias to --pack-to
98 optparser.add_option('', '--taring-to', type='string',
99 dest='pack_to', default=None,
100 help=SUPPRESS_HELP)
101 optparser.add_option('', '--pack-to', type='string',
102 dest='pack_to', default=None,
103 help='Pack the images together into the specified'
104 ' achive, extension supported: .zip, .tar, '
105 '.tar.gz, .tar.bz2, etc. by default, .tar '
106 'will be used')
107 optparser.add_option('', '--copy-kernel', action='store_true',
108 dest='copy_kernel',
109 help='Copy kernel files from image /boot directory'
110 ' to the image output directory.')
111 optparser.add_option('', '--install-pkgs', type='string', action='store',
112 dest='install_pkgs', default=None,
113 help='Specify what type of packages to be installed,'
114 ' valid: source, debuginfo, debugsource')
115 optparser.add_option('', '--tmpfs', action='store_true', dest='enabletmpfs',
116 help='Setup tmpdir as tmpfs to accelerate, experimental'
117 ' feature, use it if you have more than 4G memory')
118 optparser.add_option('', '--repourl', action='append',
119 dest='repourl', default=[],
120 help=SUPPRESS_HELP)
121 return optparser
122
123 def preoptparse(self, argv):
124 optparser = self.get_optparser()
125
126 largs = []
127 rargs = []
128 while argv:
129 arg = argv.pop(0)
130
131 if arg in ('-h', '--help'):
132 rargs.append(arg)
133
134 elif optparser.has_option(arg):
135 largs.append(arg)
136
137 if optparser.get_option(arg).takes_value():
138 try:
139 largs.append(argv.pop(0))
140 except IndexError:
141 raise errors.Usage("option %s requires arguments" % arg)
142
143 else:
144 if arg.startswith("--"):
145 if "=" in arg:
146 opt = arg.split("=")[0]
147 else:
148 opt = None
149 elif arg.startswith("-") and len(arg) > 2:
150 opt = arg[0:2]
151 else:
152 opt = None
153
154 if opt and optparser.has_option(opt):
155 largs.append(arg)
156 else:
157 rargs.append(arg)
158
159 return largs + rargs
160
161 def postoptparse(self):
162 abspath = lambda pth: os.path.abspath(os.path.expanduser(pth))
163
164 if self.options.verbose:
165 msger.set_loglevel('verbose')
166 if self.options.debug:
167 msger.set_loglevel('debug')
168
169 if self.options.logfile:
170 logfile_abs_path = abspath(self.options.logfile)
171 if os.path.isdir(logfile_abs_path):
172 raise errors.Usage("logfile's path %s should be file"
173 % self.options.logfile)
174 if not os.path.exists(os.path.dirname(logfile_abs_path)):
175 os.makedirs(os.path.dirname(logfile_abs_path))
176 msger.set_interactive(False)
177 msger.set_logfile(logfile_abs_path)
178 configmgr.create['logfile'] = self.options.logfile
179
180 if self.options.config:
181 configmgr.reset()
182 configmgr._siteconf = self.options.config
183
184 if self.options.outdir is not None:
185 configmgr.create['outdir'] = abspath(self.options.outdir)
186 if self.options.cachedir is not None:
187 configmgr.create['cachedir'] = abspath(self.options.cachedir)
188 os.environ['ZYPP_LOCKFILE_ROOT'] = configmgr.create['cachedir']
189
190 for cdir in ('outdir', 'cachedir'):
191 if os.path.exists(configmgr.create[cdir]) \
192 and not os.path.isdir(configmgr.create[cdir]):
193 msger.error('Invalid directory specified: %s' \
194 % configmgr.create[cdir])
195
196 if self.options.local_pkgs_path is not None:
197 if not os.path.exists(self.options.local_pkgs_path):
198 msger.error('Local pkgs directory: \'%s\' not exist' \
199 % self.options.local_pkgs_path)
200 configmgr.create['local_pkgs_path'] = self.options.local_pkgs_path
201
202 if self.options.release:
203 configmgr.create['release'] = self.options.release.rstrip('/')
204
205 if self.options.record_pkgs:
206 configmgr.create['record_pkgs'] = []
207 for infotype in self.options.record_pkgs.split(','):
208 if infotype not in ('name', 'content', 'license', 'vcs'):
209 raise errors.Usage('Invalid pkg recording: %s, valid ones:'
210 ' "name", "content", "license", "vcs"' \
211 % infotype)
212
213 configmgr.create['record_pkgs'].append(infotype)
214
215 if self.options.arch is not None:
216 supported_arch = sorted(rpmmisc.archPolicies.keys(), reverse=True)
217 if self.options.arch in supported_arch:
218 configmgr.create['arch'] = self.options.arch
219 else:
220 raise errors.Usage('Invalid architecture: "%s".\n'
221 ' Supported architectures are: \n'
222 ' %s' % (self.options.arch,
223 ', '.join(supported_arch)))
224
225 if self.options.pkgmgr is not None:
226 configmgr.create['pkgmgr'] = self.options.pkgmgr
227
228 if self.options.runtime:
229 configmgr.set_runtime(self.options.runtime)
230
231 if self.options.pack_to is not None:
232 configmgr.create['pack_to'] = self.options.pack_to
233
234 if self.options.copy_kernel:
235 configmgr.create['copy_kernel'] = self.options.copy_kernel
236
237 if self.options.install_pkgs:
238 configmgr.create['install_pkgs'] = []
239 for pkgtype in self.options.install_pkgs.split(','):
240 if pkgtype not in ('source', 'debuginfo', 'debugsource'):
241 raise errors.Usage('Invalid parameter specified: "%s", '
242 'valid values: source, debuginfo, '
243 'debusource' % pkgtype)
244
245 configmgr.create['install_pkgs'].append(pkgtype)
246
247 if self.options.enabletmpfs:
248 configmgr.create['enabletmpfs'] = self.options.enabletmpfs
249
250 if self.options.repourl:
251 for item in self.options.repourl:
252 try:
253 key, val = item.split('=')
254 except:
255 continue
256 configmgr.create['repourl'][key] = val
257
258 def main(self, argv=None):
259 if argv is None:
260 argv = sys.argv
261 else:
262 argv = argv[:] # don't modify caller's list
263
264 self.optparser = self.get_optparser()
265 if self.optparser:
266 try:
267 argv = self.preoptparse(argv)
268 self.options, args = self.optparser.parse_args(argv)
269
270 except cmdln.CmdlnUserError, ex:
271 msg = "%s: %s\nTry '%s help' for info.\n"\
272 % (self.name, ex, self.name)
273 msger.error(msg)
274
275 except cmdln.StopOptionProcessing, ex:
276 return 0
277 else:
278 # optparser=None means no process for opts
279 self.options, args = None, argv[1:]
280
281 if not args:
282 return self.emptyline()
283
284 self.postoptparse()
285
286 return self.cmd(args)
287
288 def precmd(self, argv): # check help before cmd
289
290 if '-h' in argv or '?' in argv or '--help' in argv or 'help' in argv:
291 return argv
292
293 if len(argv) == 1:
294 return ['help', argv[0]]
295
296 if os.geteuid() != 0:
297 raise msger.error("Root permission is required, abort")
298
299 return argv
300
301 def do_auto(self, subcmd, opts, *args):
302 """${cmd_name}: auto detect image type from magic header
303
304 Usage:
305 ${name} ${cmd_name} <ksfile>
306
307 ${cmd_option_list}
308 """
309 def parse_magic_line(re_str, pstr, ptype='mic'):
310 ptn = re.compile(re_str)
311 m = ptn.match(pstr)
312 if not m or not m.groups():
313 return None
314
315 inline_argv = m.group(1).strip()
316 if ptype == 'mic':
317 m2 = re.search('(?P<format>\w+)', inline_argv)
318 elif ptype == 'mic2':
319 m2 = re.search('(-f|--format(=)?)\s*(?P<format>\w+)',
320 inline_argv)
321 else:
322 return None
323
324 if m2:
325 cmdname = m2.group('format')
326 inline_argv = inline_argv.replace(m2.group(0), '')
327 return (cmdname, inline_argv)
328
329 return None
330
331 if len(args) != 1:
332 raise errors.Usage("Extra arguments given")
333
334 if not os.path.exists(args[0]):
335 raise errors.CreatorError("Can't find the file: %s" % args[0])
336
337 with open(args[0], 'r') as rf:
338 first_line = rf.readline()
339
340 mic_re = '^#\s*-\*-mic-options-\*-\s+(.*)\s+-\*-mic-options-\*-'
341 mic2_re = '^#\s*-\*-mic2-options-\*-\s+(.*)\s+-\*-mic2-options-\*-'
342
343 result = parse_magic_line(mic_re, first_line, 'mic') \
344 or parse_magic_line(mic2_re, first_line, 'mic2')
345 if not result:
346 raise errors.KsError("Invalid magic line in file: %s" % args[0])
347
348 if result[0] not in self._subcmds:
349 raise errors.KsError("Unsupport format '%s' in %s"
350 % (result[0], args[0]))
351
352 argv = ' '.join(result + args).split()
353 self.main(argv)
354