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 |