Ejemplo n.º 1
0
def export(
    project: Project,
    candidates: list[Candidate] | list[Requirement],
    options: Namespace,
) -> str:
    lines = []
    for candidate in sorted(candidates, key=lambda x: x.identify()):  # type: ignore
        if isinstance(candidate, Candidate):
            req = dataclasses.replace(
                candidate.req, specifier=f"=={candidate.version}", marker=None
            )
        else:
            assert isinstance(candidate, Requirement)
            req = candidate
        lines.append(
            req.as_line().replace(
                "${PROJECT_ROOT}", project.root.absolute().as_posix().lstrip("/")
            )
        )
        if options.hashes and getattr(candidate, "hashes", None):
            for item in candidate.hashes.values():  # type: ignore
                lines.append(f" \\\n    --hash={item}")
        lines.append("\n")
    sources = project.tool_settings.get("source", [])
    for source in sources:
        url = expand_env_vars_in_auth(source["url"])
        prefix = "--index-url" if source["name"] == "pypi" else "--extra-index-url"
        lines.append(f"{prefix} {url}\n")
        if not source.get("verify_ssl", True):
            host = urllib.parse.urlparse(url).hostname
            lines.append(f"--trusted-host {host}\n")
    return "".join(lines)
Ejemplo n.º 2
0
    def get_finder(
        self,
        sources: Optional[List[Source]] = None,
        ignore_requires_python: bool = False,
    ) -> Generator[pip_shims.PackageFinder, None, None]:
        """Return the package finder of given index sources.

        :param sources: a list of sources the finder should search in.
        :param ignore_requires_python: whether to ignore the python version constraint.
        """
        if sources is None:
            sources = self.project.sources
        for source in sources:
            source["url"] = expand_env_vars_in_auth(source["url"])

        python_version, _ = get_python_version(self.python_executable,
                                               digits=2)
        finder = get_finder(
            sources,
            self.project.cache_dir.as_posix(),
            python_version,
            ignore_requires_python,
        )
        # Reuse the auth across sessions to avoid prompting repeatly.
        finder.session.auth = self.auth
        yield finder
        finder.session.close()
Ejemplo n.º 3
0
 def direct_url(self) -> dict[str, Any] | None:
     """PEP 610 direct_url.json data"""
     req = self.req
     if isinstance(req, VcsRequirement):
         if req.editable:
             assert self.ireq.source_dir
             return _filter_none({
                 "url":
                 pip_shims.path_to_url(self.ireq.source_dir),
                 "dir_info": {
                     "editable": True
                 },
                 "subdirectory":
                 req.subdirectory,
             })
         return _filter_none({
             "url":
             url_without_fragments(req.repo),
             "vcs_info":
             _filter_none({
                 "vcs": req.vcs,
                 "requested_revision": req.ref,
                 "commit_id": self.revision,
             }),
             "subdirectory":
             req.subdirectory,
         })
     elif isinstance(req, FileRequirement):
         if req.is_local_dir:
             return _filter_none({
                 "url":
                 url_without_fragments(req.url),
                 "dir_info":
                 _filter_none({"editable": req.editable or None}),
                 "subdirectory":
                 req.subdirectory,
             })
         url = expand_env_vars_in_auth(
             req.url.replace(
                 "${PROJECT_ROOT}",
                 self.environment.project.root.as_posix().
                 lstrip(  # type: ignore
                     "/"),
             ))
         with self.environment.get_finder() as finder:
             hash_cache = self.environment.project.make_hash_cache()
             hash_cache.session = finder.session  # type: ignore
             return _filter_none({
                 "url": url_without_fragments(url),
                 "archive_info": {
                     "hash":
                     hash_cache.get_hash(pip_shims.Link(url)).replace(
                         ":", "=")
                 },
                 "subdirectory": req.subdirectory,
             })
     else:
         return None
Ejemplo n.º 4
0
 def ireq(self) -> pip_shims.InstallRequirement:
     rv = self.req.as_ireq()
     if rv.link:
         rv.link = pip_shims.Link(
             expand_env_vars_in_auth(
                 rv.link.url.replace(
                     "${PROJECT_ROOT}",
                     self.environment.project.root.as_posix().lstrip("/"),
                 )
             )
         )
         if rv.source_dir:
             rv.source_dir = os.path.normpath(os.path.abspath(rv.link.file_path))
         if rv.local_file_path:
             rv.local_file_path = rv.link.file_path
     return rv
Ejemplo n.º 5
0
 def get_ireq(self) -> pip_shims.InstallRequirement:
     rv, project = self.req.as_ireq(), self.environment.project
     if rv.link:
         rv.original_link = rv.link = pip_shims.Link(
             expand_env_vars_in_auth(
                 rv.link.url.replace(
                     "${PROJECT_ROOT}",
                     project.root.as_posix().lstrip("/"),  # type: ignore
                 )))
         if rv.source_dir:
             rv.source_dir = os.path.normpath(
                 os.path.abspath(rv.link.file_path))
         if rv.local_file_path:
             rv.local_file_path = rv.link.file_path
     elif self.candidate.link:
         rv.link = rv.original_link = self.candidate.link
     return rv
Ejemplo n.º 6
0
 def sources(self) -> list[Source]:
     sources = list(self.tool_settings.get("source", []))
     if all(source.get("name") != "pypi" for source in sources):
         sources.insert(
             0,
             {
                 "url": self.config["pypi.url"],
                 "verify_ssl": self.config["pypi.verify_ssl"],
                 "name": "pypi",
             },
         )
     expanded_sources: list[Source] = [
         Source(
             url=expand_env_vars_in_auth(s["url"]),
             verify_ssl=s.get("verify_ssl", True),
             name=s.get("name",
                        urlparse(s["url"]).hostname),
         ) for s in sources
     ]
     return expanded_sources
Ejemplo n.º 7
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
Ejemplo n.º 8
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)
Ejemplo n.º 9
0
def test_expend_env_vars_in_auth(given, expected, monkeypatch):
    monkeypatch.setenv("FOO", "hello")
    monkeypatch.setenv("BAR", "wo:rld")
    assert utils.expand_env_vars_in_auth(given) == expected