def package_available(self, package_ref, package_folder, check_outdated): """ Returns True if there is a local or remote package available (and up to date if check_outdated). It wont download the package, just check its hash """ output = ScopedOutput(str(package_ref.conan), self._out) remote_info = None # No package in local cache if not os.path.exists(package_folder): try: remote_info = self.get_package_info(package_ref) except (NotFoundException, NoRemoteAvailable): # 404 or no remote return False # Maybe we have the package (locally or in remote) but it's outdated if check_outdated: if remote_info: package_hash = remote_info.recipe_hash else: package_hash = self._client_cache.read_package_recipe_hash(package_folder) local_recipe_hash = self._client_cache.load_manifest(package_ref.conan).summary_hash up_to_date = local_recipe_hash == package_hash if not up_to_date: output.info("Outdated package!") else: output.info("Package is up to date") return up_to_date return True
def _config_node(self, node, down_reqs, down_ref, down_options): """ update settings and option in the current ConanFile, computing actual requirement values, cause they can be overriden by downstream requires param settings: dict of settings values => {"os": "windows"} """ try: conanfile, conanref = node.conanfile, node.conan_ref # Avoid extra time manipulating the sys.path for python with get_env_context_manager(conanfile, without_python=True): if hasattr(conanfile, "config"): if not conanref: output = ScopedOutput(str("PROJECT"), self._output) output.warn("config() has been deprecated." " Use config_options and configure") with conanfile_exception_formatter(str(conanfile), "config"): conanfile.config() with conanfile_exception_formatter(str(conanfile), "config_options"): conanfile.config_options() conanfile.options.propagate_upstream(down_options, down_ref, conanref) if hasattr(conanfile, "config"): with conanfile_exception_formatter(str(conanfile), "config"): conanfile.config() with conanfile_exception_formatter(str(conanfile), "configure"): conanfile.configure() conanfile.settings.validate() # All has to be ok! conanfile.options.validate() # Update requirements (overwrites), computing new upstream if hasattr(conanfile, "requirements"): # If re-evaluating the recipe, in a diamond graph, with different options, # it could happen that one execution path of requirements() defines a package # and another one a different package raising Duplicate dependency error # Or the two consecutive calls, adding 2 different dependencies for the two paths # So it is necessary to save the "requires" state and restore it before a second # execution of requirements(). It is a shallow copy, if first iteration is # RequireResolve'd or overridden, the inner requirements are modified if not hasattr(conanfile, "_original_requires"): conanfile._original_requires = conanfile.requires.copy() else: conanfile.requires = conanfile._original_requires.copy() with conanfile_exception_formatter(str(conanfile), "requirements"): conanfile.requirements() new_options = conanfile.options.deps_package_values new_down_reqs = conanfile.requires.update(down_reqs, self._output, conanref, down_ref) except ConanExceptionInUserConanfileMethod: raise except ConanException as e: raise ConanException("%s: %s" % (conanref or "Conanfile", str(e))) except Exception as e: raise ConanException(e) return new_down_reqs, new_options
def get_package(self, package_ref, short_paths): """ obtain a package, either from disk or retrieve from remotes if necessary and not necessary to build """ output = ScopedOutput(str(package_ref.conan), self._out) package_folder = self._client_cache.package(package_ref, short_paths=short_paths) # Check current package status if os.path.exists(package_folder): if self._check_updates: read_manifest = self._client_cache.load_package_manifest(package_ref) try: # get_conan_digest can fail, not in server upstream_manifest = self.get_package_digest(package_ref) if upstream_manifest != read_manifest: if upstream_manifest.time > read_manifest.time: output.warn("Current package is older than remote upstream one") if self._update: output.warn("Removing it to retrieve or build an updated one") rmdir(package_folder) else: output.warn("Current package is newer than remote upstream one") except ConanException: pass installed = False local_package = os.path.exists(package_folder) if local_package: output.info('Already installed!') installed = True log_package_got_from_local_cache(package_ref) else: installed = self._retrieve_remote_package(package_ref, package_folder, output) self.handle_package_manifest(package_ref, installed) return installed
def build(self, conanfile_path, source_folder, build_folder, package_folder, install_folder, test=False, should_configure=True, should_build=True, should_install=True): """ Call to build() method saved on the conanfile.py param conanfile_path: path to a conanfile.py """ logger.debug("Building in %s" % build_folder) logger.debug("Conanfile in %s" % conanfile_path) try: # Append env_vars to execution environment and clear when block code ends output = ScopedOutput(("%s (test package)" % test) if test else "Project", self._user_io.out) conan_file = self._load_consumer_conanfile(conanfile_path, install_folder, output, deps_info_required=True) except NotFoundException: # TODO: Auto generate conanfile from requirements file raise ConanException("'%s' file is needed for build.\n" "Create a '%s' and move manually the " "requirements and generators from '%s' file" % (CONANFILE, CONANFILE, CONANFILE_TXT)) if test: try: conan_file.requires.add(test) except ConanException: pass conan_file.should_configure = should_configure conan_file.should_build = should_build conan_file.should_install = should_install try: mkdir(build_folder) os.chdir(build_folder) conan_file.build_folder = build_folder conan_file.source_folder = source_folder conan_file.package_folder = package_folder conan_file.install_folder = install_folder with get_env_context_manager(conan_file): output.highlight("Running build()") with conanfile_exception_formatter(str(conan_file), "build"): conan_file.build() if test: output.highlight("Running test()") with conanfile_exception_formatter(str(conan_file), "test"): conan_file.test() except ConanException: raise # Raise but not let to reach the Exception except (not print traceback) except Exception: import traceback trace = traceback.format_exc().split('\n') raise ConanException("Unable to build it successfully\n%s" % '\n'.join(trace[3:]))
def install(self, reference, current_path, remote=None, options=None, settings=None, build_mode=False, filename=None, update=False, check_updates=False, integrity=False, scopes=None, generators=None): """ Fetch and build all dependencies for the given reference @param reference: ConanFileReference or path to user space conanfile @param current_path: where the output files will be saved @param remote: install only from that remote @param options: list of tuples: [(optionname, optionvalue), (optionname, optionvalue)...] @param settings: list of tuples: [(settingname, settingvalue), (settingname, value)...] """ generators = generators or [] objects = self._get_graph(reference, current_path, remote, options, settings, filename, update, check_updates, integrity, scopes) (_, deps_graph, _, registry, conanfile, remote_proxy, loader) = objects Printer(self._user_io.out).print_graph(deps_graph, registry) # Warn if os doesn't match try: if detected_os() != loader._settings.os: message = '''You are building this package with settings.os='%s' on a '%s' system. If this is your intention, you can ignore this message. If not: - Check the passed settings (-s) - Check your global settings in ~/.conan/conan.conf - Remove conaninfo.txt to avoid bad cached settings ''' % (loader._settings.os, detected_os()) self._user_io.out.warn(message) except ConanException: # Setting os doesn't exist pass installer = ConanInstaller(self._paths, self._user_io, remote_proxy) installer.install(deps_graph, build_mode) scope_prefix = "PROJECT" if not isinstance(reference, ConanFileReference) else str(reference) output = ScopedOutput(scope_prefix, self._user_io.out) # Write generators tmp = list(conanfile.generators) # Add the command line specified generators tmp.extend(generators) conanfile.generators = tmp write_generators(conanfile, current_path, output) if not isinstance(reference, ConanFileReference): content = normalize(conanfile.info.dumps()) save(os.path.join(current_path, CONANINFO), content) output.info("Generated %s" % CONANINFO) local_installer = FileImporter(deps_graph, self._paths, current_path) conanfile.copy = local_installer conanfile.imports() copied_files = local_installer.execute() import_output = ScopedOutput("%s imports()" % output.scope, output) report_copied_files(copied_files, import_output)
def forced(self, reference, conanfile): if self.all: return True if conanfile.build_policy_always: out = ScopedOutput(str(reference), self._out) out.info("Building package from source as defined by build_policy='always'") return True ref = reference.name # Patterns to match, if package matches pattern, build is forced force_build = any([fnmatch.fnmatch(ref, pattern) for pattern in self.patterns]) return force_build
def _build_forced(self, conan_ref, build_mode, conan_file): if conan_file.build_policy_always: out = ScopedOutput(str(conan_ref), self._out) out.info("Building package from source as defined by build_policy='always'") return True if build_mode is False: # "never" option, default return False if build_mode is True: # Build missing (just if needed), not force return False # Patterns to match, if package matches pattern, build is forced force_build = any([fnmatch.fnmatch(str(conan_ref), pattern) for pattern in build_mode]) return force_build
def package(self, reference, package_id): # Package paths conan_file_path = self._client_cache.conanfile(reference) if not os.path.exists(conan_file_path): raise ConanException("Package recipe '%s' does not exist" % str(reference)) conanfile = load_conanfile_class(conan_file_path) if hasattr(conanfile, "build_id"): raise ConanException("package command does not support recipes with 'build_id'\n" "To repackage them use 'conan install'") if not package_id: packages = [PackageReference(reference, packid) for packid in self._client_cache.conan_builds(reference)] if not packages: raise NotFoundException("%s: Package recipe has not been built locally\n" "Please read the 'conan package' command help\n" "Use 'conan install' or 'conan test_package' to build and " "create binaries" % str(reference)) else: packages = [PackageReference(reference, package_id)] package_source_folder = self._client_cache.source(reference, conanfile.short_paths) for package_reference in packages: build_folder = self._client_cache.build(package_reference, short_paths=None) if not os.path.exists(build_folder): raise NotFoundException("%s: Package binary '%s' folder doesn't exist\n" "Please read the 'conan package' command help\n" "Use 'conan install' or 'conan test_package' to build and " "create binaries" % (str(reference), package_reference.package_id)) # The package already exist, we can use short_paths if they were defined package_folder = self._client_cache.package(package_reference, short_paths=None) # Will read current conaninfo with specified options and load conanfile with them output = ScopedOutput(str(reference), self._user_io.out) output.info("Re-packaging %s" % package_reference.package_id) conanfile = load_consumer_conanfile(conan_file_path, build_folder, self._client_cache.settings, self._runner, output, reference) rmdir(package_folder) if getattr(conanfile, 'no_copy_source', False): source_folder = package_source_folder else: source_folder = build_folder with environment_append(conanfile.env): packager.create_package(conanfile, source_folder, build_folder, package_folder, output)
def source(self, conanfile_path, source_folder, info_folder): """ :param conanfile_path: Absolute path to a conanfile :param source_folder: Absolute path where to put the files :param info_folder: Absolute path where to read the info files :param package_folder: Absolute path to the package_folder, only to have the var present :return: """ output = ScopedOutput("PROJECT", self._user_io.out) # only infos if exist conanfile = self._load_consumer_conanfile(conanfile_path, info_folder, output) conanfile_folder = os.path.dirname(conanfile_path) if conanfile_folder != source_folder: output.info("Executing exports to: %s" % source_folder) _execute_export(conanfile_path, conanfile, source_folder, source_folder, output) config_source_local(source_folder, conanfile, output)
def _build_node(self, conan_ref, conan_file, build_mode): # Compute conan_file package from local (already compiled) or from remote output = ScopedOutput(str(conan_ref), self._out) package_id = conan_file.info.package_id() package_reference = PackageReference(conan_ref, package_id) conan_ref = package_reference.conan package_folder = self._paths.package(package_reference) build_folder = self._paths.build(package_reference) src_folder = self._paths.source(conan_ref) export_folder = self._paths.export(conan_ref) # If already exists do not dirt the output, the common situation # is that package is already installed and OK. If don't, the proxy # will print some other message about it if not os.path.exists(package_folder): output.info("Installing package %s" % package_id) self._handle_system_requirements(conan_ref, package_reference, conan_file, output) force_build = self._force_build(conan_ref, build_mode) if self._remote_proxy.get_package(package_reference, force_build): return # Can we build? Only if we are forced or build_mode missing and package not exists build_allowed = force_build or build_mode is True if build_allowed: try: rmdir(build_folder) rmdir(package_folder) except Exception as e: raise ConanException("%s\n\nCouldn't remove folder, might be busy or open\n" "Close any app using it, and retry" % str(e)) if force_build: output.warn('Forced build from source') self._build_package(export_folder, src_folder, build_folder, package_folder, conan_file, output) # Creating ***info.txt files save(os.path.join(build_folder, CONANINFO), conan_file.info.dumps()) output.info("Generated %s" % CONANINFO) save(os.path.join(build_folder, BUILD_INFO), TXTGenerator(conan_file).content) output.info("Generated %s" % BUILD_INFO) os.chdir(build_folder) create_package(conan_file, build_folder, package_folder, output) else: self._raise_package_not_found_error(conan_ref, conan_file)
def retrieve_conanfile(self, conan_reference, consumer=False): """ returns the requested conanfile object, retrieving it from remotes if necessary. Can raise NotFoundException """ output = ScopedOutput(str(conan_reference), self._out) conanfile_path = self._paths.conanfile(conan_reference) if not self._paths.valid_conan_digest(conan_reference): conan_dir_path = self._paths.export(conan_reference) if path_exists(conan_dir_path, self._paths.store): # If not valid conanfile, ensure empty folder output.warn("Bad conanfile detected! Removing export directory... ") rmdir(conan_dir_path) output.info("Conanfile not found, retrieving from server") # If not in localhost, download it. Will raise if not found self._remote_manager.get_conanfile(conan_reference, self._remote) conanfile = self._loader.load_conan(conanfile_path, output, consumer) return conanfile
def _get_nodes(self, nodes_by_level, skip_nodes): """Compute a list of (conan_ref, package_id, conan_file, build_node) defining what to do with each node """ nodes_to_build = [] # Now build each level, starting from the most independent one package_references = set() for level in nodes_by_level: for node in level: if node in skip_nodes: continue conan_ref, conan_file = node.conan_ref, node.conanfile build_node = False logger.debug("Processing node %s", repr(conan_ref)) package_id = conan_file.info.package_id() package_reference = PackageReference(conan_ref, package_id) # Avoid processing twice the same package reference if package_reference not in package_references: package_references.add(package_reference) package_folder = self._client_cache.package(package_reference, short_paths=conan_file.short_paths) with self._client_cache.package_lock(package_reference): if is_dirty(package_folder): output = ScopedOutput(str(conan_ref), self._out) output.warn("Package is corrupted, removing folder: %s" % package_folder) rmdir(package_folder) check_outdated = self._build_mode.outdated if self._build_mode.forced(conan_file, conan_ref): build_node = True else: available = self._remote_proxy.package_available(package_reference, package_folder, check_outdated) build_node = not available nodes_to_build.append((node, package_id, build_node)) # A check to be sure that if introduced a pattern, something is going to be built if self._build_mode.patterns: to_build = [str(n[0].conan_ref.name) for n in nodes_to_build if n[2]] self._build_mode.check_matches(to_build) return nodes_to_build
def _get_package(self, conan_ref, conan_file): '''Get remote package. It won't check if it's outdated''' # Compute conan_file package from local (already compiled) or from remote output = ScopedOutput(str(conan_ref), self._out) package_id = conan_file.info.package_id() package_reference = PackageReference(conan_ref, package_id) conan_ref = package_reference.conan package_folder = self._client_cache.package(package_reference, conan_file.short_paths) # If already exists do not dirt the output, the common situation # is that package is already installed and OK. If don't, the proxy # will print some other message about it if not os.path.exists(package_folder): output.info("Installing package %s" % package_id) if self._remote_proxy.get_package(package_reference, short_paths=conan_file.short_paths): self._handle_system_requirements(conan_ref, package_reference, conan_file, output) return True self._raise_package_not_found_error(conan_ref, conan_file)
def download(self, reference, package_ids, remote=None): """ Download conanfile and specified packages to local repository @param reference: ConanFileReference @param package_ids: Package ids or empty for download all @param remote: install only from that remote """ assert(isinstance(reference, ConanFileReference)) remote_proxy = ConanProxy(self._client_cache, self._user_io, self._remote_manager, remote) package = remote_proxy.search(reference, None) if not package: # Search the reference first, and raise if it doesn't exist raise ConanException("'%s' not found in remote" % str(reference)) if package_ids: remote_proxy.download_packages(reference, package_ids) else: packages_props = remote_proxy.search_packages(reference, None) if not packages_props: output = ScopedOutput(str(reference), self._user_io.out) output.warn("No remote binary packages found in remote") else: remote_proxy.download_packages(reference, list(packages_props.keys()))
def _compute_private_nodes(self, deps_graph, build_mode): """ computes a list of nodes that are not required to be built, as they are private requirements of already available shared libraries as binaries """ private_closure = deps_graph.private_nodes() skippable_nodes = [] for private_node, private_requirers in private_closure: for private_requirer in private_requirers: conan_ref, conan_file = private_requirer if conan_ref is None: continue package_id = conan_file.info.package_id() package_reference = PackageReference(conan_ref, package_id) package_folder = self._paths.package(package_reference) if not path_exists(package_folder, self._paths.store): if not self._force_build(conan_ref, build_mode): # Not download package output = ScopedOutput(str(conan_ref), self._out) output.info("Package not installed") if not self._retrieve_remote_package(package_reference, output): break else: skippable_nodes.append(private_node) return skippable_nodes
def download(self, reference, package_ids, remote_name, recipe): """ Download conanfile and specified packages to local repository @param reference: ConanFileReference @param package_ids: Package ids or empty for download all @param remote: install only from that remote @param only_recipe: download only the recipe """ assert(isinstance(reference, ConanFileReference)) remote_proxy = self.get_proxy(remote_name=remote_name) remote, _ = remote_proxy._get_remote() package = self._remote_manager.search_recipes(remote, reference, None) if not package: # Search the reference first, and raise if it doesn't exist raise ConanException("'%s' not found in remote" % str(reference)) # First of all download package recipe remote_proxy.get_recipe(reference, check_updates=True, update=True) if recipe: return # Download the sources too, don't be lazy conan_file_path = self._client_cache.conanfile(reference) conanfile = load_conanfile_class(conan_file_path) complete_recipe_sources(self._remote_manager, self._client_cache, self._registry, conanfile, reference) if package_ids: remote_proxy.download_packages(reference, package_ids) else: self._user_io.out.info("Getting the complete package list " "from '%s'..." % str(reference)) packages_props = self._remote_manager.search_packages(remote, reference, None) if not packages_props: output = ScopedOutput(str(reference), self._user_io.out) output.warn("No remote binary packages found in remote") else: remote_proxy.download_packages(reference, list(packages_props.keys()))
def package(self, reference, package_id): assert(isinstance(reference, ConanFileReference)) # Package paths conan_file_path = self._client_cache.conanfile(reference) if not os.path.exists(conan_file_path): raise ConanException("Package recipe '%s' does not exist" % str(reference)) if not package_id: packages = [PackageReference(reference, packid) for packid in self._client_cache.conan_builds(reference)] if not packages: raise NotFoundException("%s: Package recipe has not been built locally\n" "Please read the 'conan package' command help\n" "Use 'conan install' or 'conan test_package' to build and " "create binaries" % str(reference)) else: packages = [PackageReference(reference, package_id)] for package_reference in packages: build_folder = self._client_cache.build(package_reference, short_paths=None) if not build_exists(build_folder): raise NotFoundException("%s: Package binary '%s' folder doesn't exist\n" "Please read the 'conan package' command help\n" "Use 'conan install' or 'conan test_package' to build and " "create binaries" % (str(reference), package_reference.package_id)) # The package already exist, we can use short_paths if they were defined package_folder = self._client_cache.package(package_reference, short_paths=None) # Will read current conaninfo with specified options and load conanfile with them output = ScopedOutput(str(reference), self._user_io.out) output.info("Re-packaging %s" % package_reference.package_id) loader = self._loader(build_folder) conanfile = loader.load_conan(conan_file_path, self._user_io.out) rmdir(package_folder) packager.create_package(conanfile, build_folder, package_folder, output)
def get_recipe(self, conan_reference): output = ScopedOutput(str(conan_reference), self._out) def _refresh(): export_path = self._client_cache.export(conan_reference) rmdir(export_path) # It might need to remove shortpath rm_conandir(self._client_cache.source(conan_reference)) current_remote, _ = self._get_remote(conan_reference) output.info("Retrieving from remote '%s'..." % current_remote.name) self._remote_manager.get_recipe(conan_reference, export_path, current_remote) if self._update: output.info("Updated!") else: output.info("Installed!") # check if it is in disk conanfile_path = self._client_cache.conanfile(conan_reference) if os.path.exists(conanfile_path): log_recipe_got_from_local_cache(conan_reference) if self._check_updates: ret = self.update_available(conan_reference) if ret != 0: # Found and not equal remote, ref_remote = self._get_remote(conan_reference) if ret == 1: if not self._update: if remote != ref_remote: # Forced new remote output.warn("There is a new conanfile in '%s' remote. " "Execute 'install -u -r %s' to update it." % (remote.name, remote.name)) else: output.warn("There is a new conanfile in '%s' remote. " "Execute 'install -u' to update it." % remote.name) output.warn("Refused to install!") else: if remote != ref_remote: # Delete packages, could be non coherent with new remote DiskRemover(self._client_cache).remove_packages(conan_reference) _refresh() elif ret == -1: if not self._update: output.info("Current conanfile is newer " "than %s's one" % remote.name) else: output.error("Current conanfile is newer than %s's one. " "Run 'conan remove %s' and run install again " "to replace it." % (remote.name, conan_reference)) else: self._retrieve_recipe(conan_reference, output) if self._manifest_manager: # Just make sure that the recipe sources are there to check self.get_recipe_sources(conan_reference) remote = self._registry.get_ref(conan_reference) self._manifest_manager.check_recipe(conan_reference, remote) return conanfile_path
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 _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) logger.debug("GRAPH: new_node: %s" % str(new_ref)) 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
class ConanFile(object): """ The base class for all package recipes """ name = None version = None # Any str, can be "1.1" or whatever url = None # The URL where this File is located, as github, to collaborate in package # The license of the PACKAGE, just a shortcut, does not replace or # change the actual license of the source code license = None author = None # Main maintainer/responsible for the package, any format description = None topics = None homepage = None build_policy = None short_paths = False apply_env = True # Apply environment variables from requires deps_env_info and profiles exports = None exports_sources = None generators = ["txt"] revision_mode = "hash" # Vars to control the build steps (build(), package()) should_configure = True should_build = True should_install = True should_test = True in_local_cache = True develop = False # Defaulting the reference fields default_channel = None default_user = None # Settings and Options settings = None options = None default_options = None def __init__(self, output, runner, display_name="", user=None, channel=None): # an output stream (writeln, info, warn error) self.output = ScopedOutput(display_name, output) self.display_name = display_name # something that can run commands, as os.sytem self._conan_runner = runner self._conan_user = user self._conan_channel = channel def initialize(self, settings, env): if isinstance(self.generators, str): self.generators = [self.generators] # User defined options self.options = create_options(self) self.requires = create_requirements(self) self.settings = create_settings(self, settings) try: if self.settings.os_build and self.settings.os: self.output.writeln("*" * 60, front=Color.BRIGHT_RED) self.output.writeln( " This package defines both 'os' and 'os_build' ", front=Color.BRIGHT_RED) self.output.writeln( " Please use 'os' for libraries and 'os_build'", front=Color.BRIGHT_RED) self.output.writeln( " only for build-requires used for cross-building", front=Color.BRIGHT_RED) self.output.writeln("*" * 60, front=Color.BRIGHT_RED) except ConanException: pass if 'cppstd' in self.settings.fields: self.output.warn( "Setting 'cppstd' is deprecated in favor of 'compiler.cppstd'," " please update your recipe.") # needed variables to pack the project self.cpp_info = None # Will be initialized at processing time self.deps_cpp_info = DepsCppInfo() # environment variables declared in the package_info self.env_info = None # Will be initialized at processing time self.deps_env_info = DepsEnvInfo() # user declared variables self.user_info = None # Keys are the package names, and the values a dict with the vars self.deps_user_info = DepsUserInfo() # user specified env variables self._conan_env_values = env.copy() # user specified -e @property def env(self): """Apply the self.deps_env_info into a copy of self._conan_env_values (will prioritize the self._conan_env_values, user specified from profiles or -e first, then inherited)""" # Cannot be lazy cached, because it's called in configure node, and we still don't have # the deps_env_info objects available tmp_env_values = self._conan_env_values.copy() tmp_env_values.update(self.deps_env_info) ret, multiple = tmp_env_values.env_dicts(self.name) ret.update(multiple) return ret @property def channel(self): if not self._conan_channel: self._conan_channel = os.getenv( "CONAN_CHANNEL") or self.default_channel if not self._conan_channel: raise ConanException( "CONAN_CHANNEL environment variable not defined, " "but self.channel is used in conanfile") return self._conan_channel @property def user(self): if not self._conan_user: self._conan_user = os.getenv("CONAN_USERNAME") or self.default_user if not self._conan_user: raise ConanException( "CONAN_USERNAME environment variable not defined, " "but self.user is used in conanfile") return self._conan_user def collect_libs(self, folder=None): self.output.warn("'self.collect_libs' is deprecated, " "use 'tools.collect_libs(self)' instead") return tools.collect_libs(self, folder=folder) @property def build_policy_missing(self): return self.build_policy == "missing" @property def build_policy_always(self): return self.build_policy == "always" def source(self): pass def system_requirements(self): """ this method can be overwritten to implement logic for system package managers, as apt-get You can define self.global_system_requirements = True, if you want the installation to be for all packages (not depending on settings/options/requirements) """ def config_options(self): """ modify options, probably conditioned to some settings. This call is executed before config_settings. E.g. if self.settings.os == "Windows": del self.options.shared # shared/static not supported in win """ def configure(self): """ modify settings, probably conditioned to some options. This call is executed after config_options. E.g. if self.options.header_only: self.settings.clear() This is also the place for conditional requirements """ def build(self): """ build your project calling the desired build tools as done in the command line. E.g. self.run("cmake --build .") Or use the provided build helpers. E.g. cmake.build() """ self.output.warn("This conanfile has no build step") def package(self): """ package the needed files from source and build folders. E.g. self.copy("*.h", src="src/includes", dst="includes") """ self.output.warn("This conanfile has no package step") def package_info(self): """ define cpp_build_info, flags, etc """ def run(self, command, output=True, cwd=None, win_bash=False, subsystem=None, msys_mingw=True, ignore_errors=False, run_environment=False, with_login=True): def _run(): if not win_bash: return self._conan_runner(command, output, os.path.abspath(RUN_LOG_NAME), cwd) # FIXME: run in windows bash is not using output return tools.run_in_windows_bash(self, bashcmd=command, cwd=cwd, subsystem=subsystem, msys_mingw=msys_mingw, with_login=with_login) if run_environment: with tools.run_environment(self): if OSInfo().is_macos: command = 'DYLD_LIBRARY_PATH="%s" %s' % (os.environ.get( 'DYLD_LIBRARY_PATH', ''), command) retcode = _run() else: retcode = _run() if not ignore_errors and retcode != 0: raise ConanException("Error %d while executing %s" % (retcode, command)) return retcode def package_id(self): """ modify the binary info, typically to narrow values e.g.: self.info.settings.compiler = "Any" => All compilers will generate same ID """ def test(self): """ test the generated executable. E.g. self.run("./example") """ raise ConanException( "You need to create a method 'test' in your test/conanfile.py") def __repr__(self): return self.display_name
def _build_node(self, conan_ref, conan_file, build_mode): # Compute conan_file package from local (already compiled) or from remote output = ScopedOutput(str(conan_ref), self._out) package_id = conan_file.info.package_id() package_reference = PackageReference(conan_ref, package_id) conan_ref = package_reference.conan package_folder = self._paths.package(package_reference) build_folder = self._paths.build(package_reference, conan_file.short_paths) src_folder = self._paths.source(conan_ref, conan_file.short_paths) export_folder = self._paths.export(conan_ref) # If already exists do not dirt the output, the common situation # is that package is already installed and OK. If don't, the proxy # will print some other message about it if not os.path.exists(package_folder): output.info("Installing package %s" % package_id) self._handle_system_requirements(conan_ref, package_reference, conan_file, output) force_build = self._build_forced(conan_ref, build_mode, conan_file) if self._remote_proxy.get_package(package_reference, force_build): return # we need and can build? Only if we are forced or build_mode missing and package not exists build = force_build or build_mode is True or conan_file.build_policy_missing if build: if not force_build and not build_mode: output.info( "Building package from source as defined by build_policy='missing'" ) try: rmdir(build_folder, conan_file.short_paths) rmdir(package_folder) except Exception as e: raise ConanException( "%s\n\nCouldn't remove folder, might be busy or open\n" "Close any app using it, and retry" % str(e)) if force_build: output.warn('Forced build from source') self._build_package(export_folder, src_folder, build_folder, package_folder, conan_file, output) # Creating ***info.txt files save(os.path.join(build_folder, CONANINFO), conan_file.info.dumps()) output.info("Generated %s" % CONANINFO) save(os.path.join(build_folder, BUILD_INFO), TXTGenerator(conan_file).content) output.info("Generated %s" % BUILD_INFO) os.chdir(build_folder) create_package(conan_file, build_folder, package_folder, output) else: self._raise_package_not_found_error(conan_ref, conan_file)
def install(self, reference, current_path, profile, remote=None, build_modes=None, filename=None, update=False, manifest_folder=None, manifest_verify=False, manifest_interactive=False, generators=None, no_imports=False, inject_require=None): """ Fetch and build all dependencies for the given reference @param reference: ConanFileReference or path to user space conanfile @param current_path: 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 readed values @param build_modes: List of build_modes specified @param filename: Optional filename of the conanfile @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 """ generators = generators or [] 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 = ConanProxy(self._client_cache, self._user_io, self._remote_manager, remote, update=update, check_updates=False, manifest_manager=manifest_manager) loader = self.get_loader(profile) conanfile = self._get_conanfile_object(loader, reference, filename, current_path) if inject_require: self._inject_require(conanfile, inject_require) graph_builder = self._get_graph_builder(loader, update, remote_proxy) deps_graph = graph_builder.load(conanfile) # This line is so the conaninfo stores the correct complete info conanfile.info.scope = profile.scopes registry = RemoteRegistry(self._client_cache.registry, self._user_io.out) if inject_require: output = ScopedOutput("%s test package" % str(inject_require), self._user_io.out) output.info("Installing dependencies") else: if not isinstance(reference, ConanFileReference): output = ScopedOutput("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, registry) try: if loader._settings.os and detected_os() != loader._settings.os: message = "Cross-platform from '%s' to '%s'" % ( detected_os(), loader._settings.os) 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, registry, output, profile.build_requires) installer = ConanInstaller(self._client_cache, output, remote_proxy, build_mode, build_requires) # Apply build_requires to consumer conanfile if not isinstance(reference, ConanFileReference): build_requires.install("", conanfile, installer) installer.install(deps_graph, current_path) build_mode.report_matches() # Write generators 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, current_path, output) if not isinstance(reference, ConanFileReference): content = normalize(conanfile.info.dumps()) save(os.path.join(current_path, CONANINFO), content) output.info("Generated %s" % CONANINFO) if not no_imports: run_imports(conanfile, current_path, output) call_system_requirements(conanfile, output) if manifest_manager: manifest_manager.print_log()
def install(self, reference, current_path, profile, remote=None, build_mode=None, filename=None, update=False, check_updates=False, manifest_folder=None, manifest_verify=False, manifest_interactive=False, generators=None, no_imports=False): """ Fetch and build all dependencies for the given reference @param reference: ConanFileReference or path to user space conanfile @param current_path: where the output files will be saved @param remote: install only from that remote @param options: list of tuples: [(optionname, optionvalue), (optionname, optionvalue)...] @param settings: list of tuples: [(settingname, settingvalue), (settingname, value)...] @param package_settings: dict name=> settings: {"zlib": [(settingname, settingvalue), ...]} @param profile: name of the profile to use @param env: list of tuples for environment vars: [(var, value), (var2, value2)...] @param package_env: package dict of list of tuples: {"package_name": [(var, value), (var2, value2)...]} """ generators = generators or [] if manifest_folder: manifest_manager = ManifestManager( manifest_folder, user_io=self._user_io, client_cache=self._client_cache, verify=manifest_verify, interactive=manifest_interactive) else: manifest_manager = None objects = self._get_graph(reference, current_path, profile, remote, filename, update, check_updates, manifest_manager) (_, deps_graph, _, registry, conanfile, remote_proxy, loader) = objects Printer(self._user_io.out).print_graph(deps_graph, registry) try: if detected_os() != loader._settings.os: message = "Cross-platform from '%s' to '%s'" % ( detected_os(), loader._settings.os) self._user_io.out.writeln(message, Color.BRIGHT_MAGENTA) except ConanException: # Setting os doesn't exist pass installer = ConanInstaller(self._client_cache, self._user_io, remote_proxy) installer.install(deps_graph, build_mode) prefix = "PROJECT" if not isinstance( reference, ConanFileReference) else str(reference) output = ScopedOutput(prefix, self._user_io.out) # Write generators tmp = list( conanfile.generators) # Add the command line specified generators tmp.extend(generators) conanfile.generators = tmp write_generators(conanfile, current_path, output) if not isinstance(reference, ConanFileReference): content = normalize(conanfile.info.dumps()) save(os.path.join(current_path, CONANINFO), content) output.info("Generated %s" % CONANINFO) if not no_imports: run_imports(conanfile, current_path, output) installer.call_system_requirements(conanfile, output) if manifest_manager: manifest_manager.print_log()
def create_package(conanfile, package_id, source_folder, build_folder, package_folder, install_folder, hook_manager, conanfile_path, ref, local=False, copy_info=False): """ copies built artifacts, libs, headers, data, etc. from build_folder to package folder """ mkdir(package_folder) output = conanfile.output # Make the copy of all the patterns output.info("Generating the package") output.info("Package folder %s" % package_folder) try: conanfile.package_folder = package_folder conanfile.source_folder = source_folder conanfile.install_folder = install_folder conanfile.build_folder = build_folder hook_manager.execute("pre_package", conanfile=conanfile, conanfile_path=conanfile_path, reference=ref, package_id=package_id) package_output = ScopedOutput("%s package()" % output.scope, output) output.highlight("Calling package()") folders = [source_folder, build_folder ] if source_folder != build_folder else [build_folder] conanfile.copy = FileCopier(folders, package_folder) with conanfile_exception_formatter(str(conanfile), "package"): with chdir(build_folder): conanfile.package() except Exception as e: if not local: os.chdir(build_folder) try: rmdir(package_folder) except Exception as e_rm: output.error("Unable to remove package folder %s\n%s" % (package_folder, str(e_rm))) output.warn("**** Please delete it manually ****") if isinstance(e, ConanExceptionInUserConanfileMethod): raise raise ConanException(e) hook_manager.execute("post_package", conanfile=conanfile, conanfile_path=conanfile_path, reference=ref, package_id=package_id) manifest = _create_aux_files(install_folder, package_folder, conanfile, copy_info) _report_files_from_manifest(package_output, manifest) package_id = package_id or os.path.basename(package_folder) output.success("Package '%s' created" % package_id) prev = manifest.summary_hash output.info("Created package revision %s" % prev) return prev
def _build_package(self, export_folder, src_folder, build_folder, package_folder, conan_file, output): """ builds the package, creating the corresponding build folder if necessary and copying there the contents from the src folder. The code is duplicated in every build, as some configure processes actually change the source code """ output.info('Building your package in %s' % build_folder) if not build_exists(build_folder): config_source(export_folder, src_folder, conan_file, output) output.info('Copying sources to build folder') def check_max_path_len(src, files): if platform.system() != "Windows": return [] filtered_files = [] for the_file in files: source_path = os.path.join(src, the_file) # Without storage path, just relative rel_path = os.path.relpath(source_path, src_folder) dest_path = os.path.normpath( os.path.join(build_folder, rel_path)) # it is NOT that "/" is counted as "\\" so it counts double # seems a bug in python, overflows paths near the limit of 260, if len(dest_path) >= 249: filtered_files.append(the_file) output.warn("Filename too long, file excluded: %s" % dest_path) return filtered_files shutil.copytree(src_folder, build_folder, symlinks=True, ignore=check_max_path_len) os.chdir(build_folder) conan_file._conanfile_directory = build_folder # Read generators from conanfile and generate the needed files write_generators(conan_file, build_folder, output) # Build step might need DLLs, binaries as protoc to generate source files # So execute imports() before build, storing the list of copied_files from conans.client.importer import FileImporter local_installer = FileImporter(self._deps_graph, self._paths, build_folder) conan_file.copy = local_installer conan_file.imports() copied_files = local_installer.execute() import_output = ScopedOutput("%s imports()" % output.scope, output) report_copied_files(copied_files, import_output) try: # This is necessary because it is different for user projects # than for packages conan_file._conanfile_directory = build_folder conan_file.build() self._out.writeln("") output.success("Package '%s' built" % conan_file.info.package_id()) output.info("Build folder %s" % build_folder) except Exception as e: os.chdir(src_folder) self._out.writeln("") output.error("Package '%s' build failed" % conan_file.info.package_id()) output.warn("Build folder %s" % build_folder) raise ConanException("%s: %s" % (conan_file.name, str(e))) finally: conan_file._conanfile_directory = export_folder # Now remove all files that were imported with imports() for f in copied_files: try: if (f.startswith(build_folder)): os.remove(f) except Exception: self._out.warn( "Unable to remove imported file from build: %s" % f)
def _get_recipe(self, layout, ref, check_updates, update, remotes, recorder): output = ScopedOutput(str(ref), self._out) # check if it is in disk conanfile_path = layout.conanfile() # NOT in disk, must be retrieved from remotes if not os.path.exists(conanfile_path): remote, new_ref = self._download_recipe(layout, ref, output, remotes, remotes.selected, recorder) status = RECIPE_DOWNLOADED return conanfile_path, status, remote, new_ref metadata = layout.load_metadata() cur_revision = metadata.recipe.revision cur_remote = metadata.recipe.remote cur_remote = remotes[cur_remote] if cur_remote else None selected_remote = remotes.selected or cur_remote check_updates = check_updates or update requested_different_revision = ( ref.revision is not None) and cur_revision != ref.revision if requested_different_revision: if check_updates or self._cache.new_config[ "core:allow_explicit_revision_update"]: remote, new_ref = self._download_recipe( layout, ref, output, remotes, selected_remote, recorder) status = RECIPE_DOWNLOADED return conanfile_path, status, remote, new_ref else: raise NotFoundException( "The '%s' revision recipe in the local cache doesn't " "match the requested '%s'." " Use '--update' to check in the remote." % (cur_revision, repr(ref))) if not check_updates: status = RECIPE_INCACHE ref = ref.copy_with_rev(cur_revision) return conanfile_path, status, cur_remote, ref # Checking updates in the server if not selected_remote: status = RECIPE_NO_REMOTE ref = ref.copy_with_rev(cur_revision) return conanfile_path, status, None, ref try: # get_recipe_manifest can fail, not in server upstream_manifest, ref = self._remote_manager.get_recipe_manifest( ref, selected_remote) except NotFoundException: status = RECIPE_NOT_IN_REMOTE ref = ref.copy_with_rev(cur_revision) return conanfile_path, status, selected_remote, ref read_manifest = layout.recipe_manifest() if upstream_manifest != read_manifest: if upstream_manifest.time > read_manifest.time: if update: DiskRemover().remove_recipe(layout, output=output) output.info("Retrieving from remote '%s'..." % selected_remote.name) self._download_recipe(layout, ref, output, remotes, selected_remote, recorder) status = RECIPE_UPDATED return conanfile_path, status, selected_remote, ref else: status = RECIPE_UPDATEABLE else: status = RECIPE_NEWER else: status = RECIPE_INCACHE ref = ref.copy_with_rev(cur_revision) return conanfile_path, status, selected_remote, ref
def install(self, reference, current_path, remote=None, options=None, settings=None, build_mode=False, filename=None, update=False, check_updates=False, manifest_folder=None, manifest_verify=False, manifest_interactive=False, scopes=None, generators=None, profile_name=None, package_settings=None, env=None, package_env=None, no_imports=False): """ Fetch and build all dependencies for the given reference @param reference: ConanFileReference or path to user space conanfile @param current_path: where the output files will be saved @param remote: install only from that remote @param options: list of tuples: [(optionname, optionvalue), (optionname, optionvalue)...] @param settings: list of tuples: [(settingname, settingvalue), (settingname, value)...] @param package_settings: dict name=> settings: {"zlib": [(settingname, settingvalue), ...]} @param profile: name of the profile to use @param env: list of tuples for environment vars: [(var, value), (var2, value2)...] @param package_env: package dict of list of tuples: {"package_name": [(var, value), (var2, value2)...]} """ generators = generators or [] if manifest_folder: manifest_manager = ManifestManager(manifest_folder, user_io=self._user_io, client_cache=self._client_cache, verify=manifest_verify, interactive=manifest_interactive) else: manifest_manager = None profile = self.read_profile(profile_name, current_path) # Mix Settings, Env vars and scopes between profile and command line if profile: profile.update_settings(settings) profile.update_package_settings(package_settings) settings = profile.settings package_settings = profile.package_settings profile.update_env(env) profile.update_packages_env(package_env) env = profile.env package_env = profile.package_env profile.update_scopes(scopes) scopes = profile.scopes objects = self._get_graph(reference, current_path, remote, options, settings, filename, update, check_updates, manifest_manager, scopes, package_settings, env, package_env) (_, deps_graph, _, registry, conanfile, remote_proxy, loader) = objects Printer(self._user_io.out).print_graph(deps_graph, registry) # Warn if os doesn't match try: if detected_os() != loader._settings.os: message = '''You are building this package with settings.os='%s' on a '%s' system. If this is your intention, you can ignore this message. If not: - Check the passed settings (-s) - Check your global settings in ~/.conan/conan.conf - Remove conaninfo.txt to avoid bad cached settings ''' % (loader._settings.os, detected_os()) self._user_io.out.warn(message) except ConanException: # Setting os doesn't exist pass installer = ConanInstaller(self._client_cache, self._user_io, remote_proxy) installer.install(deps_graph, build_mode) prefix = "PROJECT" if not isinstance(reference, ConanFileReference) else str(reference) output = ScopedOutput(prefix, self._user_io.out) # Write generators tmp = list(conanfile.generators) # Add the command line specified generators tmp.extend(generators) conanfile.generators = tmp write_generators(conanfile, current_path, output) if not isinstance(reference, ConanFileReference): content = normalize(conanfile.info.dumps()) save(os.path.join(current_path, CONANINFO), content) output.info("Generated %s" % CONANINFO) if not no_imports: run_imports(conanfile, current_path, output) if manifest_manager: manifest_manager.print_log()
def create(self, conanfile_path, name=None, version=None, user=None, channel=None, profile_name=None, settings=None, options=None, env=None, test_folder=None, not_export=False, build_modes=None, keep_source=False, keep_build=False, verify=None, manifests=None, manifests_interactive=None, remote=None, update=False, cwd=None, test_build_folder=None): """ API method to create a conan package :param test_folder: default None - looks for default 'test' or 'test_package' folder), string - test_folder path False - disabling tests """ settings = settings or [] options = options or [] env = env or [] try: cwd = cwd or os.getcwd() recorder = ActionRecorder() conanfile_path = _get_conanfile_path(conanfile_path, cwd, py=True) if not name or not version: conanfile = load_conanfile_class(conanfile_path) name, version = conanfile.name, conanfile.version if not name or not version: raise ConanException("conanfile.py doesn't declare package name or version") reference = ConanFileReference(name, version, user, channel) scoped_output = ScopedOutput(str(reference), self._user_io.out) # Make sure keep_source is set for keep_build if keep_build: keep_source = True # Forcing an export! if not not_export: scoped_output.highlight("Exporting package recipe") cmd_export(conanfile_path, name, version, user, channel, keep_source, self._user_io.out, self._client_cache) if build_modes is None: # Not specified, force build the tested library build_modes = [name] manifests = _parse_manifests_arguments(verify, manifests, manifests_interactive, cwd) manifest_folder, manifest_interactive, manifest_verify = manifests profile = profile_from_args(profile_name, settings, options, env, cwd, self._client_cache) manager = self._init_manager(recorder) recorder.add_recipe_being_developed(reference) create(reference, manager, self._user_io, profile, remote, update, build_modes, manifest_folder, manifest_verify, manifest_interactive, keep_build, test_build_folder, test_folder, conanfile_path) return recorder.get_info() except ConanException as exc: recorder.error = True exc.info = recorder.get_info() raise
def install(self, reference, current_path, remote=None, options=None, settings=None, build_mode=False, info=None, filename=None): """ Fetch and build all dependencies for the given reference @param reference: ConanFileReference or path to user space conanfile @param current_path: where the output files will be saved @param remote: install only from that remote @param options: written in JSON, e.g. {"compiler": "Visual Studio 12", ...} """ reference_given = True if not isinstance(reference, ConanFileReference): conanfile_path = reference reference_given = False reference = None loader = self._loader(current_path, settings, options) installer = ConanInstaller(self._paths, self._user_io, loader, self.remote_manager, remote) if reference_given: project_reference = None conanfile = installer.retrieve_conanfile(reference, consumer=True) else: project_reference = "PROJECT" output = ScopedOutput(project_reference, self._user_io.out) try: if filename and filename.endswith(".txt"): raise NotFoundException() conan_file_path = os.path.join(conanfile_path, filename or CONANFILE) conanfile = loader.load_conan(conan_file_path, output, consumer=True) is_txt = False if conanfile.name is not None and conanfile.version is not None: project_reference = "%s/%s@" % (conanfile.name, conanfile.version) # Calculate a placeholder conan file reference for the project current_user = self._localdb.get_username() if current_user: project_reference += "%s/" % current_user project_reference += "PROJECT" except NotFoundException: # Load requirements.txt conan_path = os.path.join(conanfile_path, filename or CONANFILE_TXT) conanfile = loader.load_conan_txt(conan_path, output) is_txt = True # build deps graph and install it builder = DepsBuilder(installer, self._user_io.out) deps_graph = builder.load(reference, conanfile) if info: Printer(self._user_io.out).print_info(deps_graph, project_reference, info) return Printer(self._user_io.out).print_graph(deps_graph) installer.install(deps_graph, build_mode) if not reference_given: if is_txt: conanfile.info.settings = loader._settings.values # Just in case the current package is header only, we still store the full settings # for reference and compiler checks conanfile.info.full_settings = loader._settings.values content = normalize(conanfile.info.dumps()) save(os.path.join(current_path, CONANINFO), content) self._user_io.out.writeln("") output.info("Generated %s" % CONANINFO) write_generators(conanfile, current_path, output) local_installer = FileImporter(deps_graph, self._paths, current_path) conanfile.copy = local_installer conanfile.imports() local_installer.execute()
def _build(self, nodes_by_level, skip_private_nodes, deps_graph, profile_build_requires): """ The build assumes an input of conans ordered by degree, first level should be independent from each other, the next-second level should have dependencies only to first level conans. param nodes_by_level: list of lists [[nodeA, nodeB], [nodeC], [nodeD, ...], ...] build_mode => ["*"] if user wrote "--build" => ["hello*", "bye*"] if user wrote "--build hello --build bye" => False if user wrote "never" => True if user wrote "missing" => "outdated" if user wrote "--build outdated" """ inverse = deps_graph.inverse_levels() flat = [] for level in inverse: level = sorted(level, key=lambda x: x.conan_ref) flat.extend(n for n in level if n not in skip_private_nodes) # Get the nodes in order and if we have to build them nodes_to_process = self._get_nodes(nodes_by_level, skip_private_nodes) for conan_ref, package_id, conan_file, build_needed in nodes_to_process: output = ScopedOutput(str(conan_ref), self._out) if build_needed and (conan_ref, package_id) not in self._built_packages: package_ref = PackageReference(conan_ref, package_id) build_allowed = self._build_mode.allowed(conan_file, conan_ref) if not build_allowed: _raise_package_not_found_error(conan_file, conan_ref, output) if conan_file.build_policy_missing: output.info( "Building package from source as defined by build_policy='missing'" ) elif self._build_mode.forced(conan_file, conan_ref): output.warn('Forced build from source') self._build_requires.install(conan_ref, conan_file, self, profile_build_requires) t1 = time.time() # Assign to node the propagated info self._propagate_info(conan_file, conan_ref, flat, deps_graph) builder = _ConanPackageBuilder(conan_file, package_ref, self._client_cache, output) with self._client_cache.conanfile_write_lock(conan_ref): self._remote_proxy.get_recipe_sources( conan_ref, conan_file.short_paths) builder.prepare_build() with self._client_cache.conanfile_read_lock(conan_ref): with self._client_cache.package_lock( builder.build_reference): builder.build() builder.package() self._remote_proxy.handle_package_manifest( package_ref, installed=True) package_folder = self._client_cache.package( package_ref, conan_file.short_paths) # Call the info method call_package_info(conan_file, package_folder) # Log build self._log_built_package(conan_file, package_ref, time.time() - t1) self._built_packages.add((conan_ref, package_id)) else: # Get the package, we have a not outdated remote package package_ref = None if conan_ref: package_ref = PackageReference(conan_ref, package_id) with self._client_cache.package_lock(package_ref): self._get_remote_package(conan_file, package_ref, output) # Assign to the node the propagated info # (conan_ref could be None if user project, but of course assign the info self._propagate_info(conan_file, conan_ref, flat, deps_graph) if package_ref: # Call the info method package_folder = self._client_cache.package( package_ref, conan_file.short_paths) call_package_info(conan_file, package_folder)
def _build(self, nodes_by_level, skip_private_nodes, build_mode): """ The build assumes an input of conans ordered by degree, first level should be independent from each other, the next-second level should have dependencies only to first level conans. param nodes_by_level: list of lists [[nodeA, nodeB], [nodeC], [nodeD, ...], ...] build_mode => ["*"] if user wrote "--build" => ["hello*", "bye*"] if user wrote "--build hello --build bye" => False if user wrote "never" => True if user wrote "missing" => "outdated" if user wrote "--build outdated" """ inverse = self._deps_graph.inverse_levels() flat = [] for level in inverse: level = sorted(level, key=lambda x: x.conan_ref) flat.extend(level) # Get the nodes in order and if we have to build them nodes_to_process = self._get_nodes(nodes_by_level, skip_private_nodes, build_mode) for conan_ref, package_id, conan_file, build_needed in nodes_to_process: if build_needed: build_allowed = build_mode.allowed(conan_ref, conan_file) if not build_allowed: self._raise_package_not_found_error(conan_ref, conan_file) output = ScopedOutput(str(conan_ref), self._out) package_ref = PackageReference(conan_ref, package_id) package_folder = self._client_cache.package( package_ref, conan_file.short_paths) if conan_file.build_policy_missing: output.info( "Building package from source as defined by build_policy='missing'" ) elif build_mode.forced(conan_ref, conan_file): output.warn('Forced build from source') self._build_requires.install(conan_ref, conan_file) t1 = time.time() # Assign to node the propagated info self._propagate_info(conan_ref, conan_file, flat) self._remote_proxy.get_recipe_sources(conan_ref) # Call the conanfile's build method build_folder = self._build_conanfile(conan_ref, conan_file, package_ref, package_folder, output) # Call the conanfile's package method self._package_conanfile(conan_ref, conan_file, package_ref, build_folder, package_folder, output) # Call the info method self._package_info_conanfile(conan_ref, conan_file) duration = time.time() - t1 log_file = os.path.join(build_folder, RUN_LOG_NAME) log_file = log_file if os.path.exists(log_file) else None log_package_built(package_ref, duration, log_file) else: # Get the package, we have a not outdated remote package if conan_ref: self._get_package(conan_ref, conan_file) # Assign to the node the propagated info # (conan_ref could be None if user project, but of course assign the info self._propagate_info(conan_ref, conan_file, flat) # Call the info method self._package_info_conanfile(conan_ref, conan_file)
def package(self, reference, package_id): # Package paths conan_file_path = self._client_cache.conanfile(reference) if not os.path.exists(conan_file_path): raise ConanException("Package recipe '%s' does not exist" % str(reference)) conanfile = load_conanfile_class(conan_file_path) if hasattr(conanfile, "build_id"): raise ConanException( "package command does not support recipes with 'build_id'\n" "To repackage them use 'conan install'") if not package_id: packages = [ PackageReference(reference, packid) for packid in self._client_cache.conan_builds(reference) ] if not packages: raise NotFoundException( "%s: Package has not been built in local cache\n" "Please read the 'conan package' command help\n" "Use 'conan install' or 'conan test_package' to build and " "create binaries" % str(reference)) else: packages = [PackageReference(reference, package_id)] package_source_folder = self._client_cache.source( reference, conanfile.short_paths) for package_reference in packages: build_folder = self._client_cache.build(package_reference, short_paths=None) if not os.path.exists(build_folder): raise NotFoundException( "%s: Package binary '%s' folder doesn't exist\n" "Please read the 'conan package' command help\n" "Use 'conan install' or 'conan test_package' to build and " "create binaries" % (str(reference), package_reference.package_id)) # The package already exist, we can use short_paths if they were defined package_folder = self._client_cache.package(package_reference, short_paths=None) # Will read current conaninfo with specified options and load conanfile with them output = ScopedOutput(str(reference), self._user_io.out) output.info("Re-packaging %s" % package_reference.package_id) conanfile = self.load_consumer_conanfile(conan_file_path, build_folder, output, reference=reference) rmdir(package_folder) if getattr(conanfile, 'no_copy_source', False): source_folder = package_source_folder else: source_folder = build_folder with environment_append(conanfile.env): packager.create_package(conanfile, source_folder, build_folder, package_folder, output, copy_info=True)
def _get_recipe(self, reference, check_updates, update, remote_name, recorder): output = ScopedOutput(str(reference), self._out) # check if it is in disk conanfile_path = self._client_cache.conanfile(reference) # NOT in disk, must be retrieved from remotes if not os.path.exists(conanfile_path): remote, new_ref = self._download_recipe(reference, output, remote_name, recorder) status = RECIPE_DOWNLOADED return conanfile_path, status, remote, new_ref metadata = self._client_cache.load_metadata(reference) cur_revision = metadata.recipe.revision remote = self._registry.refs.get(reference) named_remote = self._registry.remotes.get(remote_name) if remote_name else None update_remote = named_remote or remote # Check if we have a revision different from the requested one revisions_enabled = get_env("CONAN_CLIENT_REVISIONS_ENABLED", False) if revisions_enabled and reference.revision and cur_revision != reference.revision: output.info("Different revision requested, removing current local recipe...") DiskRemover(self._client_cache).remove_recipe(reference) output.info("Retrieving from remote '%s'..." % update_remote.name) new_ref = self._remote_manager.get_recipe(reference, update_remote) self._registry.refs.set(new_ref, update_remote.name) status = RECIPE_UPDATED return conanfile_path, status, update_remote, new_ref check_updates = check_updates or update # Recipe exists in disk, but no need to check updates if not check_updates: status = RECIPE_INCACHE ref = reference.copy_with_rev(cur_revision) return conanfile_path, status, remote, ref if not update_remote: status = RECIPE_NO_REMOTE ref = reference.copy_with_rev(cur_revision) return conanfile_path, status, None, ref try: # get_conan_manifest can fail, not in server upstream_manifest = self._remote_manager.get_conan_manifest(reference, update_remote) except NotFoundException: status = RECIPE_NOT_IN_REMOTE ref = reference.copy_with_rev(cur_revision) return conanfile_path, status, update_remote, ref export = self._client_cache.export(reference) read_manifest = FileTreeManifest.load(export) if upstream_manifest != read_manifest: if upstream_manifest.time > read_manifest.time: if update: DiskRemover(self._client_cache).remove_recipe(reference) output.info("Retrieving from remote '%s'..." % update_remote.name) new_ref = self._remote_manager.get_recipe(reference, update_remote) self._registry.refs.set(new_ref, update_remote.name) status = RECIPE_UPDATED return conanfile_path, status, update_remote, new_ref else: status = RECIPE_UPDATEABLE else: status = RECIPE_NEWER else: status = RECIPE_INCACHE ref = reference.copy_with_rev(cur_revision) return conanfile_path, status, update_remote, ref
def _build_node(self, conan_ref, conan_file, build_mode): # Compute conan_file package from local (already compiled) or from remote output = ScopedOutput(str(conan_ref), self._out) package_id = conan_file.info.package_id() self._out.writeln("") output.info("Installing package %s" % package_id) package_reference = PackageReference(conan_ref, package_id) conan_ref = package_reference.conan package_folder = self._paths.package(package_reference) build_folder = self._paths.build(package_reference) src_folder = self._paths.source(conan_ref) export_folder = self._paths.export(conan_ref) self._handle_system_requirements(conan_ref, package_reference, conan_file, output) # Check if package is corrupted valid_package_digest = self._paths.valid_package_digest(package_reference) if os.path.exists(package_folder) and not valid_package_digest: # If not valid package, ensure empty folder output.warn("Bad package '%s' detected! Removing " "package directory... " % str(package_id)) rmdir(package_folder) # Check if any only_source pattern matches with package force_build = self._force_build(conan_ref, build_mode) if not force_build: local_package = os.path.exists(package_folder) if local_package: output.info("Package installed in %s" % package_folder) return output.info("Package not installed") remote_package = self._retrieve_remote_package(package_reference, output) if remote_package: return # Can we build? Only if we are forced or build_mode missing and package not exists build_allowed = force_build or build_mode is True if build_allowed: rmdir(build_folder) rmdir(package_folder) if force_build: output.warn("Forced build from source") self._build_package(export_folder, src_folder, build_folder, conan_file, output) # Creating ***info.txt files save(os.path.join(build_folder, CONANINFO), conan_file.info.dumps()) output.info("Generated %s" % CONANINFO) save( os.path.join(build_folder, BUILD_INFO), TXTGenerator(conan_file.deps_cpp_info, conan_file.cpp_info).content, ) output.info("Generated %s" % BUILD_INFO) os.chdir(build_folder) create_package(conan_file, build_folder, package_folder, output) else: self._raise_package_not_found_error(conan_ref, conan_file)
def get_package(self, package_reference, force_build): """ obtain a package, either from disk or retrieve from remotes if necessary and not necessary to build """ output = ScopedOutput(str(package_reference.conan), self._out) package_folder = self._paths.package(package_reference) # Check current package status if path_exists(package_folder, self._paths.store): if self._check_integrity or self._check_updates: read_manifest, expected_manifest = self._paths.package_manifests(package_reference) if self._check_integrity: # Check if package is corrupted if read_manifest.file_sums != expected_manifest.file_sums: # If not valid package, ensure empty folder output.warn("Bad package '%s' detected! Removing " "package directory... " % str(package_reference.package_id)) rmdir(package_folder) if self._check_updates: try: # get_conan_digest can fail, not in server upstream_manifest = self.get_package_digest(package_reference) if upstream_manifest.file_sums != read_manifest.file_sums: if upstream_manifest.time > read_manifest.time: output.warn("Current package is older than remote upstream one") if self._update: output.warn("Removing it to retrieve or build an updated one") rmdir(package_folder) else: output.warn("Current package is newer than remote upstream one") except ConanException: pass if not force_build: local_package = os.path.exists(package_folder) if local_package: output = ScopedOutput(str(package_reference.conan), self._out) output.info('Already installed!') return True return self._retrieve_remote_package(package_reference, output) return False
def get_package(self, package_reference, force_build, short_paths, check_outdated): """ obtain a package, either from disk or retrieve from remotes if necessary and not necessary to build """ output = ScopedOutput(str(package_reference.conan), self._out) package_folder = self._client_cache.package(package_reference, short_paths=short_paths) # Check current package status if os.path.exists(package_folder): if self._check_updates: read_manifest = self._client_cache.load_package_manifest( package_reference) try: # get_conan_digest can fail, not in server upstream_manifest = self.get_package_digest( package_reference) if upstream_manifest.file_sums != read_manifest.file_sums: if upstream_manifest.time > read_manifest.time: output.warn( "Current package is older than remote upstream one" ) if self._update: output.warn( "Removing it to retrieve or build an updated one" ) rmdir(package_folder) else: output.warn( "Current package is newer than remote upstream one" ) except ConanException: pass installed = False if not force_build: local_package = os.path.exists(package_folder) if local_package: output.info('Already installed!') installed = True else: installed = self._retrieve_remote_package( package_reference, package_folder, output) # Check if the package is outdated if check_outdated and os.path.exists(package_folder): if self._package_outdated(package_reference, package_folder): output.info("Outdated package!") installed = False else: output.info("Package is up to date") self.handle_package_manifest(package_reference, installed) return installed
def _build(self, nodes_by_level, skip_private_nodes, build_mode): """ The build assumes an input of conans ordered by degree, first level should be independent from each other, the next-second level should have dependencies only to first level conans. param nodes_by_level: list of lists [[nodeA, nodeB], [nodeC], [nodeD, ...], ...] build_mode => ["*"] if user wrote "--build" => ["hello*", "bye*"] if user wrote "--build hello --build bye" => False if user wrote "never" => True if user wrote "missing" => "outdated" if user wrote "--build outdated" """ inverse = self._deps_graph.inverse_levels() flat = [] for level in inverse: level = sorted(level, key=lambda x: x.conan_ref) flat.extend(level) # Get the nodes in order and if we have to build them nodes_to_process = self._get_nodes(nodes_by_level, skip_private_nodes, build_mode) for conan_ref, package_id, conan_file, build_needed in nodes_to_process: if build_needed: build_allowed = build_mode.allowed(conan_ref, conan_file) if not build_allowed: self._raise_package_not_found_error(conan_ref, conan_file) output = ScopedOutput(str(conan_ref), self._out) package_ref = PackageReference(conan_ref, package_id) package_folder = self._client_cache.package(package_ref, conan_file.short_paths) if conan_file.build_policy_missing: output.info("Building package from source as defined by build_policy='missing'") elif build_mode.forced(conan_ref, conan_file): output.warn('Forced build from source') self._build_requires.install(conan_ref, conan_file) t1 = time.time() # Assign to node the propagated info self._propagate_info(conan_ref, conan_file, flat) self._remote_proxy.get_recipe_sources(conan_ref) # Call the conanfile's build method build_folder = self._build_conanfile(conan_ref, conan_file, package_ref, package_folder, output) # Call the conanfile's package method self._package_conanfile(conan_ref, conan_file, package_ref, build_folder, package_folder, output) # Call the info method self._package_info_conanfile(conan_ref, conan_file) duration = time.time() - t1 log_file = os.path.join(build_folder, RUN_LOG_NAME) log_file = log_file if os.path.exists(log_file) else None log_package_built(package_ref, duration, log_file) else: # Get the package, we have a not outdated remote package if conan_ref: self._get_package(conan_ref, conan_file) # Assign to the node the propagated info # (conan_ref could be None if user project, but of course assign the info self._propagate_info(conan_ref, conan_file, flat) # Call the info method self._package_info_conanfile(conan_ref, conan_file)
def _config_node(self, node, down_reqs, down_ref, down_options, aliased): """ update settings and option in the current ConanFile, computing actual requirement values, cause they can be overridden by downstream requires param settings: dict of settings values => {"os": "windows"} """ try: conanfile, conanref = node.conanfile, node.conan_ref # Avoid extra time manipulating the sys.path for python with get_env_context_manager(conanfile, without_python=True): if hasattr(conanfile, "config"): if not conanref: output = ScopedOutput(str("PROJECT"), self._output) output.warn("config() has been deprecated." " Use config_options and configure") with conanfile_exception_formatter(str(conanfile), "config"): conanfile.config() with conanfile_exception_formatter(str(conanfile), "config_options"): conanfile.config_options() conanfile.options.propagate_upstream(down_options, down_ref, conanref) if hasattr(conanfile, "config"): with conanfile_exception_formatter(str(conanfile), "config"): conanfile.config() with conanfile_exception_formatter(str(conanfile), "configure"): conanfile.configure() conanfile.settings.validate() # All has to be ok! conanfile.options.validate() # Update requirements (overwrites), computing new upstream if hasattr(conanfile, "requirements"): # If re-evaluating the recipe, in a diamond graph, with different options, # it could happen that one execution path of requirements() defines a package # and another one a different package raising Duplicate dependency error # Or the two consecutive calls, adding 2 different dependencies for the two paths # So it is necessary to save the "requires" state and restore it before a second # execution of requirements(). It is a shallow copy, if first iteration is # RequireResolve'd or overridden, the inner requirements are modified if not hasattr(conanfile, "_conan_original_requires"): conanfile._conan_original_requires = conanfile.requires.copy( ) else: conanfile.requires = conanfile._conan_original_requires.copy( ) with conanfile_exception_formatter(str(conanfile), "requirements"): conanfile.requirements() new_options = conanfile.options.deps_package_values if aliased: for req in conanfile.requires.values(): req.conan_reference = aliased.get( req.conan_reference, req.conan_reference) new_down_reqs = conanfile.requires.update( down_reqs, self._output, conanref, down_ref) except ConanExceptionInUserConanfileMethod: raise except ConanException as e: raise ConanException("%s: %s" % (conanref or "Conanfile", str(e))) except Exception as e: raise ConanException(e) return new_down_reqs, new_options
def get_package(self, package_reference, force_build, short_paths, check_outdated): """ obtain a package, either from disk or retrieve from remotes if necessary and not necessary to build """ output = ScopedOutput(str(package_reference.conan), self._out) package_folder = self._client_cache.package(package_reference, short_paths=short_paths) # Check current package status if os.path.exists(package_folder): if self._check_updates: read_manifest = self._client_cache.load_package_manifest(package_reference) try: # get_conan_digest can fail, not in server upstream_manifest = self.get_package_digest(package_reference) if upstream_manifest.file_sums != read_manifest.file_sums: if upstream_manifest.time > read_manifest.time: output.warn("Current package is older than remote upstream one") if self._update: output.warn("Removing it to retrieve or build an updated one") rmdir(package_folder) else: output.warn("Current package is newer than remote upstream one") except ConanException: pass installed = False if not force_build: local_package = os.path.exists(package_folder) if local_package: output.info('Already installed!') installed = True else: installed = self._retrieve_remote_package(package_reference, package_folder, output) # Check if the package is outdated if check_outdated and os.path.exists(package_folder): if self._package_outdated(package_reference, package_folder): output.info("Outdated package!") installed = False else: output.info("Package is up to date") self.handle_package_manifest(package_reference, installed) return installed
def get_recipe(self, conan_reference): output = ScopedOutput(str(conan_reference), self._out) def _refresh(): export_path = self._client_cache.export(conan_reference) rmdir(export_path) # It might need to remove shortpath rm_conandir(self._client_cache.source(conan_reference)) current_remote, _ = self._get_remote(conan_reference) output.info("Retrieving from remote '%s'..." % current_remote.name) self._remote_manager.get_recipe(conan_reference, export_path, current_remote) if self._update: output.info("Updated!") else: output.info("Installed!") # check if it is in disk conanfile_path = self._client_cache.conanfile(conan_reference) path_exist = path_exists(conanfile_path, self._client_cache.store) if path_exist: if self._check_updates: ret = self.update_available(conan_reference) if ret != 0: # Found and not equal remote, ref_remote = self._get_remote(conan_reference) if ret == 1: if not self._update: if remote != ref_remote: # Forced new remote output.warn( "There is a new conanfile in '%s' remote. " "Execute 'install -u -r %s' to update it." % (remote.name, remote.name)) else: output.warn( "There is a new conanfile in '%s' remote. " "Execute 'install -u' to update it." % remote.name) output.warn("Refused to install!") else: if remote != ref_remote: # Delete packages, could be non coherent with new remote DiskRemover( self._client_cache).remove_packages( conan_reference) _refresh() elif ret == -1: if not self._update: output.info("Current conanfile is newer " "than %s's one" % remote.name) else: output.error( "Current conanfile is newer than %s's one. " "Run 'conan remove %s' and run install again " "to replace it." % (remote.name, conan_reference)) else: self._retrieve_recipe(conan_reference, output) if self._manifest_manager: remote = self._registry.get_ref(conan_reference) self._manifest_manager.check_recipe(conan_reference, remote) return conanfile_path
def _get_recipe(self, ref, check_updates, update, remote_name, recorder): output = ScopedOutput(str(ref), self._out) # check if it is in disk conanfile_path = self._cache.conanfile(ref) # NOT in disk, must be retrieved from remotes if not os.path.exists(conanfile_path): remote, new_ref = self._download_recipe(ref, output, remote_name, recorder) status = RECIPE_DOWNLOADED return conanfile_path, status, remote, new_ref remote = self._registry.refs.get(ref) named_remote = self._registry.remotes.get( remote_name) if remote_name else None update_remote = named_remote or remote check_updates = check_updates or update # Recipe exists in disk, but no need to check updates cur_revision = self._cache.package_layout(ref).recipe_revision() requested_different_revision = ( ref.revision is not None) and cur_revision != ref.revision if requested_different_revision and not check_updates: raise NotFoundException( "The recipe in the local cache doesn't match the specified " "revision. Use '--update' to check in the remote.") if not requested_different_revision: if not check_updates: status = RECIPE_INCACHE ref = ref.copy_with_rev(cur_revision) return conanfile_path, status, remote, ref if not update_remote: status = RECIPE_NO_REMOTE ref = ref.copy_with_rev(cur_revision) return conanfile_path, status, None, ref else: # Requested different revision and with --update remote, new_ref = self._download_recipe(ref, output, remote_name, recorder) status = RECIPE_DOWNLOADED return conanfile_path, status, remote, new_ref try: # get_recipe_manifest can fail, not in server upstream_manifest, ref = self._remote_manager.get_recipe_manifest( ref, update_remote) except NotFoundException: status = RECIPE_NOT_IN_REMOTE ref = ref.copy_with_rev(cur_revision) return conanfile_path, status, update_remote, ref export = self._cache.export(ref) read_manifest = FileTreeManifest.load(export) if upstream_manifest != read_manifest: if upstream_manifest.time > read_manifest.time: if update: DiskRemover().remove_recipe( self._cache.package_layout(ref), output=output) output.info("Retrieving from remote '%s'..." % update_remote.name) self._download_recipe(ref, output, update_remote.name, recorder) self._registry.refs.set(ref, update_remote.name) status = RECIPE_UPDATED return conanfile_path, status, update_remote, ref else: status = RECIPE_UPDATEABLE else: status = RECIPE_NEWER else: status = RECIPE_INCACHE ref = ref.copy_with_rev(cur_revision) return conanfile_path, status, update_remote, ref
def _evaluate_node(self, node, build_mode, update, evaluated_references, remote_name): assert node.binary is None conan_ref, conanfile = node.conan_ref, node.conanfile package_id = conanfile.info.package_id() package_ref = PackageReference(conan_ref, package_id) # Check that this same reference hasn't already been checked previous_node = evaluated_references.get(package_ref) if previous_node: node.binary = previous_node.binary node.binary_remote = previous_node.binary_remote return evaluated_references[package_ref] = node output = ScopedOutput(str(conan_ref), self._out) if build_mode.forced(conanfile, conan_ref): output.warn('Forced build from source') node.binary = BINARY_BUILD return package_folder = self._client_cache.package( package_ref, short_paths=conanfile.short_paths) # Check if dirty, to remove it local_project = self._workspace[conan_ref] if self._workspace else None if local_project: node.binary = BINARY_WORKSPACE return with self._client_cache.package_lock(package_ref): if is_dirty(package_folder): output.warn("Package is corrupted, removing folder: %s" % package_folder) rmdir(package_folder) if remote_name: remote = self._registry.remotes.get(remote_name) else: remote = self._registry.prefs.get(package_ref) remotes = self._registry.remotes.list if os.path.exists(package_folder): if update: if remote: if self._check_update(package_folder, package_ref, remote, output, node): node.binary = BINARY_UPDATE if build_mode.outdated: package_hash = self._get_package_info( package_ref, remote).recipe_hash elif remotes: pass else: output.warn("Can't update, no remote defined") if not node.binary: node.binary = BINARY_CACHE package_hash = ConanInfo.load_from_package( package_folder).recipe_hash else: # Binary does NOT exist locally remote_info = None if remote: remote_info = self._get_package_info(package_ref, remote) elif remotes: # Iterate all remotes to get this binary for r in remotes: remote_info = self._get_package_info(package_ref, r) if remote_info: remote = r break if remote_info: node.binary = BINARY_DOWNLOAD package_hash = remote_info.recipe_hash else: if build_mode.allowed(conanfile, conan_ref): node.binary = BINARY_BUILD else: node.binary = BINARY_MISSING if build_mode.outdated: if node.binary in (BINARY_CACHE, BINARY_DOWNLOAD, BINARY_UPDATE): local_recipe_hash = self._client_cache.load_manifest( package_ref.conan).summary_hash if local_recipe_hash != package_hash: output.info("Outdated package!") node.binary = BINARY_BUILD else: output.info("Package is up to date") node.binary_remote = remote
def get_conanfile(self, conan_reference): output = ScopedOutput(str(conan_reference), self._out) def _refresh(): conan_dir_path = self._paths.export(conan_reference) rmdir(conan_dir_path) rmdir(self._paths.source(conan_reference)) current_remote, _ = self._get_remote(conan_reference) output.info("Retrieving from remote '%s'..." % current_remote.name) self._remote_manager.get_conanfile(conan_reference, current_remote) if self._update: output.info("Updated!") else: output.info("Installed!") # check if it is in disk conanfile_path = self._paths.conanfile(conan_reference) if path_exists(conanfile_path, self._paths.store): if self._check_integrity: # Check if package is corrupted read_manifest, expected_manifest = self._paths.conan_manifests( conan_reference) if read_manifest.file_sums != expected_manifest.file_sums: output.warn( "Bad conanfile detected! Removing export directory... " ) _refresh() else: # Check for updates if self._check_updates: ret = self.update_available(conan_reference) if ret != 0: # Found and not equal remote, ref_remote = self._get_remote(conan_reference) if ret == 1: if not self._update: if remote != ref_remote: # Forced new remote output.warn( "There is a new conanfile in '%s' remote. " "Execute 'install -u -r %s' to update it." % (remote.name, remote.name)) else: output.warn( "There is a new conanfile in '%s' remote. " "Execute 'install -u' to update it." % remote.name) output.warn("Refused to install!") else: if remote != ref_remote: # Delete packages, could be non coherent with new remote rmdir( self._paths.packages(conan_reference)) _refresh() elif ret == -1: if not self._update: output.info("Current conanfile is newer " "than %s's one" % remote.name) else: output.error( "Current conanfile is newer than %s's one. " "Run 'conan remove %s' and run install again " "to replace it." % (remote.name, conan_reference)) else: self._retrieve_conanfile(conan_reference, output) return conanfile_path
def get_package(self, package_reference, force_build): """ obtain a package, either from disk or retrieve from remotes if necessary and not necessary to build """ output = ScopedOutput(str(package_reference.conan), self._out) package_folder = self._paths.package(package_reference) # Check current package status if path_exists(package_folder, self._paths.store): if self._check_integrity or self._check_updates: read_manifest, expected_manifest = self._paths.package_manifests( package_reference) if self._check_integrity: # Check if package is corrupted if read_manifest.file_sums != expected_manifest.file_sums: # If not valid package, ensure empty folder output.warn("Bad package '%s' detected! Removing " "package directory... " % str(package_reference.package_id)) rmdir(package_folder) if self._check_updates: try: # get_conan_digest can fail, not in server upstream_manifest = self.get_package_digest( package_reference) if upstream_manifest.file_sums != read_manifest.file_sums: if upstream_manifest.time > read_manifest.time: output.warn( "Current package is older than remote upstream one" ) if self._update: output.warn( "Removing it to retrieve or build an updated one" ) rmdir(package_folder) else: output.warn( "Current package is newer than remote upstream one" ) except ConanException: pass if not force_build: local_package = os.path.exists(package_folder) if local_package: output = ScopedOutput(str(package_reference.conan), self._out) output.info('Already installed!') return True return self._retrieve_remote_package(package_reference, output) return False
def install(self, reference, current_path, remote=None, options=None, settings=None, build_mode=False, info=None, filename=None, update=False, check_updates=False, integrity=False): """ Fetch and build all dependencies for the given reference @param reference: ConanFileReference or path to user space conanfile @param current_path: where the output files will be saved @param remote: install only from that remote @param options: list of tuples: [(optionname, optionvalue), (optionname, optionvalue)...] @param settings: list of tuples: [(settingname, settingvalue), (settingname, value)...] """ reference_given = True if not isinstance(reference, ConanFileReference): conanfile_path = reference reference_given = False reference = None loader = self._loader(current_path, settings, options) # Not check for updates for info command, it'll be checked when dep graph is built remote_proxy = ConanProxy(self._paths, self._user_io, self._remote_manager, remote, update=update, check_updates=check_updates, check_integrity=integrity) if reference_given: project_reference = None conanfile_path = remote_proxy.get_conanfile(reference) output = ScopedOutput(str(reference), self._user_io.out) conanfile = loader.load_conan(conanfile_path, output, consumer=True) else: project_reference = "PROJECT" output = ScopedOutput(project_reference, self._user_io.out) try: if filename and filename.endswith(".txt"): raise NotFoundException("") conan_file_path = os.path.join(conanfile_path, filename or CONANFILE) conanfile = loader.load_conan(conan_file_path, output, consumer=True) is_txt = False if conanfile.name is not None and conanfile.version is not None: project_reference = "%s/%s@" % (conanfile.name, conanfile.version) project_reference += "PROJECT" except NotFoundException: # Load requirements.txt conan_path = os.path.join(conanfile_path, filename or CONANFILE_TXT) conanfile = loader.load_conan_txt(conan_path, output) is_txt = True # build deps graph and install it builder = DepsBuilder(remote_proxy, self._user_io.out, loader) deps_graph = builder.load(reference, conanfile) registry = RemoteRegistry(self._paths.registry, self._user_io.out) if info: graph_updates_info = builder.get_graph_updates_info(deps_graph) Printer(self._user_io.out).print_info(deps_graph, project_reference, info, registry, graph_updates_info, remote) return Printer(self._user_io.out).print_graph(deps_graph, registry) installer = ConanInstaller(self._paths, self._user_io, remote_proxy) installer.install(deps_graph, build_mode) if not reference_given: if is_txt: conanfile.info.settings = loader._settings.values # Just in case the current package is header only, we still store the full settings # for reference and compiler checks conanfile.info.full_settings = loader._settings.values content = normalize(conanfile.info.dumps()) save(os.path.join(current_path, CONANINFO), content) output.info("Generated %s" % CONANINFO) write_generators(conanfile, current_path, output) local_installer = FileImporter(deps_graph, self._paths, current_path) conanfile.copy = local_installer conanfile.imports() copied_files = local_installer.execute() import_output = ScopedOutput("%s imports()" % output.scope, output) report_copied_files(copied_files, import_output)
def create(self, conanfile_path, name=None, version=None, user=None, channel=None, profile_name=None, settings=None, options=None, env=None, test_folder=None, not_export=False, build_modes=None, keep_source=False, keep_build=False, verify=None, manifests=None, manifests_interactive=None, remote=None, update=False, cwd=None, test_build_folder=None): """ API method to create a conan package :param test_folder: default None - looks for default 'test' or 'test_package' folder), string - test_folder path False - disabling tests """ settings = settings or [] options = options or [] env = env or [] cwd = cwd or os.getcwd() conanfile_path = _get_conanfile_path(conanfile_path, cwd, py=True) if not name or not version: conanfile = load_conanfile_class(conanfile_path) name, version = conanfile.name, conanfile.version if not name or not version: raise ConanException( "conanfile.py doesn't declare package name or version") reference = ConanFileReference(name, version, user, channel) scoped_output = ScopedOutput(str(reference), self._user_io.out) # Make sure keep_source is set for keep_build if keep_build: keep_source = True # Forcing an export! if not not_export: scoped_output.highlight("Exporting package recipe") self._manager.export(conanfile_path, name, version, user, channel, keep_source) if build_modes is None: # Not specified, force build the tested library build_modes = [name] manifests = _parse_manifests_arguments(verify, manifests, manifests_interactive, cwd) manifest_folder, manifest_interactive, manifest_verify = manifests profile = profile_from_args(profile_name, settings, options, env, cwd, self._client_cache) def get_test_conanfile_path(tf): """Searches in the declared test_folder or in the standard locations""" if tf is False: # Look up for testing conanfile can be disabled if tf (test folder) is False return None test_folders = [tf] if tf else ["test_package", "test"] base_folder = os.path.dirname(conanfile_path) for test_folder_name in test_folders: test_folder = os.path.join(base_folder, test_folder_name) test_conanfile_path = os.path.join(test_folder, "conanfile.py") if os.path.exists(test_conanfile_path): return test_conanfile_path else: if tf: raise ConanException("test folder '%s' not available, " "or it doesn't have a conanfile.py" % tf) test_conanfile_path = get_test_conanfile_path(test_folder) if test_conanfile_path: pt = PackageTester(self._manager, self._user_io) pt.install_build_and_test( test_conanfile_path, reference, profile, remote, update, build_modes=build_modes, manifest_folder=manifest_folder, manifest_verify=manifest_verify, manifest_interactive=manifest_interactive, keep_build=keep_build, test_build_folder=test_build_folder) else: self._manager.install( reference=reference, install_folder=None, # Not output anything manifest_folder=manifest_folder, manifest_verify=manifest_verify, manifest_interactive=manifest_interactive, remote=remote, profile=profile, build_modes=build_modes, update=update, keep_build=keep_build)
def create_package(conanfile, source_folder, build_folder, package_folder, install_folder, output, local=False, copy_info=False): """ copies built artifacts, libs, headers, data, etc. from build_folder to package folder """ mkdir(package_folder) # Make the copy of all the patterns output.info("Generating the package") output.info("Package folder %s" % package_folder) try: package_output = ScopedOutput("%s package()" % output.scope, output) output.highlight("Calling package()") conanfile.package_folder = package_folder conanfile.source_folder = source_folder conanfile.install_folder = install_folder conanfile.build_folder = build_folder def recipe_has(attribute): return attribute in conanfile.__class__.__dict__ if source_folder != build_folder: conanfile.copy = FileCopier(source_folder, package_folder, build_folder) with conanfile_exception_formatter(str(conanfile), "package"): with tools.chdir(source_folder): conanfile.package() copy_done = conanfile.copy.report(package_output) if not copy_done and recipe_has("package"): output.warn("No files copied from source folder!") conanfile.copy = FileCopier(build_folder, package_folder) with tools.chdir(build_folder): with conanfile_exception_formatter(str(conanfile), "package"): conanfile.package() copy_done = conanfile.copy.report(package_output) if not copy_done and recipe_has("build") and recipe_has("package"): output.warn("No files copied from build folder!") except Exception as e: if not local: os.chdir(build_folder) try: rmdir(package_folder) except Exception as e_rm: output.error("Unable to remove package folder %s\n%s" % (package_folder, str(e_rm))) output.warn("**** Please delete it manually ****") if isinstance(e, ConanExceptionInUserConanfileMethod): raise raise ConanException(e) _create_aux_files(install_folder, package_folder, conanfile, copy_info) output.success("Package '%s' created" % os.path.basename(package_folder))
def install(self, reference, install_folder, profile, remote=None, build_modes=None, filename=None, update=False, manifest_folder=None, manifest_verify=False, manifest_interactive=False, generators=None, no_imports=False, inject_require=None, cwd=None, install_reference=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 filename: Optional filename of the conanfile @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 @param cwd: Only used in case of reference, to get a conanfile_directory to a virtual SMELL """ 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 = ConanProxy(self._client_cache, self._user_io, self._remote_manager, remote, update=update, manifest_manager=manifest_manager) loader = self.get_loader(profile) if not install_reference and isinstance( reference, ConanFileReference): # is a create loader.dev_reference = reference conanfile = self._load_install_conanfile(loader, reference, filename, cwd=cwd) if inject_require: self._inject_require(conanfile, inject_require) graph_builder = self._get_graph_builder(loader, update, remote_proxy) deps_graph = graph_builder.load(conanfile) # This line is so the conaninfo stores the correct complete info conanfile.info.scope = profile.scopes registry = RemoteRegistry(self._client_cache.registry, self._user_io.out) if inject_require: output = ScopedOutput("%s test package" % str(inject_require), self._user_io.out) output.info("Installing dependencies") else: if not isinstance(reference, ConanFileReference): output = ScopedOutput("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, registry) try: if loader._settings.os and detected_os() != loader._settings.os: message = "Cross-platform from '%s' to '%s'" % ( detected_os(), loader._settings.os) 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, registry, output, profile.build_requires) installer = ConanInstaller(self._client_cache, output, remote_proxy, build_mode, build_requires) # Apply build_requires to consumer conanfile if not isinstance(reference, ConanFileReference): build_requires.install("", conanfile, installer) installer.install(deps_graph) 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 install(self, reference, current_path, remote=None, options=None, settings=None, build_mode=False, filename=None, update=False, check_updates=False, manifest_folder=None, manifest_verify=False, manifest_interactive=False, scopes=None, generators=None): """ Fetch and build all dependencies for the given reference @param reference: ConanFileReference or path to user space conanfile @param current_path: where the output files will be saved @param remote: install only from that remote @param options: list of tuples: [(optionname, optionvalue), (optionname, optionvalue)...] @param settings: list of tuples: [(settingname, settingvalue), (settingname, value)...] """ generators = generators or [] if manifest_folder: manifest_manager = ManifestManager( manifest_folder, user_io=self._user_io, client_cache=self._client_cache, verify=manifest_verify, interactive=manifest_interactive) else: manifest_manager = None objects = self._get_graph(reference, current_path, remote, options, settings, filename, update, check_updates, manifest_manager, scopes) (_, deps_graph, _, registry, conanfile, remote_proxy, loader) = objects Printer(self._user_io.out).print_graph(deps_graph, registry) # Warn if os doesn't match try: if detected_os() != loader._settings.os: message = '''You are building this package with settings.os='%s' on a '%s' system. If this is your intention, you can ignore this message. If not: - Check the passed settings (-s) - Check your global settings in ~/.conan/conan.conf - Remove conaninfo.txt to avoid bad cached settings ''' % (loader._settings.os, detected_os()) self._user_io.out.warn(message) except ConanException: # Setting os doesn't exist pass installer = ConanInstaller(self._client_cache, self._user_io, remote_proxy) installer.install(deps_graph, build_mode) prefix = "PROJECT" if not isinstance( reference, ConanFileReference) else str(reference) output = ScopedOutput(prefix, self._user_io.out) # Write generators tmp = list( conanfile.generators) # Add the command line specified generators tmp.extend(generators) conanfile.generators = tmp write_generators(conanfile, current_path, output) if not isinstance(reference, ConanFileReference): content = normalize(conanfile.info.dumps()) save(os.path.join(current_path, CONANINFO), content) output.info("Generated %s" % CONANINFO) local_installer = FileImporter(deps_graph, self._client_cache, current_path) conanfile.copy = local_installer conanfile.imports() copied_files = local_installer.execute() import_output = ScopedOutput("%s imports()" % output.scope, output) report_copied_files(copied_files, import_output) if manifest_manager: manifest_manager.print_log()
def get_conanfile(self, conan_reference): output = ScopedOutput(str(conan_reference), self._out) def _refresh(): conan_dir_path = self._paths.export(conan_reference) rmdir(conan_dir_path) rmdir(self._paths.source(conan_reference), True) # It might need to remove shortpath current_remote, _ = self._get_remote(conan_reference) output.info("Retrieving from remote '%s'..." % current_remote.name) self._remote_manager.get_conanfile(conan_reference, current_remote) if self._update: output.info("Updated!") else: output.info("Installed!") # check if it is in disk conanfile_path = self._paths.conanfile(conan_reference) path_exist = path_exists(conanfile_path, self._paths.store) if path_exist: if self._check_integrity: # Check if package is corrupted read_manifest, expected_manifest = self._paths.conan_manifests(conan_reference) if read_manifest.file_sums != expected_manifest.file_sums: output.warn("Bad conanfile detected! Removing export directory... ") _refresh() else: # Check for updates if self._check_updates: ret = self.update_available(conan_reference) if ret != 0: # Found and not equal remote, ref_remote = self._get_remote(conan_reference) if ret == 1: if not self._update: if remote != ref_remote: # Forced new remote output.warn("There is a new conanfile in '%s' remote. " "Execute 'install -u -r %s' to update it." % (remote.name, remote.name)) else: output.warn("There is a new conanfile in '%s' remote. " "Execute 'install -u' to update it." % remote.name) output.warn("Refused to install!") else: if remote != ref_remote: # Delete packages, could be non coherent with new remote rmdir(self._paths.packages(conan_reference)) _refresh() elif ret == -1: if not self._update: output.info("Current conanfile is newer " "than %s's one" % remote.name) else: output.error("Current conanfile is newer than %s's one. " "Run 'conan remove %s' and run install again " "to replace it." % (remote.name, conan_reference)) else: self._retrieve_conanfile(conan_reference, output) return conanfile_path
def build(self, conanfile_path, source_folder, build_folder, package_folder, install_folder, test=False, should_configure=True, should_build=True, should_install=True): """ Call to build() method saved on the conanfile.py param conanfile_path: path to a conanfile.py """ logger.debug("Building in %s" % build_folder) logger.debug("Conanfile in %s" % conanfile_path) try: # Append env_vars to execution environment and clear when block code ends output = ScopedOutput( ("%s (test package)" % test) if test else "Project", self._user_io.out) conan_file = self._load_consumer_conanfile(conanfile_path, install_folder, output, deps_info_required=True) except NotFoundException: # TODO: Auto generate conanfile from requirements file raise ConanException("'%s' file is needed for build.\n" "Create a '%s' and move manually the " "requirements and generators from '%s' file" % (CONANFILE, CONANFILE, CONANFILE_TXT)) if test: try: conan_file.requires.add(test) except ConanException: pass conan_file.should_configure = should_configure conan_file.should_build = should_build conan_file.should_install = should_install try: mkdir(build_folder) os.chdir(build_folder) conan_file.build_folder = build_folder conan_file.source_folder = source_folder conan_file.package_folder = package_folder conan_file.install_folder = install_folder with get_env_context_manager(conan_file): output.highlight("Running build()") with conanfile_exception_formatter(str(conan_file), "build"): conan_file.build() if test: output.highlight("Running test()") with conanfile_exception_formatter(str(conan_file), "test"): conan_file.test() except ConanException: raise # Raise but not let to reach the Exception except (not print traceback) except Exception: import traceback trace = traceback.format_exc().split('\n') raise ConanException("Unable to build it successfully\n%s" % '\n'.join(trace[3:]))
def install(self, reference, current_path, profile, remote=None, build_modes=None, filename=None, update=False, manifest_folder=None, manifest_verify=False, manifest_interactive=False, generators=None, no_imports=False): """ Fetch and build all dependencies for the given reference @param reference: ConanFileReference or path to user space conanfile @param current_path: 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 readed values @param build_modes: List of build_modes specified @param filename: Optional filename of the conanfile @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 """ generators = generators or [] 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 = ConanProxy(self._client_cache, self._user_io, self._remote_manager, remote, update=update, check_updates=False, manifest_manager=manifest_manager) loader = ConanFileLoader(self._runner, self._client_cache.settings, profile) conanfile = self._get_conanfile_object(loader, reference, filename, current_path) graph_builder = self._get_graph_builder(loader, update, remote_proxy) deps_graph = graph_builder.load(conanfile) # This line is so the conaninfo stores the correct complete info conanfile.info.scope = profile.scopes registry = RemoteRegistry(self._client_cache.registry, self._user_io.out) Printer(self._user_io.out).print_graph(deps_graph, registry) try: if detected_os() != loader._settings.os: message = "Cross-platform from '%s' to '%s'" % (detected_os(), loader._settings.os) 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, remote_proxy, self._user_io.out, self._client_cache, self._search_manager, profile.build_requires, current_path, build_mode) # Apply build_requires to consumer conanfile build_requires.install("", conanfile) installer = ConanInstaller(self._client_cache, self._user_io.out, remote_proxy, build_requires) installer.install(deps_graph, build_mode, current_path) build_mode.report_matches() prefix = "PROJECT" if not isinstance(reference, ConanFileReference) else str(reference) output = ScopedOutput(prefix, self._user_io.out) # Write generators tmp = list(conanfile.generators) # Add the command line specified generators tmp.extend(generators) conanfile.generators = tmp write_generators(conanfile, current_path, output) if not isinstance(reference, ConanFileReference): content = normalize(conanfile.info.dumps()) save(os.path.join(current_path, CONANINFO), content) output.info("Generated %s" % CONANINFO) if not no_imports: run_imports(conanfile, current_path, output) installer.call_system_requirements(conanfile, output) if manifest_manager: manifest_manager.print_log()
def _get_recipe(self, conan_reference): output = ScopedOutput(str(conan_reference), self._out) # check if it is in disk conanfile_path = self._client_cache.conanfile(conan_reference) if os.path.exists(conanfile_path): log_recipe_got_from_local_cache(conan_reference) if self._check_updates: ret = self.update_available(conan_reference) if ret != 0: # Found and not equal remote, ref_remote = self._get_remote(conan_reference) if ret == 1: if not self._update: if remote != ref_remote: # Forced new remote output.warn( "There is a new conanfile in '%s' remote. " "Execute 'install -u -r %s' to update it." % (remote.name, remote.name)) else: output.warn( "There is a new conanfile in '%s' remote. " "Execute 'install -u' to update it." % remote.name) output.warn("Refused to install!") else: export_path = self._client_cache.export( conan_reference) DiskRemover( self._client_cache).remove(conan_reference) output.info("Retrieving from remote '%s'..." % remote.name) self._remote_manager.get_recipe( conan_reference, export_path, remote) output.info("Updated!") elif ret == -1: if not self._update: output.info("Current conanfile is newer " "than %s's one" % remote.name) else: output.error( "Current conanfile is newer than %s's one. " "Run 'conan remove %s' and run install again " "to replace it." % (remote.name, conan_reference)) else: self._retrieve_recipe(conan_reference, output) if self._manifest_manager: # Just make sure that the recipe sources are there to check conanfile = load_conanfile_class(conanfile_path) self.get_recipe_sources(conan_reference, conanfile.short_paths) remote = self._registry.get_ref(conan_reference) self._manifest_manager.check_recipe(conan_reference, remote) return conanfile_path
def install(self, reference, current_path, remote=None, options=None, settings=None, build_mode=False, info=None, filename=None, update=False): """ Fetch and build all dependencies for the given reference @param reference: ConanFileReference or path to user space conanfile @param current_path: where the output files will be saved @param remote: install only from that remote @param options: list of tuples: [(optionname, optionvalue), (optionname, optionvalue)...] @param settings: list of tuples: [(settingname, settingvalue), (settingname, value)...] """ reference_given = True if not isinstance(reference, ConanFileReference): conanfile_path = reference reference_given = False reference = None loader = self._loader(current_path, settings, options) # Not check for updates for info command, it'll be checked when dep graph is built check_updates = not info remote_proxy = ConanProxy(self._paths, self._user_io, self._remote_manager, remote, update, check_updates) if reference_given: project_reference = None conanfile_path = remote_proxy.get_conanfile(reference) output = ScopedOutput(str(reference), self._user_io.out) conanfile = loader.load_conan(conanfile_path, output, consumer=True) else: project_reference = "PROJECT" output = ScopedOutput(project_reference, self._user_io.out) try: if filename and filename.endswith(".txt"): raise NotFoundException("") conan_file_path = os.path.join(conanfile_path, filename or CONANFILE) conanfile = loader.load_conan(conan_file_path, output, consumer=True) is_txt = False if conanfile.name is not None and conanfile.version is not None: project_reference = "%s/%s@" % (conanfile.name, conanfile.version) project_reference += "PROJECT" except NotFoundException: # Load requirements.txt conan_path = os.path.join(conanfile_path, filename or CONANFILE_TXT) conanfile = loader.load_conan_txt(conan_path, output) is_txt = True # build deps graph and install it builder = DepsBuilder(remote_proxy, self._user_io.out, loader) deps_graph = builder.load(reference, conanfile) registry = RemoteRegistry(self._paths.registry, self._user_io.out) if info: graph_updates_info = builder.get_graph_updates_info(deps_graph) Printer(self._user_io.out).print_info(deps_graph, project_reference, info, registry, graph_updates_info, remote) return Printer(self._user_io.out).print_graph(deps_graph, registry) installer = ConanInstaller(self._paths, self._user_io, remote_proxy) installer.install(deps_graph, build_mode) if not reference_given: if is_txt: conanfile.info.settings = loader._settings.values # Just in case the current package is header only, we still store the full settings # for reference and compiler checks conanfile.info.full_settings = loader._settings.values content = normalize(conanfile.info.dumps()) save(os.path.join(current_path, CONANINFO), content) output.info("Generated %s" % CONANINFO) write_generators(conanfile, current_path, output) local_installer = FileImporter(deps_graph, self._paths, current_path) conanfile.copy = local_installer conanfile.imports() copied_files = local_installer.execute() import_output = ScopedOutput("%s imports()" % output.scope, output) report_copied_files(copied_files, import_output)
class ConanFile(object): """ The base class for all package recipes """ name = None version = None # Any str, can be "1.1" or whatever url = None # The URL where this File is located, as github, to collaborate in package # The license of the PACKAGE, just a shortcut, does not replace or # change the actual license of the source code license = None author = None # Main maintainer/responsible for the package, any format description = None topics = None homepage = None build_policy = None short_paths = False apply_env = True # Apply environment variables from requires deps_env_info and profiles exports = None exports_sources = None generators = ["txt"] revision_mode = "hash" # Vars to control the build steps (build(), package()) should_configure = True should_build = True should_install = True should_test = True in_local_cache = True develop = False # Defaulting the reference fields default_channel = None default_user = None # Settings and Options settings = None options = None default_options = None provides = None deprecated = None # layout layout = None def __init__(self, output, runner, display_name="", user=None, channel=None): # an output stream (writeln, info, warn error) self.output = ScopedOutput(display_name, output) self.display_name = display_name # something that can run commands, as os.sytem self._conan_runner = runner self._conan_user = user self._conan_channel = channel self.compatible_packages = [] self._conan_using_build_profile = False self._conan_requester = None self.layout = Layout() self.buildenv_info = Environment() self.runenv_info = Environment() self._conan_buildenv = None # The profile buildenv, will be assigned initialize() self._conan_node = None # access to container Node object, to access info, context, deps... self.virtualenv = True # Set to false to opt-out automatic usage of VirtualEnv self._conan_new_cpp_info = None # Will be calculated lazy in the getter @property def context(self): return self._conan_node.context @property def dependencies(self): return ConanFileDependencies(self._conan_node) @property def ref(self): return self._conan_node.ref @property def pref(self): return self._conan_node.pref @property def buildenv(self): # Lazy computation of the package buildenv based on the profileone if not isinstance(self._conan_buildenv, Environment): # TODO: missing user/channel ref_str = "{}/{}".format(self.name, self.version) self._conan_buildenv = self._conan_buildenv.get_env(ref_str) return self._conan_buildenv def initialize(self, settings, env, buildenv=None): self._conan_buildenv = buildenv if isinstance(self.generators, str): self.generators = [self.generators] # User defined options self.options = create_options(self) self.requires = create_requirements(self) self.settings = create_settings(self, settings) conan_v2_error("Setting 'cppstd' is deprecated in favor of 'compiler.cppstd'," " please update your recipe.", 'cppstd' in self.settings.fields) # needed variables to pack the project self.cpp_info = None # Will be initialized at processing time self._conan_dep_cpp_info = None # Will be initialized at processing time self.deps_cpp_info = DepsCppInfo() # environment variables declared in the package_info self.env_info = None # Will be initialized at processing time self.deps_env_info = DepsEnvInfo() # user declared variables self.user_info = None # Keys are the package names (only 'host' if different contexts) self.deps_user_info = DepsUserInfo() # user specified env variables self._conan_env_values = env.copy() # user specified -e if self.description is not None and not isinstance(self.description, six.string_types): raise ConanException("Recipe 'description' must be a string.") @property def new_cpp_info(self): if not self._conan_new_cpp_info: self._conan_new_cpp_info = NewCppInfo.from_old_cppinfo(self.cpp_info) return self._conan_new_cpp_info @property def source_folder(self): return self.layout.source_folder @source_folder.setter def source_folder(self, folder): self.layout.set_base_source_folder(folder) @property def build_folder(self): return self.layout.build_folder @build_folder.setter def build_folder(self, folder): self.layout.set_base_build_folder(folder) @property def package_folder(self): return self.layout.base_package_folder @package_folder.setter def package_folder(self, folder): self.layout.set_base_package_folder(folder) @property def install_folder(self): return self.layout.base_install_folder @install_folder.setter def install_folder(self, folder): self.layout.set_base_install_folder(folder) @property def env(self): """Apply the self.deps_env_info into a copy of self._conan_env_values (will prioritize the self._conan_env_values, user specified from profiles or -e first, then inherited)""" # Cannot be lazy cached, because it's called in configure node, and we still don't have # the deps_env_info objects available tmp_env_values = self._conan_env_values.copy() tmp_env_values.update(self.deps_env_info) ret, multiple = tmp_env_values.env_dicts(self.name, self.version, self._conan_user, self._conan_channel) ret.update(multiple) return ret @property def channel(self): if not self._conan_channel: _env_channel = os.getenv("CONAN_CHANNEL") conan_v2_error("Environment variable 'CONAN_CHANNEL' is deprecated", _env_channel) self._conan_channel = _env_channel or self.default_channel if not self._conan_channel: raise ConanException("channel not defined, but self.channel is used in conanfile") return self._conan_channel @property def user(self): if not self._conan_user: _env_username = os.getenv("CONAN_USERNAME") conan_v2_error("Environment variable 'CONAN_USERNAME' is deprecated", _env_username) self._conan_user = _env_username or self.default_user if not self._conan_user: raise ConanException("user not defined, but self.user is used in conanfile") return self._conan_user def collect_libs(self, folder=None): conan_v2_error("'self.collect_libs' is deprecated, use 'tools.collect_libs(self)' instead") return tools.collect_libs(self, folder=folder) @property def build_policy_missing(self): return self.build_policy == "missing" @property def build_policy_always(self): return self.build_policy == "always" def source(self): pass def system_requirements(self): """ this method can be overwritten to implement logic for system package managers, as apt-get You can define self.global_system_requirements = True, if you want the installation to be for all packages (not depending on settings/options/requirements) """ def config_options(self): """ modify options, probably conditioned to some settings. This call is executed before config_settings. E.g. if self.settings.os == "Windows": del self.options.shared # shared/static not supported in win """ def configure(self): """ modify settings, probably conditioned to some options. This call is executed after config_options. E.g. if self.options.header_only: self.settings.clear() This is also the place for conditional requirements """ def build(self): """ build your project calling the desired build tools as done in the command line. E.g. self.run("cmake --build .") Or use the provided build helpers. E.g. cmake.build() """ self.output.warn("This conanfile has no build step") def package(self): """ package the needed files from source and build folders. E.g. self.copy("*.h", src="src/includes", dst="includes") """ self.output.warn("This conanfile has no package step") def package_info(self): """ define cpp_build_info, flags, etc """ def run(self, command, output=True, cwd=None, win_bash=False, subsystem=None, msys_mingw=True, ignore_errors=False, run_environment=False, with_login=True, env="conanbuildenv"): command = environment_wrap_command(env, command) def _run(): if not win_bash: return self._conan_runner(command, output, os.path.abspath(RUN_LOG_NAME), cwd) # FIXME: run in windows bash is not using output return tools.run_in_windows_bash(self, bashcmd=command, cwd=cwd, subsystem=subsystem, msys_mingw=msys_mingw, with_login=with_login) if run_environment: # When using_build_profile the required environment is already applied through # 'conanfile.env' in the contextmanager 'get_env_context_manager' with tools.run_environment(self) if not self._conan_using_build_profile else no_op(): if OSInfo().is_macos and isinstance(command, string_types): # Security policy on macOS clears this variable when executing /bin/sh. To # keep its value, set it again inside the shell when running the command. command = 'DYLD_LIBRARY_PATH="%s" DYLD_FRAMEWORK_PATH="%s" %s' % \ (os.environ.get('DYLD_LIBRARY_PATH', ''), os.environ.get("DYLD_FRAMEWORK_PATH", ''), command) retcode = _run() else: retcode = _run() if not ignore_errors and retcode != 0: raise ConanException("Error %d while executing %s" % (retcode, command)) return retcode def package_id(self): """ modify the binary info, typically to narrow values e.g.: self.info.settings.compiler = "Any" => All compilers will generate same ID """ def test(self): """ test the generated executable. E.g. self.run("./example") """ raise ConanException("You need to create a method 'test' in your test/conanfile.py") def __repr__(self): return self.display_name
def _build_node(self, conan_ref, conan_file, build_mode): # Compute conan_file package from local (already compiled) or from remote output = ScopedOutput(str(conan_ref), self._out) package_id = conan_file.info.package_id() package_reference = PackageReference(conan_ref, package_id) check_outdated = build_mode == "outdated" conan_ref = package_reference.conan package_folder = self._client_cache.package(package_reference, conan_file.short_paths) build_folder = self._client_cache.build(package_reference, conan_file.short_paths) src_folder = self._client_cache.source(conan_ref, conan_file.short_paths) export_folder = self._client_cache.export(conan_ref) # If already exists do not dirt the output, the common situation # is that package is already installed and OK. If don't, the proxy # will print some other message about it if not os.path.exists(package_folder): output.info("Installing package %s" % package_id) self._handle_system_requirements(conan_ref, package_reference, conan_file, output) force_build = self._build_forced(conan_ref, build_mode, conan_file) if self._remote_proxy.get_package(package_reference, force_build, short_paths=conan_file.short_paths, check_outdated=check_outdated): return # we need and can build? Only if we are forced or build_mode missing and package not exists # Option "--build outdated" means: missing or outdated, so don't care if it's really oudated # just build it. build = force_build or build_mode is True or check_outdated or conan_file.build_policy_missing if build: if not force_build and not build_mode: output.info("Building package from source as defined by build_policy='missing'") try: rmdir(build_folder) rmdir(package_folder) except Exception as e: raise ConanException("%s\n\nCouldn't remove folder, might be busy or open\n" "Close any app using it, and retry" % str(e)) if force_build: output.warn('Forced build from source') with environment_append(conan_file.env): self._build_package(export_folder, src_folder, build_folder, conan_file, output) # FIXME: Is weak to assign here the recipe_hash conan_file.info.recipe_hash = self._client_cache.load_manifest(conan_ref).summary_hash # Creating ***info.txt files save(os.path.join(build_folder, CONANINFO), conan_file.info.dumps()) output.info("Generated %s" % CONANINFO) save(os.path.join(build_folder, BUILD_INFO), TXTGenerator(conan_file).content) output.info("Generated %s" % BUILD_INFO) save(os.path.join(build_folder, CONANENV), ConanEnvGenerator(conan_file).content) output.info("Generated %s" % CONANENV) os.chdir(build_folder) with environment_append(conan_file.env): create_package(conan_file, build_folder, package_folder, output) self._remote_proxy.handle_package_manifest(package_reference, installed=True) else: self._raise_package_not_found_error(conan_ref, conan_file)
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 remote_proxy = self.get_proxy(remote_name=remote_name) 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") print_graph(deps_graph, self._user_io.out) 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 manifest_folder: manifest_manager = ManifestManager(manifest_folder, user_io=self._user_io, client_cache=self._client_cache) for node in deps_graph.nodes: if not node.conan_ref: continue conanfile = node.conanfile complete_recipe_sources(self._remote_manager, self._client_cache, self._registry, conanfile, node.conan_ref) manifest_manager.check_graph(deps_graph, verify=manifest_verify, interactive=manifest_interactive) manifest_manager.print_log() 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)
def _get_recipe(self, conan_reference, check_updates, update): output = ScopedOutput(str(conan_reference), self._out) check_updates = check_updates or update # check if it is in disk conanfile_path = self._client_cache.conanfile(conan_reference) if os.path.exists(conanfile_path): if check_updates: ret = self.update_available(conan_reference) if ret != 0: # Found and not equal remote, ref_remote = self._get_remote(conan_reference) if ret == 1: if not update: if remote != ref_remote: # Forced new remote output.warn("There is a new conanfile in '%s' remote. " "Execute 'install -u -r %s' to update it." % (remote.name, remote.name)) else: output.warn("There is a new conanfile in '%s' remote. " "Execute 'install -u' to update it." % remote.name) output.warn("Refused to install!") else: DiskRemover(self._client_cache).remove(conan_reference) output.info("Retrieving from remote '%s'..." % remote.name) self._remote_manager.get_recipe(conan_reference, remote) output.info("Updated!") elif ret == -1: if not update: output.info("Current conanfile is newer than %s's one" % remote.name) else: output.error("Current conanfile is newer than %s's one. " "Run 'conan remove %s' and run install again " "to replace it." % (remote.name, conan_reference)) log_recipe_got_from_local_cache(conan_reference) self._recorder.recipe_fetched_from_cache(conan_reference) else: self._retrieve_recipe(conan_reference, output) if self._manifest_manager: # Just make sure that the recipe sources are there to check conanfile = load_conanfile_class(conanfile_path) complete_recipe_sources(self._remote_manager, self._client_cache, self._registry, conanfile, conan_reference) remote = self._registry.get_ref(conan_reference) self._manifest_manager.check_recipe(conan_reference, remote) return conanfile_path
def complete_test(self): """ basic installation of a new conans """ client = TestClient() client.init_dynamic_vars() files = hello_source_files() conan_ref = ConanFileReference.loads("Hello/1.2.1@frodo/stable") reg_folder = client.client_cache.export(conan_ref) client.save(files, path=reg_folder) client.save( { CONANFILE: myconan1, "infos/%s" % CONANINFO: "//empty", "include/no_copy/lib0.h": "NO copy", "include/math/lib1.h": "copy", "include/math/lib2.h": "copy", "include/physics/lib.hpp": "copy", "my_lib/debug/libd.a": "copy", "my_data/readme.txt": "copy", "my_data/readme.md": "NO copy", "contrib/math/math.h": "copy", "contrib/physics/gravity.h": "copy", "contrib/contrib.h": "copy", "include/opencv/opencv.hpp": "copy", "include/opencv2/opencv2.hpp": "copy", "modules/simu/src/simu.cpp": "NO copy", "modules/simu/include/opencv2/simu/simu.hpp": "copy", "modules/3D/doc/readme.md": "NO copy", "modules/3D/include/opencv2/3D/3D.hpp": "copy", "modules/dev/src/dev.cpp": "NO copy", "modules/dev/include/opencv2/dev/dev.hpp": "copy", "modules/opencv_mod.hpp": "copy" }, path=reg_folder) conanfile_path = os.path.join(reg_folder, CONANFILE) package_ref = PackageReference(conan_ref, "myfakeid") build_folder = client.client_cache.build(package_ref) package_folder = client.client_cache.package(package_ref) install_folder = os.path.join(build_folder, "infos") shutil.copytree(reg_folder, build_folder) output = ScopedOutput("", TestBufferConanOutput()) loader = ConanFileLoader(None, None, ConanPythonRequire(None, None)) conanfile = loader.load_conanfile(conanfile_path, None, test_processed_profile()) create_package(conanfile, None, build_folder, build_folder, package_folder, install_folder, output, client.hook_manager, conanfile_path, conan_ref, copy_info=True) # test build folder self.assertTrue(os.path.exists(build_folder)) self.assertTrue(os.path.exists(os.path.join(package_folder, CONANINFO))) # test pack folder self.assertTrue(os.path.exists(package_folder)) def exist(rel_path): return os.path.exists(os.path.join(package_folder, rel_path)) # Expected files self.assertTrue(exist("include/lib1.h")) self.assertTrue(exist("include/lib2.h")) self.assertTrue(exist("include/physics/lib.hpp")) self.assertTrue(exist("include/contrib/math/math.h")) self.assertTrue(exist("include/contrib/physics/gravity.h")) self.assertTrue(exist("include/contrib/contrib.h")) self.assertTrue(exist("include/opencv/opencv.hpp")) self.assertTrue(exist("include/opencv2/opencv2.hpp")) self.assertTrue(exist("include/opencv2/simu/simu.hpp")) self.assertTrue(exist("include/opencv2/3D/3D.hpp")) self.assertTrue(exist("include/opencv2/dev/dev.hpp")) self.assertTrue(exist("lib/my_lib/libd.a")) self.assertTrue(exist("res/shares/readme.txt")) # Not expected files self.assertFalse(exist("include/opencv2/opencv_mod.hpp")) self.assertFalse(exist("include/opencv2/simu.hpp")) self.assertFalse(exist("include/opencv2/3D.hpp")) self.assertFalse(exist("include/opencv2/dev.hpp")) self.assertFalse(exist("include/modules/simu/src/simu.cpp")) self.assertFalse(exist("include/modules/3D/doc/readme.md")) self.assertFalse(exist("include/modules/dev/src/dev.cpp")) self.assertFalse(exist("include/opencv2/opencv_mod.hpp")) self.assertFalse(exist("include/include/no_copy/lib0.h")) self.assertFalse(exist("res/my_data/readme.md"))