# -*- coding: utf-8 -*- # Copyright 2016-2017 ACSONE SA/NV (<http://acsone.eu>) # License GPL-3.0 or later (http://www.gnu.org/licenses/gpl.html). import contextlib import logging import os import subprocess import sys from distutils.spawn import find_executable as _fe import click _logger = logging.getLogger(__name__) def _escape(s): s = s.replace("\\", "\\\\") s = s.replace('"', '\\"') s = s.replace("'", "\\'") s = s.replace("&", "\\&") s = s.replace("|", "\\|") s = s.replace(">", "\\>") s = s.replace("<", "\\<") s = s.replace(" ", "\\ ") return s def cmd_string(cmd): return " ".join([_escape(s) for s in cmd]) def log_cmd(cmd, cwd=None, level=logging.DEBUG, echo=False): s = cmd_string(cmd) if echo: click.echo(click.style(s, bold=True)) _logger.log(level, "%s$ %s", cwd or ".", s) def call(cmd, cwd=None, log_level=logging.DEBUG, echo=False): _adapt_executable(cmd) log_cmd(cmd, cwd=cwd, level=log_level, echo=echo) try: return subprocess.call(cmd, cwd=cwd) except subprocess.CalledProcessError: raise click.ClickException(cmd_string(cmd)) def check_call(cmd, cwd=None, log_level=logging.DEBUG, echo=False): _adapt_executable(cmd) log_cmd(cmd, cwd=cwd, level=log_level, echo=echo) try: return subprocess.check_call(cmd, cwd=cwd) except subprocess.CalledProcessError: raise click.ClickException(cmd_string(cmd)) def check_output( cmd, cwd=None, log_level=logging.DEBUG, echo=False, universal_newlines=True ): _adapt_executable(cmd) log_cmd(cmd, cwd=cwd, level=log_level, echo=echo) try: return subprocess.check_output( cmd, cwd=cwd, universal_newlines=universal_newlines ) except subprocess.CalledProcessError: raise click.ClickException(cmd_string(cmd)) @contextlib.contextmanager def working_directory(path): """A context manager which changes the working directory to the given path, and then changes it back to its previous value on exit. """ prev_cwd = os.getcwd() _logger.debug(".$ cd %s", _escape(path)) os.chdir(path) try: yield finally: _logger.debug(".$ cd %s", _escape(prev_cwd)) os.chdir(prev_cwd) def _adapt_executable(cmd): cmd[0] = _find_executable(cmd[0]) def _find_executable(exe): if os.path.isabs(exe): return exe python_dir = os.path.dirname(sys.executable) exe_path = os.path.join(python_dir, exe) if os.path.exists(exe_path): return exe_path exe_path = _fe(exe) if exe_path: return exe_path raise RuntimeError("{} executable not found".format(exe)) def find_python(exe): if os.path.isabs(exe): return exe exe_path = _fe(exe) if exe_path: return exe_path raise RuntimeError("{} executable not found".format(exe)) def cfg_path(filename): return os.path.join(os.path.dirname(__file__), "cfg", filename)