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
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)
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
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)
def tmp_dir() -> Iterator[str]: dir_ = tempfile.mkdtemp(prefix="poetry_") yield Path(dir_).resolve().as_posix() remove_directory(dir_, force=True)
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)
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
def tmp_dir() -> Iterator[str]: dir_ = tempfile.mkdtemp(prefix="poetry_") yield dir_ remove_directory(dir_, force=True)