def test_valid_params(self): build_mode = BuildMode(["outdated", "missing"], self.output) self.assertTrue(build_mode.outdated) self.assertTrue(build_mode.missing) self.assertFalse(build_mode.never) build_mode = BuildMode(["never"], self.output) self.assertFalse(build_mode.outdated) self.assertFalse(build_mode.missing) self.assertTrue(build_mode.never)
def test_pattern_matching(self): build_mode = BuildMode(["Boost*"], self.output) reference = ConanFileReference.loads("Boost/1.69.0@user/stable") self.assertTrue(build_mode.forced(self.conanfile, reference)) reference = ConanFileReference.loads("Boost_Addons/1.0.0@user/stable") self.assertTrue(build_mode.forced(self.conanfile, reference)) reference = ConanFileReference.loads("MyBoost/1.0@user/stable") self.assertFalse(build_mode.forced(self.conanfile, reference)) reference = ConanFileReference.loads("foo/Boost@user/stable") self.assertFalse(build_mode.forced(self.conanfile, reference)) reference = ConanFileReference.loads("foo/1.0@Boost/stable") self.assertFalse(build_mode.forced(self.conanfile, reference)) reference = ConanFileReference.loads("foo/1.0@user/Boost") self.assertFalse(build_mode.forced(self.conanfile, reference)) build_mode = BuildMode(["foo/*@user/stable"], self.output) reference = ConanFileReference.loads("foo/1.0.0@user/stable") self.assertTrue(build_mode.forced(self.conanfile, reference)) reference = ConanFileReference.loads("foo/1.0@user/stable") self.assertTrue(build_mode.forced(self.conanfile, reference)) reference = ConanFileReference.loads("foo/1.0.0-abcdefg@user/stable") self.assertTrue(build_mode.forced(self.conanfile, reference)) build_mode = BuildMode(["*@user/stable"], self.output) reference = ConanFileReference.loads("foo/1.0.0@user/stable") self.assertTrue(build_mode.forced(self.conanfile, reference)) reference = ConanFileReference.loads("bar/1.0@user/stable") self.assertTrue(build_mode.forced(self.conanfile, reference)) reference = ConanFileReference.loads("foo/1.0.0-abcdefg@user/stable") self.assertTrue(build_mode.forced(self.conanfile, reference)) reference = ConanFileReference.loads("foo/1.0.0@NewUser/stable") self.assertFalse(build_mode.forced(self.conanfile, reference)) build_mode = BuildMode(["*Tool"], self.output) reference = ConanFileReference.loads("Tool/0.1@lasote/stable") self.assertTrue(build_mode.forced(self.conanfile, reference)) reference = ConanFileReference.loads("PythonTool/0.1@lasote/stable") self.assertTrue(build_mode.forced(self.conanfile, reference)) reference = ConanFileReference.loads("SomeTool/1.2@user/channel") self.assertTrue(build_mode.forced(self.conanfile, reference)) build_mode = BuildMode(["Tool/*"], self.output) reference = ConanFileReference.loads("Tool/0.1@lasote/stable") self.assertTrue(build_mode.forced(self.conanfile, reference)) reference = ConanFileReference.loads("Tool/1.1@user/testing") self.assertTrue(build_mode.forced(self.conanfile, reference)) reference = ConanFileReference.loads("PythonTool/0.1@lasote/stable") self.assertFalse(build_mode.forced(self.conanfile, reference)) build_mode.report_matches() self.assertEqual("", self.output)
def _evaluate_node(self, node, build_mode, update, remotes): assert node.binary is None, "Node.binary should be None" assert node.package_id is not None, "Node.package_id shouldn't be None" assert node.package_id != PACKAGE_ID_UNKNOWN, "Node.package_id shouldn't be Unknown" assert node.prev is None, "Node.prev should be None" # If it has lock locked = node.graph_lock_node if locked and locked.package_id: # if package_id = None, nothing to lock here # First we update the package_id, just in case there are differences or something locked.package_id = node.package_id # necessary for PACKAGE_ID_UNKNOWN pref = PackageReference(locked.ref, locked.package_id, locked.prev) # Keep locked PREV self._process_node(node, pref, build_mode, update, remotes) if node.binary == BINARY_MISSING and build_mode.allowed( node.conanfile): node.binary = BINARY_BUILD if node.binary == BINARY_BUILD and locked.prev: raise ConanException( "Cannot build '%s' because it is already locked in the input " "lockfile" % repr(node.ref)) else: assert node.prev is None, "Non locked node shouldn't have PREV in evaluate_node" assert node.binary is None, "Node.binary should be None if not locked" pref = PackageReference(node.ref, node.package_id) self._process_node(node, pref, build_mode, update, remotes) if node.binary == BINARY_MISSING: if node.conanfile.compatible_packages: compatible_build_mode = BuildMode(None, self._out) for compatible_package in node.conanfile.compatible_packages: package_id = compatible_package.package_id() if package_id == node.package_id: node.conanfile.output.info( "Compatible package ID %s equal to the " "default package ID" % package_id) continue pref = PackageReference(node.ref, package_id) node.binary = None # Invalidate it # NO Build mode self._process_node(node, pref, compatible_build_mode, update, remotes) assert node.binary is not None if node.binary != BINARY_MISSING: node.conanfile.output.info( "Main binary package '%s' missing. Using " "compatible package '%s'" % (node.package_id, package_id)) # Modifying package id under the hood, FIXME node._package_id = package_id # So they are available in package_info() method node.conanfile.settings.values = compatible_package.settings node.conanfile.options.values = compatible_package.options break if node.binary == BINARY_MISSING and build_mode.allowed( node.conanfile): node.binary = BINARY_BUILD if locked: locked.package_id = node.package_id locked.prev = node.prev
def test_non_matching_full_reference_build_force(self): reference = ConanFileReference.loads("Bar/0.1@user/stable") build_mode = BuildMode(["Bar/0.1@user/testing"], self.output) self.assertFalse(build_mode.forced(self.conanfile, reference)) build_mode.report_matches() self.assertIn("No package matching 'Bar/0.1@user/testing' pattern", self.output)
def install_workspace(self, profile, workspace, remote_name, build_modes, update): loader = self.get_loader(profile) references = [ ConanFileReference(v, "root", "project", "develop") for v in workspace.root ] conanfile = loader.load_virtual(references) remote_proxy = self.get_proxy(remote_name=remote_name) graph_builder = self._get_graph_builder(loader, remote_proxy) graph_builder._workspace = workspace deps_graph = graph_builder.load_graph(conanfile, False, update) output = ScopedOutput(str("Workspace"), self._user_io.out) output.highlight("Installing...") print_graph(deps_graph, self._user_io.out) build_mode = BuildMode(build_modes, self._user_io.out) build_requires = BuildRequires(loader, graph_builder, self._registry) installer = ConanInstaller(self._client_cache, output, remote_proxy, build_mode, build_requires, recorder=self._recorder) installer._workspace = workspace installer.install(deps_graph, profile.build_requires, keep_build=False, update=update) build_mode.report_matches() workspace.generate()
def _resolve_graph(self, root_node, profile_host, profile_build, graph_lock, build_mode, check_updates, update, remotes, recorder, apply_build_requires=True): build_mode = BuildMode(build_mode, self._output) deps_graph = self._load_graph( root_node, check_updates, update, build_mode=build_mode, remotes=remotes, recorder=recorder, profile_host=profile_host, profile_build=profile_build, apply_build_requires=apply_build_requires, graph_lock=graph_lock) 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("") self._resolver.clear_output() build_mode.report_matches() return deps_graph
def test_casing(self): reference = ConanFileReference.loads("Boost/1.69.0@user/stable") build_mode = BuildMode(["Boost"], self.output) self.assertTrue(build_mode.forced(self.conanfile, reference)) build_mode = BuildMode(["Bo*"], self.output) self.assertTrue(build_mode.forced(self.conanfile, reference)) build_mode.report_matches() self.assertEqual("", self.output) build_mode = BuildMode(["boost"], self.output) self.assertFalse(build_mode.forced(self.conanfile, reference)) build_mode = BuildMode(["bo*"], self.output) self.assertFalse(build_mode.forced(self.conanfile, reference)) build_mode.report_matches() self.assertIn("ERROR: No package matching", self.output)
def build_consumer(self, path, profile_build_requires=None, ref=None, create_ref=None, install=True): profile = Profile() if profile_build_requires: profile.build_requires = profile_build_requires profile.process_settings(self.cache) update = check_updates = False recorder = ActionRecorder() remotes = Remotes() build_mode = [] # Means build all ref = ref or ConanFileReference(None, None, None, None, validate=False) options = OptionsValues() graph_info = GraphInfo(profile, options, root_ref=ref) app = self._get_app() deps_graph = app.graph_manager.load_graph(path, create_ref, graph_info, build_mode, check_updates, update, remotes, recorder) if install: binary_installer = BinaryInstaller(app, recorder) build_mode = BuildMode(build_mode, app.out) binary_installer.install(deps_graph, None, build_mode, update, False, graph_info) return deps_graph
def _resolve_graph(self, root_node, graph_info, build_mode, check_updates, update, remotes, recorder, apply_build_requires=True): build_mode = BuildMode(build_mode, self._output) profile_host = graph_info.profile_host graph_lock = graph_info.graph_lock deps_graph = self._load_graph(root_node, check_updates, update, build_mode=build_mode, remotes=remotes, recorder=recorder, profile_host=profile_host, profile_build=graph_info.profile_build, 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 root_node.ref: graph_info.root = root_node.ref if graph_info.graph_lock is None: graph_info.graph_lock = GraphLock(deps_graph, self._cache.config.revisions_enabled) 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("") self._resolver.clear_output() build_mode.report_matches() return deps_graph
def _build_graph(self, profile_host, profile_build, install=False): path = temp_folder() path = os.path.join(path, "conanfile.txt") save(path, textwrap.dedent(""" [requires] app/testing@user/channel """)) ref = ConanFileReference(None, None, None, None, validate=False) options = OptionsValues() graph_info = GraphInfo(profile_host=profile_host, profile_build=profile_build, options=options, root_ref=ref) recorder = ActionRecorder() app = self._get_app() deps_graph = app.graph_manager.load_graph(path, create_reference=None, graph_info=graph_info, build_mode=[], check_updates=False, update=False, remotes=Remotes(), recorder=recorder) if install: build_mode = [] # Means build all binary_installer = BinaryInstaller(app, recorder) build_mode = BuildMode(build_mode, app.out) binary_installer.install(deps_graph, None, build_mode, update=False, profile_host=profile_host, profile_build=profile_build, graph_lock=None, keep_build=False) return deps_graph
def _get_deps_graph(self, reference, profile, check_updates, update, build_mode, remote_name): loader = self.get_loader(profile) conanfile = self._load_install_conanfile(loader, reference) graph_builder = self._get_graph_builder(loader, self._recorder) build_mode = BuildMode(build_mode, self._user_io.out) deps_graph = graph_builder.load_graph(conanfile, check_updates, update, build_mode=build_mode, remote_name=remote_name, profile_build_requires=profile.build_requires) return deps_graph, conanfile
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 info_nodes_to_build(self, reference, profile, build_modes, remote_name, check_updates): remote_proxy = self.get_proxy(remote_name=remote_name) deps_graph, _, conanfile = self._get_deps_graph(reference, profile, remote_proxy, update=False, check_updates=check_updates) build_mode = BuildMode(build_modes, self._user_io.out) installer = ConanInstaller(self._client_cache, self._user_io.out, remote_proxy, build_mode, None, recorder=self._recorder) nodes = installer.nodes_to_build(deps_graph) counter = Counter(ref.conan.name for ref, _ in nodes) ret = [ref if counter[ref.conan.name] > 1 else str(ref.conan) for ref, _ in nodes] return ret, self._get_project_reference(reference, conanfile)
def _evaluate_node(self, node, build_mode, update, remotes): assert node.binary is None, "Node.binary should be None" assert node.package_id is not None, "Node.package_id shouldn't be None" assert node.package_id != PACKAGE_ID_UNKNOWN, "Node.package_id shouldn't be Unknown" assert node.prev is None, "Node.prev should be None" # If it has lock locked = node.graph_lock_node if locked and locked.pref.id == node.package_id: pref = locked.pref # Keep the locked with PREV self._process_node(node, pref, build_mode, update, remotes) if node.binary == BINARY_MISSING and build_mode.allowed( node.conanfile): node.binary = BINARY_BUILD else: assert node.prev is None, "Non locked node shouldn't have PREV in evaluate_node" pref = PackageReference(node.ref, node.package_id) self._process_node(node, pref, build_mode, update, remotes) if node.binary == BINARY_MISSING: if node.conanfile.compatible_packages: compatible_build_mode = BuildMode(None, self._out) for compatible_package in node.conanfile.compatible_packages: package_id = compatible_package.package_id() if package_id == node.package_id: node.conanfile.output.info( "Compatible package ID %s equal to the " "default package ID" % package_id) continue pref = PackageReference(node.ref, package_id) node.binary = None # Invalidate it # NO Build mode self._process_node(node, pref, compatible_build_mode, update, remotes) assert node.binary is not None if node.binary != BINARY_MISSING: node.conanfile.output.info( "Main binary package '%s' missing. Using " "compatible package '%s'" % (node.package_id, package_id)) node._package_id = package_id # So they are available in package_info() method node.conanfile.settings.values = compatible_package.settings node.conanfile.options.values = compatible_package.options break if node.binary == BINARY_MISSING and build_mode.allowed( node.conanfile): node.binary = BINARY_BUILD
def deps_install(app, ref_or_path, install_folder, graph_info, remotes=None, build_modes=None, update=False, manifest_folder=None, manifest_verify=False, manifest_interactive=False, generators=None, no_imports=False, create_reference=None, keep_build=False, use_lock=False, recorder=None): """ Fetch and build all dependencies for the given reference :param app: The ConanApp instance with all collaborators @param ref_or_path: ConanFileReference or path to user space conanfile @param install_folder: where the output files will be saved @param build_modes: List of build_modes specified @param update: Check for updated in the upstream remotes (and update) @param manifest_folder: Folder to install the manifests @param manifest_verify: Verify dependencies manifests against stored ones @param manifest_interactive: Install deps manifests in folder for later verify, asking user for confirmation @param generators: List of generators from command line. If False, no generator will be written @param no_imports: Install specified packages but avoid running imports """ out, user_io, graph_manager, cache = app.out, app.user_io, app.graph_manager, app.cache remote_manager, hook_manager = app.remote_manager, app.hook_manager if generators is not False: generators = set(generators) if generators else set() generators.add("txt") # Add txt generator by default out.info("Configuration:") out.writeln(graph_info.profile_host.dumps()) deps_graph = graph_manager.load_graph(ref_or_path, create_reference, graph_info, build_modes, False, update, remotes, recorder) root_node = deps_graph.root conanfile = root_node.conanfile if root_node.recipe == RECIPE_VIRTUAL: out.highlight("Installing package: %s" % str(ref_or_path)) else: conanfile.output.highlight("Installing package") print_graph(deps_graph, out) try: if cross_building(graph_info.profile_host.processed_settings): settings = get_cross_building_settings(graph_info.profile_host.processed_settings) message = "Cross-build from '%s:%s' to '%s:%s'" % settings out.writeln(message, Color.BRIGHT_MAGENTA) except ConanException: # Setting os doesn't exist pass installer = BinaryInstaller(app, recorder=recorder) # TODO: Extract this from the GraphManager, reuse same object, check args earlier build_modes = BuildMode(build_modes, out) installer.install(deps_graph, remotes, build_modes, update, keep_build=keep_build, graph_info=graph_info) # GraphLock always != None here (because of graph_manager.load_graph) graph_info.graph_lock.update_check_graph(deps_graph, out) if manifest_folder: manifest_manager = ManifestManager(manifest_folder, user_io=user_io, cache=cache) for node in deps_graph.nodes: if node.recipe in (RECIPE_CONSUMER, RECIPE_VIRTUAL): continue complete_recipe_sources(remote_manager, cache, node.conanfile, node.ref, remotes) manifest_manager.check_graph(deps_graph, verify=manifest_verify, interactive=manifest_interactive) manifest_manager.print_log() if install_folder: conanfile.install_folder = install_folder # Write generators output = conanfile.output if root_node.recipe != RECIPE_VIRTUAL else out if generators is not False: tmp = list(conanfile.generators) # Add the command line specified generators tmp.extend([g for g in generators if g not in tmp]) conanfile.generators = tmp write_generators(conanfile, install_folder, output) if not isinstance(ref_or_path, ConanFileReference) or use_lock: # Write conaninfo content = normalize(conanfile.info.dumps()) save(os.path.join(install_folder, CONANINFO), content) output.info("Generated %s" % CONANINFO) graph_info.save(install_folder) output.info("Generated graphinfo") if not no_imports: run_imports(conanfile, install_folder) call_system_requirements(conanfile, conanfile.output) if not create_reference and isinstance(ref_or_path, ConanFileReference): # The conanfile loaded is a virtual one. The one w deploy is the first level one neighbours = deps_graph.root.neighbors() deploy_conanfile = neighbours[0].conanfile if hasattr(deploy_conanfile, "deploy") and callable(deploy_conanfile.deploy): run_deploy(deploy_conanfile, install_folder)
def test_multiple_builds(self): reference = ConanFileReference.loads("Bar/0.1@user/stable") build_mode = BuildMode(["Bar", "Foo"], self.output) self.assertTrue(build_mode.forced(self.conanfile, reference)) build_mode.report_matches() self.assertIn("ERROR: No package matching", self.output)
def test_allowed(self): build_mode = BuildMode(["outdated", "missing"], self.output) self.assertTrue(build_mode.allowed(self.conanfile)) build_mode = BuildMode([], self.output) self.assertFalse(build_mode.allowed(self.conanfile))
def test_invalid_configuration(self): with six.assertRaisesRegex(self, ConanException, "--build=never not compatible with other options"): BuildMode(["outdated", "missing", "never"], self.output)
def test_full_reference_build_force(self): reference = ConanFileReference.loads("Bar/0.1@user/testing") build_mode = BuildMode(["Bar/0.1@user/testing"], self.output) self.assertTrue(build_mode.forced(self.conanfile, reference)) build_mode.report_matches() self.assertEqual("", self.output)
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 deps_install(app, ref_or_path, install_folder, base_folder, graph_info, remotes=None, build_modes=None, update=False, manifest_folder=None, manifest_verify=False, manifest_interactive=False, generators=None, no_imports=False, create_reference=None, keep_build=False, recorder=None, lockfile_node_id=None, is_build_require=False, add_txt_generator=True, require_overrides=None, conanfile_path=None, test=None, source_folder=None, output_folder=None): """ Fetch and build all dependencies for the given reference @param app: The ConanApp instance with all collaborators @param ref_or_path: ConanFileReference or path to user space conanfile @param install_folder: where the output files will be saved @param build_modes: List of build_modes specified @param update: Check for updated in the upstream remotes (and update) @param manifest_folder: Folder to install the manifests @param manifest_verify: Verify dependencies manifests against stored ones @param manifest_interactive: Install deps manifests in folder for later verify, asking user for confirmation @param generators: List of generators from command line. @param no_imports: Install specified packages but avoid running imports @param add_txt_generator: Add the txt to the list of generators """ out, user_io, graph_manager, cache = app.out, app.user_io, app.graph_manager, app.cache remote_manager, hook_manager = app.remote_manager, app.hook_manager profile_host, profile_build = graph_info.profile_host, graph_info.profile_build if profile_build: out.info("Configuration (profile_host):") out.writeln(profile_host.dumps()) out.info("Configuration (profile_build):") out.writeln(profile_build.dumps()) else: out.info("Configuration:") out.writeln(profile_host.dumps()) deps_graph = graph_manager.load_graph(ref_or_path, create_reference, graph_info, build_modes, False, update, remotes, recorder, lockfile_node_id=lockfile_node_id, is_build_require=is_build_require, require_overrides=require_overrides) graph_lock = graph_info.graph_lock # After the graph is loaded it is defined root_node = deps_graph.root conanfile = root_node.conanfile if root_node.recipe == RECIPE_VIRTUAL: out.highlight("Installing package: %s" % str(ref_or_path)) else: conanfile.output.highlight("Installing package") print_graph(deps_graph, out) try: if cross_building(conanfile): settings = get_cross_building_settings(conanfile) message = "Cross-build from '%s:%s' to '%s:%s'" % settings out.writeln(message, Color.BRIGHT_MAGENTA) except ConanException: # Setting os doesn't exist pass installer = BinaryInstaller(app, recorder=recorder) # TODO: Extract this from the GraphManager, reuse same object, check args earlier build_modes = BuildMode(build_modes, out) installer.install(deps_graph, remotes, build_modes, update, profile_host, profile_build, graph_lock, keep_build=keep_build) graph_lock.complete_matching_prevs() if manifest_folder: manifest_manager = ManifestManager(manifest_folder, user_io=user_io, cache=cache) for node in deps_graph.nodes: if node.recipe in (RECIPE_CONSUMER, RECIPE_VIRTUAL): continue retrieve_exports_sources(remote_manager, cache, node.conanfile, node.ref, remotes) manifest_manager.check_graph(deps_graph, verify=manifest_verify, interactive=manifest_interactive) manifest_manager.print_log() if hasattr(conanfile, "layout") and not test: conanfile.folders.set_base_source(source_folder or conanfile_path) conanfile.folders.set_base_install(output_folder or conanfile_path) conanfile.folders.set_base_imports(output_folder or conanfile_path) conanfile.folders.set_base_generators(output_folder or conanfile_path) else: conanfile.folders.set_base_install(install_folder) conanfile.folders.set_base_imports(install_folder) conanfile.folders.set_base_generators(base_folder) output = conanfile.output if root_node.recipe != RECIPE_VIRTUAL else out if install_folder: # Write generators tmp = list( conanfile.generators) # Add the command line specified generators generators = set(generators) if generators else set() tmp.extend([g for g in generators if g not in tmp]) if add_txt_generator: tmp.append("txt") conanfile.generators = tmp app.generator_manager.write_generators(conanfile, install_folder, conanfile.generators_folder, output) write_toolchain(conanfile, conanfile.generators_folder, output) if not isinstance(ref_or_path, ConanFileReference): # Write conaninfo content = normalize(conanfile.info.dumps()) save(os.path.join(install_folder, CONANINFO), content) output.info("Generated %s" % CONANINFO) graph_info.save(install_folder) output.info("Generated graphinfo") graph_lock_file = GraphLockFile(profile_host, profile_build, graph_lock) graph_lock_file.save(os.path.join(install_folder, "conan.lock")) if not no_imports: run_imports(conanfile) if type(conanfile ).system_requirements != ConanFile.system_requirements: call_system_requirements(conanfile, conanfile.output) if not create_reference and isinstance(ref_or_path, ConanFileReference): # The conanfile loaded is a virtual one. The one w deploy is the first level one neighbours = deps_graph.root.neighbors() deploy_conanfile = neighbours[0].conanfile if hasattr(deploy_conanfile, "deploy") and callable( deploy_conanfile.deploy): run_deploy(deploy_conanfile, install_folder)
def test_no_user_channel_revision_included(self): reference = ConanFileReference.loads("Hello/0.1@#rrev1") build_mode = BuildMode(["Hello/0.1@#rrev1"], self.output) self.assertTrue(build_mode.forced(self.conanfile, reference)) build_mode.report_matches() self.assertEqual("", self.output)
def install(self, reference, install_folder, profile, remote_name=None, build_modes=None, update=False, manifest_folder=None, manifest_verify=False, manifest_interactive=False, generators=None, no_imports=False, inject_require=None, install_reference=False, keep_build=False): """ Fetch and build all dependencies for the given reference @param reference: ConanFileReference or path to user space conanfile @param install_folder: where the output files will be saved @param remote: install only from that remote @param profile: Profile object with both the -s introduced options and profile read values @param build_modes: List of build_modes specified @param update: Check for updated in the upstream remotes (and update) @param manifest_folder: Folder to install the manifests @param manifest_verify: Verify dependencies manifests against stored ones @param manifest_interactive: Install deps manifests in folder for later verify, asking user for confirmation @param generators: List of generators from command line. If False, no generator will be written @param no_imports: Install specified packages but avoid running imports @param inject_require: Reference to add as a requirement to the conanfile """ if generators is not False: generators = set(generators) if generators else set() generators.add("txt") # Add txt generator by default manifest_manager = ManifestManager(manifest_folder, user_io=self._user_io, client_cache=self._client_cache, verify=manifest_verify, interactive=manifest_interactive) if manifest_folder else None remote_proxy = self.get_proxy(remote_name=remote_name, manifest_manager=manifest_manager) loader = self.get_loader(profile) if not install_reference: if isinstance(reference, ConanFileReference): # is a create loader.dev_reference = reference elif inject_require: loader.dev_reference = inject_require conanfile = self._load_install_conanfile(loader, reference) if inject_require: self._inject_require(conanfile, inject_require) graph_builder = self._get_graph_builder(loader, remote_proxy) deps_graph = graph_builder.load_graph(conanfile, False, update) if not isinstance(reference, ConanFileReference): output = ScopedOutput(("%s (test package)" % str(inject_require)) if inject_require else "PROJECT", self._user_io.out) output.highlight("Installing %s" % reference) else: output = ScopedOutput(str(reference), self._user_io.out) output.highlight("Installing package") Printer(self._user_io.out).print_graph(deps_graph, self._registry) try: if cross_building(loader._settings): b_os, b_arch, h_os, h_arch = get_cross_building_settings(loader._settings) message = "Cross-build from '%s:%s' to '%s:%s'" % (b_os, b_arch, h_os, h_arch) self._user_io.out.writeln(message, Color.BRIGHT_MAGENTA) except ConanException: # Setting os doesn't exist pass build_mode = BuildMode(build_modes, self._user_io.out) build_requires = BuildRequires(loader, graph_builder, self._registry) installer = ConanInstaller(self._client_cache, output, remote_proxy, build_mode, build_requires, recorder=self._recorder) # Apply build_requires to consumer conanfile if not isinstance(reference, ConanFileReference): build_requires.install("", conanfile, installer, profile.build_requires, output, update) installer.install(deps_graph, profile.build_requires, keep_build, update=update) build_mode.report_matches() if install_folder: # Write generators if generators is not False: tmp = list(conanfile.generators) # Add the command line specified generators tmp.extend([g for g in generators if g not in tmp]) conanfile.generators = tmp write_generators(conanfile, install_folder, output) if not isinstance(reference, ConanFileReference): # Write conaninfo content = normalize(conanfile.info.dumps()) save(os.path.join(install_folder, CONANINFO), content) output.info("Generated %s" % CONANINFO) if not no_imports: run_imports(conanfile, install_folder, output) call_system_requirements(conanfile, output) if install_reference: # The conanfile loaded is really a virtual one. The one with the deploy is the first level one deploy_conanfile = deps_graph.inverse_levels()[1][0].conanfile if hasattr(deploy_conanfile, "deploy") and callable(deploy_conanfile.deploy): run_deploy(deploy_conanfile, install_folder, output) if manifest_manager: manifest_manager.print_log()
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
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 _evaluate_node(self, node, build_mode, update, remotes): assert node.binary is None, "Node.binary should be None" assert node.package_id is not None, "Node.package_id shouldn't be None" assert node.package_id != PACKAGE_ID_UNKNOWN, "Node.package_id shouldn't be Unknown" assert node.prev is None, "Node.prev should be None" # If it has lock locked = node.graph_lock_node if locked and locked.package_id and locked.package_id != PACKAGE_ID_UNKNOWN: pref = PackageReference(locked.ref, locked.package_id, locked.prev) # Keep locked PREV self._process_node(node, pref, build_mode, update, remotes) if node.binary == BINARY_MISSING and build_mode.allowed(node.conanfile): node.binary = BINARY_BUILD if node.binary == BINARY_BUILD: locked.unlock_prev() if node.package_id != locked.package_id: # It was a compatible package # https://github.com/conan-io/conan/issues/9002 # We need to iterate to search the compatible combination for compatible_package in node.conanfile.compatible_packages: comp_package_id = compatible_package.package_id() if comp_package_id == locked.package_id: node._package_id = locked.package_id # FIXME: Ugly definition of private node.conanfile.settings.values = compatible_package.settings node.conanfile.options.values = compatible_package.options break else: raise ConanException("'%s' package-id '%s' doesn't match the locked one '%s'" % (repr(locked.ref), node.package_id, locked.package_id)) else: assert node.prev is None, "Non locked node shouldn't have PREV in evaluate_node" assert node.binary is None, "Node.binary should be None if not locked" pref = PackageReference(node.ref, node.package_id) self._process_node(node, pref, build_mode, update, remotes) if node.binary in (BINARY_MISSING, BINARY_INVALID): if node.conanfile.compatible_packages: compatible_build_mode = BuildMode(None, self._out) for compatible_package in node.conanfile.compatible_packages: package_id = compatible_package.package_id() if package_id == node.package_id: node.conanfile.output.info("Compatible package ID %s equal to the " "default package ID" % package_id) continue pref = PackageReference(node.ref, package_id) node.binary = None # Invalidate it # NO Build mode self._process_node(node, pref, compatible_build_mode, update, remotes) assert node.binary is not None if node.binary not in (BINARY_MISSING, ): node.conanfile.output.info("Main binary package '%s' missing. Using " "compatible package '%s'" % (node.package_id, package_id)) # Modifying package id under the hood, FIXME node._package_id = package_id # So they are available in package_info() method node.conanfile.settings.values = compatible_package.settings # TODO: Conan 2.0 clean this ugly node.conanfile.options._package_options.values = compatible_package.options._package_values break if node.binary == BINARY_MISSING and node.package_id == PACKAGE_ID_INVALID: node.binary = BINARY_INVALID if node.binary == BINARY_MISSING and build_mode.allowed(node.conanfile): node.binary = BINARY_BUILD if locked: # package_id was not locked, this means a base lockfile that is being completed locked.complete_base_node(node.package_id, node.prev)