Skip to content

Commit db16b7b

Browse files
authored
New "no_skip=True" trait for tool-require wrappers for transitive deps with different versions (#18101)
* test for tool-require wrappers for transitive deps with different versions * fix test in Linux * new test with skip_binaries=False * poc * improved test * check skip_binaries conf doesn't affect * rename trait
1 parent 004cc56 commit db16b7b

File tree

3 files changed

+95
-2
lines changed

3 files changed

+95
-2
lines changed

conan/internal/model/requires.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ class Requirement:
1111
"""
1212
def __init__(self, ref, *, headers=None, libs=None, build=False, run=None, visible=None,
1313
transitive_headers=None, transitive_libs=None, test=None, package_id_mode=None,
14-
force=None, override=None, direct=None, options=None):
14+
force=None, override=None, direct=None, options=None, no_skip=False):
1515
# * prevents the usage of more positional parameters, always ref + **kwargs
1616
# By default this is a generic library requirement
1717
self.ref = ref
@@ -38,6 +38,7 @@ def __init__(self, ref, *, headers=None, libs=None, build=False, run=None, visib
3838
self.is_test = test # to store that it was a test, even if used as regular requires too
3939
self.skip = False
4040
self.required_nodes = set() # store which intermediate nodes are required, to compute "Skip"
41+
self.no_skip = no_skip
4142

4243
@property
4344
def files(self): # require needs some files in dependency package

conans/client/graph/graph_binaries.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,8 @@ def _skip_binaries(graph):
503503

504504
# Finally accumulate all needed nodes for marking binaries as SKIP download
505505
news_req = [r for r in deps_required
506-
if r.binary in (BINARY_BUILD, BINARY_EDITABLE_BUILD, BINARY_EDITABLE)
506+
if (r.binary in (BINARY_BUILD, BINARY_EDITABLE_BUILD, BINARY_EDITABLE)
507+
or any(req.no_skip for req in r.transitive_deps))
507508
if r not in required_nodes] # Avoid already expanded before
508509
new_root_nodes.update(news_req) # For expanding the next iteration
509510
required_nodes.update(deps_required)

test/integration/graph/test_require_same_pkg_versions.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import re
12
import textwrap
23

34
from conan.test.assets.genconanfile import GenConanfile
@@ -186,3 +187,93 @@ def build(self):
186187
lock = c.load("wine/conan.lock")
187188
# Testing it doesn't crash or anything like that
188189
assert "gcc/1.0#616ce3babcecef39a27806c1a5f4b4ff" in lock
190+
191+
192+
def test_require_different_versions_transitive():
193+
"""
194+
https://github.com/conan-io/conan/issues/18086
195+
"""
196+
c = TestClient(default_server_user=True, path_with_spaces=False)
197+
qemu = textwrap.dedent(r"""
198+
import os
199+
from conan import ConanFile
200+
from conan.tools.files import save
201+
class Pkg(ConanFile):
202+
name = "myqemu"
203+
package_type = "application"
204+
205+
def package(self):
206+
echo = f"@echo off\necho RUNNING {self.name}/{self.version}!!"
207+
save(self, os.path.join(self.package_folder, "bin", f"{self.name}.bat"), echo)
208+
save(self, os.path.join(self.package_folder, "bin", f"{self.name}.sh"), echo)
209+
os.chmod(os.path.join(self.package_folder, "bin", f"{self.name}.sh"), 0o777)
210+
""")
211+
mytool = textwrap.dedent(r"""
212+
import os, platform
213+
from conan import ConanFile
214+
from conan.tools.files import save, chdir
215+
class Pkg(ConanFile):
216+
version = "1.0"
217+
package_type = "application"
218+
219+
def requirements(self):
220+
version = "1.0" if self.name == "snippy" else "2.0"
221+
self.requires(f"myqemu/{version}", visible=False, no_skip=True)
222+
223+
def package(self):
224+
c = f'call "%1/myqemu.bat"' if platform.system() == "Windows" else f'"$1/myqemu.sh"'
225+
echo = f"@echo off\necho RUNNING {self.name}/{self.version}!!\n{c}"
226+
save(self, os.path.join(self.package_folder, "bin", f"{self.name}.bat"), echo)
227+
save(self, os.path.join(self.package_folder, "bin", f"{self.name}"), echo)
228+
os.chmod(os.path.join(self.package_folder, "bin", f"{self.name}"), 0o777)
229+
230+
def package_info(self):
231+
pf = self.dependencies["myqemu"].cpp_info.bindir.replace("\\", "/")
232+
self.conf_info.define_path(f"user.myorg:{self.name}_qemu", pf)
233+
""")
234+
consumer = textwrap.dedent("""
235+
from conan import ConanFile
236+
237+
class Pkg(ConanFile):
238+
name = "consumer"
239+
version = "1.0"
240+
def build_requirements(self):
241+
self.tool_requires("snippy/1.0")
242+
self.tool_requires("valgrind/1.0")
243+
def build(self):
244+
qemu_snippy = self.conf.get("user.myorg:snippy_qemu")
245+
qemu_valgrind = self.conf.get("user.myorg:valgrind_qemu")
246+
self.run(f"valgrind {qemu_valgrind}")
247+
self.run(f'snippy {qemu_snippy}')
248+
""")
249+
250+
c.save({"qemu/conanfile.py": qemu,
251+
"tool/conanfile.py": mytool,
252+
"consumer/conanfile.py": consumer})
253+
254+
c.run("create qemu --version=1.0")
255+
c.run("create qemu --version=2.0")
256+
c.run("create tool --name=snippy")
257+
c.run("create tool --name=valgrind")
258+
c.run("build consumer")
259+
assert "RUNNING valgrind/1.0!!" in c.out
260+
assert "RUNNING myqemu/2.0!!" in c.out
261+
assert "RUNNING snippy/1.0!!" in c.out
262+
assert "RUNNING myqemu/1.0!!" in c.out
263+
264+
c.run("upload * -r=default -c")
265+
# The "tools.graph:skip_binaries" shouldn't affect the result, it is never skipped
266+
for skip in ("-c tools.graph:skip_binaries=True", "-c tools.graph:skip_binaries=False", ""):
267+
c.run("remove * -c")
268+
# Re-downloads and it works
269+
c.run(f"build consumer {skip}")
270+
assert "RUNNING valgrind/1.0!!" in c.out
271+
assert "RUNNING myqemu/2.0!!" in c.out
272+
assert "RUNNING snippy/1.0!!" in c.out
273+
assert "RUNNING myqemu/1.0!!" in c.out
274+
275+
c.run("create consumer")
276+
c.run("upload consumer/1.0 -r=default -c")
277+
c.run("remove * -c")
278+
c.run("install --requires=consumer/1.0")
279+
assert re.search(r"Skipped binaries(\s*)myqemu/1.0, myqemu/2.0, snippy/1.0, valgrind/1.0", c.out)

0 commit comments

Comments
 (0)