def _create_new_node(self, current_node, dep_graph, requirement, public_deps, name_req, aliased, check_updates, update, alias_ref=None): """ creates and adds a new node to the dependency graph """ result = self._proxy.get_recipe(requirement.conan_reference, check_updates, update) conanfile_path, remote = result output = ScopedOutput(str(requirement.conan_reference), self._output) dep_conanfile = self._loader.load_conan(conanfile_path, output, reference=requirement.conan_reference) if getattr(dep_conanfile, "alias", None): alias_reference = alias_ref or requirement.conan_reference requirement.conan_reference = ConanFileReference.loads(dep_conanfile.alias) aliased[alias_reference] = requirement.conan_reference return self._create_new_node(current_node, dep_graph, requirement, public_deps, name_req, aliased, check_updates, update, alias_ref=alias_reference) new_node = Node(requirement.conan_reference, dep_conanfile) new_node.remote = remote dep_graph.add_node(new_node) dep_graph.add_edge(current_node, new_node, requirement.private) if not requirement.private: public_deps[name_req] = new_node, None return new_node
def root(self, content, profile): conan_path = os.path.join(self.folder, "data", "root.py") save(conan_path, content) conanfile = self.loader.load_consumer(conan_path, profile) node = Node(None, conanfile, "rootpath") node.recipe = RECIPE_CONSUMER return node
def _load_root_consumer(self, path, graph_lock, profile, ref): """ load a CONSUMER node from a user space conanfile.py or conanfile.txt install|info|create|graph <path> :path full path to a conanfile :graph_lock: might be None, information of lockfiles :profile: data to inject to the consumer node: settings, options :ref: previous reference of a previous command. Can be used for finding itself in the lockfile, or to initialize """ if path.endswith(".py"): lock_python_requires = None if graph_lock: if ref.name is None: # If the graph_info information is not there, better get what we can from # the conanfile # Using load_named() to run set_name() set_version() and get them # so it can be found by name in the lockfile conanfile = self._loader.load_named( path, None, None, None, None) ref = ConanFileReference(ref.name or conanfile.name, ref.version or conanfile.version, ref.user, ref.channel, validate=False) node_id = graph_lock.get_consumer(ref) lock_python_requires = graph_lock.python_requires(node_id) conanfile = self._loader.load_consumer( path, profile, name=ref.name, version=ref.version, user=ref.user, channel=ref.channel, lock_python_requires=lock_python_requires) ref = ConanFileReference(conanfile.name, conanfile.version, ref.user, ref.channel, validate=False) root_node = Node(ref, conanfile, context=CONTEXT_HOST, recipe=RECIPE_CONSUMER, path=path) else: conanfile = self._loader.load_conanfile_txt(path, profile, ref=ref) root_node = Node(None, conanfile, context=CONTEXT_HOST, recipe=RECIPE_CONSUMER, path=path) if graph_lock: # Find the Node ID in the lock of current root node_id = graph_lock.get_consumer(root_node.ref) root_node.id = node_id return root_node
def _create_new_node(self, current_node, dep_graph, requirement, public_deps, name_req, aliased, check_updates, update, remote_name, processed_profile, alias_ref=None): """ creates and adds a new node to the dependency graph """ workspace_package = self._workspace[requirement.ref] if self._workspace else None if workspace_package: conanfile_path = workspace_package.conanfile_path recipe_status = RECIPE_WORKSPACE remote = WORKSPACE_FILE new_ref = requirement.ref else: try: result = self._proxy.get_recipe(requirement.ref, check_updates, update, remote_name, self._recorder) except ConanException as e: if current_node.ref: self._output.error("Failed requirement '%s' from '%s'" % (requirement.ref, current_node.conanfile.display_name)) raise e conanfile_path, recipe_status, remote, new_ref = result dep_conanfile = self._loader.load_conanfile(conanfile_path, processed_profile, ref=requirement.ref) if recipe_status == RECIPE_EDITABLE: dep_conanfile.in_local_cache = False if workspace_package: workspace_package.conanfile = dep_conanfile if getattr(dep_conanfile, "alias", None): alias_ref = alias_ref or new_ref.copy_clear_rev() requirement.ref = ConanFileReference.loads(dep_conanfile.alias) aliased[alias_ref] = requirement.ref return self._create_new_node(current_node, dep_graph, requirement, public_deps, name_req, aliased, check_updates, update, remote_name, processed_profile, alias_ref=alias_ref) logger.debug("GRAPH: new_node: %s" % str(new_ref)) new_node = Node(new_ref, dep_conanfile) new_node.revision_pinned = requirement.ref.revision is not None new_node.recipe = recipe_status new_node.remote = remote dep_graph.add_node(new_node) dep_graph.add_edge(current_node, new_node, requirement.private) if not requirement.private: public_deps[name_req] = new_node, None return new_node
def _load_root_test_package(self, path, create_reference, graph_lock, profile): """ when a test_package/conanfile.py is provided, together with the reference that is being created and need to be tested :return a CONSUMER root_node with a conanfile.py with an injected requires to the created reference """ test = str(create_reference) # do not try apply lock_python_requires for test_package/conanfile.py consumer conanfile = self._loader.load_consumer( path, profile, user=create_reference.user, channel=create_reference.channel) conanfile.display_name = "%s (test package)" % str(test) conanfile.output.scope = conanfile.display_name # Injecting the tested reference require = conanfile.requires.get(create_reference.name) if require: require.ref = require.range_ref = create_reference else: conanfile.requires.add_ref(create_reference) ref = ConanFileReference(conanfile.name, conanfile.version, create_reference.user, create_reference.channel, validate=False) root_node = Node(ref, conanfile, recipe=RECIPE_CONSUMER, path=path) if graph_lock: node_id = graph_lock.get_node(create_reference) locked_ref = graph_lock.pref(node_id).ref conanfile.requires[create_reference.name].lock(locked_ref, node_id) return root_node
def _load_root_direct_reference(self, reference, graph_lock, profile, lockfile_node_id, is_build_require, require_overrides): """ When a full reference is provided: install|info|graph <ref> or export-pkg . :return a VIRTUAL root_node with a conanfile that requires the reference """ if not self._cache.config.revisions_enabled and reference.revision is not None: raise ConanException( "Revisions not enabled in the client, specify a " "reference without revision") conanfile = self._loader.load_virtual( [reference], profile, is_build_require=is_build_require, require_overrides=require_overrides) root_node = Node(ref=None, conanfile=conanfile, context=CONTEXT_HOST, recipe=RECIPE_VIRTUAL) # Build_requires cannot be found as early as this, because there is no require yet if graph_lock and not is_build_require: # Find the Node ID in the lock of current root graph_lock.find_require_and_lock(reference, conanfile, lockfile_node_id) return root_node
def _load_root_node(self, reference, create_reference, profile_host, graph_lock, root_ref, lockfile_node_id): """ creates the first, root node of the graph, loading or creating a conanfile and initializing it (settings, options) as necessary. Also locking with lockfile information """ profile_host.dev_reference = create_reference # Make sure the created one has develop=True if isinstance(reference, list): # Install workspace with multiple root nodes conanfile = self._loader.load_virtual(reference, profile_host, scope_options=False) # Locking in workspaces not implemented yet return Node(ref=None, context=CONTEXT_HOST, conanfile=conanfile, recipe=RECIPE_VIRTUAL) # create (without test_package), install|info|graph|export-pkg <ref> if isinstance(reference, ConanFileReference): return self._load_root_direct_reference(reference, graph_lock, profile_host, lockfile_node_id) path = reference # The reference must be pointing to a user space conanfile if create_reference: # Test_package -> tested reference return self._load_root_test_package(path, create_reference, graph_lock, profile_host) # It is a path to conanfile.py or conanfile.txt root_node = self._load_root_consumer(path, graph_lock, profile_host, root_ref) return root_node
def _create_new_node(self, current_node, dep_graph, requirement, public_deps, name_req, aliased, check_updates, update, remote_name, processed_profile, alias_ref=None): """ creates and adds a new node to the dependency graph """ output = ScopedOutput(str(requirement.conan_reference), self._output) workspace_package = self._workspace[requirement.conan_reference] if self._workspace else None if workspace_package: conanfile_path = workspace_package.conanfile_path recipe_status = RECIPE_WORKSPACE remote = WORKSPACE_FILE new_ref = requirement.conan_reference else: try: result = self._proxy.get_recipe(requirement.conan_reference, check_updates, update, remote_name, self._recorder) except ConanException as e: base_ref = str(current_node.conan_ref or "PROJECT") self._output.error("Failed requirement '%s' from '%s'" % (requirement.conan_reference, base_ref)) raise e conanfile_path, recipe_status, remote, new_ref = result dep_conanfile = self._loader.load_conanfile(conanfile_path, output, processed_profile, reference=requirement.conan_reference) if workspace_package: workspace_package.conanfile = dep_conanfile if getattr(dep_conanfile, "alias", None): alias_reference = alias_ref or new_ref.copy_clear_rev() requirement.conan_reference = ConanFileReference.loads(dep_conanfile.alias) aliased[alias_reference] = requirement.conan_reference return self._create_new_node(current_node, dep_graph, requirement, public_deps, name_req, aliased, check_updates, update, remote_name, processed_profile, alias_ref=alias_reference) new_node = Node(new_ref, dep_conanfile) new_node.revision_pinned = requirement.conan_reference.revision is not None new_node.recipe = recipe_status new_node.remote = remote dep_graph.add_node(new_node) dep_graph.add_edge(current_node, new_node, requirement.private) if not requirement.private: public_deps[name_req] = new_node, None return new_node
def root(self, content, processed_profile): conan_path = os.path.join(self.folder, "root.py") save(conan_path, content) conanfile = self.loader.load_conanfile(conan_path, self.output, processed_profile, consumer=True) return Node(None, conanfile)
def _load_root_test_package(self, path, create_reference, graph_lock, profile, require_overrides): """ when a test_package/conanfile.py is provided, together with the reference that is being created and need to be tested :return a CONSUMER root_node with a conanfile.py with an injected requires to the created reference """ test = str(create_reference) # do not try apply lock_python_requires for test_package/conanfile.py consumer conanfile = self._loader.load_consumer( path, profile, user=create_reference.user, channel=create_reference.channel, require_overrides=require_overrides) conanfile.display_name = "%s (test package)" % str(test) conanfile.output.scope = conanfile.display_name conanfile.tested_reference_str = repr(create_reference) # Injection of the tested reference test_type = getattr(conanfile, "test_type", ("requires", )) if not isinstance(test_type, (list, tuple)): test_type = (test_type, ) if "explicit" not in test_type: # 2.0 mode, not automatically add the require, always explicit if "build_requires" in test_type: if getattr(conanfile, "build_requires", None): # Injecting the tested reference existing = conanfile.build_requires if not isinstance(existing, (list, tuple)): existing = [existing] conanfile.build_requires = list(existing) + [ create_reference ] else: conanfile.build_requires = str(create_reference) if "requires" in test_type: require = conanfile.requires.get(create_reference.name) if require: require.ref = require.range_ref = create_reference else: conanfile.requires.add_ref(create_reference) ref = ConanFileReference(conanfile.name, conanfile.version, create_reference.user, create_reference.channel, validate=False) root_node = Node(ref, conanfile, recipe=RECIPE_CONSUMER, context=CONTEXT_HOST, path=path) if graph_lock: graph_lock.find_require_and_lock(create_reference, conanfile) return root_node
def load_graph(self, reference, create_reference, profile, build_mode, check_updates, update, remote_name, recorder, workspace): def _inject_require(conanfile, reference): """ test_package functionality requires injecting the tested package as requirement before running the install """ require = conanfile.requires.get(reference.name) if require: require.conan_reference = require.range_reference = reference else: conanfile.requires(str(reference)) conanfile._conan_user = reference.user conanfile._conan_channel = reference.channel # Computing the full dependency graph 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) if isinstance(reference, list): # Install workspace with multiple root nodes conanfile = self._loader.load_virtual(reference, processed_profile) elif isinstance(reference, ConanFileReference): # create without test_package and install <ref> conanfile = self._loader.load_virtual([reference], processed_profile) else: output = ScopedOutput("PROJECT", self._output) if reference.endswith(".py"): conanfile = self._loader.load_conanfile(reference, output, processed_profile, consumer=True) if create_reference: # create with test_package _inject_require(conanfile, create_reference) else: conanfile = self._loader.load_conanfile_txt( reference, output, processed_profile) build_mode = BuildMode(build_mode, self._output) root_node = Node(None, conanfile) deps_graph = self._load_graph( root_node, check_updates, update, build_mode=build_mode, remote_name=remote_name, profile_build_requires=profile.build_requires, recorder=recorder, workspace=workspace, processed_profile=processed_profile) build_mode.report_matches() return deps_graph, conanfile, cache_settings
def _load_root_direct_reference(self, reference, graph_lock, profile): """ When a full reference is provided: install|info|graph <ref> or export-pkg . :return a VIRTUAL root_node with a conanfile that requires the reference """ if not self._cache.config.revisions_enabled and reference.revision is not None: raise ConanException("Revisions not enabled in the client, specify a " "reference without revision") conanfile = self._loader.load_virtual([reference], profile) root_node = Node(ref=None, conanfile=conanfile, context=CONTEXT_HOST, recipe=RECIPE_VIRTUAL) if graph_lock: # Find the Node ID in the lock of current root graph_lock.find_require_and_lock(reference, conanfile) return root_node
def _create_new_node(self, current_node, dep_graph, requirement, name_req, check_updates, update, remote_name, processed_profile, alias_ref=None): """ creates and adds a new node to the dependency graph """ try: result = self._proxy.get_recipe(requirement.ref, check_updates, update, remote_name, self._recorder) except ConanException as e: if current_node.ref: self._output.error( "Failed requirement '%s' from '%s'" % (requirement.ref, current_node.conanfile.display_name)) raise e conanfile_path, recipe_status, remote, new_ref = result dep_conanfile = self._loader.load_conanfile(conanfile_path, processed_profile, ref=requirement.ref) if recipe_status == RECIPE_EDITABLE: dep_conanfile.in_local_cache = False dep_conanfile.develop = True if getattr(dep_conanfile, "alias", None): alias_ref = alias_ref or new_ref.copy_clear_rev() requirement.ref = ConanFileReference.loads(dep_conanfile.alias) dep_graph.aliased[alias_ref] = requirement.ref return self._create_new_node(current_node, dep_graph, requirement, name_req, check_updates, update, remote_name, processed_profile, alias_ref=alias_ref) logger.debug("GRAPH: new_node: %s" % str(new_ref)) new_node = Node(new_ref, dep_conanfile) new_node.revision_pinned = requirement.ref.revision is not None new_node.recipe = recipe_status new_node.remote = remote new_node.ancestors = current_node.ancestors.copy() new_node.ancestors.add(current_node.name) dep_graph.add_node(new_node) dep_graph.add_edge(current_node, new_node, requirement.private, requirement.build_require) return new_node
def _create_new_node(self, current_node, dep_graph, requirement, public_deps, name_req, aliased, check_updates, update, remote_name, alias_ref=None): """ creates and adds a new node to the dependency graph """ workspace_package = self._workspace[requirement.conan_reference] if self._workspace else None if workspace_package: conanfile_path = workspace_package.conanfile_path recipe_status = RECIPE_WORKSPACE remote = WORKSPACE_FILE else: result = self._proxy.get_recipe(requirement.conan_reference, check_updates, update, remote_name) conanfile_path, recipe_status, remote = result output = ScopedOutput(str(requirement.conan_reference), self._output) dep_conanfile = self._loader.load_conan(conanfile_path, output, reference=requirement.conan_reference) if workspace_package: workspace_package.conanfile = dep_conanfile if getattr(dep_conanfile, "alias", None): alias_reference = alias_ref or requirement.conan_reference requirement.conan_reference = ConanFileReference.loads(dep_conanfile.alias) aliased[alias_reference] = requirement.conan_reference return self._create_new_node(current_node, dep_graph, requirement, public_deps, name_req, aliased, check_updates, update, remote_name, alias_ref=alias_reference) new_node = Node(requirement.conan_reference, dep_conanfile) new_node.recipe = recipe_status new_node.remote = remote dep_graph.add_node(new_node) dep_graph.add_edge(current_node, new_node, requirement.private) if not requirement.private: public_deps[name_req] = new_node, None return new_node
def load_graph(self, conanfile, check_updates, update, remote_name): check_updates = check_updates or update 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 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) 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_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 _create_new_node(self, current_node, dep_graph, requirement, check_updates, update, remotes, profile_host, profile_build, graph_lock, context_switch, populate_settings_target): # If there is a context_switch, it is because it is a BR-build if context_switch: profile = profile_build context = CONTEXT_BUILD else: profile = profile_host if current_node.context == CONTEXT_HOST else profile_build context = current_node.context result = self._resolve_recipe(current_node, dep_graph, requirement, check_updates, update, remotes, profile, graph_lock) new_ref, dep_conanfile, recipe_status, remote, locked_id = result # Assign the profiles depending on the context if profile_build: # Keep existing behavior (and conanfile members) if no profile_build dep_conanfile.settings_build = profile_build.processed_settings.copy( ) if not context_switch: if populate_settings_target: dep_conanfile.settings_target = current_node.conanfile.settings_target else: dep_conanfile.settings_target = None else: if current_node.context == CONTEXT_HOST: dep_conanfile.settings_target = profile_host.processed_settings.copy( ) else: dep_conanfile.settings_target = profile_build.processed_settings.copy( ) logger.debug("GRAPH: new_node: %s" % str(new_ref)) new_node = Node(new_ref, dep_conanfile, context=context) new_node.revision_pinned = requirement.ref.revision is not None new_node.recipe = recipe_status new_node.remote = remote # Ancestors are a copy of the parent, plus the parent itself new_node.ancestors.assign(current_node.ancestors) new_node.ancestors.add(current_node) if locked_id is not None: new_node.id = locked_id dep_graph.add_node(new_node) dep_graph.add_edge(current_node, new_node, requirement) return new_node
def _create_new_node(self, current_node, dep_graph, requirement, check_updates, update, remotes, profile, graph_lock): result = self._resolve_recipe(current_node, dep_graph, requirement, check_updates, update, remotes, profile, graph_lock) new_ref, dep_conanfile, recipe_status, remote, locked_id = result logger.debug("GRAPH: new_node: %s" % str(new_ref)) new_node = Node(new_ref, dep_conanfile) new_node.revision_pinned = requirement.ref.revision is not None new_node.recipe = recipe_status new_node.remote = remote # Ancestors are a copy of the parent, plus the parent itself new_node.ancestors = current_node.ancestors.copy() new_node.ancestors.add(current_node.name) if locked_id is not None: new_node.id = locked_id dep_graph.add_node(new_node) dep_graph.add_edge(current_node, new_node, requirement) return new_node
def load_graph(self, reference, create_reference, graph_info, build_mode, check_updates, update, remote_name, recorder, apply_build_requires=True): def _inject_require(conanfile, ref): """ test_package functionality requires injecting the tested package as requirement before running the install """ require = conanfile.requires.get(ref.name) if require: require.ref = require.range_ref = ref else: conanfile.requires(str(ref)) conanfile._conan_user = ref.user conanfile._conan_channel = ref.channel # Computing the full dependency graph profile = graph_info.profile processed_profile = ProcessedProfile(profile, create_reference) ref = None if isinstance(reference, list): # Install workspace with multiple root nodes conanfile = self._loader.load_virtual(reference, processed_profile, scope_options=False) root_node = Node(ref, conanfile, recipe=RECIPE_VIRTUAL) elif isinstance(reference, ConanFileReference): if not self._cache.config.revisions_enabled and reference.revision is not None: raise ConanException("Revisions not enabled in the client, specify a " "reference without revision") # create without test_package and install <ref> conanfile = self._loader.load_virtual([reference], processed_profile) root_node = Node(ref, conanfile, recipe=RECIPE_VIRTUAL) else: path = reference if path.endswith(".py"): test = str(create_reference) if create_reference else None conanfile = self._loader.load_consumer(path, processed_profile, test=test, name=graph_info.root.name, version=graph_info.root.version, user=graph_info.root.user, channel=graph_info.root.channel) if create_reference: # create with test_package _inject_require(conanfile, create_reference) ref = ConanFileReference(conanfile.name, conanfile.version, conanfile._conan_user, conanfile._conan_channel, validate=False) else: conanfile = self._loader.load_conanfile_txt(path, processed_profile, ref=graph_info.root) root_node = Node(ref, conanfile, recipe=RECIPE_CONSUMER) build_mode = BuildMode(build_mode, self._output) deps_graph = self._load_graph(root_node, check_updates, update, build_mode=build_mode, remote_name=remote_name, profile_build_requires=profile.build_requires, recorder=recorder, processed_profile=processed_profile, apply_build_requires=apply_build_requires) # THIS IS NECESSARY to store dependencies options in profile, for consumer # FIXME: This is a hack. Might dissapear if the graph for local commands is always recomputed graph_info.options = root_node.conanfile.options.values version_ranges_output = self._resolver.output if version_ranges_output: self._output.success("Version ranges solved") for msg in version_ranges_output: self._output.info(" %s" % msg) self._output.writeln("") build_mode.report_matches() return deps_graph, conanfile
def root(self, content, processed_profile): conan_path = os.path.join(self.folder, ".conan", "data", "root.py") save(conan_path, content) conanfile = self.loader.load_consumer(conan_path, processed_profile) return Node(None, conanfile, "rootpath")
def _create_new_node(self, current_node, dep_graph, requirement, name_req, check_updates, update, remotes, processed_profile, graph_lock, alias_ref=None): """ creates and adds a new node to the dependency graph """ try: result = self._proxy.get_recipe(requirement.ref, check_updates, update, remotes, self._recorder) except ConanException as e: if current_node.ref: self._output.error( "Failed requirement '%s' from '%s'" % (requirement.ref, current_node.conanfile.display_name)) raise e conanfile_path, recipe_status, remote, new_ref = result locked_id = requirement.locked_id lock_python_requires = graph_lock.python_requires( locked_id) if locked_id else None dep_conanfile = self._loader.load_conanfile( conanfile_path, processed_profile, ref=requirement.ref, lock_python_requires=lock_python_requires) if recipe_status == RECIPE_EDITABLE: dep_conanfile.in_local_cache = False dep_conanfile.develop = True if getattr(dep_conanfile, "alias", None): alias_ref = alias_ref or new_ref.copy_clear_rev() requirement.ref = ConanFileReference.loads(dep_conanfile.alias) dep_graph.aliased[alias_ref] = requirement.ref return self._create_new_node(current_node, dep_graph, requirement, name_req, check_updates, update, remotes, processed_profile, graph_lock, alias_ref=alias_ref) logger.debug("GRAPH: new_node: %s" % str(new_ref)) new_node = Node(new_ref, dep_conanfile) new_node.revision_pinned = requirement.ref.revision is not None new_node.recipe = recipe_status new_node.remote = remote # Ancestors are a copy of the parent, plus the parent itself new_node.ancestors = current_node.ancestors.copy() new_node.ancestors.add(current_node.name) if locked_id: new_node.id = locked_id # build-requires and private affect transitively. If "node" is already # a build_require or a private one, its requirements will inherit that property # Or if the require specify that property, then it will get it too new_node.build_require = current_node.build_require or requirement.build_require new_node.private = current_node.private or requirement.private dep_graph.add_node(new_node) dep_graph.add_edge(current_node, new_node, requirement) return new_node
def load_graph(self, reference, create_reference, graph_info, build_mode, check_updates, update, remote_name, recorder, workspace): def _inject_require(conanfile, reference): """ test_package functionality requires injecting the tested package as requirement before running the install """ require = conanfile.requires.get(reference.name) if require: require.conan_reference = require.range_reference = reference else: conanfile.requires(str(reference)) conanfile._conan_user = reference.user conanfile._conan_channel = reference.channel # Computing the full dependency graph profile = graph_info.profile cache_settings = profile.processed_settings processed_profile = ProcessedProfile(profile, create_reference) if isinstance(reference, list): # Install workspace with multiple root nodes conanfile = self._loader.load_virtual(reference, processed_profile) elif isinstance(reference, ConanFileReference): # create without test_package and install <ref> conanfile = self._loader.load_virtual([reference], processed_profile) else: output = ScopedOutput("PROJECT", self._output) if reference.endswith(".py"): conanfile = self._loader.load_conanfile(reference, output, processed_profile, consumer=True) if create_reference: # create with test_package _inject_require(conanfile, create_reference) else: conanfile = self._loader.load_conanfile_txt( reference, output, processed_profile) build_mode = BuildMode(build_mode, self._output) root_node = Node(None, conanfile) deps_graph = self._load_graph( root_node, check_updates, update, build_mode=build_mode, remote_name=remote_name, profile_build_requires=profile.build_requires, recorder=recorder, workspace=workspace, processed_profile=processed_profile) # THIS IS NECESSARY to store dependencies options in profile, for consumer # FIXME: This is a hack. Might dissapear if the graph for local commands is always recomputed graph_info.options = root_node.conanfile.options.values version_ranges_output = self._resolver.output if version_ranges_output: self._output.success("Version ranges solved") for msg in version_ranges_output: self._output.info(" %s" % msg) self._output.writeln("") build_mode.report_matches() return deps_graph, conanfile, cache_settings
def _recurse_build_requires(self, graph, check_updates, update, build_mode, remote_name, profile_build_requires, recorder, workspace, processed_profile): for node in list(graph.nodes): # Virtual conanfiles doesn't have output, but conanfile.py and conanfile.txt do # FIXME: To be improved and build a explicit model for this if node.conanfile.output is None: continue if node.binary not in (BINARY_BUILD, BINARY_WORKSPACE) and node.conan_ref: continue package_build_requires = self._get_recipe_build_requires( node.conanfile) str_ref = str(node.conan_ref or "") new_profile_build_requires = OrderedDict() profile_build_requires = profile_build_requires or {} for pattern, build_requires in profile_build_requires.items(): if ((not str_ref and pattern == "&") or (str_ref and pattern == "&!") or fnmatch.fnmatch(str_ref, pattern)): for build_require in build_requires: if build_require.name in package_build_requires: # Override existing package_build_requires[ build_require.name] = build_require else: # Profile one new_profile_build_requires[ build_require.name] = build_require if package_build_requires: node.conanfile.build_requires_options.clear_unscoped_options() build_requires_options = node.conanfile.build_requires_options virtual = self._loader.load_virtual( package_build_requires.values(), scope_options=False, build_requires_options=build_requires_options, processed_profile=processed_profile) virtual_node = Node(None, virtual) build_requires_package_graph = self._load_graph( virtual_node, check_updates, update, build_mode, remote_name, profile_build_requires, recorder, workspace, processed_profile) graph.add_graph(node, build_requires_package_graph, build_require=True) if new_profile_build_requires: node.conanfile.build_requires_options.clear_unscoped_options() build_requires_options = node.conanfile.build_requires_options virtual = self._loader.load_virtual( new_profile_build_requires.values(), scope_options=False, build_requires_options=build_requires_options, processed_profile=processed_profile) virtual_node = Node(None, virtual) build_requires_profile_graph = self._load_graph( virtual_node, check_updates, update, build_mode, remote_name, new_profile_build_requires, recorder, workspace, processed_profile) graph.add_graph(node, build_requires_profile_graph, build_require=True)
def load_graph(self, reference, create_reference, graph_info, build_mode, check_updates, update, remotes, recorder, apply_build_requires=True): def _inject_require(conanfile, ref): """ test_package functionality requires injecting the tested package as requirement before running the install """ require = conanfile.requires.get(ref.name) if require: require.ref = require.range_ref = ref else: conanfile.requires.add_ref(ref) conanfile._conan_user = ref.user conanfile._conan_channel = ref.channel # Computing the full dependency graph profile = graph_info.profile processed_profile = profile processed_profile.dev_reference = create_reference ref = None graph_lock = graph_info.graph_lock if isinstance(reference, list): # Install workspace with multiple root nodes conanfile = self._loader.load_virtual(reference, processed_profile, scope_options=False) root_node = Node(ref, conanfile, recipe=RECIPE_VIRTUAL) elif isinstance(reference, ConanFileReference): if not self._cache.config.revisions_enabled and reference.revision is not None: raise ConanException("Revisions not enabled in the client, specify a " "reference without revision") # create without test_package and install <ref> conanfile = self._loader.load_virtual([reference], processed_profile) root_node = Node(ref, conanfile, recipe=RECIPE_VIRTUAL) if graph_lock: # Find the Node ID in the lock of current root graph_lock.find_consumer_node(root_node, reference) else: path = reference if path.endswith(".py"): test = str(create_reference) if create_reference else None lock_python_requires = None # do not try apply lock_python_requires for test_package/conanfile.py consumer if graph_lock and not create_reference: if graph_info.root.name is None: # If the graph_info information is not there, better get what we can from # the conanfile conanfile = self._loader.load_class(path) graph_info.root = ConanFileReference(graph_info.root.name or conanfile.name, graph_info.root.version or conanfile.version, graph_info.root.user, graph_info.root.channel, validate=False) node_id = graph_lock.get_node(graph_info.root) lock_python_requires = graph_lock.python_requires(node_id) conanfile = self._loader.load_consumer(path, processed_profile, test=test, name=graph_info.root.name, version=graph_info.root.version, user=graph_info.root.user, channel=graph_info.root.channel, lock_python_requires=lock_python_requires) if create_reference: # create with test_package _inject_require(conanfile, create_reference) ref = ConanFileReference(conanfile.name, conanfile.version, conanfile._conan_user, conanfile._conan_channel, validate=False) else: conanfile = self._loader.load_conanfile_txt(path, processed_profile, ref=graph_info.root) root_node = Node(ref, conanfile, recipe=RECIPE_CONSUMER, path=path) if graph_lock: # Find the Node ID in the lock of current root graph_lock.find_consumer_node(root_node, create_reference) build_mode = BuildMode(build_mode, self._output) deps_graph = self._load_graph(root_node, check_updates, update, build_mode=build_mode, remotes=remotes, profile_build_requires=profile.build_requires, recorder=recorder, processed_profile=processed_profile, apply_build_requires=apply_build_requires, graph_lock=graph_lock) # THIS IS NECESSARY to store dependencies options in profile, for consumer # FIXME: This is a hack. Might dissapear if graph for local commands is always recomputed graph_info.options = root_node.conanfile.options.values if ref: graph_info.root = ref if graph_info.graph_lock is None: graph_info.graph_lock = GraphLock(deps_graph) else: graph_info.graph_lock.update_check_graph(deps_graph, self._output) version_ranges_output = self._resolver.output if version_ranges_output: self._output.success("Version ranges solved") for msg in version_ranges_output: self._output.info(" %s" % msg) self._output.writeln("") build_mode.report_matches() return deps_graph, conanfile