Example #1
0
 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
Example #2
0
 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-")
Example #3
0
    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
Example #4
0
    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)
Example #5
0
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
Example #6
0
    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)