203 def __init__(self, command, working_dir=None, capture_stderr=True, env=None):
204 """Changes into a specified directory, if provided, and executes a command.
205
206 Restores the old directory afterwards.
207
208 Args:
209 command: The command to run, in the form of sys.argv.
210 working_dir: The directory to change into.
211 capture_stderr: Determines whether to capture stderr in the output member
212 or to discard it.
213 env: Dictionary with environment to pass to the subprocess.
214
215 Returns:
216 An object that represents outcome of the executed process. It has the
217 following attributes:
218 terminated_by_signal True if and only if the child process has been
219 terminated by a signal.
220 exited True if and only if the child process exited
221 normally.
222 exit_code The code with which the child process exited.
223 output Child process's stdout and stderr output
224 combined in a string.
225 """
226
227
228
229
230
231
232
233
234 if _SUBPROCESS_MODULE_AVAILABLE:
235 if capture_stderr:
236 stderr = subprocess.STDOUT
237 else:
238 stderr = subprocess.PIPE
239
240 p = subprocess.Popen(command,
241 stdout=subprocess.PIPE, stderr=stderr,
242 cwd=working_dir, universal_newlines=True, env=env)
243
244
245 self.output = p.communicate()[0]
246 self._return_code = p.returncode
247 else:
248 old_dir = os.getcwd()
249
250 def _ReplaceEnvDict(dest, src):
251
252
253
254 for key in dest.keys():
255 del dest[key]
256 dest.update(src)
257
258
259
260
261
262 if env is not None:
263 old_environ = os.environ.copy()
264 _ReplaceEnvDict(os.environ, env)
265
266 try:
267 if working_dir is not None:
268 os.chdir(working_dir)
269 if capture_stderr:
270 p = popen2.Popen4(command)
271 else:
272 p = popen2.Popen3(command)
273 p.tochild.close()
274 self.output = p.fromchild.read()
275 ret_code = p.wait()
276 finally:
277 os.chdir(old_dir)
278
279
280
281 if env is not None:
282 _ReplaceEnvDict(os.environ, old_environ)
283
284
285
286 if os.WIFSIGNALED(ret_code):
287 self._return_code = -os.WTERMSIG(ret_code)
288 else:
289 self._return_code = os.WEXITSTATUS(ret_code)
290
291 if bool(self._return_code & 0x80000000):
292 self.terminated_by_signal = True
293 self.exited = False
294 else:
295 self.terminated_by_signal = False
296 self.exited = True
297 self.exit_code = self._return_code
298
299