Skip to content

Commit 5a551cd

Browse files
authored
[develop2] Fix bug in override=True trait propagation (#10624)
* fix overrides * fixing override bug * wip * fix test * fix test
1 parent 80b47f1 commit 5a551cd

File tree

8 files changed

+54
-216
lines changed

8 files changed

+54
-216
lines changed

conans/cli/formatters/graph.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ def _format_resolved(title, reqs_to_print):
6666
reason = f": {reason}" if reason else ""
6767
output.info(" {}{}".format(d, reason), Color.BRIGHT_CYAN)
6868

69+
if graph.error:
70+
output.info("Graph error", Color.BRIGHT_RED)
71+
output.info(" {}".format(graph.error), Color.BRIGHT_RED)
72+
6973

7074
def print_graph_packages(graph):
7175
# I am excluding the "download"-"cache" or remote information, that is not

conans/client/graph/graph_error.py

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33

44
class GraphError(ConanException):
5+
# TODO: refactor into multiple classes, do not do type by attribute "kind"
56
LOOP = "graph loop"
67
VERSION_CONFLICT = "version conflict"
78
PROVIDE_CONFLICT = "provide conflict"
@@ -16,6 +17,9 @@ def __str__(self):
1617
# TODO: Nicer error reporting
1718
if self.kind == GraphError.MISSING_RECIPE:
1819
return f"Package '{self.require.ref}' not resolved: {self.missing_error}"
20+
elif self.kind == GraphError.VERSION_CONFLICT:
21+
return f"Version conflict: {self.node.ref}->{self.require.ref}, "\
22+
f"{self.base_previous.ref}->{self.prev_require.ref}."
1923
return self.kind
2024

2125
@staticmethod
@@ -81,28 +85,3 @@ def conflict_config(node, require, prev_node, prev_require, base_previous,
8185
if prev_node:
8286
prev_node.error = result
8387
return result
84-
85-
def report_graph_error(self):
86-
# FIXME: THis is completely broken and useless
87-
# print("REPORTING GRAPH ERRORS")
88-
conflict_nodes = [n for n in self.nodes if n.conflict]
89-
# print("PROBLEMATIC NODES ", conflict_nodes)
90-
for node in conflict_nodes: # At the moment there should be only 1 conflict at most
91-
conflict = node.conflict
92-
# print("CONFLICT ", conflict)
93-
if conflict[0] == GraphError.LOOP:
94-
loop_ref = node.ref
95-
parent = node.dependants[0]
96-
parent_ref = parent.src.ref
97-
msg = "Loop detected in context host: '{}' requires '{}' which "\
98-
"is an ancestor too"
99-
msg = msg.format(parent_ref, loop_ref)
100-
raise ConanException(msg)
101-
elif conflict[0] == GraphError.VERSION_CONFLICT:
102-
raise ConanException(
103-
"There was a version conflict building the dependency graph")
104-
elif conflict[0] == GraphError.PROVIDE_CONFLICT:
105-
raise ConanException(
106-
"There was a provides conflict building the dependency graph")
107-
108-
raise ConanException("Thre was an error in the graph: {}".format(self.error))

conans/client/graph/printer.py

Lines changed: 0 additions & 89 deletions
This file was deleted.

conans/model/requires.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,8 @@ def aggregate(self, other):
212212
self.libs |= other.libs
213213
self.run = self.run or other.run
214214
self.visible |= other.visible
215+
# The force trait is also defined from an override
216+
self.force |= other.force or other.override
215217
# TODO: self.package_id_mode => Choose more restrictive?
216218

217219
def transform_downstream(self, pkg_type, require, dep_pkg_type):

conans/test/functional/revisions_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def test_diamond_revisions_conflict(self):
8383
self.c_v2.create(project,
8484
conanfile=GenConanfile().with_requirement(lib2).with_requirement(lib3),
8585
assert_error=True)
86-
self.assertIn("ERROR: version conflict", self.c_v2.out)
86+
self.assertIn("ERROR: Version conflict", self.c_v2.out)
8787
# self.assertIn("Different revisions of {} has been requested".format(lib1), self.c_v2.out)
8888

8989
def test_alias_to_a_rrev(self):
Lines changed: 42 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,91 +1,46 @@
1-
import os
2-
import textwrap
3-
import unittest
1+
from conans.test.assets.genconanfile import GenConanfile
2+
from conans.test.utils.tools import TestClient
43

5-
import pytest
64

7-
from conans.util.env import environment_update
8-
from conans.paths import CONANFILE
9-
from conans.test.utils.tools import TestClient, load
10-
import json
11-
12-
13-
@pytest.mark.xfail(reason="Conflict Output have changed")
14-
class ConflictDiamondTest(unittest.TestCase):
15-
conanfile = textwrap.dedent("""
16-
from conan import ConanFile
17-
18-
class HelloReuseConan(ConanFile):
19-
name = "%s"
20-
version = "%s"
21-
requires = %s
22-
""")
23-
24-
def _export(self, name, version, deps=None, export=True):
25-
deps = ", ".join(['"%s"' % d for d in deps or []]) or '""'
26-
conanfile = self.conanfile % (name, version, deps)
27-
files = {CONANFILE: conanfile}
28-
self.client.save(files, clean_first=True)
29-
if export:
30-
self.client.run("export . --user=lasote --channel=stable")
31-
32-
def setUp(self):
33-
self.client = TestClient()
34-
self._export("hello0", "0.1")
35-
self._export("hello0", "0.2")
36-
self._export("hello1", "0.1", ["hello0/0.1@lasote/stable"])
37-
self._export("Hello2", "0.1", ["hello0/0.2@lasote/stable"])
38-
39-
def test_conflict(self):
40-
""" There is a conflict in the graph: branches with requirement in different
41-
version, Conan will raise
5+
class TestConflictDiamondTest:
6+
def test_version_diamond_conflict(self):
427
"""
43-
self._export("Hello3", "0.1", ["hello1/0.1@lasote/stable", "hello2/0.1@lasote/stable"],
44-
export=False)
45-
self.client.run("install . --build missing", assert_error=True)
46-
self.assertIn("Conflict in hello2/0.1@lasote/stable:\n"
47-
" 'hello2/0.1@lasote/stable' requires 'hello0/0.2@lasote/stable' "
48-
"while 'hello1/0.1@lasote/stable' requires 'hello0/0.1@lasote/stable'.\n"
49-
" To fix this conflict you need to override the package 'hello0' in "
50-
"your root package.", self.client.out)
51-
self.assertNotIn("Generated conaninfo.txt", self.client.out)
52-
53-
def test_override_silent(self):
54-
""" There is a conflict in the graph, but the consumer project depends on the conflicting
55-
library, so all the graph will use the version from the consumer project
8+
test that we obtain a version conflict with a diamond, and that we can fix it by
9+
defining an override in the "game" consumer
5610
"""
57-
self._export("Hello3", "0.1",
58-
["hello1/0.1@lasote/stable", "hello2/0.1@lasote/stable",
59-
"hello0/0.1@lasote/stable"], export=False)
60-
self.client.run("install . --build missing", assert_error=False)
61-
self.assertIn("hello2/0.1@lasote/stable: requirement hello0/0.2@lasote/stable overridden"
62-
" by Hello3/0.1 to hello0/0.1@lasote/stable",
63-
self.client.out)
64-
65-
66-
@pytest.mark.xfail(reason="UX conflict error to be completed")
67-
def test_create_werror():
68-
client = TestClient()
69-
client.save({"conanfile.py": """from conan import ConanFile
70-
class Pkg(ConanFile):
71-
pass
72-
"""})
73-
client.run("export . --name=LibA --version=0.1 --user=user --channel=channel")
74-
client.run("export conanfile.py --name=LibA --version=0.2 --user=user --channel=channel")
75-
client.save({"conanfile.py": """from conan import ConanFile
76-
class Pkg(ConanFile):
77-
requires = "LibA/0.1@user/channel"
78-
"""})
79-
client.run("export ./ --name=LibB --version=0.1 --user=user --channel=channel")
80-
client.save({"conanfile.py": """from conan import ConanFile
81-
class Pkg(ConanFile):
82-
requires = "LibA/0.2@user/channel"
83-
"""})
84-
client.run("export . --name=LibC --version=0.1 --user=user --channel=channel")
85-
client.save({"conanfile.py": """from conan import ConanFile
86-
class Pkg(ConanFile):
87-
requires = "LibB/0.1@user/channel", "LibC/0.1@user/channel"
88-
"""})
89-
client.run("create ./conanfile.py consumer/0.1@lasote/testing", assert_error=True)
90-
self.assertIn("ERROR: Conflict in LibC/0.1@user/channel",
91-
client.out)
11+
c = TestClient()
12+
c.save({"math/conanfile.py": GenConanfile("math"),
13+
"engine/conanfile.py": GenConanfile("engine", "1.0").with_requires("math/1.0"),
14+
"ai/conanfile.py": GenConanfile("ai", "1.0").with_requires("math/1.0.1"),
15+
"game/conanfile.py": GenConanfile("game", "1.0").with_requires("engine/1.0",
16+
"ai/1.0"),
17+
})
18+
c.run("create math --version=1.0")
19+
c.run("create math --version=1.0.1")
20+
c.run("create math --version=1.0.2")
21+
c.run("create engine")
22+
c.run("create ai")
23+
c.run("install game", assert_error=True)
24+
assert "Version conflict: ai/1.0->math/1.0.1, game/1.0->math/1.0" in c.out
25+
26+
def _game_conanfile(version, reverse=False):
27+
if reverse:
28+
return GenConanfile("game", "1.0")\
29+
.with_requirement(f"math/{version}", override=True)\
30+
.with_requirement("engine/1.0")\
31+
.with_requirement("ai/1.0")
32+
else:
33+
return GenConanfile("game", "1.0").with_requirement("engine/1.0") \
34+
.with_requirement("ai/1.0") \
35+
.with_requirement(f"math/{version}", override=True)
36+
37+
for v in ("1.0", "1.0.1", "1.0.2"):
38+
c.save({"game/conanfile.py": _game_conanfile(v)})
39+
c.run("install game")
40+
c.assert_listed_require({f"math/{v}": "Cache"})
41+
42+
# Check that order of requirements doesn't affect
43+
for v in ("1.0", "1.0.1", "1.0.2"):
44+
c.save({"game/conanfile.py": _game_conanfile(v, reverse=True)})
45+
c.run("install game")
46+
c.assert_listed_require({f"math/{v}": "Cache"})

conans/test/integration/graph/core/graph_manager_test.py

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -884,19 +884,6 @@ def test_diamond(self):
884884
self._check_node(libb, "libb/0.1#123", deps=[liba], dependents=[app])
885885
self._check_node(liba, "liba/0.2#123", dependents=[libb, app])
886886

887-
# FIXME: Remove
888-
def test_a_ver_si_me_entero(self):
889-
# consumer -> dep1 -> dep2
890-
# \-> dep3
891-
self.recipe_cache("dep2/0")
892-
self.recipe_cache("dep1/0", ["dep2/0"])
893-
self.recipe_cache("dep3/0")
894-
consumer = self.consumer_conanfile(GenConanfile("consumer", "0").with_require("dep1/0")
895-
.with_require("dep3/0"))
896-
deps_graph = self.build_consumer(consumer)
897-
898-
self.assertEqual(4, len(deps_graph.nodes))
899-
900887
def test_diamond_conflict(self):
901888
# app -> libb0.1 -> liba0.2 (overriden to lib0.2)
902889
# \-> --------- ->/

conans/test/integration/remote/download_retries_test.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,4 @@ def get(self, *args, **kwargs):
5858
requester_class=BuggyRequester)
5959
client.run("install --reference=pkg/0.1@lasote/stable", assert_error=True)
6060
self.assertEqual(str(client.out).count("Waiting 0 seconds to retry..."), 2)
61-
self.assertEqual(str(client.out).count("Error 200 downloading"), 3)
61+
self.assertEqual(str(client.out).count("Error 200 downloading"), 4)

0 commit comments

Comments
 (0)