Skip to content

Commit

Permalink
Add ConanInvalidConfiguration exception and handle error codes. (#3517)
Browse files Browse the repository at this point in the history
* add exception

* test for command line

* move exit codes to global scope
  • Loading branch information
jgsogo authored and lasote committed Sep 24, 2018
1 parent 4f0d283 commit eecc16f
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 11 deletions.
38 changes: 27 additions & 11 deletions conans/client/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from conans.client.conan_command_output import CommandOutputer
from conans.client.output import Color

from conans.errors import ConanException, NoRemoteAvailable
from conans.errors import ConanException, NoRemoteAvailable, ConanInvalidConfiguration
from conans.model.ref import ConanFileReference
from conans.util.config_parser import get_bool_from_text
from conans.util.log import logger
Expand All @@ -21,6 +21,16 @@
UPLOAD_POLICY_NO_OVERWRITE, UPLOAD_POLICY_NO_OVERWRITE_RECIPE, UPLOAD_POLICY_SKIP


# Exit codes for conan command:
SUCCESS = 0 # 0: Success (done)
ERROR_GENERAL = 1 # 1: General ConanException error (done)
ERROR_MIGRATION = 2 # 2: Migration error
USER_CTRL_C = 3 # 3: Ctrl+C
USER_CTRL_BREAK = 4 # 4: Ctrl+Break
ERROR_SIGTERM = 5 # 5: SIGTERM
ERROR_INVALID_CONFIGURATION = 6 # 6: Invalid configuration (done)


class Extender(argparse.Action):
"""Allows to use the same flag several times in a command and creates a list with the values.
For example:
Expand Down Expand Up @@ -1316,7 +1326,7 @@ def run(self, *args):
"""HIDDEN: entry point for executing commands, dispatcher to class
methods
"""
errors = False
ret_code = SUCCESS
try:
try:
command = args[0][0]
Expand All @@ -1337,24 +1347,28 @@ def run(self, *args):
method(args[0][1:])
except KeyboardInterrupt as exc:
logger.error(exc)
errors = True
ret_code = SUCCESS
except SystemExit as exc:
if exc.code != 0:
logger.error(exc)
self._user_io.out.error("Exiting with code: %d" % exc.code)
errors = exc.code
ret_code = exc.code
except ConanInvalidConfiguration as exc:
ret_code = ERROR_INVALID_CONFIGURATION
msg = exception_message_safe(exc)
self._user_io.out.error(msg)
except ConanException as exc:
errors = True
ret_code = ERROR_GENERAL
msg = exception_message_safe(exc)
self._user_io.out.error(msg)
except Exception as exc:
import traceback
print(traceback.format_exc())
errors = True
ret_code = ERROR_GENERAL
msg = exception_message_safe(exc)
self._user_io.out.error(msg)

return errors
return ret_code


def get_reference_fields(arg_reference):
Expand Down Expand Up @@ -1444,11 +1458,13 @@ def main(args):
2: Migration error
3: Ctrl+C
4: Ctrl+Break
5: SIGTERM
6: Invalid configuration (done)
"""
try:
conan_api, client_cache, user_io = Conan.factory()
except ConanException: # Error migrating
sys.exit(2)
sys.exit(ERROR_MIGRATION)

outputer = CommandOutputer(user_io, client_cache)
command = Command(conan_api, client_cache, user_io, outputer)
Expand All @@ -1458,15 +1474,15 @@ def main(args):

def ctrl_c_handler(_, __):
print('You pressed Ctrl+C!')
sys.exit(3)
sys.exit(USER_CTRL_C)

def sigterm_handler(_, __):
print('Received SIGTERM!')
sys.exit(5)
sys.exit(ERROR_SIGTERM)

def ctrl_break_handler(_, __):
print('You pressed Ctrl+Break!')
sys.exit(4)
sys.exit(USER_CTRL_BREAK)

signal.signal(signal.SIGINT, ctrl_c_handler)
signal.signal(signal.SIGTERM, sigterm_handler)
Expand Down
7 changes: 7 additions & 0 deletions conans/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ def conanfile_exception_formatter(conanfile_name, func_name):
"""
try:
yield
except ConanInvalidConfiguration as exc:
msg = "{}: Invalid configuration: {}".format(conanfile_name, exc) # TODO: Move from here?
raise ConanInvalidConfiguration(msg)
except Exception as exc:
msg = _format_conanfile_exception(conanfile_name, func_name, exc)
raise ConanExceptionInUserConanfileMethod(msg)
Expand Down Expand Up @@ -95,6 +98,10 @@ class ConanExceptionInUserConanfileMethod(ConanException):
pass


class ConanInvalidConfiguration(ConanExceptionInUserConanfileMethod):
pass


# Remote exceptions #
class InternalErrorException(ConanException):
"""
Expand Down
61 changes: 61 additions & 0 deletions conans/test/command/invalid_configuration_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@

import unittest

from conans.test.utils.tools import TestClient
from conans.client.command import ERROR_INVALID_CONFIGURATION


class InvalidConfigurationTest(unittest.TestCase):

def setUp(self):
self.client = TestClient()
self.client.save({"conanfile.py": """
from conans import ConanFile
from conans.errors import ConanInvalidConfiguration
class MyPkg(ConanFile):
settings = "os", "compiler", "build_type", "arch"
def configure(self):
if self.settings.compiler.version == "12":
raise ConanInvalidConfiguration("user says that compiler.version=12 is invalid")
"""})
settings = "-s os=Windows -s compiler='Visual Studio' -s compiler.version={ver}"
self.settings_msvc15 = settings.format(ver="15")
self.settings_msvc12 = settings.format(ver="12")

def test_install_method(self):
self.client.run("install . %s" % self.settings_msvc15)

error = self.client.run("install . %s" % self.settings_msvc12, ignore_error=True)
self.assertEqual(error, ERROR_INVALID_CONFIGURATION)
self.assertIn("Invalid configuration: user says that compiler.version=12 is invalid",
self.client.out)

def test_create_method(self):
self.client.run("create . name/ver@jgsogo/test %s" % self.settings_msvc15)

error = self.client.run("create . name/ver@jgsogo/test %s" % self.settings_msvc12,
ignore_error=True)
self.assertEqual(error, ERROR_INVALID_CONFIGURATION)
self.assertIn("name/ver@jgsogo/test: Invalid configuration: user says that "
"compiler.version=12 is invalid", self.client.out)

def test_as_requirement(self):
self.client.run("create . name/ver@jgsogo/test %s" % self.settings_msvc15)
self.client.save({"other/conanfile.py": """
from conans import ConanFile
from conans.errors import ConanInvalidConfiguration
class MyPkg(ConanFile):
requires = "name/ver@jgsogo/test"
settings = "os", "compiler", "build_type", "arch"
"""})
self.client.run("create other/ other/ver@jgsogo/test %s" % self.settings_msvc15)

error = self.client.run("create other/ other/ver@jgsogo/test %s" % self.settings_msvc12,
ignore_error=True)
self.assertEqual(error, ERROR_INVALID_CONFIGURATION)
self.assertIn("name/ver@jgsogo/test: Invalid configuration: user says that "
"compiler.version=12 is invalid", self.client.out)

0 comments on commit eecc16f

Please sign in to comment.