def _load_graph(self, root_node, check_updates, update, build_mode, remotes, recorder, profile_host, profile_build, apply_build_requires, graph_lock): assert isinstance(build_mode, BuildMode) profile_host_build_requires = profile_host.build_requires builder = DepsGraphBuilder(self._proxy, self._output, self._loader, self._resolver, recorder) graph = builder.load_graph(root_node, check_updates, update, remotes, profile_host, profile_build, graph_lock) self._recurse_build_requires(graph, builder, check_updates, update, build_mode, remotes, profile_host_build_requires, recorder, profile_host, profile_build, graph_lock, apply_build_requires=apply_build_requires) # Sort of closures, for linking order inverse_levels = { n: i for i, level in enumerate(graph.inverse_levels()) for n in level } for node in graph.nodes: node.public_closure.pop(node.name, context=node.context) # List sort is stable, will keep the original order of closure, but prioritize levels node.public_closure.sort(key_fn=lambda n: inverse_levels[n]) return graph
def _load_graph(self, root_node, check_updates, update, build_mode, remote_name, profile_build_requires, recorder, processed_profile, apply_build_requires): assert isinstance(build_mode, BuildMode) builder = DepsGraphBuilder(self._proxy, self._output, self._loader, self._resolver, recorder) graph = builder.load_graph(root_node, check_updates, update, remote_name, processed_profile) binaries_analyzer = GraphBinariesAnalyzer(self._cache, self._output, self._remote_manager) self._recurse_build_requires(graph, builder, binaries_analyzer, check_updates, update, build_mode, remote_name, profile_build_requires, recorder, processed_profile, apply_build_requires=apply_build_requires) # Sort of closures, for linking order inverse_levels = {n: i for i, level in enumerate(graph.inverse_levels()) for n in level} for node in graph.nodes: closure = node.public_closure closure.pop(node.name) node_order = list(closure.values()) # List sort is stable, will keep the original order of the closure, but prioritize levels node_order.sort(key=lambda n: inverse_levels[n]) node.public_closure = node_order return graph
def _load_graph(self, root_node, check_updates, update, build_mode, remote_name, profile_build_requires, recorder, workspace, processed_profile): builder = DepsGraphBuilder(self._proxy, self._output, self._loader, self._resolver, workspace, recorder) graph = builder.load_graph(root_node, check_updates, update, remote_name, processed_profile) if build_mode is None: return graph binaries_analyzer = GraphBinariesAnalyzer(self._cache, self._output, self._remote_manager, workspace) binaries_analyzer.evaluate_graph(graph, build_mode, update, remote_name) self._recurse_build_requires(graph, check_updates, update, build_mode, remote_name, profile_build_requires, recorder, workspace, processed_profile) return graph
def setUp(self): self.output = TestBufferConanOutput() self.loader = ConanFileLoader(None, Settings.loads(""), Profile()) self.retriever = Retriever(self.loader, self.output) self.remote_search = MockSearchRemote() paths = SimplePaths(self.retriever.folder) self.resolver = RangeResolver(self.output, paths, self.remote_search) self.builder = DepsGraphBuilder(self.retriever, self.output, self.loader, self.resolver) for v in ["0.1", "0.2", "0.3", "1.1", "1.1.2", "1.2.1", "2.1", "2.2.1"]: say_content = """ from conans import ConanFile class SayConan(ConanFile): name = "Say" version = "%s" """ % v say_ref = ConanFileReference.loads("Say/%s@memsharded/testing" % v) self.retriever.conan(say_ref, say_content)
def load_simple_graph(self, reference, profile, recorder): # Loads a graph without computing the binaries. It is necessary for # export-pkg command, not hitting the server # # https://github.com/conan-io/conan/issues/3432 builder = DepsGraphBuilder(self._proxy, self._output, self._loader, self._resolver, workspace=None, recorder=recorder) processed_profile = ProcessedProfile(profile, create_reference=None) conanfile = self._loader.load_virtual([reference], processed_profile) root_node = Node(None, conanfile, recipe=RECIPE_VIRTUAL) graph = builder.load_graph(root_node, check_updates=False, update=False, remote_name=None, processed_profile=processed_profile) return graph
def load_simple_graph(self, reference, profile, recorder): # Loads a graph without computing the binaries. It is necessary for # export-pkg command, not hitting the server # # https://github.com/conan-io/conan/issues/3432 builder = DepsGraphBuilder(self._proxy, self._output, self._loader, self._resolver, workspace=None, recorder=recorder) cache_settings = self._client_cache.settings.copy() cache_settings.values = profile.settings_values settings_preprocessor.preprocess(cache_settings) processed_profile = ProcessedProfile(cache_settings, profile, create_reference=None) conanfile = self._loader.load_virtual([reference], processed_profile) graph = builder.load_graph(conanfile, check_updates=False, update=False, remote_name=None, processed_profile=processed_profile) return graph
def load_graph(self, conanfile, check_updates, update, build_mode, remote_name=None, profile_build_requires=None): builder = DepsGraphBuilder(self._proxy, self._output, self._loader, self._resolver, self._workspace) graph = builder.load_graph(conanfile, check_updates, update, remote_name) if build_mode is None: return graph binaries_analyzer = GraphBinariesAnalyzer(self._client_cache, self._output, self._remote_manager, self._registry, self._workspace) binaries_analyzer.evaluate_graph(graph, build_mode, update, remote_name) self._recurse_build_requires(graph, check_updates, update, build_mode, remote_name, profile_build_requires) return graph
def setUp(self): self.output = TestBufferConanOutput() self.loader = ConanFileLoader(None, Settings.loads(""), Profile()) self.retriever = Retriever(self.loader, self.output) self.remote_search = MockSearchRemote() self.resolver = RequireResolver(self.output, self.retriever, self.remote_search) self.builder = DepsGraphBuilder(self.retriever, self.output, self.loader, self.resolver) for v in ["0.1", "0.2", "0.3", "1.1", "1.1.2", "1.2.1", "2.1", "2.2.1"]: say_content = """ from conans import ConanFile class SayConan(ConanFile): name = "Say" version = "%s" """ % v say_ref = ConanFileReference.loads("Say/%s@memsharded/testing" % v) self.retriever.conan(say_ref, say_content)
def _get_graph_builder(self, loader, remote_proxy): resolver = RangeResolver(self._user_io.out, self._client_cache, remote_proxy) graph_builder = DepsGraphBuilder(remote_proxy, self._user_io.out, loader, resolver) return graph_builder
class VersionRangesTest(unittest.TestCase): def setUp(self): self.output = TestBufferConanOutput() self.loader = ConanFileLoader(None, self.output, ConanPythonRequire(None, None)) self.retriever = Retriever(self.loader) self.remote_search = MockSearchRemote() paths = SimplePaths(self.retriever.folder) self.resolver = RangeResolver(paths, self.remote_search) self.builder = DepsGraphBuilder(self.retriever, self.output, self.loader, self.resolver, None, None) for v in ["0.1", "0.2", "0.3", "1.1", "1.1.2", "1.2.1", "2.1", "2.2.1"]: say_content = """ from conans import ConanFile class SayConan(ConanFile): name = "Say" version = "%s" """ % v say_ref = ConanFileReference.loads("Say/%s@myuser/testing" % v) self.retriever.conan(say_ref, say_content) def root(self, content, update=False): self.loader.cached_conanfiles = {} processed_profile = test_processed_profile() root_conan = self.retriever.root(content, processed_profile) deps_graph = self.builder.load_graph(root_conan, update, update, None, processed_profile) self.output.write("\n".join(self.resolver.output)) return deps_graph def test_local_basic(self): for expr, solution in [(">0.0", "2.2.1"), (">0.1,<1", "0.3"), (">0.1,<1||2.1", "2.1"), ("", "2.2.1"), ("~0", "0.3"), ("~=1", "1.2.1"), ("~1.1", "1.1.2"), ("~=2", "2.2.1"), ("~=2.1", "2.1"), ]: deps_graph = self.root(hello_content % expr) self.assertEqual(2, len(deps_graph.nodes)) hello = _get_nodes(deps_graph, "Hello")[0] say = _get_nodes(deps_graph, "Say")[0] self.assertEqual(_get_edges(deps_graph), {Edge(hello, say)}) self.assertEqual(hello.ref, None) conanfile = hello.conanfile self.assertEqual(conanfile.version, "1.2") self.assertEqual(conanfile.name, "Hello") say_ref = ConanFileReference.loads("Say/%s@myuser/testing" % solution) self.assertEqual(_clear_revs(conanfile.requires), Requirements(str(say_ref))) def test_remote_basic(self): self.resolver._local_search = None remote_packages = [] for v in ["0.1", "0.2", "0.3", "1.1", "1.1.2", "1.2.1", "2.1", "2.2.1"]: say_ref = ConanFileReference.loads("Say/%s@myuser/testing" % v) remote_packages.append(say_ref) self.remote_search.packages = remote_packages for expr, solution in [(">0.0", "2.2.1"), (">0.1,<1", "0.3"), (">0.1,<1||2.1", "2.1"), ("", "2.2.1"), ("~0", "0.3"), ("~=1", "1.2.1"), ("~1.1", "1.1.2"), ("~=2", "2.2.1"), ("~=2.1", "2.1"), ]: deps_graph = self.root(hello_content % expr, update=True) self.assertEqual(self.remote_search.count, {'Say/*@myuser/testing': 1}) self.assertEqual(2, len(deps_graph.nodes)) hello = _get_nodes(deps_graph, "Hello")[0] say = _get_nodes(deps_graph, "Say")[0] self.assertEqual(_get_edges(deps_graph), {Edge(hello, say)}) self.assertEqual(hello.ref, None) conanfile = hello.conanfile self.assertEqual(conanfile.version, "1.2") self.assertEqual(conanfile.name, "Hello") say_ref = ConanFileReference.loads("Say/%s@myuser/testing" % solution) self.assertEqual(_clear_revs(conanfile.requires), Requirements(str(say_ref))) def test_remote_optimized(self): self.resolver._local_search = None remote_packages = [] for v in ["0.1", "0.2", "0.3", "1.1", "1.1.2", "1.2.1", "2.1", "2.2.1"]: say_ref = ConanFileReference.loads("Say/%s@myuser/testing" % v) remote_packages.append(say_ref) self.remote_search.packages = remote_packages dep_content = """from conans import ConanFile class Dep1Conan(ConanFile): requires = "Say/[%s]@myuser/testing" """ dep_ref = ConanFileReference.loads("Dep1/0.1@myuser/testing") self.retriever.conan(dep_ref, dep_content % ">=0.1") dep_ref = ConanFileReference.loads("Dep2/0.1@myuser/testing") self.retriever.conan(dep_ref, dep_content % ">=0.1") hello_content = """from conans import ConanFile class HelloConan(ConanFile): name = "Hello" requires = "Dep1/0.1@myuser/testing", "Dep2/0.1@myuser/testing" """ deps_graph = self.root(hello_content, update=True) self.assertEqual(4, len(deps_graph.nodes)) hello = _get_nodes(deps_graph, "Hello")[0] say = _get_nodes(deps_graph, "Say")[0] dep1 = _get_nodes(deps_graph, "Dep1")[0] dep2 = _get_nodes(deps_graph, "Dep2")[0] self.assertEqual(_get_edges(deps_graph), {Edge(hello, dep1), Edge(hello, dep2), Edge(dep1, say), Edge(dep2, say)}) # Most important check: counter of calls to remote self.assertEqual(self.remote_search.count, {'Say/*@myuser/testing': 1}) @parameterized.expand([("", "0.3", None, None), ('"Say/1.1@myuser/testing"', "1.1", False, False), ('"Say/0.2@myuser/testing"', "0.2", False, True), ('("Say/1.1@myuser/testing", "override")', "1.1", True, False), ('("Say/0.2@myuser/testing", "override")', "0.2", True, True), # ranges ('"Say/[<=1.2]@myuser/testing"', "1.2.1", False, False), ('"Say/[>=0.2,<=1.0]@myuser/testing"', "0.3", False, True), ('"Say/[>=0.2 <=1.0]@myuser/testing"', "0.3", False, True), ('("Say/[<=1.2]@myuser/testing", "override")', "1.2.1", True, False), ('("Say/[>=0.2,<=1.0]@myuser/testing", "override")', "0.3", True, True), ('("Say/[>=0.2 <=1.0]@myuser/testing", "override")', "0.3", True, True), ]) def transitive_test(self, version_range, solution, override, valid): hello_text = hello_content % ">0.1, <1" hello_ref = ConanFileReference.loads("Hello/1.2@myuser/testing") self.retriever.conan(hello_ref, hello_text) chat_content = """ from conans import ConanFile class ChatConan(ConanFile): name = "Chat" version = "2.3" requires = "Hello/1.2@myuser/testing", %s """ if valid is False: with self.assertRaisesRegexp(ConanException, "not valid"): self.root(chat_content % version_range) return deps_graph = self.root(chat_content % version_range) hello = _get_nodes(deps_graph, "Hello")[0] say = _get_nodes(deps_graph, "Say")[0] chat = _get_nodes(deps_graph, "Chat")[0] edges = {Edge(hello, say), Edge(chat, hello)} if override is not None: self.assertIn("overridden", self.output) else: self.assertNotIn("overridden", self.output) if override is False: edges = {Edge(hello, say), Edge(chat, say), Edge(chat, hello)} if valid is True: self.assertIn(" valid", self.output) self.assertNotIn("not valid", self.output) elif valid is False: self.assertIn("not valid", self.output) self.assertEqual(3, len(deps_graph.nodes)) self.assertEqual(_get_edges(deps_graph), edges) self.assertEqual(hello.ref.copy_clear_rev(), hello_ref) conanfile = hello.conanfile self.assertEqual(conanfile.version, "1.2") self.assertEqual(conanfile.name, "Hello") say_ref = ConanFileReference.loads("Say/%s@myuser/testing" % solution) self.assertEqual(_clear_revs(conanfile.requires), Requirements(str(say_ref))) def duplicated_error_test(self): content = """ from conans import ConanFile class Log3cppConan(ConanFile): name = "log4cpp" version = "1.1.1" """ log4cpp_ref = ConanFileReference.loads("log4cpp/1.1.1@myuser/testing") self.retriever.conan(log4cpp_ref, content) content = """ from conans import ConanFile class LoggerInterfaceConan(ConanFile): name = "LoggerInterface" version = "0.1.1" def requirements(self): self.requires("log4cpp/[~1.1]@myuser/testing") """ logiface_ref = ConanFileReference.loads("LoggerInterface/0.1.1@myuser/testing") self.retriever.conan(logiface_ref, content) content = """ from conans import ConanFile class OtherConan(ConanFile): name = "other" version = "2.0.11549" requires = "LoggerInterface/[~0.1]@myuser/testing" """ other_ref = ConanFileReference.loads("other/2.0.11549@myuser/testing") self.retriever.conan(other_ref, content) content = """ from conans import ConanFile class Project(ConanFile): requires = "LoggerInterface/[~0.1]@myuser/testing", "other/[~2.0]@myuser/testing" """ deps_graph = self.root(content) log4cpp = _get_nodes(deps_graph, "log4cpp")[0] logger_interface = _get_nodes(deps_graph, "LoggerInterface")[0] other = _get_nodes(deps_graph, "other")[0] self.assertEqual(4, len(deps_graph.nodes)) self.assertEqual(log4cpp.ref.copy_clear_rev(), log4cpp_ref) conanfile = log4cpp.conanfile self.assertEqual(conanfile.version, "1.1.1") self.assertEqual(conanfile.name, "log4cpp") self.assertEqual(logger_interface.ref.copy_clear_rev(), logiface_ref) conanfile = logger_interface.conanfile self.assertEqual(conanfile.version, "0.1.1") self.assertEqual(conanfile.name, "LoggerInterface") self.assertEqual(other.ref.copy_clear_rev(), other_ref) conanfile = other.conanfile self.assertEqual(conanfile.version, "2.0.11549") self.assertEqual(conanfile.name, "other")
def _get_graph_builder(self, loader, remote_proxy): local_search = self._search_manager resolver = RequireResolver(self._user_io.out, local_search, remote_proxy) graph_builder = DepsGraphBuilder(remote_proxy, self._user_io.out, loader, resolver) return graph_builder
class VersionRangesTest(unittest.TestCase): def setUp(self): self.output = TestBufferConanOutput() self.loader = ConanFileLoader(None, Settings.loads(""), Profile()) self.retriever = Retriever(self.loader, self.output) self.remote_search = MockSearchRemote() self.resolver = RequireResolver(self.output, self.retriever, self.remote_search) self.builder = DepsGraphBuilder(self.retriever, self.output, self.loader, self.resolver) for v in ["0.1", "0.2", "0.3", "1.1", "1.1.2", "1.2.1", "2.1", "2.2.1"]: say_content = """ from conans import ConanFile class SayConan(ConanFile): name = "Say" version = "%s" """ % v say_ref = ConanFileReference.loads("Say/%s@memsharded/testing" % v) self.retriever.conan(say_ref, say_content) def root(self, content): root_conan = self.retriever.root(content) deps_graph = self.builder.load_graph(root_conan, False, False) return deps_graph def test_local_basic(self): for expr, solution in [(">0.0", "2.2.1"), (">0.1,<1", "0.3"), (">0.1,<1||2.1", "2.1"), ("", "2.2.1"), ("~0", "0.3"), ("~=1", "1.2.1"), ("~1.1", "1.1.2"), ("~=2", "2.2.1"), ("~=2.1", "2.1"), ]: deps_graph = self.root(hello_content % expr) self.assertEqual(2, len(deps_graph.nodes)) hello = _get_nodes(deps_graph, "Hello")[0] say = _get_nodes(deps_graph, "Say")[0] self.assertEqual(_get_edges(deps_graph), {Edge(hello, say)}) self.assertEqual(hello.conan_ref, None) conanfile = hello.conanfile self.assertEqual(conanfile.version, "1.2") self.assertEqual(conanfile.name, "Hello") say_ref = ConanFileReference.loads("Say/%s@memsharded/testing" % solution) self.assertEqual(conanfile.requires, Requirements(str(say_ref))) def test_remote_basic(self): self.resolver._local_search = None remote_packages = [] for v in ["0.1", "0.2", "0.3", "1.1", "1.1.2", "1.2.1", "2.1", "2.2.1"]: say_ref = ConanFileReference.loads("Say/%s@memsharded/testing" % v) remote_packages.append(say_ref) self.remote_search.packages = remote_packages self.test_local_basic() @parameterized.expand([("", "0.3", None, None), ('"Say/1.1@memsharded/testing"', "1.1", False, False), ('"Say/0.2@memsharded/testing"', "0.2", False, True), ('("Say/1.1@memsharded/testing", "override")', "1.1", True, False), ('("Say/0.2@memsharded/testing", "override")', "0.2", True, True), # ranges ('"Say/[<=1.2]@memsharded/testing"', "1.2.1", False, False), ('"Say/[>=0.2,<=1.0]@memsharded/testing"', "0.3", False, True), ('("Say/[<=1.2]@memsharded/testing", "override")', "1.2.1", True, False), ('("Say/[>=0.2,<=1.0]@memsharded/testing", "override")', "0.3", True, True), ]) def transitive_test(self, version_range, solution, override, valid): hello_text = hello_content % ">0.1, <1" hello_ref = ConanFileReference.loads("Hello/1.2@memsharded/testing") self.retriever.conan(hello_ref, hello_text) chat_content = """ from conans import ConanFile class ChatConan(ConanFile): name = "Chat" version = "2.3" requires = "Hello/1.2@memsharded/testing", %s """ if valid is False: with self.assertRaisesRegexp(ConanException, "not valid"): self.root(chat_content % version_range) return deps_graph = self.root(chat_content % version_range) hello = _get_nodes(deps_graph, "Hello")[0] say = _get_nodes(deps_graph, "Say")[0] chat = _get_nodes(deps_graph, "Chat")[0] edges = {Edge(hello, say), Edge(chat, hello)} if override is not None: self.assertIn("override", self.output) else: self.assertNotIn("override", self.output) if override is False: edges = {Edge(hello, say), Edge(chat, say), Edge(chat, hello)} if valid is True: self.assertIn(" valid", self.output) elif valid is False: self.assertIn("not valid", self.output) self.assertEqual(3, len(deps_graph.nodes)) self.assertEqual(_get_edges(deps_graph), edges) self.assertEqual(hello.conan_ref, hello_ref) conanfile = hello.conanfile self.assertEqual(conanfile.version, "1.2") self.assertEqual(conanfile.name, "Hello") say_ref = ConanFileReference.loads("Say/%s@memsharded/testing" % solution) self.assertEqual(conanfile.requires, Requirements(str(say_ref))) def duplicated_error_test(self): content = """ from conans import ConanFile class Log3cppConan(ConanFile): name = "log4cpp" version = "1.1.1" """ log4cpp_ref = ConanFileReference.loads("log4cpp/1.1.1@memsharded/testing") self.retriever.conan(log4cpp_ref, content) content = """ from conans import ConanFile class LoggerInterfaceConan(ConanFile): name = "LoggerInterface" version = "0.1.1" def requirements(self): self.requires("log4cpp/[~1.1]@memsharded/testing") """ logiface_ref = ConanFileReference.loads("LoggerInterface/0.1.1@memsharded/testing") self.retriever.conan(logiface_ref, content) content = """ from conans import ConanFile class OtherConan(ConanFile): name = "other" version = "2.0.11549" requires = "LoggerInterface/[~0.1]@memsharded/testing" """ other_ref = ConanFileReference.loads("other/2.0.11549@memsharded/testing") self.retriever.conan(other_ref, content) content = """ from conans import ConanFile class Project(ConanFile): requires = "LoggerInterface/[~0.1]@memsharded/testing", "other/[~2.0]@memsharded/testing" """ deps_graph = self.root(content) log4cpp = _get_nodes(deps_graph, "log4cpp")[0] logger_interface = _get_nodes(deps_graph, "LoggerInterface")[0] other = _get_nodes(deps_graph, "other")[0] self.assertEqual(4, len(deps_graph.nodes)) self.assertEqual(log4cpp.conan_ref, log4cpp_ref) conanfile = log4cpp.conanfile self.assertEqual(conanfile.version, "1.1.1") self.assertEqual(conanfile.name, "log4cpp") self.assertEqual(logger_interface.conan_ref, logiface_ref) conanfile = logger_interface.conanfile self.assertEqual(conanfile.version, "0.1.1") self.assertEqual(conanfile.name, "LoggerInterface") self.assertEqual(other.conan_ref, other_ref) conanfile = other.conanfile self.assertEqual(conanfile.version, "2.0.11549") self.assertEqual(conanfile.name, "other")
class VersionRangesTest(unittest.TestCase): def setUp(self): self.output = TestBufferConanOutput() self.loader = ConanFileLoader(None, Settings.loads(""), Profile()) self.retriever = Retriever(self.loader, self.output) self.remote_search = MockSearchRemote() self.resolver = RequireResolver(self.output, self.retriever, self.remote_search) self.builder = DepsGraphBuilder(self.retriever, self.output, self.loader, self.resolver) for v in [ "0.1", "0.2", "0.3", "1.1", "1.1.2", "1.2.1", "2.1", "2.2.1" ]: say_content = """ from conans import ConanFile class SayConan(ConanFile): name = "Say" version = "%s" """ % v say_ref = ConanFileReference.loads("Say/%s@memsharded/testing" % v) self.retriever.conan(say_ref, say_content) def root(self, content): root_conan = self.retriever.root(content) deps_graph = self.builder.load_graph(root_conan, False, False) return deps_graph def test_local_basic(self): for expr, solution in [ (">0.0", "2.2.1"), (">0.1,<1", "0.3"), (">0.1,<1||2.1", "2.1"), ("", "2.2.1"), ("~0", "0.3"), ("~=1", "1.2.1"), ("~1.1", "1.1.2"), ("~=2", "2.2.1"), ("~=2.1", "2.1"), ]: deps_graph = self.root(hello_content % expr) self.assertEqual(2, len(deps_graph.nodes)) hello = _get_nodes(deps_graph, "Hello")[0] say = _get_nodes(deps_graph, "Say")[0] self.assertEqual(_get_edges(deps_graph), {Edge(hello, say)}) self.assertEqual(hello.conan_ref, None) conanfile = hello.conanfile self.assertEqual(conanfile.version, "1.2") self.assertEqual(conanfile.name, "Hello") say_ref = ConanFileReference.loads("Say/%s@memsharded/testing" % solution) self.assertEqual(conanfile.requires, Requirements(str(say_ref))) def test_remote_basic(self): self.resolver._local_search = None remote_packages = [] for v in [ "0.1", "0.2", "0.3", "1.1", "1.1.2", "1.2.1", "2.1", "2.2.1" ]: say_ref = ConanFileReference.loads("Say/%s@memsharded/testing" % v) remote_packages.append(say_ref) self.remote_search.packages = remote_packages self.test_local_basic() @parameterized.expand([ ("", "0.3", None, None), ('"Say/1.1@memsharded/testing"', "1.1", False, False), ('"Say/0.2@memsharded/testing"', "0.2", False, True), ('("Say/1.1@memsharded/testing", "override")', "1.1", True, False), ('("Say/0.2@memsharded/testing", "override")', "0.2", True, True), # ranges ('"Say/[<=1.2]@memsharded/testing"', "1.2.1", False, False), ('"Say/[>=0.2,<=1.0]@memsharded/testing"', "0.3", False, True), ('("Say/[<=1.2]@memsharded/testing", "override")', "1.2.1", True, False), ('("Say/[>=0.2,<=1.0]@memsharded/testing", "override")', "0.3", True, True), ]) def transitive_test(self, version_range, solution, override, valid): hello_text = hello_content % ">0.1, <1" hello_ref = ConanFileReference.loads("Hello/1.2@memsharded/testing") self.retriever.conan(hello_ref, hello_text) chat_content = """ from conans import ConanFile class ChatConan(ConanFile): name = "Chat" version = "2.3" requires = "Hello/1.2@memsharded/testing", %s """ if valid is False: with self.assertRaisesRegexp(ConanException, "not valid"): self.root(chat_content % version_range) return deps_graph = self.root(chat_content % version_range) hello = _get_nodes(deps_graph, "Hello")[0] say = _get_nodes(deps_graph, "Say")[0] chat = _get_nodes(deps_graph, "Chat")[0] edges = {Edge(hello, say), Edge(chat, hello)} if override is not None: self.assertIn("override", self.output) else: self.assertNotIn("override", self.output) if override is False: edges = {Edge(hello, say), Edge(chat, say), Edge(chat, hello)} if valid is True: self.assertIn(" valid", self.output) elif valid is False: self.assertIn("not valid", self.output) self.assertEqual(3, len(deps_graph.nodes)) self.assertEqual(_get_edges(deps_graph), edges) self.assertEqual(hello.conan_ref, hello_ref) conanfile = hello.conanfile self.assertEqual(conanfile.version, "1.2") self.assertEqual(conanfile.name, "Hello") say_ref = ConanFileReference.loads("Say/%s@memsharded/testing" % solution) self.assertEqual(conanfile.requires, Requirements(str(say_ref))) def duplicated_error_test(self): content = """ from conans import ConanFile class Log3cppConan(ConanFile): name = "log4cpp" version = "1.1.1" """ log4cpp_ref = ConanFileReference.loads( "log4cpp/1.1.1@memsharded/testing") self.retriever.conan(log4cpp_ref, content) content = """ from conans import ConanFile class LoggerInterfaceConan(ConanFile): name = "LoggerInterface" version = "0.1.1" def requirements(self): self.requires("log4cpp/[~1.1]@memsharded/testing") """ logiface_ref = ConanFileReference.loads( "LoggerInterface/0.1.1@memsharded/testing") self.retriever.conan(logiface_ref, content) content = """ from conans import ConanFile class OtherConan(ConanFile): name = "other" version = "2.0.11549" requires = "LoggerInterface/[~0.1]@memsharded/testing" """ other_ref = ConanFileReference.loads( "other/2.0.11549@memsharded/testing") self.retriever.conan(other_ref, content) content = """ from conans import ConanFile class Project(ConanFile): requires = "LoggerInterface/[~0.1]@memsharded/testing", "other/[~2.0]@memsharded/testing" """ deps_graph = self.root(content) log4cpp = _get_nodes(deps_graph, "log4cpp")[0] logger_interface = _get_nodes(deps_graph, "LoggerInterface")[0] other = _get_nodes(deps_graph, "other")[0] self.assertEqual(4, len(deps_graph.nodes)) self.assertEqual(log4cpp.conan_ref, log4cpp_ref) conanfile = log4cpp.conanfile self.assertEqual(conanfile.version, "1.1.1") self.assertEqual(conanfile.name, "log4cpp") self.assertEqual(logger_interface.conan_ref, logiface_ref) conanfile = logger_interface.conanfile self.assertEqual(conanfile.version, "0.1.1") self.assertEqual(conanfile.name, "LoggerInterface") self.assertEqual(other.conan_ref, other_ref) conanfile = other.conanfile self.assertEqual(conanfile.version, "2.0.11549") self.assertEqual(conanfile.name, "other")