Beispiel #1
0
    def _clone_legacy(url: str, refspec: GitRefSpec, target: Path) -> Repo:
        """
        Helper method to facilitate fallback to using system provided git client via
        subprocess calls.
        """
        from poetry.vcs.git.system import SystemGit

        logger.debug("Cloning '%s' using system git client", url)

        if target.exists():
            remove_directory(path=target, force=True)

        revision = refspec.tag or refspec.branch or refspec.revision or "HEAD"

        try:
            SystemGit.clone(url, target)
        except CalledProcessError:
            raise PoetrySimpleConsoleException(
                f"Failed to clone {url}, check your git configuration and permissions"
                " for this repository."
            )

        if revision:
            revision.replace("refs/head/", "")
            revision.replace("refs/tags/", "")

        try:
            SystemGit.checkout(revision, target)
        except CalledProcessError:
            raise PoetrySimpleConsoleException(
                f"Failed to checkout {url} at '{revision}'"
            )

        repo = Repo(str(target))  # type: ignore[no-untyped-call]
        return repo
Beispiel #2
0
 def err_on_rm_venv_only(path: Path | str, *args: Any,
                         **kwargs: Any) -> None:
     if str(path) == str(venv_path):
         raise OSError(16,
                       "Test error")  # ERRNO 16: Device or resource busy
     else:
         remove_directory(path)
Beispiel #3
0
    def _remove(self, operation: Uninstall) -> int:
        package = operation.package

        # If we have a VCS package, remove its source directory
        if package.source_type == "git":
            src_dir = self._env.path / "src" / package.name
            if src_dir.exists():
                remove_directory(src_dir, force=True)

        try:
            return self.run_pip("uninstall", package.name, "-y")
        except CalledProcessError as e:
            if "not installed" in str(e):
                return 0

            raise
Beispiel #4
0
    def remove(self, package: Package) -> None:
        try:
            self.run("uninstall", package.name, "-y")
        except CalledProcessError as e:
            if "not installed" in str(e):
                return

            raise

        # This is a workaround for https://github.com/pypa/pip/issues/4176
        for nspkg_pth_file in self._env.site_packages.find_distribution_nspkg_pth_files(
                distribution_name=package.name):
            nspkg_pth_file.unlink()

        # If we have a VCS package, remove its source directory
        if package.source_type == "git":
            src_dir = self._env.path / "src" / package.name
            if src_dir.exists():
                remove_directory(src_dir, force=True)
Beispiel #5
0
def tmp_dir() -> Iterator[str]:
    dir_ = tempfile.mkdtemp(prefix="poetry_")

    yield Path(dir_).resolve().as_posix()

    remove_directory(dir_, force=True)
Beispiel #6
0
    def clone(
        cls,
        url: str,
        name: str | None = None,
        branch: str | None = None,
        tag: str | None = None,
        revision: str | None = None,
        source_root: Path | None = None,
        clean: bool = False,
    ) -> Repo:
        source_root = source_root or cls.get_default_source_root()
        source_root.mkdir(parents=True, exist_ok=True)

        name = name or cls.get_name_from_source_url(url=url)
        target = source_root / name
        refspec = GitRefSpec(branch=branch, revision=revision, tag=tag)

        if target.exists():
            if clean:
                # force clean the local copy if it exists, do not reuse
                remove_directory(target, force=True)
            else:
                # check if the current local copy matches the requested ref spec
                try:
                    current_repo = Repo(str(target))  # type: ignore[no-untyped-call]

                    with current_repo:
                        current_sha = current_repo.head().decode("utf-8")
                except (NotGitRepository, AssertionError, KeyError):
                    # something is wrong with the current checkout, clean it
                    remove_directory(target, force=True)
                else:
                    if not is_revision_sha(revision=current_sha):
                        # head is not a sha, this will cause issues later, lets reset
                        remove_directory(target, force=True)
                    elif (
                        refspec.is_sha
                        and refspec.revision is not None
                        and current_sha.startswith(refspec.revision)
                    ):
                        # if revision is used short-circuit remote fetch head matches
                        return current_repo

        try:
            if not cls.is_using_legacy_client():
                local = cls._clone(url=url, refspec=refspec, target=target)
                cls._clone_submodules(repo=local)
                return local
        except HTTPUnauthorized:
            # we do this here to handle http authenticated repositories as dulwich
            # does not currently support using credentials from git-credential helpers.
            # upstream issue: https://github.com/jelmer/dulwich/issues/873
            #
            # this is a little inefficient, however preferred as this is transparent
            # without additional configuration or changes for existing projects that
            # use http basic auth credentials.
            logger.debug(
                "Unable to fetch from private repository '%s', falling back to"
                " system git",
                url,
            )

        # fallback to legacy git client
        return cls._clone_legacy(url=url, refspec=refspec, target=target)
Beispiel #7
0
    def _clone(cls, url: str, refspec: GitRefSpec, target: Path) -> Repo:
        """
        Helper method to clone a remove repository at the given `url` at the specified
        ref spec.
        """
        local: Repo
        if not target.exists():
            local = Repo.init(str(target), mkdir=True)  # type: ignore[no-untyped-call]
            porcelain.remote_add(local, "origin", url)  # type: ignore[no-untyped-call]
        else:
            local = Repo(str(target))  # type: ignore[no-untyped-call]

        remote_refs = cls._fetch_remote_refs(url=url, local=local)

        logger.debug(
            "Cloning <c2>%s</> at '<c2>%s</>' to <c1>%s</>", url, refspec.key, target
        )

        try:
            refspec.resolve(remote_refs=remote_refs)
        except KeyError:  # branch / ref does not exist
            raise PoetrySimpleConsoleException(
                f"Failed to clone {url} at '{refspec.key}', verify ref exists on"
                " remote."
            )

        # ensure local HEAD matches remote
        local.refs[b"HEAD"] = remote_refs.refs[b"HEAD"]

        if refspec.is_ref:
            # set ref to current HEAD
            local.refs[refspec.ref] = local.refs[b"HEAD"]

        for base, prefix in {
            (b"refs/remotes/origin", b"refs/heads/"),
            (b"refs/tags", b"refs/tags"),
        }:
            local.refs.import_refs(  # type: ignore[no-untyped-call]
                base=base,
                other={
                    n[len(prefix) :]: v
                    for (n, v) in remote_refs.refs.items()
                    if n.startswith(prefix) and not n.endswith(ANNOTATED_TAG_SUFFIX)
                },
            )

        try:
            with local:
                local.reset_index()  # type: ignore[no-untyped-call]
        except (AssertionError, KeyError) as e:
            # this implies the ref we need does not exist or is invalid
            if isinstance(e, KeyError):
                # the local copy is at a bad state, lets remove it
                logger.debug(
                    "Removing local clone (<c1>%s</>) of repository as it is in a"
                    " broken state.",
                    local.path,
                )
                remove_directory(local.path, force=True)

            if isinstance(e, AssertionError) and "Invalid object name" not in str(e):
                raise

            logger.debug(
                "\nRequested ref (<c2>%s</c2>) was not fetched to local copy and cannot"
                " be used. The following error was raised:\n\n\t<warning>%s</>",
                refspec.key,
                e,
            )

            raise PoetrySimpleConsoleException(
                f"Failed to clone {url} at '{refspec.key}', verify ref exists on"
                " remote."
            )

        return local
Beispiel #8
0
def tmp_dir() -> Iterator[str]:
    dir_ = tempfile.mkdtemp(prefix="poetry_")

    yield dir_

    remove_directory(dir_, force=True)