Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat] Introduce exception raised in 'configure' that will propagate only if 'build' #6952

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions conans/client/conanfile/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ def run_build_method(conanfile, hook_manager, **hook_kwargs):
with get_env_context_manager(conanfile):
conanfile.output.highlight("Calling build()")
with conanfile_exception_formatter(str(conanfile), "build"):
configure_exception = getattr(conanfile, '_conan_exception_build', None)
if configure_exception:
raise configure_exception
conanfile.build()

hook_manager.execute("post_build", conanfile=conanfile, **hook_kwargs)
9 changes: 7 additions & 2 deletions conans/client/conanfile/configure.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from conans.errors import (conanfile_exception_formatter)
from conans.errors import ConanIWontBuild, conanfile_exception_formatter
from conans.model.conan_file import get_env_context_manager
from conans.util.conan_v2_mode import conan_v2_behavior

Expand All @@ -25,7 +25,12 @@ def run_configure_method(conanfile, down_options, down_ref, ref):
conanfile.config()

with conanfile_exception_formatter(str(conanfile), "configure"):
conanfile.configure()
try:
conanfile.configure()
except ConanIWontBuild as e:
# Capture and silence this exception until the 'build' method.
# TODO: This has to be the last exception after any ConanInvalidConfiguration
conanfile._conan_exception_build = e

conanfile.settings.validate() # All has to be ok!
conanfile.options.validate()
4 changes: 4 additions & 0 deletions conans/errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ class ConanInvalidConfiguration(ConanExceptionInUserConanfileMethod):
pass


class ConanIWontBuild(ConanInvalidConfiguration):
pass


class ConanMigrationError(ConanException):
pass

Expand Down
99 changes: 99 additions & 0 deletions conans/test/functional/conanfile/i_wont_build_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import textwrap
import unittest

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


class IWontBuildTestCase(unittest.TestCase):

def setUp(self):
self.client = TestClient()
self.client.save({"conanfile.py": textwrap.dedent("""
from conans import ConanFile
from conans.errors import ConanIWontBuild

class MyPkg(ConanFile):
settings = "os", "compiler", "build_type", "arch"

def configure(self):
if self.settings.compiler.version == "10":
raise ConanIWontBuild("won't build with compiler.version=10")

""")})
settings = "-s os=Windows -s compiler='Visual Studio' -s compiler.version={ver}"
self.settings_msvc15 = settings.format(ver="15")
self.settings_msvc10 = settings.format(ver="10")

def test_install_method(self):
self.client.run("install . %s" % self.settings_msvc15, assert_error=False)
self.client.run("install . %s" % self.settings_msvc10, assert_error=False)

def test_info_method(self):
self.client.run("info . %s" % self.settings_msvc15, assert_error=False)
self.client.run("info . %s" % self.settings_msvc10, assert_error=False)

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_msvc10,
assert_error=True)
self.assertEqual(error, ERROR_INVALID_CONFIGURATION)
self.assertIn("ERROR: name/ver@jgsogo/test: Invalid configuration: won't"
" build with compiler.version=10", 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": textwrap.dedent("""
from conans import ConanFile
from conans.errors import ConanIWontBuild

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@ %s --build missing" % self.settings_msvc10,
assert_error=True)
self.assertEqual(error, ERROR_INVALID_CONFIGURATION)
self.assertIn("ERROR: name/ver@jgsogo/test: Invalid configuration: won't"
" build with compiler.version=10", self.client.out)


class IWontBuildCompatiblePackagesTestCase(unittest.TestCase):
conanfile = textwrap.dedent("""
from conans import ConanFile
from conans.errors import ConanIWontBuild

class Recipe(ConanFile):
settings = "os", "compiler", "arch", "build_type"

def configure(self):
if self.settings.compiler.version == "15":
raise ConanIWontBuild("Invalid compiler version: 15")

def package_id(self):
if self.settings.compiler.version == "15":
for version in ("10", "12"):
compatible_pkg = self.info.clone()
compatible_pkg.settings.compiler.version = version
self.compatible_packages.append(compatible_pkg)
""")

def test_compatible_package(self):
client = TestClient()
client.save({"conanfile.py": self.conanfile})

# Create binaries for VS 12
client.run("create . name/version@ -s compiler='Visual Studio' -s compiler.version=12")

# It doesn't compile using VS 15
error = client.run("install name/version@ -s compiler='Visual Studio'"
" -s compiler.version=15 --build=name", assert_error=True)
self.assertEqual(error, ERROR_INVALID_CONFIGURATION)
self.assertIn("Invalid compiler version: 15", client.out)

# ...but it can be consumed
client.run("install name/version@ -s compiler='Visual Studio' -s compiler.version=15")
self.assertIn("Using compatible package", client.out)