def _download_file(self, url, auth, headers, file_path, try_resume=False): t1 = time.time() if try_resume and file_path and os.path.exists(file_path): range_start = os.path.getsize(file_path) headers = headers.copy() if headers else {} headers["range"] = "bytes={}-".format(range_start) else: range_start = 0 try: response = self._requester.get(url, stream=True, verify=self._verify_ssl, auth=auth, headers=headers) except Exception as exc: raise ConanException("Error downloading file %s: '%s'" % (url, exc)) if not response.ok: if response.status_code == 404: raise NotFoundException("Not found: %s" % url) elif response.status_code == 403: if auth is None or (hasattr(auth, "token") and auth.token is None): # TODO: This is a bit weird, why this conversion? Need to investigate raise AuthenticationException(response_to_str(response)) raise ForbiddenException(response_to_str(response)) elif response.status_code == 401: raise AuthenticationException() raise ConanException("Error %d downloading file %s" % (response.status_code, url)) def read_response(size): for chunk in response.iter_content(size): yield chunk def write_chunks(chunks, path): ret = None downloaded_size = range_start if path: mkdir(os.path.dirname(path)) mode = "ab" if range_start else "wb" with open(path, mode) as file_handler: for chunk in chunks: assert ((six.PY3 and isinstance(chunk, bytes)) or (six.PY2 and isinstance(chunk, str))) file_handler.write(chunk) downloaded_size += len(chunk) else: ret_data = bytearray() for chunk in chunks: ret_data.extend(chunk) downloaded_size += len(chunk) ret = bytes(ret_data) return ret, downloaded_size def get_total_length(): if range_start: content_range = response.headers.get("Content-Range", "") match = re.match(r"^bytes (\d+)-(\d+)/(\d+)", content_range) if not match or range_start != int(match.group(1)): raise ConanException("Error in resumed download from %s\n" "Incorrect Content-Range header %s" % (url, content_range)) return int(match.group(3)) else: total_size = response.headers.get('Content-Length') or len( response.content) return int(total_size) try: logger.debug("DOWNLOAD: %s" % url) total_length = get_total_length() action = "Downloading" if range_start == 0 else "Continuing download of" description = "{} {}".format( action, os.path.basename(file_path)) if file_path else None progress = progress_bar.Progress(total_length, self._output, description) progress.initial_value(range_start) chunk_size = 1024 if not file_path else 1024 * 100 written_chunks, total_downloaded_size = write_chunks( progress.update(read_response(chunk_size)), file_path) gzip = (response.headers.get("content-encoding") == "gzip") response.close() # it seems that if gzip we don't know the size, cannot resume and shouldn't raise if total_downloaded_size != total_length and not gzip: if (file_path and total_length > total_downloaded_size > range_start and response.headers.get("Accept-Ranges") == "bytes"): written_chunks = self._download_file(url, auth, headers, file_path, try_resume=True) else: raise ConanException( "Transfer interrupted before complete: %s < %s" % (total_downloaded_size, total_length)) duration = time.time() - t1 log_download(url, duration) return written_chunks except Exception as e: logger.debug(e.__class__) logger.debug(traceback.format_exc()) # If this part failed, it means problems with the connection to server raise ConanConnectionError( "Download failed, check server, possibly try again\n%s" % str(e))
def _check_field(self, field): if field not in self._data: raise ConanException( undefined_field(self._name, field, self.fields, self._parent_value))
def test(self, args=None, build_dir=None, target=None): if isinstance(args, ConanFile): raise ConanException(deprecated_conanfile_param_message) if not target: target = "RUN_TESTS" if self._compiler == "Visual Studio" else "test" self._build_new(args=args, build_dir=build_dir, target=target)
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 value(self, v): v = str(v) if self._definition != "ANY" and v not in self._definition: raise ConanException( bad_value_msg(self._name, v, self.values_range)) self._value = v
def patch(base_path=None, patch_file=None, patch_string=None, strip=0, output=None): """Applies a diff from file (patch_file) or string (patch_string) in base_path directory or current dir if None""" class PatchLogHandler(logging.Handler): def __init__(self): logging.Handler.__init__(self, logging.DEBUG) self.output = output or ConanOutput(sys.stdout, True) self.patchname = patch_file if patch_file else "patch" def emit(self, record): logstr = self.format(record) if record.levelno == logging.WARN: self.output.warn("%s: %s" % (self.patchname, logstr)) else: self.output.info("%s: %s" % (self.patchname, logstr)) patchlog = logging.getLogger("patch") if patchlog: patchlog.handlers = [] patchlog.addHandler(PatchLogHandler()) if not patch_file and not patch_string: return if patch_file: patchset = fromfile(patch_file) else: patchset = fromstring(patch_string.encode()) if not patchset: raise ConanException("Failed to parse patch: %s" % (patch_file if patch_file else "string")) # account for new and deleted files, upstream dep won't fix them items = [] for p in patchset: source = p.source.decode("utf-8") if source.startswith("a/"): source = source[2:] target = p.target.decode("utf-8") if target.startswith("b/"): target = target[2:] if "dev/null" in source: if base_path: target = os.path.join(base_path, target) hunks = [s.decode("utf-8") for s in p.hunks[0].text] new_file = "".join(hunk[1:] for hunk in hunks) save(target, new_file) elif "dev/null" in target: if base_path: source = os.path.join(base_path, source) os.unlink(source) else: items.append(p) patchset.items = items if not patchset.apply(root=base_path, strip=strip): raise ConanException("Failed to apply patch: %s" % patch_file)
def patch_config_paths(self): """ changes references to the absolute path of the installed package and its dependencies in exported cmake config files to the appropriate conan variable. This makes most (sensible) cmake config files portable. For example, if a package foo installs a file called "fooConfig.cmake" to be used by cmake's find_package method, normally this file will contain absolute paths to the installed package folder, for example it will contain a line such as: SET(Foo_INSTALL_DIR /home/developer/.conan/data/Foo/1.0.0/...) This will cause cmake find_package() method to fail when someone else installs the package via conan. This function will replace such mentions to SET(Foo_INSTALL_DIR ${CONAN_FOO_ROOT}) which is a variable that is set by conanbuildinfo.cmake, so that find_package() now correctly works on this conan package. For dependent packages, if a package foo installs a file called "fooConfig.cmake" to be used by cmake's find_package method and if it depends to a package bar, normally this file will contain absolute paths to the bar package folder, for example it will contain a line such as: SET_TARGET_PROPERTIES(foo PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "/home/developer/.conan/data/Bar/1.0.0/user/channel/id/include") This function will replace such mentions to SET_TARGET_PROPERTIES(foo PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${CONAN_BAR_ROOT}/include") If the install() method of the CMake object in the conan file is used, this function should be called _after_ that invocation. For example: def build(self): cmake = CMake(self) cmake.configure() cmake.build() cmake.install() cmake.patch_config_paths() """ if not self._conanfile.should_install: return if not self._conanfile.name: raise ConanException( "cmake.patch_config_paths() can't work without package name. " "Define name in your recipe") pf = self.definitions.get(cmake_install_prefix_var_name) replstr = "${CONAN_%s_ROOT}" % self._conanfile.name.upper() allwalk = chain(walk(self._conanfile.build_folder), walk(self._conanfile.package_folder)) # We don't want warnings printed because there is no replacement of the abs path. # there could be MANY cmake files in the package and the normal thing is to not find # the abs paths _null_out = ConanOutput(StringIO()) for root, _, files in allwalk: for f in files: if f.endswith(".cmake") and not f.startswith("conan"): path = os.path.join(root, f) tools.replace_path_in_file(path, pf, replstr, strict=False, output=_null_out) # patch paths of dependent packages that are found in any cmake files of the # current package for dep in self._conanfile.deps_cpp_info.deps: from_str = self._conanfile.deps_cpp_info[dep].rootpath dep_str = "${CONAN_%s_ROOT}" % dep.upper() ret = tools.replace_path_in_file(path, from_str, dep_str, strict=False, output=_null_out) if ret: self._conanfile.output.info( "Patched paths for %s: %s to %s" % (dep, from_str, dep_str))
def run_in_windows_bash(conanfile, bashcmd, cwd=None, subsystem=None, msys_mingw=True, env=None, with_login=True): """ Will run a unix command inside a bash terminal It requires to have MSYS2, CYGWIN, or WSL """ env = env or {} if platform.system() != "Windows": raise ConanException("Command only for Windows operating system") subsystem = subsystem or OSInfo.detect_windows_subsystem() if not subsystem: raise ConanException( "Cannot recognize the Windows subsystem, install MSYS2/cygwin " "or specify a build_require to apply it.") if subsystem == MSYS2 and msys_mingw: # This needs to be set so that msys2 bash profile will set up the environment correctly. env_vars = { "MSYSTEM": ("MINGW32" if conanfile.settings.get_safe("arch") == "x86" else "MINGW64"), "MSYS2_PATH_TYPE": "inherit" } else: env_vars = {} with environment_append(env_vars): hack_env = "" # In the bash.exe from WSL this trick do not work, always the /usr/bin etc at first place if subsystem != WSL: def get_path_value(container, subsystem_name): """Gets the path from the container dict and returns a string with the path for the subsystem_name""" _path_key = next( (name for name in container.keys() if "path" == name.lower()), None) if _path_key: _path_value = container.get(_path_key) if isinstance(_path_value, list): return ":".join([ unix_path(path, path_flavor=subsystem_name) for path in _path_value ]) else: return unix_path(_path_value, path_flavor=subsystem_name) # First get the PATH from the conanfile.env inherited_path = get_path_value(conanfile.env, subsystem) # Then get the PATH from the real env env_path = get_path_value(env, subsystem) # Both together full_env = ":".join(v for v in [env_path, inherited_path] if v) # Put the build_requires and requires path at the first place inside the shell hack_env = ' && PATH="%s:$PATH"' % full_env if full_env else "" for var_name, value in env.items(): if var_name == "PATH": continue hack_env += ' && %s=%s' % (var_name, value) # Needed to change to that dir inside the bash shell if cwd and not os.path.isabs(cwd): cwd = os.path.join(get_cwd(), cwd) curdir = unix_path(cwd or get_cwd(), path_flavor=subsystem) to_run = 'cd "%s"%s && %s ' % (curdir, hack_env, bashcmd) bash_path = OSInfo.bash_path() bash_path = '"%s"' % bash_path if " " in bash_path else bash_path login = "******" if with_login else "" wincmd = '%s %s -c %s' % (bash_path, login, escape_windows_cmd(to_run)) conanfile.output.info('run_in_windows_bash: %s' % wincmd) # If is there any other env var that we know it contains paths, convert it to unix_path used_special_vars = [ var for var in ["AR", "AS", "RANLIB", "LD", "STRIP", "CC", "CXX"] if var in conanfile.env.keys() ] normalized_env = { p: unix_path(conanfile.env[p], path_flavor=subsystem) for p in used_special_vars } # https://github.com/conan-io/conan/issues/2839 (subprocess=True) with environment_append(normalized_env): return conanfile._conan_runner(wincmd, output=conanfile.output, subprocess=True)
def gzopen_patched(name, mode="r", fileobj=None, compresslevel=None, **kwargs): raise ConanException("Error gzopen %s" % name)
def vswhere(all_=False, prerelease=False, products=None, requires=None, version="", latest=False, legacy=False, property_="", nologo=True): # 'version' option only works if Visual Studio 2017 is installed: # https://github.com/Microsoft/vswhere/issues/91 products = list() if products is None else products requires = list() if requires is None else requires if legacy and (products or requires): raise ConanException( "The 'legacy' parameter cannot be specified with either the " "'products' or 'requires' parameter") installer_path = None program_files = get_env("ProgramFiles(x86)") or get_env("ProgramFiles") if program_files: expected_path = os.path.join(program_files, "Microsoft Visual Studio", "Installer", "vswhere.exe") if os.path.isfile(expected_path): installer_path = expected_path vswhere_path = installer_path or which("vswhere") if not vswhere_path: raise ConanException( "Cannot locate vswhere in 'Program Files'/'Program Files (x86)' " "directory nor in PATH") arguments = list() arguments.append(vswhere_path) # Output json format arguments.append("-format") arguments.append("json") if all_: arguments.append("-all") if prerelease: arguments.append("-prerelease") if products: arguments.append("-products") arguments.extend(products) if requires: arguments.append("-requires") arguments.extend(requires) if len(version) != 0: arguments.append("-version") arguments.append(version) if latest: arguments.append("-latest") if legacy: arguments.append("-legacy") if len(property_) != 0: arguments.append("-property") arguments.append(property_) if nologo: arguments.append("-nologo") try: output = check_output(arguments).strip() # Ignore the "description" field, that even decoded contains non valid charsets for json # (ignored ones) output = "\n".join([ line for line in output.splitlines() if not line.strip().startswith('"description"') ]) except (ValueError, subprocess.CalledProcessError, UnicodeDecodeError) as e: raise ConanException("vswhere error: %s" % str(e)) return json.loads(output)
def vcvars_command(settings, arch=None, compiler_version=None, force=False, vcvars_ver=None, winsdk_version=None, output=None): output = default_output(output, 'conans.client.tools.win.vcvars_command') arch_setting = arch or settings.get_safe("arch") compiler = settings.get_safe("compiler") if compiler == 'Visual Studio': compiler_version = compiler_version or settings.get_safe( "compiler.version") else: # vcvars might be still needed for other compilers, e.g. clang-cl or Intel C++, # as they might be using Microsoft STL and other tools # (e.g. resource compiler, manifest tool, etc) # in this case, use the latest Visual Studio available on the machine last_version = latest_vs_version_installed(output=output) compiler_version = compiler_version or last_version os_setting = settings.get_safe("os") if not compiler_version: raise ConanException( "compiler.version setting required for vcvars not defined") # https://msdn.microsoft.com/en-us/library/f2ccy3wt.aspx arch_setting = arch_setting or 'x86_64' arch_build = settings.get_safe("arch_build") or detected_architecture() if os_setting == 'WindowsCE': vcvars_arch = "x86" elif arch_build == 'x86_64': # Only uses x64 tooling if arch_build explicitly defines it, otherwise # Keep the VS default, which is x86 toolset # This will probably be changed in conan 2.0 if ((settings.get_safe("arch_build") or os.getenv("PreferredToolArchitecture") == "x64") and int(compiler_version) >= 12): x86_cross = "amd64_x86" else: x86_cross = "x86" vcvars_arch = { 'x86': x86_cross, 'x86_64': 'amd64', 'armv7': 'amd64_arm', 'armv8': 'amd64_arm64' }.get(arch_setting) elif arch_build == 'x86': vcvars_arch = { 'x86': 'x86', 'x86_64': 'x86_amd64', 'armv7': 'x86_arm', 'armv8': 'x86_arm64' }.get(arch_setting) if not vcvars_arch: raise ConanException('unsupported architecture %s' % arch_setting) existing_version = os.environ.get("VisualStudioVersion") if existing_version: command = ["echo Conan:vcvars already set"] existing_version = existing_version.split(".")[0] if existing_version != compiler_version: message = "Visual environment already set to %s\n " \ "Current settings visual version: %s" % (existing_version, compiler_version) if not force: raise ConanException("Error, %s" % message) else: output.warn(message) else: vs_path = vs_installation_path(str(compiler_version)) if not vs_path or not os.path.isdir(vs_path): raise ConanException( "VS non-existing installation: Visual Studio %s" % str(compiler_version)) else: if int(compiler_version) > 14: vcvars_path = os.path.join(vs_path, "VC/Auxiliary/Build/vcvarsall.bat") command = [ 'set "VSCMD_START_DIR=%%CD%%" && ' 'call "%s" %s' % (vcvars_path, vcvars_arch) ] else: vcvars_path = os.path.join(vs_path, "VC/vcvarsall.bat") command = ['call "%s" %s' % (vcvars_path, vcvars_arch)] if int(compiler_version) >= 14: if winsdk_version: command.append(winsdk_version) if vcvars_ver: command.append("-vcvars_ver=%s" % vcvars_ver) if os_setting == 'WindowsStore': os_version_setting = settings.get_safe("os.version") if os_version_setting == '8.1': command.append('store 8.1') elif os_version_setting == '10.0': windows_10_sdk = find_windows_10_sdk() if not windows_10_sdk: raise ConanException( "cross-compiling for WindowsStore 10 (UWP), " "but Windows 10 SDK wasn't found") command.append('store %s' % windows_10_sdk) else: raise ConanException('unsupported Windows Store version %s' % os_version_setting) return " ".join(command)
def configure(self): del self.settings.compiler.libcxx if self.settings.compiler == "Visual Studio" and int( str(self.settings.compiler.version)) < 14: raise ConanException("Visual Studio >= 14 (2015) is required")
def configure(self): if self.settings.compiler == 'Visual Studio' and int( self.settings.compiler.version.value) < 14: raise ConanException( "{} requires Visual Studio version 14 or greater".format( self.name))
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 _ensure_exists(self, field): if field not in self._data: raise ConanException( option_not_exist_msg(field, list(self._data.keys())))
def _check_git_repo(self): try: self.run("status") except Exception: raise ConanException("Not a valid git repository")
def __getitem__(self, item): raise ConanException( "self.%s not defined. If you need it for a " "local command run 'conan install'" % field_name)
def get_gnu_triplet(os_, arch, compiler=None): """ Returns string with <machine>-<vendor>-<op_system> triplet (<vendor> can be omitted in practice) :param os_: os to be used to create the triplet :param arch: arch to be used to create the triplet :param compiler: compiler used to create the triplet (only needed fo windows) """ if os_ == "Windows" and compiler is None: raise ConanException( "'compiler' parameter for 'get_gnu_triplet()' is not specified and " "needed for os=Windows") # Calculate the arch machine = { "x86": "i686" if os_ != "Linux" else "x86", "x86_64": "x86_64", "armv8": "aarch64", "armv8_32": "aarch64", # https://wiki.linaro.org/Platform/arm64-ilp32 "armv8.3": "aarch64", "asm.js": "asmjs", "wasm": "wasm32", }.get(arch, None) if not machine: # https://wiki.debian.org/Multiarch/Tuples if os_ == "AIX": if "ppc32" in arch: machine = "rs6000" elif "ppc64" in arch: machine = "powerpc" elif "arm" in arch: machine = "arm" elif "ppc32be" in arch: machine = "powerpcbe" elif "ppc64le" in arch: machine = "powerpc64le" elif "ppc64" in arch: machine = "powerpc64" elif "ppc32" in arch: machine = "powerpc" elif "mips64" in arch: machine = "mips64" elif "mips" in arch: machine = "mips" elif "sparcv9" in arch: machine = "sparc64" elif "sparc" in arch: machine = "sparc" elif "s390x" in arch: machine = "s390x-ibm" elif "s390" in arch: machine = "s390-ibm" elif "sh4" in arch: machine = "sh4" if machine is None: raise ConanException( "Unknown '%s' machine, Conan doesn't know how to " "translate it to the GNU triplet, please report at " " https://github.com/conan-io/conan/issues" % arch) # Calculate the OS if compiler == "gcc": windows_op = "w64-mingw32" elif compiler == "Visual Studio": windows_op = "windows-msvc" else: windows_op = "windows" op_system = { "Windows": windows_op, "Linux": "linux-gnu", "Darwin": "apple-darwin", "Android": "linux-android", "Macos": "apple-darwin", "iOS": "apple-darwin", "watchOS": "apple-darwin", "tvOS": "apple-darwin", # NOTE: it technically must be "asmjs-unknown-emscripten" or # "wasm32-unknown-emscripten", but it's not recognized by old config.sub versions "Emscripten": "local-emscripten", "AIX": "ibm-aix", "Neutrino": "nto-qnx" }.get(os_, os_.lower()) if os_ in ("Linux", "Android"): if "arm" in arch and "armv8" not in arch: op_system += "eabi" if (arch == "armv5hf" or arch == "armv7hf") and os_ == "Linux": op_system += "hf" if arch == "armv8_32" and os_ == "Linux": op_system += "_ilp32" # https://wiki.linaro.org/Platform/arm64-ilp32 return "%s-%s" % (machine, op_system)
def __init__(self, conanfile, generator=None, cmake_system_name=True, parallel=True, build_type=None, toolset=None, make_program=None, set_cmake_flags=False, msbuild_verbosity="minimal", cmake_program=None, generator_platform=None, append_vcvars=False): """ :param conanfile: Conanfile instance :param generator: Generator name to use or none to autodetect :param cmake_system_name: False to not use CMAKE_SYSTEM_NAME variable, True for auto-detect or directly a string with the system name :param parallel: Try to build with multiple cores if available :param build_type: Overrides default build type coming from settings :param toolset: Toolset name to use (such as llvm-vs2014) or none for default one, applies only to certain generators (e.g. Visual Studio) :param set_cmake_flags: whether or not to set CMake flags like CMAKE_CXX_FLAGS, CMAKE_C_FLAGS, etc. it's vital to set for certain projects (e.g. using CMAKE_SIZEOF_VOID_P or CMAKE_LIBRARY_ARCHITECTURE) :param msbuild_verbosity: verbosity level for MSBuild (in case of Visual Studio generator) :param cmake_program: Path to the custom cmake executable :param generator_platform: Generator platform name or none to autodetect (-A cmake option) """ if not isinstance(conanfile, ConanFile): raise ConanException( "First argument of CMake() has to be ConanFile. Use CMake(self)" ) self._append_vcvars = append_vcvars self._conanfile = conanfile self._settings = conanfile.settings self._build_type = build_type or conanfile.settings.get_safe( "build_type") self._cmake_program = os.getenv( "CONAN_CMAKE_PROGRAM") or cmake_program or "cmake" self.generator_platform = generator_platform self.generator = generator or get_generator(conanfile) if not self.generator: self._conanfile.output.warn( "CMake generator could not be deduced from settings") self.parallel = parallel # Initialize definitions (won't be updated if conanfile or any of these variables change) builder = CMakeDefinitionsBuilder(self._conanfile, cmake_system_name=cmake_system_name, make_program=make_program, parallel=parallel, generator=self.generator, set_cmake_flags=set_cmake_flags, forced_build_type=build_type, output=self._conanfile.output) # FIXME CONAN 2.0: CMake() interface should be always the constructor and self.definitions. # FIXME CONAN 2.0: Avoid properties and attributes to make the user interface more clear self.definitions = builder.get_definitions() self.definitions["CONAN_EXPORTED"] = "1" self.toolset = toolset or get_toolset(self._settings) self.build_dir = None self.msbuild_verbosity = os.getenv( "CONAN_MSBUILD_VERBOSITY") or msbuild_verbosity
def load_conanfile_class(conanfile_path): loaded, filename = _parse_file(conanfile_path) try: return _parse_module(loaded, filename) except Exception as e: # re-raise with file name raise ConanException("%s: %s" % (conanfile_path, str(e)))
def _get_conf(self, varname): """Gets the section from config file or raises an exception""" try: return self.items(varname) except NoSectionError: raise ConanException("Invalid configuration, missing %s" % varname)
def _raise_incorrect_components_definition(self, package_name, package_requires): if not self.components and not self.requires: return # Raise if mixing components if self.components and \ (self.includedirs != [self._default_values.includedir] or self.libdirs != [self._default_values.libdir] or self.bindirs != [self._default_values.bindir] or self.resdirs != [self._default_values.resdir] or self.builddirs != [self._default_values.builddir] or self.frameworkdirs != [self._default_values.frameworkdir] or self.libs or self.system_libs or self.frameworks or self.defines or self.cflags or self.cxxflags or self.sharedlinkflags or self.exelinkflags or self.get_build_modules() or self.requires): raise ConanException("self.cpp_info.components cannot be used with self.cpp_info " "global values at the same time") if self._configs: raise ConanException("self.cpp_info.components cannot be used with self.cpp_info configs" " (release/debug/...) at the same time") pkg_requires = [require.ref.name for require in package_requires.values()] def _check_components_requires_instersection(comp_requires): reqs = [it.split(COMPONENT_SCOPE)[0] for it in comp_requires if COMPONENT_SCOPE in it] # Raise on components requires without package requires for pkg_require in pkg_requires: if package_requires[pkg_require].private or package_requires[pkg_require].override: # Not standard requires, skip continue if pkg_require not in reqs: raise ConanException("Package require '%s' not used in components requires" % pkg_require) # Raise on components requires requiring inexistent package requires for comp_require in reqs: reason = None if comp_require not in pkg_requires: reason = "not defined as a recipe requirement" elif package_requires[comp_require].private and package_requires[ comp_require].override: reason = "it was defined as an overridden private recipe requirement" elif package_requires[comp_require].private: reason = "it was defined as a private recipe requirement" elif package_requires[comp_require].override: reason = "it was defined as an overridden recipe requirement" if reason is not None: raise ConanException("Package require '%s' declared in components requires " "but %s" % (comp_require, reason)) if self.components: # Raise on component name for comp_name, comp in self.components.items(): if comp_name == package_name: raise ConanException( "Component name cannot be the same as the package name: '%s'" % comp_name) # check that requires are used in components and check that components exists in requires requires_from_components = set() for comp_name, comp in self.components.items(): requires_from_components.update(comp.requires) _check_components_requires_instersection(requires_from_components) else: _check_components_requires_instersection(self.requires)
def cmd_new(ref, header=False, pure_c=False, test=False, exports_sources=False, bare=False, visual_versions=None, linux_gcc_versions=None, linux_clang_versions=None, osx_clang_versions=None, shared=None, upload_url=None, gitignore=None, gitlab_gcc_versions=None, gitlab_clang_versions=None): try: tokens = ref.split("@") name, version = tokens[0].split("/") if len(tokens) == 2: user, channel = tokens[1].split("/") else: user, channel = "user", "channel" pattern = re.compile('[\W_]+') package_name = pattern.sub('', name).capitalize() except ValueError: raise ConanException("Bad parameter, please use full package name," "e.g: MyLib/1.2.3@user/testing") # Validate it is a valid reference ConanFileReference(name, version, user, channel) if header and exports_sources: raise ConanException("'header' and 'sources' are incompatible options") if pure_c and (header or exports_sources): raise ConanException( "'pure_c' is incompatible with 'header' and 'sources'") if bare and (header or exports_sources): raise ConanException( "'bare' is incompatible with 'header' and 'sources'") if header: files = { "conanfile.py": conanfile_header.format(name=name, version=version, package_name=package_name) } elif exports_sources: files = { "conanfile.py": conanfile_sources.format(name=name, version=version, package_name=package_name), "src/hello.cpp": hello_cpp, "src/hello.h": hello_h, "src/CMakeLists.txt": cmake } elif bare: files = { "conanfile.py": conanfile_bare.format(name=name, version=version, package_name=package_name) } else: files = { "conanfile.py": conanfile.format(name=name, version=version, package_name=package_name) } if pure_c: config = "\n def configure(self):\n del self.settings.compiler.libcxx" files["conanfile.py"] = files["conanfile.py"] + config if test: files["test_package/conanfile.py"] = test_conanfile.format( name=name, version=version, user=user, channel=channel, package_name=package_name) files["test_package/CMakeLists.txt"] = test_cmake files["test_package/example.cpp"] = test_main if gitignore: files[".gitignore"] = gitignore_template files.update( ci_get_files(name, version, user, channel, visual_versions, linux_gcc_versions, linux_clang_versions, osx_clang_versions, shared, upload_url, gitlab_gcc_versions, gitlab_clang_versions)) return files
def update(self, remote_name, url, verify_ssl=True, insert=None): if remote_name not in self._remotes: raise ConanException("Remote '%s' not found in remotes" % remote_name) self._add_update(remote_name, url, verify_ssl, insert)
def validate(self): if self._value is None and "None" not in self._definition: raise ConanException(undefined_value(self._name)) if isinstance(self._definition, dict): self._definition[self._value].validate()
def __init__(self, conanfile, generator=None, cmake_system_name=True, parallel=True, build_type=None, toolset=None, make_program=None, set_cmake_flags=False): """ :param settings_or_conanfile: Conanfile instance (or settings for retro compatibility) :param generator: Generator name to use or none to autodetect :param cmake_system_name: False to not use CMAKE_SYSTEM_NAME variable, True for auto-detect or directly a string with the system name :param parallel: Try to build with multiple cores if available :param build_type: Overrides default build type comming from settings :param toolset: Toolset name to use (such as llvm-vs2014) or none for default one, applies only to certain generators (e.g. Visual Studio) :param set_cmake_flags: whether or not to set CMake flags like CMAKE_CXX_FLAGS, CMAKE_C_FLAGS, etc. it's vital to set for certain projects (e.g. using CMAKE_SIZEOF_VOID_P or CMAKE_LIBRARY_ARCHITECTURE) """ if not isinstance(conanfile, ConanFile): raise ConanException( "First argument of CMake() has to be ConanFile. Use CMake(self)" ) self._settings = conanfile.settings self._conanfile = conanfile self._os = self._settings.get_safe("os") self._os_build, _, self._os_host, _ = get_cross_building_settings( self._settings) self._compiler = self._settings.get_safe("compiler") self._compiler_version = self._settings.get_safe("compiler.version") self._arch = self._settings.get_safe("arch") self._op_system_version = self._settings.get_safe("os.version") self._libcxx = self._settings.get_safe("compiler.libcxx") self._runtime = self._settings.get_safe("compiler.runtime") self._build_type = self._settings.get_safe("build_type") self._cppstd = self._settings.get_safe("cppstd") self.generator = generator or self._generator() self.toolset = self._toolset(toolset) self.build_dir = None self._cmake_system_name = _get_env_cmake_system_name() if self._cmake_system_name is None: # Not overwritten using environment self._cmake_system_name = cmake_system_name self.parallel = parallel self._set_cmake_flags = set_cmake_flags self.definitions = self._get_cmake_definitions() if build_type and build_type != self._build_type: # Call the setter to warn and update the definitions if needed self.build_type = build_type make_program = os.getenv("CONAN_MAKE_PROGRAM") or make_program if make_program: if not tools.which(make_program): self._conanfile.output.warn( "The specified make program '%s' cannot be found" "and will be ignored" % make_program) else: self._conanfile.output.info( "Using '%s' as CMAKE_MAKE_PROGRAM" % make_program) self.definitions["CMAKE_MAKE_PROGRAM"] = make_program
def _get_key(self, item): for reference in self._data: if reference.conan.name == item: return reference raise ConanException("No requirement matching for %s" % (item))
def validate(self): if self._value is None and "None" not in self._possible_values: raise ConanException(option_undefined_msg(self._name))
def call_system_requirements(conanfile, output): try: return conanfile.system_requirements() except Exception as e: output.error("while executing system_requirements(): %s" % str(e)) raise ConanException("Error in system requirements")
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) # 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): for filename in os.listdir(source_sources_folder): shutil.move(os.path.join(source_sources_folder, filename), os.path.join(src_folder, filename)) # finally remove copied folder os.rmdir(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: 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) msg = format_conanfile_exception(output.scope, "source", e) raise ConanException(msg)