def __init__(self, src_dir: str | Path, environment: Environment) -> None: self._env = environment self._path = self.get_env_path(src_dir) self.executable = self._env.interpreter.executable self.src_dir = src_dir self._prefix = _Prefix(self.executable, self._path) logger.debug("Preparing isolated env for PEP 517 build...") try: with open(os.path.join(src_dir, "pyproject.toml"), encoding="utf8") as f: spec = toml.load(f) except FileNotFoundError: spec = {} except Exception as e: raise BuildError(e) from e self._build_system = spec.get("build-system", self.DEFAULT_BACKEND) if "build-backend" not in self._build_system: self._build_system["build-backend"] = self.DEFAULT_BACKEND[ "build-backend"] if "requires" not in self._build_system: raise BuildError( "Missing 'build-system.requires' in pyproject.toml") self._backend = self._build_system["build-backend"] self._hook = Pep517HookCaller( src_dir, self._backend, backend_path=self._build_system.get("backend-path"), runner=self.subprocess_runner, python_executable=self.executable, )
def __init__(self, src_dir: str | Path, environment: Environment) -> None: """If isolated is True(default), the builder will set up a *clean* environment. Otherwise, the environment of the host Python will be used. """ self._env = environment self.executable = self._env.interpreter.executable.as_posix() self.src_dir = src_dir self.isolated = environment.project.config["build_isolation"] logger.debug("Preparing isolated env for PEP 517 build...") try: with open(os.path.join(src_dir, "pyproject.toml"), "rb") as f: spec = tomli.load(f) except FileNotFoundError: spec = {} except Exception as e: raise BuildError(e) from e build_system = spec.get("build-system", self.DEFAULT_BACKEND) if "build-backend" not in build_system: build_system["build-backend"] = self.DEFAULT_BACKEND[ "build-backend"] if "requires" not in build_system: raise BuildError( "Missing 'build-system.requires' in pyproject.toml") self.init_build_system(build_system)
def __init__(self, src_dir: str | Path, environment: Environment) -> None: self._env = environment self.executable = self._env.interpreter.executable self.src_dir = src_dir logger.debug("Preparing isolated env for PEP 517 build...") try: with open(os.path.join(src_dir, "pyproject.toml"), "rb") as f: spec = tomli.load(f) except FileNotFoundError: spec = {} except Exception as e: raise BuildError(e) from e build_system = spec.get("build-system", self.DEFAULT_BACKEND) if "build-backend" not in build_system: build_system["build-backend"] = self.DEFAULT_BACKEND[ "build-backend"] if "requires" not in build_system: raise BuildError( "Missing 'build-system.requires' in pyproject.toml") self.init_build_system(build_system) self._prefix = _Prefix( self.executable, shared=self.get_shared_env(hash(frozenset(self._requires))), overlay=self.get_overlay_env( os.path.normcase(self.src_dir).rstrip("\\/")), )
def get_shared_env(cls, key: int) -> str: if key in cls._shared_envs: logger.debug("Reusing shared build env: %s", cls._shared_envs[key]) return cls._shared_envs[key] # We don't save the cache here, instead it will be done after the installation # finished. return create_tracked_tempdir("-shared", "pdm-build-env-")
def install_wheel_with_cache(wheel: str, environment: Environment, direct_url: dict[str, Any] | None = None) -> None: """Only create .pth files referring to the cached package. If the cache doesn't exist, create one. """ wheel_stem = Path(wheel).stem cache_path = environment.project.cache("packages") / wheel_stem package_cache = CachedPackage(cache_path) interpreter = environment.interpreter.executable script_kind = _get_kind(environment) if not cache_path.is_dir(): logger.debug("Installing wheel into cached location %s", cache_path) cache_path.mkdir(exist_ok=True) _install_wheel( wheel=wheel, interpreter=interpreter, script_kind=script_kind, scheme_dict=package_cache.scheme(), ) additional_metadata = {"REFER_TO": package_cache.path.as_posix().encode()} if direct_url is not None: additional_metadata["direct_url.json"] = json.dumps(direct_url, indent=2).encode() def skip_files(scheme: Scheme, path: str) -> bool: return not (scheme == "scripts" or path.split("/")[0].endswith(".dist-info") or path.endswith(".pth")) filename = wheel_stem.split("-")[0] + ".pth" lib_path = package_cache.scheme()["purelib"] dist_info_dir = _install_wheel( wheel=wheel, interpreter=interpreter, script_kind=script_kind, scheme_dict=environment.get_paths(), excludes=skip_files, additional_files=[(None, filename, io.BytesIO(f"{lib_path}\n".encode()))], additional_metadata=additional_metadata, ) package_cache.add_referrer(dist_info_dir)
def __enter__(self) -> EnvBuilder: self._path = tempfile.mkdtemp(prefix="pdm-build-env-") paths = get_sys_config_paths(self.executable, vars={ "base": self._path, "platbase": self._path }) old_path = os.getenv("PATH") self._saved_env = { "PYTHONPATH": paths["purelib"], "PATH": paths["scripts"] if not old_path else os.pathsep.join([paths["scripts"], old_path]), "PYTHONNOUSERSITE": "1", "PDM_PYTHON_PEP582": "0", } logger.debug("Preparing isolated env for PEP 517 build...") return self
def get_shared_env(cls, key: int) -> str: if key in cls._shared_envs: logger.debug("Reusing shared build env: %s", cls._shared_envs[key]) return cls._shared_envs[key] # Postpone the cache after installation is done return create_tracked_tempdir("-shared", "pdm-build-env-")
def install_wheel_with_cache(wheel: str, environment: Environment, direct_url: dict[str, Any] | None = None) -> None: """Only create .pth files referring to the cached package. If the cache doesn't exist, create one. """ wheel_stem = Path(wheel).stem cache_path = environment.project.cache("packages") / wheel_stem package_cache = CachedPackage(cache_path) interpreter = str(environment.interpreter.executable) script_kind = _get_kind(environment) supports_symlink = (environment.project.config["install.cache_method"] == "symlink" and fs_supports_symlink()) if not cache_path.is_dir(): logger.debug("Installing wheel into cached location %s", cache_path) cache_path.mkdir(exist_ok=True) destination = InstallDestination( scheme_dict=package_cache.scheme(), interpreter=interpreter, script_kind=script_kind, ) _install_wheel(wheel=wheel, destination=destination) additional_metadata = {"REFER_TO": package_cache.path.as_posix().encode()} if direct_url is not None: additional_metadata["direct_url.json"] = json.dumps(direct_url, indent=2).encode() def skip_files(source: WheelFile, element: WheelContentElement) -> bool: root_scheme = _process_WHEEL_file(source) scheme, path = _determine_scheme(element[0][0], source, root_scheme) return not ( scheme not in ("purelib", "platlib") or path.split("/")[0].endswith(".dist-info") # We need to skip the *-nspkg.pth files generated by setuptools' # namespace_packages merchanism. See issue#623 for details or not supports_symlink and path.endswith(".pth") and not path.endswith("-nspkg.pth")) additional_contents: list[WheelContentElement] = [] lib_path = package_cache.scheme()["purelib"] if not supports_symlink: # HACK: Prefix with aaa_ to make it processed as early as possible filename = "aaa_" + wheel_stem.split("-")[0] + ".pth" stream = io.BytesIO(f"{lib_path}\n".encode()) additional_contents.append( ((filename, "", str(len(stream.getvalue()))), stream, False)) destination = InstallDestination( scheme_dict=environment.get_paths(), interpreter=interpreter, script_kind=script_kind, symlink_to=lib_path if supports_symlink else None, ) dist_info_dir = _install_wheel( wheel=wheel, destination=destination, excludes=skip_files, additional_contents=additional_contents, additional_metadata=additional_metadata, ) package_cache.add_referrer(dist_info_dir)