Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(251)

Side by Side Diff: chromite/chromite.py

Issue 6005004: WIP Chromite supporting "LEGACY" mode, as requested by Anush. (Closed) Base URL: ssh://git@gitrw.chromium.org:9222/crosutils.git@master
Patch Set: Use Info instead of printing to stderr. Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chromite/chromite ('k') | chromite/chromite.sh » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 #!/usr/bin/python
2 # Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Chromite."""
7
8 # Python imports
9 import base64
sosa 2010/12/23 01:52:27 Maybe sort ascii ... Capitals first, lowercase sec
diandersAtChromium 2011/01/06 00:23:23 No. Current order matches Google python conventio
10 import ConfigParser
11 import cPickle as pickle
sosa 2010/12/23 01:52:27 it's preferred not to rename.
diandersAtChromium 2011/01/06 00:23:23 Done.
12 import optparse
13 import os
14 import StringIO
15 import sys
16
17
18 # Ugly chunk of code to find the Chromium OS root and Chromite root, even if
19 # we're not in the chroot.
20 if 'CROS_WORKON_SRCROOT' in os.environ:
21 _SRCROOT_PATH = os.environ['CROS_WORKON_SRCROOT']
22 _CHROMITE_PATH = os.path.join(_SRCROOT_PATH, 'src', 'scripts', 'chromite')
23 else:
24 _CHROMITE_PATH = os.path.dirname(os.path.realpath(__file__))
25 _SRCROOT_PATH = os.path.realpath(os.path.join(_CHROMITE_PATH,
sosa 2010/12/23 01:52:27 can't you always do this? Just just use the else.
diandersAtChromium 2011/01/06 00:23:23 Done.
26 '..', '..', '..'))
27 sys.path.insert(0, os.path.join(_CHROMITE_PATH, 'lib'))
sosa 2010/12/23 01:52:27 Can't you do some gooey goodness with __init__.py
diandersAtChromium 2011/01/06 00:23:23 ...or, I can just not be completely stupid and cha
28
29
30 # Local library imports
31 from cros_build_lib import Die
32 from cros_build_lib import Info
33 from cros_build_lib import RunCommand
34 from cros_build_lib import RunCommandError
35 import text_menu
36
37
38 # Usage and description strings for OptionParser.
39 _USAGE = 'usage: %prog [options] [cmd [build.spec]]'
sosa 2010/12/23 01:52:27 Define these in your main
diandersAtChromium 2011/01/06 00:23:23 Done.
40 _DESCRIPTION = """The chromite script is a wrapper to make it easy to do
41 various build things. Current commands: %(command_list)s. For a description
42 of commands, run chromite without any options."""
43
44
45 # A list of paths that we'll search through to find spec files.
sosa 2010/12/23 01:52:27 Why are these globals? You use both of these once
diandersAtChromium 2011/01/06 00:23:23 Moved to where they are used; they are lists in an
46 _BUILD_SPEC_SEARCH_PATH = [
47 os.path.join(_CHROMITE_PATH, 'specs', 'build'),
48 ]
49 _CHROOT_SPEC_SEARCH_PATH = [
50 os.path.join(_CHROMITE_PATH, 'specs', 'chroot'),
51 ]
52
53
54 # Spec files must end with this suffix.
55 _SPEC_SUFFIX = '.spec'
56
57
58 # This "file" will be fed into the SafeConfigParser to provide defaults.
59 _DEFAULT_BUILD_SPEC = """
sosa 2010/12/23 01:52:27 Why are these defined here vs legacy.spc etc
diandersAtChromium 2011/01/06 00:23:23 Done. Moved to specs/build/_defaults and specs/ch
60 [LEGACY]
61 board: %(name)s
62 chroot_spec: chroot
63
64 [LEGACY_BUILD]
65 setup_board_flags:
66 build_packages_flags:
67
68 [LEGACY_IMAGE]
69 build_image_flags:
70 """
71
72 # This "file" will be fed into the SafeConfigParser to provide defaults.
73 _DEFAULT_CHROOT_SPEC = """
74 [LEGACY_CHROOT]
75 path: %(name)s
76 make_chroot_flags:
77 enter_chroot_flags:
78 """
79
80 # Define command handlers and command strings. We define them in this way
81 # so that someone searching for what calls _CmdXyz can find it easy with a grep.
82 #
83 # ORDER MATTERS here when we show the menu.
84 _COMMAND_HANDLERS = [
85 '_CmdBuild',
86 '_CmdClean',
87 '_CmdDistClean',
88 ]
89 _COMMAND_STRS = [fn_str[len('_Cmd'):].lower() for fn_str in _COMMAND_HANDLERS]
90
91
92 def _IsInsideChroot():
sosa 2010/12/23 01:52:27 Already defined in chromite lib
diandersAtChromium 2011/01/06 00:23:23 Done.
93 """Returns True if we're inside the chroot; False if not."""
94 return os.path.exists('/etc/debian_chroot')
95
96
97 def _GetBoardDir(build_config):
98 """Returns the board directory (inside the chroot) given the name.
99
100 Args:
101 build_config: A SafeConfigParser representing the config that we're
102 building.
103
104 Returns:
105 The absolute path to the board.
106 """
107 board_name = build_config.get('LEGACY', 'board')
108
109 # Extra checks on these, since we sometimes might do a rm -f on the board
110 # directory and these could cause some really bad behavior.
111 assert board_name, "Didn't expect blank board name."
112 assert len(board_name.split()) == 1, 'Board name should have no white space.'
113
114 return os.path.join('/', 'build', board_name)
115
116
117 def _GetChrootAbsDir(chroot_config):
118 """Returns the absolute chroot directory the chroot config.
119
120 Args:
121 chroot_config: A SafeConfigParser representing the config for the chroot.
122 Returns:
123 The chroot directory, always absolute.
124 """
125 chroot_dir = chroot_config.get('LEGACY_CHROOT', 'path')
126 return os.path.join(_SRCROOT_PATH, chroot_dir)
127
128
129 def _FindCommand(cmd_name):
sosa 2010/12/23 01:52:27 Def good candidate for unit test. Mock out TextMe
130 """Find the command that matches the given command name.
131
132 This tries to be smart. See the cmd_name parameter for details.
133
134 Args:
135 cmd_name: Can be any of the following:
136 1. The full name of a command. This is checked first so that if one
137 command name is a substring of another, you can still specify
138 the shorter spec name and know you won't get a menu (the exact
139 match prevents the menu).
140 2. A substring that will be used to pare-down a menu of commands
141 Can be the empty string to show a menu of all commands
142
143 Returns:
144 The command name.
145 """
146 # Always make cmd_name lower. Commands are case-insensitive.
147 cmd_name = cmd_name.lower()
148
149 # If we're an exact match, we're done!
150 if cmd_name in _COMMAND_STRS:
151 return cmd_name
152
153 # Find ones that match and put them in a menu...
154 possible_cmds = []
155 possible_choices = []
156 for cmd_num, this_cmd in enumerate(_COMMAND_STRS):
157 if cmd_name in this_cmd:
sosa 2010/12/23 01:52:27 regex is better. "in" does any substring ... not
diandersAtChromium 2011/01/06 00:23:23 Changed to startswith(). You're right that prefix
158 handler = eval(_COMMAND_HANDLERS[cmd_num])
159 assert hasattr(handler, '__doc__'), \
160 ('All handlers must have docstrings: %s' % cmd_name)
161 desc = handler.__doc__.splitlines()[0]
162
163 possible_cmds.append(this_cmd)
164 possible_choices.append('%s - %s' % (this_cmd, desc))
165
166 if not possible_choices:
167 Die('No commands matched: "%s". '
sosa 2010/12/23 01:52:27 I would consider throwing exceptions rather than d
diandersAtChromium 2011/01/06 00:23:23 I don't think so in this case. Exceptions are bet
sosa 2011/01/11 04:44:22 I can go either way. On 2011/01/06 00:23:23, di
168 'Try running with no arguments for a menu.' %
169 cmd_name)
170
171 if len(possible_choices) == 1:
172 choice = 0
173 Info("Running command '%s'.\n" % possible_cmds[choice])
174 else:
175 choice = text_menu.TextMenu(possible_choices, 'Which chromite command:',
sosa 2010/12/23 01:52:27 neat!
176 menu_width=0)
177 return possible_cmds[choice]
178
179
180 def _FindSpec(spec_name, is_chroot_spec=False, can_show_ui=True):
181 """Find the spec with the given name.
182
183 This tries to be smart about helping the user to find the right spec. See
184 the spec_name parameter for details.
185
186 Args:
187 spec_name: Can be any of the following:
188 1. A full path to a spec file (including the .spec suffix). This is
189 checked first (i.e. if os.path.isfile(spec_name), we assume we've
190 got this case).
191 2. The full name of a spec file somewhere in the spec search path
sosa 2010/12/23 01:52:27 I think it'd be better to combine 2 and 3 into one
diandersAtChromium 2011/01/06 00:23:23 No. I really wanted a substring for finding the s
192 (not including the .spec suffix). This is checked second. Putting
193 this check second means that if one spec name is a substring of
194 another, you can still specify the shorter spec name and know you
195 won't get a menu (the exact match prevents the menu).
196 3. A substring that will be used to pare-down a menu of spec files
197 found in the spec search path. Can be the empty string to show a
198 menu of all spec files in the spec path. NOTE: Only possible if
199 can_show_ui is True.
200 is_chroot_spec: If True, this is a chroot spec.
201 can_show_ui: If True, enables the spec name to be a substring since we can
202 then show a menu if the substring matches more than one thing.
203
204 Returns:
205 A path to the spec file.
206 """
207 # Get a string for the spec type (for debugging)
208 if is_chroot_spec:
209 spec_type = 'chroot'
210 else:
211 spec_type = 'build'
212
213 # If we have an exact path name, that's it. No searching.
214 if os.path.isfile(spec_name):
215 return spec_name
216
217 # Figure out what our search path should be.
218 if is_chroot_spec:
219 search_path = _CHROOT_SPEC_SEARCH_PATH
220 else:
221 search_path = _BUILD_SPEC_SEARCH_PATH
222
223 # Look for an exact match of a spec name. An exact match will go through with
224 # no menu.
225 for dir_path in search_path:
226 spec_path = os.path.join(dir_path, spec_name + _SPEC_SUFFIX)
227 if os.path.isfile(spec_path):
228 return spec_path
229
230 # Die right away if we can't show UI and didn't have an exact match.
231 if not can_show_ui:
232 Die("Couldn't find %s spec: %s" % (spec_type, spec_name))
233
234 # No full path and no exact match. Move onto a menu.
235 # First step is to construct the options. We'll store in a dict keyed by
236 # spec name.
237 options = {}
238 for dir_path in search_path:
239 for file_name in os.listdir(dir_path):
240 file_path = os.path.join(dir_path, file_name)
241 file_base_path, _ = os.path.splitext(file_path)
242
243 # Skip if this isn't a spec file. Use samefile to check, which I think
244 # avoids any case-sensitiveness in the filesystem.
245 if not os.path.samefile(file_path, file_base_path + _SPEC_SUFFIX):
246 continue
sosa 2010/12/23 01:52:27 add line after
diandersAtChromium 2011/01/06 00:23:23 Done.
247 this_spec_name, _ = os.path.splitext(file_name)
248
249 # Skip if this spec file doesn't contain our substring. We are _always_
250 # case insensitive here to be helpful to the user.
251 if spec_name.lower() not in this_spec_name.lower():
252 continue
253
254 # Skip if we've already seen this spec. This means that if the same spec
255 # name is in multiple parts of the path, we'll only match the first one.
256 if this_spec_name in options:
257 continue
258
259 # OK, it's good. Store the path.
260 options[this_spec_name] = file_path
sosa 2010/12/23 01:52:27 You could probably merge the majority of this func
diandersAtChromium 2011/01/06 00:23:23 I'd rather not merge them. It is true that there
261
262 # If no match, die.
263 if not options:
264 Die("Couldn't find any matching %s specs for: %s" % (spec_type, spec_name))
265
266 # If exactly one match, we're done.
267 if len(options) == 1:
268 _, spec_path = options.popitem()
269 return spec_path
270
271 # If more than one, show a menu...
272 option_keys = sorted(options.iterkeys())
273 choice = text_menu.TextMenu(option_keys, 'Choose a build spec:')
274 return options[option_keys[choice]]
275
276
277 def _ParseCommandLine(arguments):
278 """Parse the command line to figure out the build command and build spec.
279
280 Note that the command and buildspec are specified directly on the command
281 line (not using "options") because every command needs to specify them and
282 we want to make it that much easier for people to type the commands. Also
283 note that the buildspec can be specified as any substring of the spec name
284 (and if that specifies more than one thing, we'll show a menu).
285
286 That means you can run chromite like this:
287 chromite build mario
288 ...instead of:
289 chromite --cmd=build --board=x86-mario
290
291 If the user specified a bad command line, this function will call Die().
292
293 Args:
294 arguments: The non options from the OptionParser.
295
296 Returns:
297 chromite_cmd: The chromite command that was specified (default is "build").
298 build_spec_path: The path to the build spec.
299 """
300 # Set defaults.
301 chromite_cmd = ''
302 spec_name = ''
303
304 # Make a copy of arguments so we can futz with it and caller doesn't see it
305 # change...
306 arguments = list(arguments)
sosa 2010/12/23 01:52:27 [] is a shorthand for list() is it not?
diandersAtChromium 2011/01/06 00:23:23 You are saying to do this instead? arguments = a
sosa 2011/01/11 04:44:22 I meant arguments = [arguments]. Are these not eq
diandersAtChromium 2011/01/12 00:04:45 Not equivalent. In [1]: l = range(10) In [2]: li
307
308 # Pull the command off if it was specified.
309 if arguments:
310 chromite_cmd = arguments.pop(0).lower()
311
312 # Validate the chromite_cmd, popping a menu if needed.
313 try:
314 chromite_cmd = _FindCommand(chromite_cmd)
315 except KeyboardInterrupt:
316 Die('OK, cancelling...')
sosa 2010/12/23 01:52:27 Maybe you should add a extra option that does exit
diandersAtChromium 2011/01/06 00:23:23 Done.
317
318 # There should be 0 or 1 more arguments.
319 # If too many: error
320 # If 1, it's the spec name.
321 # If 0, we'll use the default spec name.
322 if len(arguments) > 1:
323 Die('Too many arguments. Try passing --help.')
324 elif arguments:
325 spec_name = arguments[0]
326
327 # Find the spec given the name...
328 try:
329 build_spec_path = _FindSpec(spec_name)
330 except KeyboardInterrupt:
331 Die('OK, cancelling...')
sosa 2010/12/23 01:52:27 same
diandersAtChromium 2011/01/06 00:23:23 Done.
332
333 return chromite_cmd, build_spec_path
334
335
336 def _ReadConfigs(build_spec_path):
337 """Read the build_config and chroot_config from spec files.
338
339 Args:
340 build_spec_path: The path to the build spec.
341
342 Returns:
343 build_config: A SafeConfigParser representing the config that we're
344 building.
345 build_config: A SafeConfigParser representing the config of the chroot.
346 """
347 build_spec_name, _ = os.path.splitext(os.path.basename(build_spec_path))
348
349 build_config = ConfigParser.SafeConfigParser()
350 default_build_spec = _DEFAULT_BUILD_SPEC % dict(name=build_spec_name)
sosa 2010/12/23 01:52:27 {} not dict
diandersAtChromium 2011/01/06 00:23:23 Done.
351 build_config.readfp(StringIO.StringIO(default_build_spec), '<defaults>')
352 build_config.read(build_spec_path)
353
354 chroot_spec = build_config.get('LEGACY', 'chroot_spec')
sosa 2010/12/23 01:52:27 erm why read specified build spec but legacy chroo
diandersAtChromium 2011/01/06 00:23:23 This is the chroot spec specified in the LEGACY se
sosa 2011/01/11 04:44:22 ping @anush On 2011/01/06 00:23:23, diandersAtChr
355 chroot_spec_path = _FindSpec(chroot_spec, is_chroot_spec=True,
356 can_show_ui=False)
357 chroot_spec_name, _ = os.path.splitext(os.path.basename(chroot_spec_path))
358
359 default_chroot_spec = _DEFAULT_CHROOT_SPEC % dict(name=chroot_spec_name)
sosa 2010/12/23 01:52:27 {}
diandersAtChromium 2011/01/06 00:23:23 Done.
360 chroot_config = ConfigParser.SafeConfigParser()
361 chroot_config.readfp(StringIO.StringIO(default_chroot_spec), '<defaults>')
362 chroot_config.read(chroot_spec_path)
363
364 return build_config, chroot_config
365
366
367 def _DoesChrootExist(chroot_config):
368 """Returns whether the chroot already appears to exist.
369
370 Args:
371 chroot_config: A SafeConfigParser representing the config for the chroot.
372
373 Returns:
374 True if the chroot appears to exist; False if it appears not to exist.
375 Note that we're just checking for the existence of the folder--we don't
376 check whether the chroot was properly configured.
377 """
378 chroot_dir = _GetChrootAbsDir(chroot_config)
379 return os.path.isdir(chroot_dir)
380
381
382 def _DoMakeChroot(chroot_config):
383 """Build the chroot, if needed.
384
385 Args:
386 chroot_config: A SafeConfigParser representing the config for the chroot.
387 """
388 # Skip this whole command if things already exist.
389 # TODO(dianders): Theoretically, calling make_chroot a second time is OK
390 # and "fixes up" the chroot. ...but build_packages will do the fixups
391 # anyway (I think), so this isn't that important.
392 chroot_dir = _GetChrootAbsDir(chroot_config)
sosa 2010/12/23 01:52:27 use DoesChrootExist()
diandersAtChromium 2011/01/06 00:23:23 Added ability for _GetChrootAbsDir() to check and
393 if os.path.isdir(chroot_dir):
394 Info('%s already exists, skipping make_chroot.' % chroot_dir)
395 return
396
397 Info('MAKING THE CHROOT')
398
399 # Put together command. We're going to force the shell to do all of the
400 # splitting of arguments, since we're throwing all of the flags from the
401 # config file in there.
402 cmd = './make_chroot --chroot="%s" %s' % (
sosa 2010/12/23 01:52:27 Why are you setting --chroot here if we always use
diandersAtChromium 2011/01/06 00:23:23 Boards can specify alternate chroots. The --chroo
403 chroot_dir,
404 chroot_config.get('LEGACY_CHROOT', 'make_chroot_flags')
405 )
406
407 # We'll put CWD as src/scripts when running the command. Since everyone
408 # running by hand has their cwd there, it is probably the safest.
409 cwd = os.path.join(_SRCROOT_PATH, 'src', 'scripts')
410
411 # Run it. Pass any failures upward.
412 try:
413 RunCommand(cmd, shell=True, cwd=cwd, ignore_sigint=True)
414 except RunCommandError, e:
415 Die(str(e))
sosa 2010/12/23 01:52:27 don't catch it
diandersAtChromium 2011/01/06 00:23:23 Done.
416
417
418 def _DoEnterChroot(chroot_config, fn, *args, **kwargs):
419 """Re-run the given function inside the chroot.
420
421 When the function is run, it will be run in a SEPARATE INSTANCE of chromite,
422 which will be run in the chroot. This is a little weird. Specifically:
423 - When the callee executes, it will be a separate python instance.
424 - Globals will be reset back to defaults.
425 - A different version of python (with different modules) may end up running
426 the script in the chroot.
427 - All arguments are pickled up, encoded, and sent through the command line.
428 - That means that args must be pickleable and not too huge.
429 - It also means that modifications to the parameters by the callee are not
430 visible to the caller.
431 - Even the function is "pickled". The way the pickle works, I belive it
432 just passes the name of the function. If this name somehow resolves
433 differently in the chroot, you may get weirdness.
434 - Since we're in the chroot, obviously files may have different paths. It's
435 up to you to convert parameters if you need to.
436 - The stdin, stdout, and stderr aren't touched.
437
438 Args:
439 chroot_config: A SafeConfigParser representing the config for the chroot.
440 fn: The function to call.
441 args: All other arguments will be passed to the function as is.
442 kwargs: All other arguments will be passed to the function as is.
443 """
444 Info('ENTERING THE CHROOT')
445
446 # Encode our state in something that can be passed on the command line.
447 # TODO(dianders): What kind of limits do we have here? 64K?
448 resume_state = pickle.dumps((fn, args, kwargs), pickle.HIGHEST_PROTOCOL)
449 resume_state = base64.b64encode(resume_state)
sosa 2010/12/23 01:52:27 Can you store state to a temp file? tempfile.mkst
diandersAtChromium 2011/01/06 00:23:23 I researched this and it looks like I have 2 megs
450
451 # Put together command. We're going to force the shell to do all of the
452 # splitting of arguments, since we're throwing all of the flags from the
453 # config file in there.
454 # TODO(dianders): Once chromite is in the path inside the chroot, we should
455 # change it from 'chromite/chromite' to just 'chromite'.
456 cmd = (
457 './enter_chroot.sh --chroot="%s" %s --'
458 ' chromite/chromite --resume-state=%s') % (
459 _GetChrootAbsDir(chroot_config),
460 chroot_config.get('LEGACY_CHROOT', 'enter_chroot_flags'),
461 resume_state)
462
463 # We'll put CWD as src/scripts when running the command. Since everyone
464 # running by hand has their cwd there, it is probably the safest.
465 cwd = os.path.join(_SRCROOT_PATH, 'src', 'scripts')
466
467 # Run it. We allow "error" so we don't print a confusing error message
468 # filled with out resume-state garbage on control-C.
469 cmd_result = RunCommand(cmd, shell=True, cwd=cwd, print_cmd=False,
470 exit_code=True, error_ok=True, ignore_sigint=True)
471
472 if cmd_result.returncode:
473 Die('Chroot exited with error code %d' % cmd_result.returncode)
474
475
476 def _DoSetupBoard(build_config):
477 """Setup the board, if needed.
478
479 This just runs the setup_board command with the proper args, if needed.
480
481 Args:
482 build_config: A SafeConfigParser representing the build config.
483 """
484 # Skip this whole command if things already exist.
485 board_dir = _GetBoardDir(build_config)
sosa 2010/12/23 01:52:27 How do you --force?
diandersAtChromium 2011/01/06 00:23:23 You don't. You do a ./chromite clean first. This
sosa 2011/01/11 04:44:22 Difference between make_chroot --replace and setu
diandersAtChromium 2011/01/12 00:04:45 Done.
486 if os.path.isdir(board_dir):
487 Info('%s already exists, skipping setup_board.' % board_dir)
488 return
489
490 Info('SETTING UP THE BOARD')
491
492 # Put together command. We're going to force the shell to do all of the
493 # splitting of arguments, since we're throwing all of the flags from the
494 # config file in there.
495 cmd = './setup_board --board="%s" %s' % (
496 build_config.get('LEGACY', 'board'),
497 build_config.get('LEGACY_BUILD', 'setup_board_flags')
498 )
499
500 # We'll put CWD as src/scripts when running the command. Since everyone
501 # running by hand has their cwd there, it is probably the safest.
502 cwd = os.path.join(_SRCROOT_PATH, 'src', 'scripts')
503
504 # Run it. Exit upon failure.
505 try:
506 RunCommand(cmd, shell=True, cwd=cwd, ignore_sigint=True)
507 except RunCommandError, e:
508 Die(str(e))
sosa 2010/12/23 01:52:27 ditto on the die here
diandersAtChromium 2011/01/06 00:23:23 Done.
509
510
511 def _DoBuildPackages(build_config):
512 """Build packages.
513
514 This just runs the build_packages command with the proper args.
515
516 Args:
517 build_config: A SafeConfigParser representing the build config.
518 """
519 Info('BUILDING PACKAGES')
520
521 # Put together command. We're going to force the shell to do all of the
522 # splitting of arguments, since we're throwing all of the flags from the
523 # config file in there.
524 cmd = './build_packages --board="%s" %s' % (
525 build_config.get('LEGACY', 'board'),
526 build_config.get('LEGACY_BUILD', 'build_packages_flags')
527 )
528
529 # We'll put CWD as src/scripts when running the command. Since everyone
530 # running by hand has their cwd there, it is probably the safest.
531 cwd = os.path.join(_SRCROOT_PATH, 'src', 'scripts')
532
533 # Run it. Exit upon failure.
534 try:
535 RunCommand(cmd, shell=True, cwd=cwd, ignore_sigint=True)
536 except RunCommandError, e:
537 Die(str(e))
538
539
540 def _DoBuildImage(build_config):
541 """Build an image.
542
543 This just runs the build_image command with the proper args.
544
545 Args:
546 build_config: A SafeConfigParser representing the build config.
547 """
548 Info('BUILDING THE IMAGE')
549
550 # Put together command. We're going to force the shell to do all of the
551 # splitting of arguments, since we're throwing all of the flags from the
552 # config file in there.
553 cmd = './build_image --board="%s" %s' % (
554 build_config.get('LEGACY', 'board'),
555 build_config.get('LEGACY_IMAGE', 'build_image_flags')
556 )
557
558 # We'll put CWD as src/scripts when running the command. Since everyone
559 # running by hand has their cwd there, it is probably the safest.
560 cwd = os.path.join(_SRCROOT_PATH, 'src', 'scripts')
561
562 # Run it. Exit upon failure.
563 try:
564 RunCommand(cmd, shell=True, cwd=cwd, ignore_sigint=True)
565 except RunCommandError, e:
566 Die(str(e))
567
568
569 def _CmdBuild(chromite_cmd, build_config, chroot_config, options):
570 """Build the chroot, the packages, and the image for a board.
571
572 This is the main chromite command and builds an image for you.
573
574 Args:
575 chromite_cmd: The command that was called.
576 build_config: A SafeConfigParser representing the build config.
577 chroot_config: A SafeConfigParser representing the chroot config.
578 options: Options from the OptionParser
579 """
580 if not _IsInsideChroot():
581 _DoMakeChroot(chroot_config)
582 _DoEnterChroot(chroot_config, _CmdBuild, chromite_cmd, build_config,
583 chroot_config, options)
584 else:
585 _DoSetupBoard(build_config)
586 _DoBuildPackages(build_config)
587 _DoBuildImage(build_config)
588
589
590 def _CmdClean(chromite_cmd, build_config, chroot_config, options):
591 """Clean out built packages for a board.
sosa 2010/12/23 01:52:27 Wait, what is this for? When would we want to do t
diandersAtChromium 2011/01/06 00:23:23 You would do this instead of setup_board --force.
sosa 2011/01/11 04:44:22 That is nice! On 2011/01/06 00:23:23, diandersAtC
diandersAtChromium 2011/01/12 00:04:45 Done.
592
593 Args:
594 chromite_cmd: The command that was called.
595 build_config: A SafeConfigParser representing the build config.
596 chroot_config: A SafeConfigParser representing the chroot config.
597 options: Options from the OptionParser
598 """
599 # These vars are part of the standard signature, but not used.
600 _ = chromite_cmd
601
602 # We'll need the directory so we can delete stuff.
603 board_dir = _GetBoardDir(build_config)
604
605 if not _IsInsideChroot():
606 if not _DoesChrootExist(chroot_config):
607 Die("Chroot doesn't appear to exist, nothing to do.")
608
609 # We'll need to make the board directory relative to the chroot.
610 chroot_dir = _GetChrootAbsDir(chroot_config)
611 assert board_dir.startswith('/'), 'Expected unix-style, absolute path.'
612 board_dir = board_dir.lstrip('/')
613 board_dir = os.path.join(chroot_dir, board_dir)
614
615 if not os.path.isdir(board_dir):
616 Die("Nothing to clean: the board directory doesn't exist.\n %s" %
617 board_dir)
618
619 if not options.yes:
620 sys.stderr.write('\n'
621 'Board dir is at: %s\n'
622 'Are you sure you want to delete it (YES/NO)? ' %
623 board_dir)
624 answer = raw_input()
625 if answer != 'YES':
626 Die("You must answer exactly 'YES' if you want to proceed.")
627
628 # Since we're about to do a sudo rm -rf, these are just extra precautions.
629 # This shouldn't be the only place testing these (assert fails are ugly and
630 # can be turned off), but better safe than sorry.
631 # Note that the restriction on '*' is a bit unnecessary, since no shell
632 # expansion should happen. ...but again, I'd rather be safe.
633 assert os.path.isabs(board_dir), 'Board dir better be absolute'
634 assert board_dir != '/', 'Board dir better not be /'
635 assert '*' not in board_dir, 'Board dir better not have any *s'
636 assert build_config.get('LEGACY', 'board'), 'Board better not be blank'
637 assert build_config.get('LEGACY', 'board') in board_dir, \
638 'Board name better be in board dir'
639
640 args = ['sudo', '--', 'rm', '-rf', board_dir]
641 RunCommand(args)
642 Info('Deleted: %s' % board_dir)
643
644
645 def _CmdDistClean(chromite_cmd, build_config, chroot_config, options):
646 """Delete the chroot.
647
648 Args:
649 chromite_cmd: The command that was called.
650 build_config: A SafeConfigParser representing the build config.
651 chroot_config: A SafeConfigParser representing the chroot config.
652 options: Options from the OptionParser
653 """
654 # These vars are part of the standard signature, but not used.
655 _ = (chromite_cmd, build_config)
656
657 if _IsInsideChroot():
658 Die('Please exit the chroot before running distclean.')
659
660 chroot_dir = _GetChrootAbsDir(chroot_config)
661
662 if not os.path.isdir(chroot_dir):
sosa 2010/12/23 01:52:27 This isn't necessary. Make_chroot --delete handle
diandersAtChromium 2011/01/06 00:23:23 Yes, but it is a nicety to do this check before gi
sosa 2011/01/11 04:44:22 The question is fine. I specifically meant the os
diandersAtChromium 2011/01/12 00:04:45 Done.
663 Die("Nothing to clean: the chroot doesn't exist.\n %s" %
664 chroot_dir)
665
666 if not options.yes:
667 sys.stderr.write('\n'
668 'Chroot is at: %s\n'
669 'Are you sure you want to delete it (YES/NO)? ' %
670 chroot_dir)
671 answer = raw_input()
672 if answer != 'YES':
673 Die("You must answer exactly 'YES' if you want to proceed.")
674
675 # Can pass args and not shell=True, since no user flags. :)
676 args = ['./make_chroot', '--chroot=%s' % chroot_dir, '--delete']
677
678 # We'll put CWD as src/scripts when running the command. Since everyone
679 # running by hand has their cwd there, it is probably the safest.
680 cwd = os.path.join(_SRCROOT_PATH, 'src', 'scripts')
681
682 # Run it. Pass any failures upward.
683 RunCommand(args, cwd=cwd)
684
685
686 def main():
687 command_list = ', '.join(sorted(_COMMAND_STRS))
688 parser = optparse.OptionParser(
689 usage=_USAGE, description=_DESCRIPTION % dict(command_list=command_list)
690 )
691 parser.add_option('-y', '--yes', default=False, action='store_true',
692 help='Answer "YES" to "are you sure?" questions.')
693 parser.add_option('--resume-state', default='',
694 help='Base64 of state pickle (internal use only).')
695 (options, arguments) = parser.parse_args()
696
697 if options.resume_state:
698 # We've called to resume ourselves in the chroot.
699 fn, args, kwargs = pickle.loads(base64.b64decode(options.resume_state))
700 fn(*args, **kwargs)
701 else:
702 chromite_cmd, build_spec_path = _ParseCommandLine(arguments)
703 Info("Running command '%s' with spec:\n %s" % (chromite_cmd,
704 build_spec_path))
705
706 build_config, chroot_config = _ReadConfigs(build_spec_path)
707
708 cmd_fn = eval(_COMMAND_HANDLERS[_COMMAND_STRS.index(chromite_cmd)])
709 cmd_fn(chromite_cmd, build_config, chroot_config, options)
710
sosa 2010/12/23 01:52:27 2 lines here
diandersAtChromium 2011/01/06 00:23:23 Done.
711 if __name__ == '__main__':
712 main()
OLDNEW
« no previous file with comments | « chromite/chromite ('k') | chromite/chromite.sh » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698