def run_configure_method(conanfile, down_options, down_ref, ref): """ Run all the config-related functions for the given conanfile object """ # Avoid extra time manipulating the sys.path for python with get_env_context_manager(conanfile, without_python=True): if hasattr(conanfile, "config"): conan_v2_behavior("config() has been deprecated. " "Use config_options() and configure()", v1_behavior=conanfile.output.warn) 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, ref) 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() _validate_fpic(conanfile)
def write_toolchain(conanfile, path, output): if hasattr(conanfile, "toolchain"): msg = ("\n*****************************************************************\n" "******************************************************************\n" "The 'toolchain' attribute or method has been deprecated.\n" "It will be removed in next Conan release.\n" "Use 'generators = \"ClassName\"' or 'generate()' method instead.\n" "********************************************************************\n" "********************************************************************\n") output.warn(msg) warnings.warn(msg) output.highlight("Generating toolchain files") if callable(conanfile.toolchain): # This is the toolchain with chdir(path): with conanfile_exception_formatter(str(conanfile), "toolchain"): conanfile.toolchain() else: try: toolchain = {"cmake": CMakeToolchain}[conanfile.toolchain] except KeyError: raise ConanException("Unknown toolchain '%s'" % conanfile.toolchain) tc = toolchain(conanfile) with chdir(path): tc.generate() # TODO: Lets discuss what to do with the environment if hasattr(conanfile, "generate"): output.highlight("Calling generate()") with chdir(path): with conanfile_exception_formatter(str(conanfile), "generate"): conanfile.generate()
def load_consumer_conanfile(self, conanfile_path, info_folder, deps_info_required=False, test=False): """loads a conanfile for local flow: source, imports, package, build """ try: graph_info = GraphInfo.load(info_folder) graph_lock_file = GraphLockFile.load( info_folder, self._cache.config.revisions_enabled) graph_lock = graph_lock_file.graph_lock self._output.info( "Using lockfile: '{}/conan.lock'".format(info_folder)) profile_host = graph_lock_file.profile_host self._output.info("Using cached profile from lockfile") except IOError: # Only if file is missing graph_lock = None # This is very dirty, should be removed for Conan 2.0 (source() method only) profile_host = self._cache.default_profile profile_host.process_settings(self._cache) name, version, user, channel = None, None, None, None else: name, version, user, channel, _ = graph_info.root profile_host.process_settings(self._cache, preprocess=False) # This is the hack of recovering the options from the graph_info profile_host.options.update(graph_info.options) if conanfile_path.endswith(".py"): lock_python_requires = None if graph_lock and not test: # Only lock python requires if it is not test_package node_id = graph_lock.get_node(graph_info.root) lock_python_requires = graph_lock.python_requires(node_id) conanfile = self._loader.load_consumer( conanfile_path, profile_host=profile_host, name=name, version=version, user=user, channel=channel, lock_python_requires=lock_python_requires) if test: conanfile.display_name = "%s (test package)" % str(test) conanfile.output.scope = conanfile.display_name with get_env_context_manager(conanfile, without_python=True): with conanfile_exception_formatter(str(conanfile), "config_options"): conanfile.config_options() with conanfile_exception_formatter(str(conanfile), "configure"): conanfile.configure() conanfile.settings.validate() # All has to be ok! conanfile.options.validate() else: conanfile = self._loader.load_conanfile_txt( conanfile_path, profile_host) load_deps_info(info_folder, conanfile, required=deps_info_required) return conanfile
def load_named(self, conanfile_path, name, version, user, channel, lock_python_requires=None): """ loads the basic conanfile object and evaluates its name and version """ conanfile, _ = self.load_basic_module(conanfile_path, lock_python_requires, user, channel) conanfile.recipe_folder = os.path.dirname(conanfile_path) if hasattr(conanfile, "set_name"): if conanfile.name: raise ConanException("Conanfile defined package 'name', set_name() redundant") with conanfile_exception_formatter("conanfile.py", "set_name"): conanfile.set_name() if hasattr(conanfile, "set_version"): if conanfile.version: raise ConanException("Conanfile defined package 'version', set_version() redundant") with conanfile_exception_formatter("conanfile.py", "set_version"): conanfile.set_version() # Make sure this is nowhere else available del conanfile.recipe_folder # Export does a check on existing name & version if name: if conanfile.name and name != conanfile.name: raise ConanException("Package recipe with name %s!=%s" % (name, conanfile.name)) conanfile.name = name if version: if conanfile.version and version != conanfile.version: raise ConanException("Package recipe with version %s!=%s" % (version, conanfile.version)) conanfile.version = version return conanfile
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(conanfile, 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() warn = recipe_has(conanfile, "package") conanfile.copy.report(package_output, warn=warn) conanfile.copy = FileCopier(build_folder, package_folder) with tools.chdir(build_folder): with conanfile_exception_formatter(str(conanfile), "package"): conanfile.package() warn = recipe_has(conanfile, "build") and recipe_has( conanfile, "package") conanfile.copy.report(package_output, warn=warn) 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 run_configure_method(conanfile, down_options, down_ref, ref): """ Run all the config-related functions for the given conanfile object """ # Avoid extra time manipulating the sys.path for python with get_env_context_manager(conanfile, without_python=True): if hasattr(conanfile, "config"): conan_v2_error("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, ref) 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() # Recipe provides its own name if nothing else is defined conanfile.provides = make_tuple(conanfile.provides or conanfile.name) if conanfile.deprecated: from six import string_types message = "Recipe '%s' is deprecated" % conanfile.display_name if isinstance(conanfile.deprecated, string_types): message += " in favor of '%s'" % conanfile.deprecated message += ". Please, consider changing your requirements." conanfile.output.warn(message)
def load_named(self, conanfile_path, name, version, user, channel, lock_python_requires=None): """ loads the basic conanfile object and evaluates its name and version """ conanfile, _ = self.load_basic_module(conanfile_path, lock_python_requires, user, channel) # Export does a check on existing name & version if name: if conanfile.name and name != conanfile.name: raise ConanException("Package recipe with name %s!=%s" % (name, conanfile.name)) conanfile.name = name if version: if conanfile.version and version != conanfile.version: raise ConanException("Package recipe with version %s!=%s" % (version, conanfile.version)) conanfile.version = version if hasattr(conanfile, "set_name"): with conanfile_exception_formatter("conanfile.py", "set_name"): conanfile.set_name() if name and name != conanfile.name: raise ConanException("Package recipe with name %s!=%s" % (name, conanfile.name)) if hasattr(conanfile, "set_version"): with conanfile_exception_formatter("conanfile.py", "set_version"): conanfile.set_version() if version and version != conanfile.version: raise ConanException("Package recipe with version %s!=%s" % (version, conanfile.version)) return conanfile
def build(self, conanfile_path, source_folder, build_folder, package_folder, install_folder, test=False): """ 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 try: mkdir(build_folder) os.chdir(build_folder) conan_file.conanfile_directory = source_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 environment_append(conan_file.env): 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 _config_node(self, graph, node, down_reqs, down_ref, down_options): """ 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, ref = node.conanfile, node.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 ref: conanfile.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, ref) 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 graph.aliased: for req in conanfile.requires.values(): req.ref = graph.aliased.get(req.ref, req.ref) new_down_reqs = conanfile.requires.update(down_reqs, self._output, ref, down_ref) except ConanExceptionInUserConanfileMethod: raise except ConanException as e: raise ConanException("%s: %s" % (ref or "Conanfile", str(e))) except Exception as e: raise ConanException(e) return new_down_reqs, new_options
def _compute_package_id(self, node, default_package_id_mode, default_python_requires_id_mode): """ Compute the binary package ID of this node :param node: the node to compute the package-ID :param default_package_id_mode: configuration of the package-ID mode """ # TODO Conan 2.0. To separate the propagation of the graph (options) of the package-ID # A bit risky to be done now conanfile = node.conanfile neighbors = node.neighbors() direct_reqs, indirect_reqs = self.package_id_transitive_reqs(node) # FIXME: Conan v2.0 This is introducing a bug for backwards compatibility, it will add # only the requirements available in the 'neighbour.info' object, not all the closure if not self._fixed_package_id: old_indirect = set() for neighbor in neighbors: old_indirect.update( (p.ref, p.id) for p in neighbor.conanfile.info.requires.refs()) indirect_reqs = set(p for p in indirect_reqs if (p.ref, p.id) in old_indirect) indirect_reqs.difference_update(direct_reqs) python_requires = getattr(conanfile, "python_requires", None) if python_requires: if isinstance(python_requires, dict): python_requires = None # Legacy python-requires do not change package-ID else: python_requires = python_requires.all_refs() conanfile.info = ConanInfo.create( conanfile.settings.values, conanfile.options.values, direct_reqs, indirect_reqs, default_package_id_mode=default_package_id_mode, python_requires=python_requires, default_python_requires_id_mode=default_python_requires_id_mode) # Once we are done, call package_id() to narrow and change possible values with conanfile_exception_formatter(str(conanfile), "package_id"): with conan_v2_property( conanfile, 'cpp_info', "'self.cpp_info' access in package_id() method is deprecated" ): conanfile.package_id() if hasattr(conanfile, "validate") and callable(conanfile.validate): with conanfile_exception_formatter(str(conanfile), "validate"): try: conanfile.validate() except ConanInvalidConfiguration as e: conanfile.info.invalid = str(e) info = conanfile.info node.package_id = info.package_id()
def create_package(conanfile, source_folder, build_folder, package_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)) def wrap(dst_folder): def new_method(pattern, src=""): conanfile.copy(pattern, dst_folder, src) return new_method # FIXME: Deprecate these methods. Not documented. Confusing. Rely on LINTER conanfile.copy_headers = wrap(DEFAULT_INCLUDE) conanfile.copy_libs = wrap(DEFAULT_LIB) conanfile.copy_bins = wrap(DEFAULT_BIN) conanfile.copy_res = wrap(DEFAULT_RES) try: package_output = ScopedOutput("%s package()" % output.scope, output) output.highlight("Calling package()") if source_folder != build_folder: conanfile.copy = FileCopier(source_folder, package_folder, build_folder) with conanfile_exception_formatter(str(conanfile), "package"): conanfile.package() conanfile.copy.report(package_output, warn=True) conanfile.copy = FileCopier(build_folder, package_folder) with conanfile_exception_formatter(str(conanfile), "package"): conanfile.package() conanfile.copy.report(package_output, warn=True) 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(build_folder, package_folder, conanfile, copy_info) output.success("Package '%s' created" % os.path.basename(package_folder))
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 build(graph_manager, hook_manager, conanfile_path, source_folder, build_folder, package_folder, install_folder, test=False, should_configure=True, should_build=True, should_install=True, should_test=True): """ Call to build() method saved on the conanfile.py param conanfile_path: path to a conanfile.py """ logger.debug("BUILD: folder '%s'" % build_folder) logger.debug("BUILD: Conanfile at '%s'" % conanfile_path) try: conan_file = graph_manager.load_consumer_conanfile(conanfile_path, install_folder, deps_info_required=True, test=test) 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_ref(test) except ConanException: pass conan_file.should_configure = should_configure conan_file.should_build = should_build conan_file.should_install = should_install conan_file.should_test = should_test 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 hook_manager.execute("pre_build", conanfile=conan_file, conanfile_path=conanfile_path) with get_env_context_manager(conan_file): conan_file.output.highlight("Running build()") with conanfile_exception_formatter(str(conan_file), "build"): conan_file.build() hook_manager.execute("post_build", conanfile=conan_file, conanfile_path=conanfile_path) if test: conan_file.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 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 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()") 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() conanfile.copy = FileCopier(build_folder, package_folder) with tools.chdir(build_folder): with conanfile_exception_formatter(str(conanfile), "package"): 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) _create_aux_files(install_folder, package_folder, conanfile, copy_info) _report_files_from_manifest(package_output, package_folder) package_id = package_id or os.path.basename(package_folder) output.success("Package '%s' created" % package_id) hook_manager.execute("post_package", conanfile=conanfile, conanfile_path=conanfile_path, reference=ref, package_id=package_id)
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 load_basic_module(self, conanfile_path, lock_python_requires=None, user=None, channel=None, display=""): """ loads a conanfile basic object without evaluating anything, returns the module too """ cached = self._cached_conanfile_classes.get(conanfile_path) if cached and cached[1] == lock_python_requires: conanfile = cached[0](self._output, self._runner, display, user, channel, self._requester) if hasattr(conanfile, "init") and callable(conanfile.init): with conanfile_exception_formatter(str(conanfile), "init"): conanfile.init() return conanfile, cached[2] if lock_python_requires is not None: self._python_requires.locked_versions = {r.name: r for r in lock_python_requires} try: self._python_requires.valid = True module, conanfile = parse_conanfile(conanfile_path, self._python_requires, self._generator_manager) self._python_requires.valid = False self._python_requires.locked_versions = None # This is the new py_requires feature, to supersede the old python_requires if self._pyreq_loader: self._pyreq_loader.load_py_requires(conanfile, lock_python_requires, self) conanfile.recipe_folder = os.path.dirname(conanfile_path) # If the scm is inherited, create my own instance if hasattr(conanfile, "scm") and "scm" not in conanfile.__class__.__dict__: if isinstance(conanfile.scm, dict): conanfile.scm = conanfile.scm.copy() # Load and populate dynamic fields from the data file conan_data = self._load_data(conanfile_path) conanfile.conan_data = conan_data if conan_data and '.conan' in conan_data: scm_data = conan_data['.conan'].get('scm') if scm_data: conanfile.scm.update(scm_data) self._cached_conanfile_classes[conanfile_path] = (conanfile, lock_python_requires, module) result = conanfile(self._output, self._runner, display, user, channel, self._requester) if hasattr(result, "init") and callable(result.init): with conanfile_exception_formatter(str(result), "init"): result.init() return result, module except ConanException as e: raise ConanException("Error loading conanfile at '{}': {}".format(conanfile_path, e))
def _call_package_info(conanfile, package_folder): conanfile.cpp_info = CppInfo(package_folder) conanfile.cpp_info.version = conanfile.version conanfile.cpp_info.description = conanfile.description conanfile.env_info = EnvInfo() conanfile.user_info = UserInfo() # Get deps_cpp_info from upstream nodes public_deps = [ name for name, req in conanfile.requires.items() if not req.private ] conanfile.cpp_info.public_deps = public_deps # Once the node is build, execute package info, so it has access to the # package folder and artifacts with pythonpath( conanfile ): # Minimal pythonpath, not the whole context, make it 50% slower with tools.chdir(package_folder): with conanfile_exception_formatter(str(conanfile), "package_info"): conanfile.package_folder = package_folder conanfile.source_folder = None conanfile.build_folder = None conanfile.install_folder = None conanfile.package_info()
def _compute_package_id(node, default_package_id_mode): conanfile = node.conanfile neighbors = node.neighbors() direct_reqs = [] # of PackageReference indirect_reqs = set() # of PackageReference, avoid duplicates for neighbor in neighbors: ref, nconan = neighbor.ref, neighbor.conanfile direct_reqs.append(neighbor.pref) indirect_reqs.update(nconan.info.requires.refs()) conanfile.options.propagate_downstream(ref, nconan.info.full_options) # Might be never used, but update original requirement, just in case conanfile.requires[ref.name].ref = ref # Make sure not duplicated indirect_reqs.difference_update(direct_reqs) # There might be options that are not upstream, backup them, might be # for build-requires conanfile.build_requires_options = conanfile.options.values conanfile.options.clear_unused(indirect_reqs.union(direct_reqs)) conanfile.options.freeze() conanfile.info = ConanInfo.create( conanfile.settings.values, conanfile.options.values, direct_reqs, indirect_reqs, default_package_id_mode=default_package_id_mode) # Once we are done, call package_id() to narrow and change possible values with conanfile_exception_formatter(str(conanfile), "package_id"): conanfile.package_id() info = conanfile.info node.package_id = info.package_id()
def write_toolchain(conanfile, path, output): if hasattr(conanfile, "toolchain"): msg = ( "\n*****************************************************************\n" "******************************************************************\n" "The 'toolchain' attribute or method has been deprecated and removed\n" "Use 'generators = \"ClassName\"' or 'generate()' method instead.\n" "********************************************************************\n" "********************************************************************\n" ) raise ConanException(msg) _receive_conf(conanfile) if hasattr(conanfile, "generate"): output.highlight("Calling generate()") mkdir(path) with chdir(path): with conanfile_exception_formatter(str(conanfile), "generate"): conanfile.generate() # tools.env.virtualenv:auto_use will be always True in Conan 2.0 if conanfile.conf["tools.env.virtualenv:auto_use"] and conanfile.virtualenv: with chdir(path): from conan.tools.env.virtualbuildenv import VirtualBuildEnv env = VirtualBuildEnv(conanfile) env.generate() env = VirtualRunEnv(conanfile) env.generate() output.highlight("Aggregating env generators") _generate_aggregated_env(conanfile)
def compute_package_ids(self): ordered = self.by_levels() for level in ordered: for node in level: conanfile = node.conanfile neighbors = node.neighbors() direct_reqs = [] # of PackageReference indirect_reqs = set() # of PackageReference, avoid duplicates for neighbor in neighbors: nref, nconan = neighbor.conan_ref, neighbor.conanfile package_id = nconan.info.package_id() package_reference = PackageReference(nref, package_id) direct_reqs.append(package_reference) indirect_reqs.update(nconan.info.requires.refs()) conanfile.options.propagate_downstream(nref, nconan.info.full_options) # Might be never used, but update original requirement, just in case conanfile.requires[nref.name].conan_reference = nref # Make sure not duplicated indirect_reqs.difference_update(direct_reqs) # There might be options that are not upstream, backup them, might be # for build-requires conanfile.build_requires_options = conanfile.options.values conanfile.options.clear_unused(indirect_reqs.union(direct_reqs)) conanfile.info = ConanInfo.create(conanfile.settings.values, conanfile.options.values, direct_reqs, indirect_reqs) # Once we are done, call package_id() to narrow and change possible values with conanfile_exception_formatter(str(conanfile), "package_id"): conanfile.package_id() return ordered
def config_source_local(dest_dir, conan_file, conanfile_folder, output): output.info('Configuring sources in %s' % dest_dir) conan_file.source_folder = dest_dir with tools.chdir(dest_dir): try: with conanfile_exception_formatter(str(conan_file), "source"): with get_env_context_manager(conan_file): conan_file.build_folder = None conan_file.package_folder = None scm = get_scm(conan_file, dest_dir) if scm: if scm.capture_origin or scm.capture_revision: output.info("Getting sources from folder: %s" % conanfile_folder) merge_directories(conanfile_folder, dest_dir) _clean_source_folder(dest_dir) else: output.info("Getting sources from url: '%s'" % scm.url) scm.clone() scm.checkout() conan_file.source() except ConanExceptionInUserConanfileMethod: raise except Exception as e: raise ConanException(e)
def _build(self, conanfile, pref, build_folder): # Read generators from conanfile and generate the needed files logger.info("GENERATORS: Writing generators") write_generators(conanfile, build_folder, self._output) # Build step might need DLLs, binaries as protoc to generate source files # So execute imports() before build, storing the list of copied_files copied_files = run_imports(conanfile, build_folder) try: self._hook_manager.execute("pre_build", conanfile=conanfile, reference=pref.ref, package_id=pref.id) logger.debug("Call conanfile.build() with files in build folder: %s", os.listdir(build_folder)) self._output.highlight("Calling build()") with conanfile_exception_formatter(str(conanfile), "build"): conanfile.build() self._output.success("Package '%s' built" % pref.id) self._output.info("Build folder %s" % build_folder) self._hook_manager.execute("post_build", conanfile=conanfile, reference=pref.ref, package_id=pref.id) except Exception as exc: self._output.writeln("") self._output.error("Package '%s' build failed" % pref.id) self._output.warn("Build folder %s" % build_folder) if isinstance(exc, ConanExceptionInUserConanfileMethod): raise exc raise ConanException(exc) finally: # Now remove all files that were imported with imports() remove_imports(conanfile, copied_files, self._output)
def _run_source(conanfile, conanfile_path, src_folder, hook_manager, reference, cache, get_sources_from_exports): """Execute the source core functionality, both for local cache and user space, in order: - Calling pre_source hook - Getting sources from SCM - Getting sources from exported folders in the local cache - Clean potential TGZ and other files in the local cache - Executing the recipe source() method - Calling post_source hook """ conanfile.source_folder = src_folder conanfile.build_folder = None conanfile.package_folder = None with tools.chdir(src_folder): try: with get_env_context_manager(conanfile): hook_manager.execute("pre_source", conanfile=conanfile, conanfile_path=conanfile_path, reference=reference) output = conanfile.output output.info('Configuring sources in %s' % src_folder) get_sources_from_exports() if cache: _clean_source_folder(src_folder) # TODO: Why is it needed in cache? with conanfile_exception_formatter(conanfile.display_name, "source"): conanfile.source() hook_manager.execute("post_source", conanfile=conanfile, conanfile_path=conanfile_path, reference=reference) except ConanExceptionInUserConanfileMethod: raise except Exception as e: raise ConanException(e)
def _build_package(self): """ 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. Receives the build_folder because it can change if the method build_id() exists """ package_folder = self._client_cache.package( self._package_reference, self._conan_file.short_paths) os.chdir(self.build_folder) self._conan_file.build_folder = self.build_folder self._conan_file.conanfile_directory = self.build_folder self._conan_file.package_folder = package_folder # In local cache, install folder always is build_folder self._conan_file.install_folder = self.build_folder # Read generators from conanfile and generate the needed files logger.debug("Writing generators") write_generators(self._conan_file, self.build_folder, self._out) logger.debug("Files copied after generators %s", os.listdir(self.build_folder)) # 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 run_imports copied_files = run_imports(self._conan_file, self.build_folder, self._out) try: # This is necessary because it is different for user projects # than for packages logger.debug( "Call conanfile.build() with files in build folder: %s", os.listdir(self.build_folder)) self._out.highlight("Calling build()") with conanfile_exception_formatter(str(self._conan_file), "build"): self._conan_file.build() self._out.success("Package '%s' built" % self._conan_file.info.package_id()) self._out.info("Build folder %s" % self.build_folder) except Exception as exc: self._out.writeln("") self._out.error("Package '%s' build failed" % self._conan_file.info.package_id()) self._out.warn("Build folder %s" % self.build_folder) if isinstance(exc, ConanExceptionInUserConanfileMethod): raise exc raise ConanException(exc) finally: export_folder = self._client_cache.export(self._conan_ref) self._conan_file.conanfile_directory = export_folder # Now remove all files that were imported with imports() for f in copied_files: try: if f.startswith(self.build_folder): os.remove(f) except OSError: self._out.warn( "Unable to remove imported file from build: %s" % f)
def config_source_local(dest_dir, conanfile, conanfile_folder, output, conanfile_path, hook_manager): conanfile.source_folder = dest_dir conanfile.build_folder = None conanfile.package_folder = None with tools.chdir(dest_dir): try: with conanfile_exception_formatter(str(conanfile), "source"): with get_env_context_manager(conanfile): hook_manager.execute("pre_source", conanfile=conanfile, conanfile_path=conanfile_path) output.info('Configuring sources in %s' % dest_dir) scm_data = get_scm_data(conanfile) if scm_data: dest_dir = os.path.join(dest_dir, scm_data.subfolder) capture = scm_data.capture_origin or scm_data.capture_revision local_sources_path = conanfile_folder if capture else None _fetch_scm(scm_data, dest_dir, local_sources_path, output) conanfile.source() hook_manager.execute("post_source", conanfile=conanfile, conanfile_path=conanfile_path) except ConanExceptionInUserConanfileMethod: raise except Exception as e: raise ConanException(e)
def _compute_package_id(node, default_package_id_mode): """ Compute the binary package ID of this node :param node: the node to compute the package-ID :param default_package_id_mode: configuration of the package-ID mode """ # TODO Conan 2.0. To separate the propagation of the graph (options) of the package-ID # A bit risky to be done now conanfile = node.conanfile neighbors = node.neighbors() direct_reqs = [] # of PackageReference indirect_reqs = set() # of PackageReference, avoid duplicates for neighbor in neighbors: ref, nconan = neighbor.ref, neighbor.conanfile direct_reqs.append(neighbor.pref) indirect_reqs.update(nconan.info.requires.refs()) # Make sure not duplicated indirect_reqs.difference_update(direct_reqs) conanfile.info = ConanInfo.create( conanfile.settings.values, conanfile.options.values, direct_reqs, indirect_reqs, default_package_id_mode=default_package_id_mode) # Once we are done, call package_id() to narrow and change possible values with conanfile_exception_formatter(str(conanfile), "package_id"): conanfile.package_id() info = conanfile.info node.package_id = info.package_id()
def _call_package(conanfile, package_id, source_folder, build_folder, package_folder, install_folder, hook_manager, conanfile_path, ref, copy_info): output = conanfile.output hook_manager.execute("pre_package", conanfile=conanfile, conanfile_path=conanfile_path, reference=ref, package_id=package_id) 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): with conan_v2_property(conanfile, 'info', "'self.info' access in package() method is deprecated"): conanfile.package() 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) package_output = ScopedOutput("%s package()" % output.scope, output) 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 _call_package_info(self, conanfile, package_folder, ref): conanfile.cpp_info = CppInfo(conanfile.name, package_folder) conanfile.cpp_info.version = conanfile.version conanfile.cpp_info.description = conanfile.description conanfile.env_info = EnvInfo() conanfile.user_info = UserInfo() # Get deps_cpp_info from upstream nodes public_deps = [name for name, req in conanfile.requires.items() if not req.private and not req.override] conanfile.cpp_info.public_deps = public_deps # Once the node is build, execute package info, so it has access to the # package folder and artifacts conan_v2 = get_env(CONAN_V2_MODE_ENVVAR, False) with pythonpath(conanfile) if not conan_v2 else no_op(): # Minimal pythonpath, not the whole context, make it 50% slower with tools.chdir(package_folder): with conanfile_exception_formatter(str(conanfile), "package_info"): conanfile.package_folder = package_folder conanfile.source_folder = None conanfile.build_folder = None conanfile.install_folder = None self._hook_manager.execute("pre_package_info", conanfile=conanfile, reference=ref) conanfile.package_info() if conanfile._conan_dep_cpp_info is None: try: conanfile.cpp_info._raise_incorrect_components_definition( conanfile.name, conanfile.requires) except ConanException as e: raise ConanException("%s package_info(): %s" % (str(conanfile), e)) conanfile._conan_dep_cpp_info = DepCppInfo(conanfile.cpp_info) self._hook_manager.execute("post_package_info", conanfile=conanfile, reference=ref)
def load_consumer_conanfile(self, conanfile_path, info_folder, deps_info_required=False, test=None): """loads a conanfile for local flow: source, imports, package, build """ try: graph_info = GraphInfo.load(info_folder) except IOError: # Only if file is missing # This is very dirty, should be removed for Conan 2.0 (source() method only) profile = self._cache.default_profile profile.process_settings(self._cache) name, version, user, channel = None, None, None, None else: name, version, user, channel, _ = graph_info.root profile = graph_info.profile profile.process_settings(self._cache, preprocess=False) # This is the hack of recovering the options from the graph_info profile.options.update(graph_info.options) processed_profile = ProcessedProfile(profile, None) if conanfile_path.endswith(".py"): conanfile = self._loader.load_consumer( conanfile_path, processed_profile=processed_profile, test=test, name=name, version=version, user=user, channel=channel) with get_env_context_manager(conanfile, without_python=True): with conanfile_exception_formatter(str(conanfile), "config_options"): conanfile.config_options() with conanfile_exception_formatter(str(conanfile), "configure"): conanfile.configure() conanfile.settings.validate() # All has to be ok! conanfile.options.validate() else: conanfile = self._loader.load_conanfile_txt( conanfile_path, processed_profile) load_deps_info(info_folder, conanfile, required=deps_info_required) return conanfile
def _get_recipe_build_requires(conanfile): conanfile.build_requires = _RecipeBuildRequires(conanfile) if hasattr(conanfile, "build_requirements"): with get_env_context_manager(conanfile): with conanfile_exception_formatter(str(conanfile), "build_requirements"): conanfile.build_requirements() return conanfile.build_requires
def _get_recipe_build_requires(conanfile): conanfile.build_requires = _RecipeBuildRequires(conanfile) if hasattr(conanfile, "build_requirements"): with get_env_context_manager(conanfile): with conanfile_exception_formatter(str(conanfile), "build_requirements"): conanfile.build_requirements() return conanfile.build_requires
def _compute_package_id(self, node, default_package_id_mode, default_python_requires_id_mode): """ Compute the binary package ID of this node :param node: the node to compute the package-ID :param default_package_id_mode: configuration of the package-ID mode """ # TODO Conan 2.0. To separate the propagation of the graph (options) of the package-ID # A bit risky to be done now conanfile = node.conanfile neighbors = node.neighbors() if not self._fixed_package_id: direct_reqs = [] # of PackageReference indirect_reqs = set() # of PackageReference, avoid duplicates for neighbor in neighbors: ref, nconan = neighbor.ref, neighbor.conanfile direct_reqs.append(neighbor.pref) indirect_reqs.update(nconan.info.requires.refs()) # Make sure not duplicated indirect_reqs.difference_update(direct_reqs) else: node.id_direct_prefs = set() # of PackageReference node.id_indirect_prefs = set( ) # of PackageReference, avoid duplicates for neighbor in neighbors: node.id_direct_prefs.add(neighbor.pref) node.id_indirect_prefs.update(neighbor.id_direct_prefs) node.id_indirect_prefs.update(neighbor.id_indirect_prefs) # Make sure not duplicated, totally necessary node.id_indirect_prefs.difference_update(node.id_direct_prefs) direct_reqs = node.id_direct_prefs indirect_reqs = node.id_indirect_prefs python_requires = getattr(conanfile, "python_requires", None) if python_requires: if isinstance(python_requires, dict): python_requires = None # Legacy python-requires do not change package-ID else: python_requires = python_requires.all_refs() conanfile.info = ConanInfo.create( conanfile.settings.values, conanfile.options.values, direct_reqs, indirect_reqs, default_package_id_mode=default_package_id_mode, python_requires=python_requires, default_python_requires_id_mode=default_python_requires_id_mode) # Once we are done, call package_id() to narrow and change possible values with conanfile_exception_formatter(str(conanfile), "package_id"): with conan_v2_property( conanfile, 'cpp_info', "'self.cpp_info' access in package_id() method is deprecated" ): conanfile.package_id() info = conanfile.info node.package_id = info.package_id()
def call_package_info(conanfile, package_folder): # Once the node is build, execute package info, so it has access to the # package folder and artifacts with tools.chdir(package_folder): with conanfile_exception_formatter(str(conanfile), "package_info"): conanfile.source_folder = None conanfile.build_folder = None conanfile.install_folder = None conanfile.package_info()
def build_id(conanfile): if hasattr(conanfile, "build_id"): # construct new ConanInfo build_id_info = conanfile.info.copy() conanfile.info_build = build_id_info # effectively call the user function to change the package values with conanfile_exception_formatter(str(conanfile), "build_id"): conanfile.build_id() # compute modified ID return build_id_info.package_id() return None
def config_source_local(dest_dir, conan_file, output): output.info('Configuring sources in %s' % dest_dir) conan_file.source_folder = dest_dir with tools.chdir(dest_dir): try: with conanfile_exception_formatter(str(conan_file), "source"): with get_env_context_manager(conan_file): conan_file.build_folder = None conan_file.package_folder = None conan_file.source() except ConanExceptionInUserConanfileMethod: raise except Exception as e: raise ConanException(e)
def config_source_local(current_path, conan_file, output): output.info('Configuring sources in %s' % current_path) dirty = os.path.join(current_path, DIRTY_FILE) if os.path.exists(dirty): output.warn("Your previous source command failed") save(dirty, "") # Creation of DIRTY flag try: with conanfile_exception_formatter(str(conan_file), "source"): with tools.environment_append(conan_file.env): conan_file.source() os.remove(dirty) # Everything went well, remove DIRTY flag except ConanExceptionInUserConanfileMethod: raise except Exception as e: raise ConanException(e)
def propagate_info(self): """ takes the exports from upper level and updates the imports right now also the imports are propagated, but should be checked E.g. Conan A, depends on B. A=>B B exports an include directory "my_dir", with root "/...../0123efe" A imports are the exports of B, plus any other conans it depends on A.imports.include_dirs = B.export.include_paths. Note the difference, include_paths used to compute full paths as the user defines export relative to its folder """ ordered = self.by_levels() for level in ordered: for node in level: _, conanfile = node neighbors = self._neighbors[node] direct_reqs = [] # of PackageReference indirect_reqs = set() # of PackageReference, avoid duplicates for nref, nconan in neighbors: package_id = nconan.info.package_id() package_reference = PackageReference(nref, package_id) direct_reqs.append(package_reference) indirect_reqs.update(nconan.info.requires.refs()) conanfile.options.propagate_downstream(nref, nconan.info.full_options) # Might be never used, but update original requirement, just in case conanfile.requires[nref.name].conan_reference = nref # Make sure not duplicated indirect_reqs.difference_update(direct_reqs) # There might be options that are not upstream conanfile.options.clear_unused(indirect_reqs.union(direct_reqs)) non_devs = self.non_dev_nodes(node) conanfile.info = ConanInfo.create(conanfile.settings.values, conanfile.options.values, direct_reqs, indirect_reqs, non_devs) # Once we are done, call package_id() to narrow and change possible values if hasattr(conanfile, "conan_info"): # Deprecated in 0.19 conanfile.conan_info() else: with conanfile_exception_formatter(str(conanfile), "package_id"): conanfile.package_id() return ordered
def _call_package_info(conanfile, package_folder): conanfile.cpp_info = CppInfo(package_folder) conanfile.cpp_info.version = conanfile.version conanfile.cpp_info.description = conanfile.description conanfile.env_info = EnvInfo() conanfile.user_info = UserInfo() # Get deps_cpp_info from upstream nodes public_deps = [name for name, req in conanfile.requires.items() if not req.private] conanfile.cpp_info.public_deps = public_deps # Once the node is build, execute package info, so it has access to the # package folder and artifacts with pythonpath(conanfile): # Minimal pythonpath, not the whole context, make it 50% slower with tools.chdir(package_folder): with conanfile_exception_formatter(str(conanfile), "package_info"): conanfile.package_folder = package_folder conanfile.source_folder = None conanfile.build_folder = None conanfile.install_folder = None conanfile.package_info()
def _build_package(self): """ calls the imports + conanfile.build() method """ os.chdir(self.build_folder) self._conan_file.build_folder = self.build_folder self._conan_file.package_folder = self.package_folder # In local cache, install folder always is build_folder self._conan_file.install_folder = self.build_folder # Read generators from conanfile and generate the needed files logger.debug("Writing generators") write_generators(self._conan_file, self.build_folder, self._out) logger.debug("Files copied after generators %s", os.listdir(self.build_folder)) # 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 run_imports copied_files = run_imports(self._conan_file, self.build_folder, self._out) try: # This is necessary because it is different for user projects # than for packages logger.debug("Call conanfile.build() with files in build folder: %s", os.listdir(self.build_folder)) self._out.highlight("Calling build()") with conanfile_exception_formatter(str(self._conan_file), "build"): self._conan_file.build() self._out.success("Package '%s' built" % self._conan_file.info.package_id()) self._out.info("Build folder %s" % self.build_folder) except Exception as exc: self._out.writeln("") self._out.error("Package '%s' build failed" % self._conan_file.info.package_id()) self._out.warn("Build folder %s" % self.build_folder) if isinstance(exc, ConanExceptionInUserConanfileMethod): raise exc raise ConanException(exc) finally: # Now remove all files that were imported with imports() remove_imports(self._conan_file, copied_files, self._out)
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 """ 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)) output.info('Building your package in %s' % 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 if getattr(conan_file, 'no_copy_source', False): mkdir(build_folder) conan_file.source_folder = src_folder else: shutil.copytree(src_folder, build_folder, symlinks=True, ignore=check_max_path_len) logger.debug("Copied to %s" % build_folder) logger.debug("Files copied %s" % os.listdir(build_folder)) conan_file.source_folder = build_folder os.chdir(build_folder) conan_file.build_folder = build_folder conan_file._conanfile_directory = build_folder # Read generators from conanfile and generate the needed files logger.debug("Writing generators") write_generators(conan_file, build_folder, output) logger.debug("Files copied after generators %s" % os.listdir(build_folder)) # 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 run_imports copied_files = run_imports(conan_file, build_folder, output) try: # This is necessary because it is different for user projects # than for packages logger.debug("Call conanfile.build() with files in build folder: %s" % os.listdir(build_folder)) with conanfile_exception_formatter(str(conan_file), "build"): 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 exc: 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) if isinstance(exc, ConanExceptionInUserConanfileMethod): raise exc raise ConanException(exc) 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 config_source(export_folder, src_folder, conan_file, output, force=False): """ creates src folder and retrieve, calling source() from conanfile the necessary source code """ dirty = os.path.join(src_folder, DIRTY_FILE) def remove_source(raise_error=True): output.warn("This can take a while for big packages") try: rmdir(src_folder) except BaseException as e_rm: save(dirty, "") # Creation of DIRTY flag msg = str(e_rm) if six.PY2: msg = str(e_rm).decode("latin1") # Windows prints some chars in latin1 output.error("Unable to remove source folder %s\n%s" % (src_folder, msg)) output.warn("**** Please delete it manually ****") if raise_error or isinstance(e_rm, KeyboardInterrupt): raise ConanException("Unable to remove source folder") if force: output.warn("Forced removal of source folder") remove_source() elif os.path.exists(dirty): output.warn("Trying to remove dirty source folder") remove_source() elif conan_file.build_policy_always: output.warn("Detected build_policy 'always', trying to remove source folder") remove_source() if not os.path.exists(src_folder): output.info('Configuring sources in %s' % src_folder) shutil.copytree(export_folder, src_folder, symlinks=True) # Now move the export-sources to the right location source_sources_folder = os.path.join(src_folder, EXPORT_SOURCES_DIR) if os.path.exists(source_sources_folder): _merge_directories(source_sources_folder, src_folder) # finally remove copied folder shutil.rmtree(source_sources_folder) for f in (EXPORT_TGZ_NAME, EXPORT_SOURCES_TGZ_NAME, CONANFILE+"c", CONANFILE+"o"): try: os.remove(os.path.join(src_folder, f)) except OSError: pass try: shutil.rmtree(os.path.join(src_folder, "__pycache__")) except OSError: pass save(dirty, "") # Creation of DIRTY flag os.chdir(src_folder) try: with tools.environment_append(conan_file.env): with conanfile_exception_formatter(str(conan_file), "source"): conan_file.source() os.remove(dirty) # Everything went well, remove DIRTY flag except Exception as e: os.chdir(export_folder) # in case source() fails (user error, typically), remove the src_folder # and raise to interrupt any other processes (build, package) output.warn("Trying to remove dirty source folder") remove_source(raise_error=False) if isinstance(e, ConanExceptionInUserConanfileMethod): raise e raise ConanException(e)
def _package_info_conanfile(self, conan_ref, conan_file): # Once the node is build, execute package info, so it has access to the # package folder and artifacts with conanfile_exception_formatter(str(conan_file), "package_info"): conan_file.package_info()