def create_requirements(conanfile): try: # Actual requirements of this conans if not hasattr(conanfile, "requires"): return Requirements() else: if isinstance(conanfile.requires, tuple): return Requirements(*conanfile.requires) else: return Requirements(conanfile.requires, ) except Exception as e: raise ConanException("Error while initializing requirements. %s" % str(e))
def extend_build_requires(self, graph, node, build_requires_refs, check_updates, update, remotes, profile_host, graph_lock): # The options that will be defined in the node will be the real options values that have # been already propagated downstream from the dependency graph. This will override any # other possible option in the build_requires dependency graph. This means that in theory # an option conflict while expanding the build_requires is impossible node.conanfile.build_requires_options.clear_unscoped_options() new_options = node.conanfile.build_requires_options._reqs_options new_reqs = Requirements() conanfile = node.conanfile scope = conanfile.display_name requires = [Requirement(ref) for ref in build_requires_refs] for r in requires: r.build_require = True if graph_lock: graph_lock.pre_lock_node(node) graph_lock.lock_node(node, requires, build_requires=True) self._resolve_ranges(graph, requires, scope, update, remotes) for require in requires: self._expand_require(require, node, graph, check_updates, update, remotes, profile_host, new_reqs, new_options, graph_lock) new_nodes = set(n for n in graph.nodes if n.package_id is None) # This is to make sure that build_requires have precedence over the normal requires ordered_closure = list(node.public_closure.items()) ordered_closure.sort(key=lambda x: x[1] not in new_nodes) node.public_closure = OrderedDict(ordered_closure) return new_nodes
def load_graph(self, root_node, check_updates, update, remotes, profile_host, graph_lock=None): check_updates = check_updates or update initial = graph_lock.initial_counter if graph_lock else None dep_graph = DepsGraph(initial_node_id=initial) # compute the conanfile entry point for this dependency graph name = root_node.name root_node.public_closure = OrderedDict([(name, root_node)]) root_node.transitive_closure = OrderedDict([(name, root_node)]) root_node.public_deps = {name: root_node} root_node.ancestors = set() dep_graph.add_node(root_node) # enter recursive computation t1 = time.time() self._expand_node(root_node, dep_graph, Requirements(), None, None, check_updates, update, remotes, profile_host, graph_lock) logger.debug("GRAPH: Time to load deps %s" % (time.time() - t1)) return dep_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"), ]: req = ConanFileReference.loads("Say/[%s]@myuser/testing" % expr) deps_graph = self.build_graph(GenConanfile().with_name( "Hello").with_version("1.2").with_require(req)) 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_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 load_graph(self, root_node, check_updates, update, remotes, profile_host, profile_build, graph_lock=None): check_updates = check_updates or update initial = graph_lock.initial_counter if graph_lock else None dep_graph = DepsGraph(initial_node_id=initial) # compute the conanfile entry point for this dependency graph root_node.public_closure.add(root_node) root_node.public_deps.add(root_node) root_node.transitive_closure[root_node.name] = root_node if profile_build: root_node.conanfile.settings_build = profile_build.processed_settings.copy( ) root_node.conanfile.settings_target = None dep_graph.add_node(root_node) # enter recursive computation t1 = time.time() self._expand_node(root_node, dep_graph, Requirements(), None, None, check_updates, update, remotes, profile_host, profile_build, graph_lock) logger.debug("GRAPH: Time to load deps %s" % (time.time() - t1)) return dep_graph
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 extend_build_requires(self, graph, node, build_requires_refs, check_updates, update, remotes, profile_host, profile_build, graph_lock): # The options that will be defined in the node will be the real options values that have # been already propagated downstream from the dependency graph. This will override any # other possible option in the build_requires dependency graph. This means that in theory # an option conflict while expanding the build_requires is impossible node.conanfile.build_requires_options.clear_unscoped_options() new_options = node.conanfile.build_requires_options._reqs_options new_reqs = Requirements() conanfile = node.conanfile scope = conanfile.display_name build_requires = [] for ref, context in build_requires_refs: r = Requirement(ref) r.build_require = True r.build_require_context = context r.force_host_context = getattr(ref, "force_host_context", False) build_requires.append(r) if graph_lock: graph_lock.pre_lock_node(node) # TODO: Add info about context? graph_lock.lock_node(node, build_requires, build_requires=True) for require in build_requires: self._resolve_alias(node, require, graph, update, update, remotes) self._resolve_ranges(graph, build_requires, scope, update, remotes) for br in build_requires: context_switch = bool(br.build_require_context == CONTEXT_BUILD) populate_settings_target = context_switch # Avoid 'settings_target' for BR-host self._expand_require( br, node, graph, check_updates, update, remotes, profile_host, profile_build, new_reqs, new_options, graph_lock, context_switch=context_switch, populate_settings_target=populate_settings_target) new_nodes = set(n for n in graph.nodes if n.package_id is None) # This is to make sure that build_requires have precedence over the normal requires node.public_closure.sort(key_fn=lambda x: x not in new_nodes) return new_nodes
def load(self, conan_ref, conanfile): """ compute the dependencies graph for: param conan_ref: ConanFileReference for installed conanfile or path to user one might be None for user conanfile.py or .txt """ dep_graph = DepsGraph() # compute the conanfile entry point for this dependency graph root_node = Node(conan_ref, conanfile) dep_graph.add_node(root_node) public_deps = {} # {name: Node} dict with public nodes, so they are not added again # enter recursive computation self._load_deps(root_node, Requirements(), dep_graph, public_deps, conan_ref, None) dep_graph.propagate_info() return dep_graph
def transitive_test(self, version_range, solution, override, valid): hello_text = TestConanFile("Hello", "1.2", requires=["Say/[>0.1, <1]@myuser/testing"]) 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 six.assertRaisesRegex(self, ConanException, "not valid"): self.build_graph(chat_content % version_range) return deps_graph = self.build_graph(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 load(self, conanfile): dep_graph = DepsGraph() # compute the conanfile entry point for this dependency graph root_node = Node(None, conanfile) dep_graph.add_node(root_node) public_deps = {} # {name: Node} dict with public nodes, so they are not added again # enter recursive computation t1 = time.time() loop_ancestors = [] self._load_deps(root_node, Requirements(), dep_graph, public_deps, None, None, loop_ancestors) logger.debug("Deps-builder: Time to load deps %s" % (time.time() - t1)) t1 = time.time() dep_graph.propagate_info() logger.debug("Deps-builder: Propagate info %s" % (time.time() - t1)) return dep_graph
def load_graph(self, root_node, check_updates, update, remotes, processed_profile): check_updates = check_updates or update dep_graph = DepsGraph() # compute the conanfile entry point for this dependency graph name = root_node.name root_node.public_closure = OrderedDict([(name, root_node)]) root_node.public_deps = {name: root_node} root_node.ancestors = set() dep_graph.add_node(root_node) # enter recursive computation t1 = time.time() self._load_deps(dep_graph, root_node, Requirements(), None, None, check_updates, update, remotes, processed_profile) logger.debug("GRAPH: Time to load deps %s" % (time.time() - t1)) return dep_graph
def load_graph(self, root_node, check_updates, update, remote_name, processed_profile): check_updates = check_updates or update dep_graph = DepsGraph() # compute the conanfile entry point for this dependency graph dep_graph.add_node(root_node) public_deps = {} # {name: Node} dict with public nodes, so they are not added again aliased = {} # enter recursive computation t1 = time.time() loop_ancestors = [] self._load_deps(root_node, Requirements(), dep_graph, public_deps, None, None, loop_ancestors, aliased, check_updates, update, remote_name, processed_profile) logger.debug("Deps-builder: Time to load deps %s" % (time.time() - t1)) t1 = time.time() dep_graph.compute_package_ids() logger.debug("Deps-builder: Propagate info %s" % (time.time() - t1)) return dep_graph
def load(self, conan_ref, conanfile): """ compute the dependencies graph for: param conan_ref: ConanFileReference for installed conanfile or path to user one might be None for user conanfile.py or .txt """ dep_graph = DepsGraph() # compute the conanfile entry point for this dependency graph root_node = Node(conan_ref, conanfile) dep_graph.add_node(root_node) public_deps = {} # {name: Node} dict with public nodes, so they are not added again # enter recursive computation t1 = time.time() loop_ancestors = [] self._load_deps(root_node, Requirements(), dep_graph, public_deps, conan_ref, None, loop_ancestors) logger.debug("Deps-builder: Time to load deps %s" % (time.time() - t1)) t1 = time.time() dep_graph.propagate_info() logger.debug("Deps-builder: Propagate info %s" % (time.time() - t1)) return dep_graph
def transitive_test(self, version_range, solution, override, valid): hello_text = hello_content % ">0.1, <1" hello_ref = ConanFileReference.loads("Hello/1.0@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.0@memsharded/testing", %s """ 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 extend_build_requires(self, graph, node, build_requires_refs, check_updates, update, remotes, processed_profile): # The options that will be defined in the node will be the real options values that have # been already propagated downstream from the dependency graph. This will override any # other possible option in the build_requires dependency graph. This means that in theory # an option conflict while expanding the build_requires is impossible node.conanfile.build_requires_options.clear_unscoped_options() new_options = node.conanfile.build_requires_options._reqs_options new_reqs = Requirements() conanfile = node.conanfile scope = conanfile.display_name requires = [Requirement(ref) for ref in build_requires_refs] self._resolve_ranges(graph, requires, scope, update, remotes) for require in requires: name = require.ref.name require.build_require = True self._handle_require(name, node, require, graph, check_updates, update, remotes, processed_profile, new_reqs, new_options) new_nodes = set([n for n in graph.nodes if n.package_id is None]) # This is to make sure that build_requires have precedence over the normal requires ordered_closure = list(node.public_closure.items()) ordered_closure.sort(key=lambda x: x[1] not in new_nodes) node.public_closure = OrderedDict(ordered_closure) subgraph = DepsGraph() subgraph.aliased = graph.aliased subgraph.evaluated = graph.evaluated subgraph.nodes = new_nodes for n in subgraph.nodes: n.build_require = True return subgraph
def load_conan_txt_test(self): file_content = '''[requires] OpenCV/2.4.10@phil/stable OpenCV2/2.4.10@phil/stable [build_requires] MyPkg/1.0.0@phil/stable [generators] one two [imports] OpenCV/bin, * -> ./bin # I need this binaries OpenCV/lib, * -> ./lib [options] OpenCV:use_python=True OpenCV:other_option=False OpenCV2:use_python2=1 OpenCV2:other_option=Cosa ''' tmp_dir = temp_folder() file_path = os.path.join(tmp_dir, "file.txt") save(file_path, file_content) loader = ConanFileLoader(None, TestBufferConanOutput(), None) ret = loader.load_conanfile_txt(file_path, test_processed_profile()) options1 = OptionsValues.loads("""OpenCV:use_python=True OpenCV:other_option=False OpenCV2:use_python2=1 OpenCV2:other_option=Cosa""") requirements = Requirements() requirements.add("OpenCV/2.4.10@phil/stable") requirements.add("OpenCV2/2.4.10@phil/stable") build_requirements = [] build_requirements.append("MyPkg/1.0.0@phil/stable") self.assertEqual(ret.requires, requirements) self.assertEqual(ret.build_requires, build_requirements) self.assertEqual(ret.generators, ["one", "two"]) self.assertEqual(ret.options.values.dumps(), options1.dumps()) ret.copy = Mock() ret.imports() self.assertTrue(ret.copy.call_args_list, [('*', './bin', 'OpenCV/bin'), ('*', './lib', 'OpenCV/lib')]) # Now something that fails file_content = '''[requires] OpenCV/2.4.104phil/stable ''' tmp_dir = temp_folder() file_path = os.path.join(tmp_dir, "file.txt") save(file_path, file_content) loader = ConanFileLoader(None, TestBufferConanOutput(), None) with six.assertRaisesRegex(self, ConanException, "The reference has too many '/'"): loader.load_conanfile_txt(file_path, test_processed_profile()) file_content = '''[requires] OpenCV/2.4.10@phil/stable111111111111111111111111111111111111111111111111111111111111111 [imports] OpenCV/bin/* - ./bin ''' tmp_dir = temp_folder() file_path = os.path.join(tmp_dir, "file.txt") save(file_path, file_content) loader = ConanFileLoader(None, TestBufferConanOutput(), None) with six.assertRaisesRegex(self, ConanException, "is too long. Valid names must contain"): loader.load_conanfile_txt(file_path, test_processed_profile())
def load_conan_txt_test(self): file_content = '''[requires] OpenCV/2.4.10@phil/stable OpenCV2/2.4.10@phil/stable [generators] one two [imports] OpenCV/bin, * -> ./bin # I need this binaries OpenCV/lib, * -> ./lib [options] OpenCV:use_python=True OpenCV:other_option=False OpenCV2:use_python2=1 OpenCV2:other_option=Cosa ''' tmp_dir = temp_folder() file_path = os.path.join(tmp_dir, "file.txt") save(file_path, file_content) loader = ConanFileLoader(None, Settings(), OptionsValues.loads(""), Scopes()) ret = loader.load_conan_txt(file_path, None) options1 = OptionsValues.loads("""OpenCV:use_python=True OpenCV:other_option=False OpenCV2:use_python2=1 OpenCV2:other_option=Cosa""") requirements = Requirements() requirements.add("OpenCV/2.4.10@phil/stable") requirements.add("OpenCV2/2.4.10@phil/stable") self.assertEquals(ret.requires, requirements) self.assertEquals(ret.generators, ["one", "two"]) self.assertEquals(ret.options.values.dumps(), options1.dumps()) ret.copy = Mock() ret.imports() self.assertTrue(ret.copy.call_args_list, [('*', './bin', 'OpenCV/bin'), ('*', './lib', 'OpenCV/lib')]) # Now something that fails file_content = '''[requires] OpenCV/2.4.104phil/stable <- use_python:True, other_option:False ''' tmp_dir = temp_folder() file_path = os.path.join(tmp_dir, "file.txt") save(file_path, file_content) loader = ConanFileLoader(None, Settings(), OptionsValues.loads(""), Scopes()) with self.assertRaisesRegexp(ConanException, "Wrong package recipe reference(.*)"): loader.load_conan_txt(file_path, None) file_content = '''[requires] OpenCV/2.4.10@phil/stable <- use_python:True, other_option:False [imports] OpenCV/bin/* - ./bin ''' tmp_dir = temp_folder() file_path = os.path.join(tmp_dir, "file.txt") save(file_path, file_content) loader = ConanFileLoader(None, Settings(), OptionsValues.loads(""), Scopes()) with self.assertRaisesRegexp(ConanException, "is too long. Valid names must contain"): loader.load_conan_txt(file_path, None)
def load_conan_txt_test(self): file_content = '''[requires] OpenCV/2.4.10@phil/stable OpenCV2/2.4.10@phil/stable [generators] one two [imports] OpenCV/bin, * -> ./bin # I need this binaries OpenCV/lib, * -> ./lib [options] OpenCV:use_python=True OpenCV:other_option=False OpenCV2:use_python2=1 OpenCV2:other_option=Cosa ''' tmp_dir = temp_folder() file_path = os.path.join(tmp_dir, "file.txt") save(file_path, file_content) loader = ConanFileLoader(None, Settings(), None, OptionsValues.loads(""), Scopes(), None, None) ret = loader.load_conan_txt(file_path, None) options1 = OptionsValues.loads("""OpenCV:use_python=True OpenCV:other_option=False OpenCV2:use_python2=1 OpenCV2:other_option=Cosa""") requirements = Requirements() requirements.add("OpenCV/2.4.10@phil/stable") requirements.add("OpenCV2/2.4.10@phil/stable") self.assertEquals(ret.requires, requirements) self.assertEquals(ret.generators, ["one", "two"]) self.assertEquals(ret.options.values.dumps(), options1.dumps()) ret.copy = Mock() ret.imports() self.assertTrue(ret.copy.call_args_list, [('*', './bin', 'OpenCV/bin'), ('*', './lib', 'OpenCV/lib')]) # Now something that fails file_content = '''[requires] OpenCV/2.4.104phil/stable <- use_python:True, other_option:False ''' tmp_dir = temp_folder() file_path = os.path.join(tmp_dir, "file.txt") save(file_path, file_content) loader = ConanFileLoader(None, Settings(), None, OptionsValues.loads(""), Scopes(), None, None) with self.assertRaisesRegexp(ConanException, "Wrong package recipe reference(.*)"): loader.load_conan_txt(file_path, None) file_content = '''[requires] OpenCV/2.4.10@phil/stable <- use_python:True, other_option:False [imports] OpenCV/bin/* - ./bin ''' tmp_dir = temp_folder() file_path = os.path.join(tmp_dir, "file.txt") save(file_path, file_content) loader = ConanFileLoader(None, Settings(), None, OptionsValues.loads(""), Scopes(), None, None) with self.assertRaisesRegexp(ConanException, "is too long. Valid names must contain"): loader.load_conan_txt(file_path, None)