cmd_helper.py revision 424c4d7b64af9d0d8fd9624f381f469654d5e3d2
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)"""A wrapper for subprocess to make calling shell commands easier."""
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import os
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import logging
9c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import pipes
10c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import signal
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)import subprocess
12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)import tempfile
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import constants
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
16c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
17424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)def Call(args, stdout=None, stderr=None, shell=None, cwd=None, env=None):
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return subprocess.call(
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      args=args, cwd=cwd, stdout=stdout, stderr=stderr,
20424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)      shell=shell, close_fds=True, env=env,
21c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      preexec_fn=lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL))
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
23c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def RunCmd(args, cwd=None):
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Opens a subprocess to execute a program and returns its return value.
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    args: A string or a sequence of program arguments. The program to execute is
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      the string or the first item in the args sequence.
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cwd: If not None, the subprocess's current directory will be changed to
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      |cwd| before it's executed.
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Return code from the command execution.
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  logging.info(str(args) + ' ' + (cwd or ''))
37424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  return Call(args, cwd=cwd)
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GetCmdOutput(args, cwd=None, shell=False):
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Open a subprocess to execute a program and returns its output.
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    args: A string or a sequence of program arguments. The program to execute is
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      the string or the first item in the args sequence.
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cwd: If not None, the subprocess's current directory will be changed to
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      |cwd| before it's executed.
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shell: Whether to execute args as a shell command.
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Captures and returns the command's stdout.
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    Prints the command's stderr to logger (which defaults to stdout).
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  (_, output) = GetCmdStatusAndOutput(args, cwd, shell)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return output
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)def GetCmdStatusAndOutput(args, cwd=None, shell=False):
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """Executes a subprocess and returns its exit code and output.
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Args:
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    args: A string or a sequence of program arguments. The program to execute is
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      the string or the first item in the args sequence.
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    cwd: If not None, the subprocess's current directory will be changed to
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      |cwd| before it's executed.
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    shell: Whether to execute args as a shell command.
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Returns:
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    The tuple (exit code, output).
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  """
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if isinstance(args, basestring):
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    args_repr = args
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    if not shell:
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      raise Exception('string args must be run with shell=True')
75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  elif shell:
76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    raise Exception('array args must be run with shell=False')
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  else:
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    args_repr = ' '.join(map(pipes.quote, args))
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  s = '[host]'
81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if cwd:
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    s += ':' + cwd
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  s += '> ' + args_repr
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  logging.info(s)
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  tmpout = tempfile.TemporaryFile(bufsize=0)
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  tmperr = tempfile.TemporaryFile(bufsize=0)
87424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  exit_code = Call(args, cwd=cwd, stdout=tmpout, stderr=tmperr, shell=shell)
88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  tmperr.seek(0)
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  stderr = tmperr.read()
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  tmperr.close()
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if stderr:
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    logging.critical(stderr)
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  tmpout.seek(0)
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  stdout = tmpout.read()
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  tmpout.close()
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  if len(stdout) > 4096:
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    logging.debug('Truncated output:')
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  logging.debug(stdout[:4096])
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return (exit_code, stdout)
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class OutDirectory(object):
103ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch  _out_directory = os.path.join(constants.DIR_SOURCE_ROOT,
104ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch      os.environ.get('CHROMIUM_OUT_DIR','out'))
1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @staticmethod
1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def set(out_directory):
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    OutDirectory._out_directory = out_directory
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @staticmethod
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def get():
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return OutDirectory._out_directory
111