diff --git a/pymake/__init__.py b/pymake/__init__.py index 0406938..01e822f 100644 --- a/pymake/__init__.py +++ b/pymake/__init__.py @@ -1,7 +1,7 @@ from ._main import main from ._version import __version__ # NOQA from ._pymake import __author__, \ - PymakeTypeError, PymakeKeyError + PymakeTypeError, PymakeKeyError, CmdExecutionError __all__ = ['main', '__version__', '__author__', - 'PymakeTypeError', 'PymakeKeyError'] + 'PymakeTypeError', 'PymakeKeyError', 'CmdExecutionError'] diff --git a/pymake/_pymake.py b/pymake/_pymake.py index fdd21c8..c8eb91c 100644 --- a/pymake/_pymake.py +++ b/pymake/_pymake.py @@ -3,7 +3,7 @@ """ from __future__ import absolute_import # import compatibility functions and utilities -from ._utils import ConfigParser, StringIO, shlex +from ._utils import ConfigParser, StringIO, shlex, raise_from import io import re from subprocess import check_call @@ -109,6 +109,24 @@ def parse_makefile_aliases(filepath): return commands, default_alias +class CmdExecutionError(Exception): + """ + Exception raised when a command execution returned an error. + + The python __cause__ is hidden, + and only the command and final message is displayed. + """ + __slots__ = 'cause', 'parsed_cmd' + + def __init__(self, parsed_cmd, cause): + super(CmdExecutionError, self).__init__() + self.cause = cause + self.parsed_cmd = parsed_cmd + + def __str__(self): + return "Error executing CMD '%s': %s" % (self.parsed_cmd, self.cause) + + def execute_makefile_commands( commands, alias, silent=False, just_print=False, ignore_errors=False): """ @@ -141,6 +159,7 @@ def execute_makefile_commands( # Launch the command and wait to finish (synchronized call) try: check_call(parsed_cmd) - except: + except Exception as e: if not ignore_errors: - raise + raise_from(CmdExecutionError(' '.join(parsed_cmd), e), + None) diff --git a/pymake/_utils.py b/pymake/_utils.py index 09b5259..6939364 100644 --- a/pymake/_utils.py +++ b/pymake/_utils.py @@ -20,6 +20,29 @@ except NameError: _unicode = str + try: + from six import raise_from + except ImportError: + if sys.version_info[:2] == (3, 2): + exec("""def raise_from(value, from_value): + try: + if from_value is None: + raise value + raise value from from_value + finally: + value = None + """) + elif sys.version_info[:2] > (3, 2): + exec("""def raise_from(value, from_value): + try: + raise value from from_value + finally: + value = None + """) + else: + def raise_from(value, from_value): + raise value + if sys.version_info >= (2, 7): # pragma: no cover import shlex else: # pragma: no cover diff --git a/pymake/tests/tests_main.py b/pymake/tests/tests_main.py index 800fd17..41047fe 100644 --- a/pymake/tests/tests_main.py +++ b/pymake/tests/tests_main.py @@ -1,7 +1,7 @@ import sys import subprocess from os import path -from pymake import main, PymakeKeyError, PymakeTypeError +from pymake import main, PymakeKeyError, PymakeTypeError, CmdExecutionError dn = path.dirname fname = path.join(dn(dn(dn(path.abspath(__file__)))), @@ -64,8 +64,8 @@ def test_ignore_errors(): """Test --ignore-errors""" try: main(['-s', '-f', fname, 'err']) - except OSError: - pass # test passed if file not found + except CmdExecutionError as e: + assert "Error executing CMD" in str(e) # test passed if file not found else: raise PymakeTypeError('err')