# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this file, # You can obtain one at http://mozilla.org/MPL/2.0/. """Functions for running commands""" from __future__ import absolute_import, print_function import subprocess import os import time import logging log = logging.getLogger(__name__) # timeout message, used in TRANSIENT_HG_ERRORS and in tests. TERMINATED_PROCESS_MSG = "timeout, process terminated" def log_cmd(cmd, **kwargs): # cwd is special in that we always want it printed, even if it's not # explicitly chosen kwargs = kwargs.copy() if 'cwd' not in kwargs: kwargs['cwd'] = os.getcwd() log.info("command: START") log.info("command: %s" % subprocess.list2cmdline(cmd)) for key, value in kwargs.iteritems(): log.info("command: %s: %s", key, str(value)) def merge_env(env): new_env = os.environ.copy() new_env.update(env) return new_env def run_cmd(cmd, **kwargs): """Run cmd (a list of arguments). Raise subprocess.CalledProcessError if the command exits with non-zero. If the command returns successfully, return 0.""" log_cmd(cmd, **kwargs) # We update this after logging because we don't want all of the inherited # env vars muddling up the output if 'env' in kwargs: kwargs['env'] = merge_env(kwargs['env']) try: t = time.time() log.info("command: output:") return subprocess.check_call(cmd, **kwargs) except subprocess.CalledProcessError: log.info('command: ERROR', exc_info=True) raise finally: elapsed = time.time() - t log.info("command: END (%.2fs elapsed)\n", elapsed)