| OLD | NEW |
| 1 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved. | 1 # Copyright (c) 2011 The Chromium OS Authors. All rights reserved. |
| 2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
| 3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
| 4 | 4 |
| 5 """Chromite base class. | 5 """Chromite base class. |
| 6 | 6 |
| 7 This module maintains information about the build environemnt, including | 7 This module maintains information about the build environemnt, including |
| 8 paths and defaults. It includes methods for querying the environemnt. | 8 paths and defaults. It includes methods for querying the environemnt. |
| 9 | 9 |
| 10 (For now this is just a placeholder to illustrate the concept) | 10 (For now this is just a placeholder to illustrate the concept) |
| 11 """ | 11 """ |
| 12 | 12 |
| 13 import os | |
| 14 import signal | |
| 15 import utils | |
| 16 from chromite.lib import operation | 13 from chromite.lib import operation |
| 17 from chromite.lib import cros_subprocess | |
| 18 | 14 |
| 19 | 15 |
| 20 class ChromiteError(Exception): | 16 class ChromiteError(Exception): |
| 21 """A Chromite exception, such as a build error or missing file. | 17 """A Chromite exception, such as a build error or missing file. |
| 22 | 18 |
| 23 We define this as an exception type so that we can report proper | 19 We define this as an exception type so that we can report proper |
| 24 meaningful errors to upper layers rather than just the OS 'File not | 20 meaningful errors to upper layers rather than just the OS 'File not |
| 25 found' low level message. | 21 found' low level message. |
| 26 """ | 22 """ |
| 27 pass | 23 pass |
| (...skipping 11 matching lines...) Expand all Loading... |
| 39 # We have at least a single overall operation always, so set it up. | 35 # We have at least a single overall operation always, so set it up. |
| 40 self._oper = operation.Operation('operation') | 36 self._oper = operation.Operation('operation') |
| 41 | 37 |
| 42 def __del__(self): | 38 def __del__(self): |
| 43 del self._oper | 39 del self._oper |
| 44 | 40 |
| 45 def GetOperation(self): | 41 def GetOperation(self): |
| 46 """Returns the current operation in progress | 42 """Returns the current operation in progress |
| 47 """ | 43 """ |
| 48 return self._oper | 44 return self._oper |
| 49 | |
| 50 def RunScript(self, name, cmd, args, env=None, shell_vars=None): | |
| 51 """Run a legacy script in src/scripts. | |
| 52 | |
| 53 This is the only place in chromite where legacy scripts are invoked. We | |
| 54 aim to replace all calls to this method with a proper python alternative | |
| 55 complete with unit tests. For now this allows chromite to do its job. | |
| 56 | |
| 57 We'll ignore signal.SIGINT before calling the child. This is the desired | |
| 58 behavior if we know our child will handle Ctrl-C. If we don't do this, I | |
| 59 think we and the child will both get Ctrl-C at the same time, which means | |
| 60 we'll forcefully kill the child. | |
| 61 | |
| 62 The specified command will be executed through the shell. | |
| 63 | |
| 64 We'll put CWD as src/scripts when running the commands, since many of these | |
| 65 legacy commands live in src/scripts. | |
| 66 | |
| 67 This code has come from RunCommand but we have removed the so-far unused | |
| 68 extra features like input, entering chroot and various controls. | |
| 69 | |
| 70 Also removed is argument handling. This function does not handle arguments | |
| 71 with spaces in them. Also it does not escape any special characters that | |
| 72 are passed in. The command is executed with 'sh -c ...' so the limitations | |
| 73 of that must be kept in mind. | |
| 74 | |
| 75 Args: | |
| 76 name: A name for the script, as might be displayed to the user. | |
| 77 cmd: Command to run. Should be input to subprocess.Popen. | |
| 78 args: list of arguments to pass to command. | |
| 79 env: If non-None, this is the environment for the new process. | |
| 80 shell_vars: If non-None, this is the shell variables to define before | |
| 81 running the script. | |
| 82 | |
| 83 Raises: | |
| 84 ChromiteError(msg) if subprocess return code is not 0. | |
| 85 Args: | |
| 86 msg: Error message | |
| 87 | |
| 88 TODO(sjg): Can we remove shell_vars and require callers to use env? | |
| 89 And _SplitEnvFromArgs already does this! | |
| 90 """ | |
| 91 #TODO(sjg): Make printing the operation name optional | |
| 92 self._oper.Outline(name) | |
| 93 if shell_vars is None: | |
| 94 shell_vars = '' | |
| 95 | |
| 96 # In verbose mode we don't try to separate stdout and stderr since we | |
| 97 # can't be sure we will interleave output correctly for verbose | |
| 98 # subprocesses. | |
| 99 stderr = cros_subprocess.PIPE_PTY | |
| 100 if self._oper.verbose: | |
| 101 stderr = cros_subprocess.STDOUT | |
| 102 | |
| 103 child = cros_subprocess.Popen( | |
| 104 ["sh", "-c", shell_vars + ' ' + cmd + ' ' + ' '.join(args)], | |
| 105 stderr=stderr, | |
| 106 env=env, | |
| 107 cwd=os.path.join(utils.SRCROOT_PATH, 'src', 'scripts')) | |
| 108 old_sigint = signal.signal(signal.SIGINT, signal.SIG_IGN) | |
| 109 | |
| 110 try: | |
| 111 child.CommunicateFilter(self._oper.Output) | |
| 112 finally: | |
| 113 signal.signal(signal.SIGINT, old_sigint) | |
| 114 | |
| 115 if child.returncode != 0: | |
| 116 msg = ("Error: command '%s' exited with error code %d" % | |
| 117 (cmd, child.returncode)) | |
| 118 self._oper.Outline(msg) | |
| 119 raise ChromiteError(msg) | |
| 120 elif self._oper.WereErrorsDetected(): | |
| 121 self._oper.Outline("Error output detected, but command indicated "\ | |
| 122 "success.") | |
| 123 | |
| 124 self._oper.FinishOutput() | |
| OLD | NEW |