def should_cache(self) -> bool: """Determine whether to cache the dependencies and built wheel.""" link, source_dir = self.ireq.original_link, self.ireq.source_dir if self.req.is_vcs and not self.req.editable: if not source_dir: # If the candidate isn't prepared, we can't cache it return False vcs = pip_shims.VcsSupport() assert link vcs_backend = vcs.get_backend_for_scheme(link.scheme) return bool(vcs_backend and vcs_backend.is_immutable_rev_checkout( link.url, source_dir)) elif self.req.is_named: return True elif link and not link.is_existing_dir(): base, _ = link.splitext() # Cache if the link contains egg-info like 'foo-1.0' return _egg_info_re.search(base) is not None return False
def _get_wheel_dir(self) -> str: should_cache = False wheel_cache = self.environment.project.make_wheel_cache() assert self.link if self.link.is_vcs and not self.req.editable: vcs = pip_shims.VcsSupport() vcs_backend = vcs.get_backend_for_scheme(self.link.scheme) if vcs_backend and vcs_backend.is_immutable_rev_checkout( self.link.url, cast(str, self.ireq.source_dir)): should_cache = True elif not self.link.is_existing_dir(): base, _ = self.link.splitext() if _egg_info_re.search(base) is not None: # Determine whether the string looks like an egg_info. should_cache = True if should_cache: return wheel_cache.get_path_for_link(self.link) else: return create_tracked_tempdir(prefix="pdm-wheel-")
def build( self, ireq: pip_shims.InstallRequirement, hashes: Optional[Dict[str, str]] = None, allow_all: bool = True, ) -> str: """Build egg_info directory for editable candidates and a wheel for others. :param ireq: the InstallRequirment of the candidate. :param hashes: a dictionary of filename: hash_value to check against downloaded artifacts. :param allow_all: Allow building incompatible wheels. :returns: The full path of the built artifact. """ kwargs = self._make_building_args(ireq) wheel_cache = self.project.make_wheel_cache() with self.get_finder() as finder: with allow_all_wheels(allow_all): # temporarily allow all wheels to get a link. populate_link(finder, ireq, False) if hashes is None: cache_entry = wheel_cache.get_cache_entry( ireq.link, ireq.req.project_name, pip_shims.get_supported( version="".join( map( str, get_python_version(self.python_executable)[0][:2], ) ) ), ) if cache_entry is not None: stream.logger.debug( "Using cached wheel link: %s", cache_entry.link ) ireq.link = cache_entry.link if not ireq.editable and not ireq.req.name: ireq.source_dir = kwargs["build_dir"] else: ireq.ensure_has_source_dir(kwargs["build_dir"]) download_dir = kwargs["download_dir"] only_download = False if ireq.link.is_wheel: download_dir = kwargs["wheel_download_dir"] only_download = True if hashes: ireq.hash_options = convert_hashes(hashes) if not (ireq.editable and ireq.req.is_local_dir): downloader = pip_shims.Downloader(finder.session, "off") if ireq.link.is_vcs: ireq.link = pip_shims.Link(expand_env_vars_in_auth(ireq.link.url)) downloaded = pip_shims.unpack_url( ireq.link, ireq.source_dir, downloader, download_dir, ireq.hashes(False), ) # Preserve the downloaded file so that it won't be cleared. if downloaded and only_download: try: shutil.copy(downloaded.path, download_dir) except shutil.SameFileError: pass if ireq.link.is_wheel: # If the file is a wheel, should be already present under download dir. return (self.project.cache("wheels") / ireq.link.filename).as_posix() else: # Check the built wheel cache again after hashes are resolved. cache_entry = wheel_cache.get_cache_entry( ireq.link, ireq.req.project_name, pip_shims.get_supported( version="".join( map(str, get_python_version(self.python_executable)[0][:2]) ) ), ) if cache_entry is not None: stream.logger.debug("Using cached wheel link: %s", cache_entry.link) return cache_entry.link.file_path # Otherwise, now all source is prepared, build it. with EnvBuilder(ireq.unpacked_source_directory, self) as builder: if ireq.editable: ret = builder.build_egg_info(kwargs["build_dir"]) ireq.metadata_directory = ret else: should_cache = False if ireq.link.is_vcs: vcs = pip_shims.VcsSupport() vcs_backend = vcs.get_backend_for_scheme(ireq.link.scheme) if vcs_backend.is_immutable_rev_checkout( ireq.link.url, ireq.source_dir ): should_cache = True else: base, _ = ireq.link.splitext() if _egg_info_re.search(base) is not None: # Determine whether the string looks like an egg_info. should_cache = True output_dir = ( wheel_cache.get_path_for_link(ireq.link) if should_cache else kwargs["build_dir"] ) if not os.path.exists(output_dir): os.makedirs(output_dir, exist_ok=True) ret = builder.build_wheel(output_dir) return ret
def build( self, ireq: pip_shims.InstallRequirement, hashes: Optional[Dict[str, str]] = None, allow_all: bool = True, ) -> str: """Build egg_info directory for editable candidates and a wheel for others. :param ireq: the InstallRequirment of the candidate. :param hashes: a dictionary of filename: hash_value to check against downloaded artifacts. :param allow_all: Allow building incompatible wheels. :returns: The full path of the built artifact. """ build_dir = self._get_build_dir(ireq) wheel_cache = self.project.make_wheel_cache() supported_tags = pip_shims.get_supported("".join( map(str, get_python_version(self.python_executable, digits=2)[0]))) with self.get_finder(ignore_requires_python=True) as finder: with allow_all_wheels(allow_all): # temporarily allow all wheels to get a link. populate_link(finder, ireq, False) ireq.link = pip_shims.Link( expand_env_vars_in_auth( ireq.link.url.replace( "${PROJECT_ROOT}", self.project.root.as_posix().lstrip("/")))) if hashes is None and not ireq.editable: # If hashes are not given and cache is hit, replace the link with the # cached one. This can speed up by skipping the download and build. cache_entry = wheel_cache.get_cache_entry( ireq.link, ireq.req.project_name, supported_tags, ) if cache_entry is not None: termui.logger.debug("Using cached wheel link: %s", cache_entry.link) ireq.link = cache_entry.link if not ireq.editable and not ireq.req.name: ireq.source_dir = build_dir else: ireq.ensure_has_source_dir(build_dir) if hashes: ireq.hash_options = convert_hashes(hashes) if not (ireq.editable and ireq.req.is_local_dir): downloader = pip_shims.Downloader(finder.session, "off") downloaded = pip_shims.unpack_url( ireq.link, ireq.source_dir, downloader, hashes=ireq.hashes(False), ) if ireq.link.is_wheel: # If the file is a wheel, return the downloaded file directly. return downloaded.path # Check the built wheel cache again after hashes are resolved. if not ireq.editable: cache_entry = wheel_cache.get_cache_entry( ireq.link, ireq.req.project_name, supported_tags, ) if cache_entry is not None: termui.logger.debug("Using cached wheel link: %s", cache_entry.link) return cache_entry.link.file_path # Otherwise, as all source is already prepared, build it. with EnvBuilder(ireq.unpacked_source_directory, self) as builder: if ireq.editable: ret = builder.build_egg_info(build_dir) ireq.metadata_directory = ret return ret should_cache = False if ireq.link.is_vcs: vcs = pip_shims.VcsSupport() vcs_backend = vcs.get_backend_for_scheme(ireq.link.scheme) if vcs_backend.is_immutable_rev_checkout( ireq.link.url, ireq.source_dir): should_cache = True else: base, _ = ireq.link.splitext() if _egg_info_re.search(base) is not None: # Determine whether the string looks like an egg_info. should_cache = True output_dir = (wheel_cache.get_path_for_link(ireq.link) if should_cache else build_dir) if not os.path.exists(output_dir): os.makedirs(output_dir, exist_ok=True) return builder.build_wheel(output_dir)
from pip._vendor.pkg_resources import safe_extra from pdm import termui from pdm.exceptions import BuildError, ExtrasError, RequirementError from pdm.models import pip_shims from pdm.models.markers import Marker from pdm.models.readers import SetupReader from pdm.models.requirements import Requirement, filter_requirements_with_extras from pdm.utils import cached_property, get_rev_from_url, path_replace if TYPE_CHECKING: from distlib.metadata import Metadata from pdm.models.environment import Environment vcs = pip_shims.VcsSupport() def get_sdist(egg_info: str) -> Optional[EggInfoDistribution]: """Get a distribution from egg_info directory.""" return EggInfoDistribution(egg_info) if egg_info else None def _patch_version_parsing(): """Monkey patches the version parsing to allow empty parts in version constraint list. """ from distlib.version import VersionScheme from packaging.requirements import InvalidRequirement from packaging.requirements import Requirement as PRequirement
def build( self, ireq: pip_shims.InstallRequirement, hashes: dict[str, str] | None = None, allow_all: bool = True, ) -> str: """Build egg_info directory for editable candidates and a wheel for others. :param ireq: the InstallRequirment of the candidate. :param hashes: a dictionary of filename: hash_value to check against downloaded artifacts. :param allow_all: Allow building incompatible wheels. :returns: The full path of the built artifact. """ from pdm.builders import EnvEggInfoBuilder, EnvWheelBuilder wheel_cache = self.project.make_wheel_cache() supported_tags = pip_shims.get_supported(self.interpreter.for_tag()) if hashes: ireq.hash_options = convert_hashes(hashes) with self.get_finder(ignore_requires_python=True) as finder: with allow_all_wheels(allow_all): # temporarily allow all wheels to get a link. populate_link(finder, ireq, False) assert ireq.link if hashes is None and not ireq.editable: # If hashes are not given and cache is hit, replace the link with the # cached one. This can speed up by skipping the download and build. cache_entry = wheel_cache.get_cache_entry( ireq.link, ireq.req.project_name, # type: ignore supported_tags, ) if cache_entry is not None: termui.logger.debug("Using cached wheel link: %s", cache_entry.link) ireq.link = cache_entry.link build_dir = self._get_build_dir(ireq) if not ireq.source_dir: ireq.source_dir = build_dir if not ireq.link.is_existing_dir(): downloader = pip_shims.Downloader(finder.session, "off") # type: ignore downloaded = pip_shims.unpack_url( ireq.link, ireq.source_dir, downloader, hashes=ireq.hashes(False), ) if ireq.link.is_wheel: # If the file is a wheel, return the downloaded file directly. assert downloaded return downloaded.path # Check the built wheel cache again after hashes are resolved. if not ireq.editable: cache_entry = wheel_cache.get_cache_entry( ireq.link, ireq.req.project_name, # type: ignore supported_tags, ) if cache_entry is not None: termui.logger.debug("Using cached wheel link: %s", cache_entry.link) return cache_entry.link.file_path # Otherwise, as all source is already prepared, build it. output_dir = os.path.join(build_dir, "dist") if not os.path.exists(output_dir): os.makedirs(output_dir, exist_ok=True) if ireq.editable: builder = EnvEggInfoBuilder(ireq.unpacked_source_directory, self) ret = ireq.metadata_directory = builder.build(output_dir) return ret should_cache = False if ireq.link.is_vcs: vcs = pip_shims.VcsSupport() vcs_backend = vcs.get_backend_for_scheme(ireq.link.scheme) if vcs_backend and vcs_backend.is_immutable_rev_checkout( ireq.link.url, ireq.source_dir): should_cache = True elif not ireq.link.is_existing_dir: base, _ = ireq.link.splitext() if _egg_info_re.search(base) is not None: # Determine whether the string looks like an egg_info. should_cache = True if should_cache: output_dir = wheel_cache.get_path_for_link(ireq.link) if not os.path.exists(output_dir): os.makedirs(output_dir, exist_ok=True) return EnvWheelBuilder(ireq.unpacked_source_directory, self).build(output_dir)