cmd_helper.py revision c2e0dbddbe15c98d52c4786dac06cb8952a8ae6d
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) 17c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)def _Call(args, stdout=None, stderr=None, shell=None, cwd=None): 18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return subprocess.call( 19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) args=args, cwd=cwd, stdout=stdout, stderr=stderr, 20c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) shell=shell, close_fds=True, 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 '')) 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (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) 87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (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): 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) _out_directory = os.path.join(constants.CHROME_DIR, 'out') 1042a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) @staticmethod 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def set(out_directory): 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OutDirectory._out_directory = out_directory 1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) @staticmethod 1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def get(): 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return OutDirectory._out_directory 110