Skip to content

Commit

Permalink
feature: Improve dependency-cycle error to show the cycle (#11519)
Browse files Browse the repository at this point in the history
* Improve dependency-cycle error to show the cycle

Original message isn't help when diagnosing problems with a recipe...
Now it will print out all the X->Y dependencies that remain after the
irrelevant components have been eliminated.

Within that list will be the problematic cycle.

For example, as a test I introduced a cycle into my prototype VTK recipe,

I added:
self.cpp_info.components["vtksys"].requires.append("CommonDataModel")

The cycle would be:
vtksys -> CommonDataModel -> CommonCore -> vtksys

The message was a bit more verbose than that, but enough to be helpful:

ERROR: There is a dependency loop in 'self.cpp_info.components' requires:
   CommonTransforms requires CommonMath
   CommonDataModel requires CommonCore
   CommonMath requires CommonCore
   CommonCore requires vtksys
   CommonTransforms requires CommonCore
   CommonCore requires kwiml
   CommonDataModel requires CommonMath
   vtksys requires CommonDataModel
   CommonDataModel requires CommonTransforms
   CommonMath requires kissfft

* add test

Co-authored-by: memsharded <james@conan.io>
  • Loading branch information
paulharris and memsharded committed Jun 28, 2022
1 parent 99ac788 commit a498cf2
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 1 deletion.
9 changes: 8 additions & 1 deletion conans/model/build_info.py
Expand Up @@ -608,8 +608,15 @@ def _get_sorted_components(self):
del components[comp_name]
break
else:
dset = set()
for comp_name, comp in components.items():
for dep_name, dep in components.items():
for require in self._filter_component_requires(dep.requires):
if require == comp_name:
dset.add(" {} requires {}".format(dep_name, comp_name))
dep_mesg = "\n".join(dset)
raise ConanException("There is a dependency loop in "
"'self.cpp_info.components' requires")
"'self.cpp_info.components' requires:\n{}".format(dep_mesg))
self._sorted_components = ordered
else: # If components do not have requirements, keep them in the same order
self._sorted_components = self._cpp_info.components
Expand Down
25 changes: 25 additions & 0 deletions conans/test/integration/test_components.py
@@ -0,0 +1,25 @@
import textwrap

from conans.test.utils.tools import TestClient


def test_components_cycles():
c = TestClient()
conanfile = textwrap.dedent("""
from conan import ConanFile
class TestcycleConan(ConanFile):
name = "testcycle"
version = "1.0"
def package_info(self):
self.cpp_info.components["c"].requires = ["b"]
self.cpp_info.components["b"].requires = ["a"]
self.cpp_info.components["a"].requires = ["c"] # cycle!
""")
c.save({"conanfile.py": conanfile})
c.run("create .", assert_error=True)
assert "ERROR: There is a dependency loop in 'self.cpp_info.components' requires:" in c.out
assert "a requires c"
assert "b requires a"
assert "c rquires b"

0 comments on commit a498cf2

Please sign in to comment.