Skip to content

Commit

Permalink
fix definition of patterns for dependencies options in configure() (#…
Browse files Browse the repository at this point in the history
…13263)

* fix definition of patterns for dependencies options in configure()

* fix test
  • Loading branch information
memsharded authored Mar 1, 2023
1 parent a52c24b commit 54cc742
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 25 deletions.
19 changes: 2 additions & 17 deletions conans/model/options.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from conans.errors import ConanException
from conans.model.recipe_ref import RecipeReference, ref_matches
from conans.model.recipe_ref import ref_matches

_falsey_options = ["false", "none", "0", "off", ""]

Expand Down Expand Up @@ -308,22 +308,7 @@ def __delattr__(self, field):
self._package_options.__delattr__(field)

def __getitem__(self, item):
# FIXME: Kept for configure => self.options["xxx"].shared = True
# To access dependencies options like ``options["mydep"]``. This will no longer be
# a read case, only for defining values. Read access will be via self.dependencies["dep"]
if isinstance(item, str):
if "/" not in item: # FIXME: To allow patterns like "*" or "foo*"
item += "/*"
item = RecipeReference.loads(item)

return self.get(item, is_consumer=False)

def get(self, ref, is_consumer):
ret = _PackageOptions()
for pattern, options in self._deps_package_options.items():
if ref_matches(ref, pattern, is_consumer):
ret.update(options)
return self._deps_package_options.setdefault(ref.repr_notime(), ret)
return self._deps_package_options.setdefault(item, _PackageOptions())

def scope(self, ref):
""" when there are free options like "shared=True", they apply to the "consumer" package
Expand Down
111 changes: 110 additions & 1 deletion conans/test/integration/options/options_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ class Pkg(ConanFile):
version = "0.1"
requires = "pkg/0.1"
def configure(self):
self.options["pkg"].backend = 1
self.options["pkg*"].backend = 1
""")
c.save({"conanfile.py": consumer})
c.run("install . -s os=Windows")
Expand All @@ -395,3 +395,112 @@ def configure(self):
# This fails in Conan 1.X
c.run("create . -s os=Windows -o pkg*:backend=3")
assert "pkg/0.1: Package with option:3!" in c.out


class TestMultipleOptionsPatterns:
"""
https://github.com/conan-io/conan/issues/13240
"""

dep = textwrap.dedent("""
from conan import ConanFile
class Pkg(ConanFile):
version = "1.0"
options = {"shared": [True, False]}
default_options = {"shared": False}
def package_info(self):
self.output.info(f"SHARED: {self.options.shared}!!")
""")

def test_multiple_options_patterns_cli(self):
"""
https://github.com/conan-io/conan/issues/13240
"""
c = TestClient()
consumer = textwrap.dedent("""
from conan import ConanFile
class Pkg(ConanFile):
settings = "os", "arch", "compiler", "build_type"
def requirements(self):
self.requires("dep1/1.0")
self.requires("dep2/1.0")
self.requires("dep3/1.0")
self.requires("dep4/1.0")
""")
c.save({"dep/conanfile.py": self.dep,
"pkg/conanfile.py": consumer})
for d in (1, 2, 3, 4):
c.run(f"export dep --name dep{d}")

# match in order left to right
c.run('install pkg -o *:shared=True -o dep1*:shared=False -o dep2*:shared=False -b missing')
assert "dep1/1.0: SHARED: False!!" in c.out
assert "dep2/1.0: SHARED: False!!" in c.out
assert "dep3/1.0: SHARED: True!!" in c.out
assert "dep4/1.0: SHARED: True!!" in c.out

# All match in order, left to right
c.run('install pkg -o dep1*:shared=False -o dep2*:shared=False -o *:shared=True -b missing')
assert "dep1/1.0: SHARED: True!!" in c.out
assert "dep2/1.0: SHARED: True!!" in c.out
assert "dep3/1.0: SHARED: True!!" in c.out
assert "dep4/1.0: SHARED: True!!" in c.out

def test_multiple_options_patterns(self):
c = TestClient()
configure_consumer = textwrap.dedent("""
from conan import ConanFile
class Pkg(ConanFile):
settings = "os", "arch", "compiler", "build_type"
def requirements(self):
self.requires("dep1/1.0")
self.requires("dep2/1.0")
self.requires("dep3/1.0")
self.requires("dep4/1.0")
def configure(self):
self.options["*"].shared = True
self.options["dep1*"].shared = False
self.options["dep2*"].shared = False
""")
c.save({"dep/conanfile.py": self.dep,
"pkg/conanfile.py": configure_consumer})
for d in (1, 2, 3, 4):
c.run(f"export dep --name dep{d}")

c.run("install pkg --build=missing")
assert "dep1/1.0: SHARED: False!!" in c.out
assert "dep2/1.0: SHARED: False!!" in c.out
assert "dep3/1.0: SHARED: True!!" in c.out
assert "dep4/1.0: SHARED: True!!" in c.out

def test_multiple_options_patterns_order(self):
c = TestClient()
configure_consumer = textwrap.dedent("""
from conan import ConanFile
class Pkg(ConanFile):
settings = "os", "arch", "compiler", "build_type"
def requirements(self):
self.requires("dep1/1.0")
self.requires("dep2/1.0")
self.requires("dep3/1.0")
self.requires("dep4/1.0")
def configure(self):
self.options["dep1*"].shared = False
self.options["dep2*"].shared = False
self.options["*"].shared = True
""")
c.save({"dep/conanfile.py": self.dep,
"pkg/conanfile.py": configure_consumer})
for d in (1, 2, 3, 4):
c.run(f"export dep --name dep{d}")

c.run("install pkg --build=missing")
assert "dep1/1.0: SHARED: True!!" in c.out
assert "dep2/1.0: SHARED: True!!" in c.out
assert "dep3/1.0: SHARED: True!!" in c.out
assert "dep4/1.0: SHARED: True!!" in c.out
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def package_id(self):
if self.dependencies["pkg"].package_type == "static-library":
self.output.info("EMBED MODE!!")
self.info.requires["pkg"].package_id = None
self.info.options["pkg"].affect = self.dependencies["pkg"].options.affect
self.info.options["pkg/*"].affect = self.dependencies["pkg"].options.affect
""")
client.save({"conanfile.py": app})
client.run("create . -o pkg*:noaffect=1 -o pkg*:affect=False")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,8 @@ def save_profile(txt, name):
profile = profile_loader.load_profile("./profile4.txt", tmp)

assert profile.settings == {"os": "1"}
assert profile.options["zlib/1.2.11"].aoption == 1
assert profile.options["zlib/*"].otheroption == 12
assert profile.options["zlib*"].aoption == 1
assert profile.options["zlib*"].otheroption == 12
assert profile.tool_requires == {"*": [RecipeReference.loads("one/1.5@lasote/stable"),
RecipeReference.loads("two/1.2@lasote/stable")]}

Expand Down
6 changes: 2 additions & 4 deletions conans/test/unittests/model/options_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,8 @@ def test_load(self):
assert sut.path != "whatever" # Non validating
assert sut.static == "True"
assert sut.static != "whatever" # Non validating
assert sut["zlib/1*"].option == 8
assert sut["zlib/1.2.11"].option == 8
assert sut["zlib/*"].option != "whatever" # Non validating
assert sut["*/*"].common == "value"
assert sut["zlib*"].option == 8
assert sut["zlib*"].option != "whatever" # Non validating
assert sut["*"].common == "value"
assert sut["*"].common != "whatever" # Non validating

Expand Down

0 comments on commit 54cc742

Please sign in to comment.