def configure_sources(cls, poetry: Poetry, sources: list[dict[str, str]], config: Config, io: IO) -> None: for source in sources: repository = cls.create_legacy_repository(source, config) is_default = bool(source.get("default", False)) is_secondary = bool(source.get("secondary", False)) if io.is_debug(): message = f"Adding repository {repository.name} ({repository.url})" if is_default: message += " and setting it as the default one" elif is_secondary: message += " and setting it as secondary" io.write_line(message) poetry.pool.add_repository(repository, is_default, secondary=is_secondary) # Put PyPI last to prefer private repositories # unless we have no default source AND no primary sources # (default = false, secondary = false) if poetry.pool.has_default(): if io.is_debug(): io.write_line("Deactivating the PyPI repository") else: from poetry.repositories.pypi_repository import PyPiRepository default = not poetry.pool.has_primary_repositories() poetry.pool.add_repository(PyPiRepository(), default, not default)
def _download(self, destination: pathlib.Path, io: cleo_io.IO) -> pathlib.Path: req = requests.get(self.url, stream=True) length = int(req.headers.get("content-length", 0)) progress = progress_bar.ProgressBar(io, max=length) io.write_line(f"Downloading <info>{self.url}</>") if req.status_code < 200 or req.status_code >= 300: raise RuntimeError(f"download failed: {req.status_code}") progress.start(length) try: with open(destination, "wb") as f: for chunk in req.iter_content(chunk_size=4096): if chunk: progress.advance(len(chunk)) f.write(chunk) except BaseException: if destination.exists(): destination.unlink() finally: progress.finish() io.write_line("") try: self.verify(destination) except Exception: destination.unlink() raise return destination
def display_package_tree(self, io: IO, package: Package, installed_repo: Repository) -> None: io.write(f"<c1>{package.pretty_name}</c1>") description = "" if package.description: description = " " + package.description io.write_line(f" <b>{package.pretty_version}</b>{description}") dependencies = package.requires dependencies = sorted(dependencies, key=lambda x: x.name) tree_bar = "├" total = len(dependencies) for i, dependency in enumerate(dependencies, 1): if i == total: tree_bar = "└" level = 1 color = self.colors[level] info = (f"{tree_bar}── <{color}>{dependency.name}</{color}>" f" {dependency.pretty_constraint}") self._write_tree_line(io, info) tree_bar = tree_bar.replace("└", " ") packages_in_tree = [package.name, dependency.name] self._display_tree(io, dependency, installed_repo, packages_in_tree, tree_bar, level + 1)
def _write_tree_line(self, io: IO, line: str) -> None: if not io.output.supports_utf8(): line = line.replace("└", "`-") line = line.replace("├", "|-") line = line.replace("──", "-") line = line.replace("│", "|") io.write_line(line)
def download(self, io: cleo_io.IO) -> pathlib.Path: destination_dir = cache.cachedir() / "distfiles" if not destination_dir.exists(): destination_dir.mkdir() destination = destination_dir / self.name if destination.exists(): try: self.verify(destination) except Exception: io.write_line( f"<warning>Cached {self.name} exists, but does pass " f"verification. Downloading anew.") else: return destination return self._download(destination, io)
def deactivate(self, io: IO) -> None: venv_path = self._poetry.config.get("virtualenvs.path") if venv_path is None: venv_path = Path(CACHE_DIR) / "virtualenvs" else: venv_path = Path(venv_path) name = self._poetry.package.name name = self.generate_env_name(name, str(self._poetry.file.parent)) envs_file = TOMLFile(venv_path / self.ENVS_FILE) if envs_file.exists(): envs = envs_file.read() env = envs.get(name) if env is not None: io.write_line( "Deactivating virtualenv: <comment>{}</comment>".format( venv_path / (name + "-py{}".format(env["minor"])))) del envs[name] envs_file.write(envs)
def create_venv( self, io: IO, name: Optional[str] = None, executable: Optional[str] = None, force: bool = False, ) -> Union["SystemEnv", "VirtualEnv"]: if self._env is not None and not force: return self._env cwd = self._poetry.file.parent env = self.get(reload=True) if not env.is_sane(): force = True if env.is_venv() and not force: # Already inside a virtualenv. return env create_venv = self._poetry.config.get("virtualenvs.create") root_venv = self._poetry.config.get("virtualenvs.in-project") venv_path = self._poetry.config.get("virtualenvs.path") if root_venv: venv_path = cwd / ".venv" elif venv_path is None: venv_path = Path(CACHE_DIR) / "virtualenvs" else: venv_path = Path(venv_path) if not name: name = self._poetry.package.name python_patch = ".".join([str(v) for v in sys.version_info[:3]]) python_minor = ".".join([str(v) for v in sys.version_info[:2]]) if executable: python_patch = decode( subprocess.check_output( list_to_shell_command([ executable, "-c", "\"import sys; print('.'.join([str(s) for s in sys.version_info[:3]]))\"", ]), shell=True, ).strip()) python_minor = ".".join(python_patch.split(".")[:2]) supported_python = self._poetry.package.python_constraint if not supported_python.allows(Version.parse(python_patch)): # The currently activated or chosen Python version # is not compatible with the Python constraint specified # for the project. # If an executable has been specified, we stop there # and notify the user of the incompatibility. # Otherwise, we try to find a compatible Python version. if executable: raise NoCompatiblePythonVersionFound( self._poetry.package.python_versions, python_patch) io.write_line( "<warning>The currently activated Python version {} " "is not supported by the project ({}).\n" "Trying to find and use a compatible version.</warning> ". format(python_patch, self._poetry.package.python_versions)) for python_to_try in reversed( sorted( self._poetry.package.AVAILABLE_PYTHONS, key=lambda v: (v.startswith("3"), -len(v), v), )): if len(python_to_try) == 1: if not parse_constraint("^{}.0".format( python_to_try)).allows_any(supported_python): continue elif not supported_python.allows_all( parse_constraint(python_to_try + ".*")): continue python = "python" + python_to_try if io.is_debug(): io.write_line("<debug>Trying {}</debug>".format(python)) try: python_patch = decode( subprocess.check_output( list_to_shell_command([ python, "-c", "\"import sys; print('.'.join([str(s) for s in sys.version_info[:3]]))\"", ]), stderr=subprocess.STDOUT, shell=True, ).strip()) except CalledProcessError: continue if not python_patch: continue if supported_python.allows(Version.parse(python_patch)): io.write_line("Using <c1>{}</c1> ({})".format( python, python_patch)) executable = python python_minor = ".".join(python_patch.split(".")[:2]) break if not executable: raise NoCompatiblePythonVersionFound( self._poetry.package.python_versions) if root_venv: venv = venv_path else: name = self.generate_env_name(name, str(cwd)) name = "{}-py{}".format(name, python_minor.strip()) venv = venv_path / name if not venv.exists(): if create_venv is False: io.write_line("<fg=black;bg=yellow>" "Skipping virtualenv creation, " "as specified in config file." "</>") return SystemEnv(Path(sys.prefix)) io.write_line("Creating virtualenv <c1>{}</> in {}".format( name, str(venv_path))) self.build_venv( venv, executable=executable, flags=self._poetry.config.get("virtualenvs.options"), ) else: if force: if not env.is_sane(): io.write_line( "<warning>The virtual environment found in {} seems to be broken.</warning>" .format(env.path)) io.write_line("Recreating virtualenv <c1>{}</> in {}".format( name, str(venv))) self.remove_venv(venv) self.build_venv( venv, executable=executable, flags=self._poetry.config.get("virtualenvs.options"), ) elif io.is_very_verbose(): io.write_line( "Virtualenv <c1>{}</> already exists.".format(name)) # venv detection: # stdlib venv may symlink sys.executable, so we can't use realpath. # but others can symlink *to* the venv Python, # so we can't just use sys.executable. # So we just check every item in the symlink tree (generally <= 3) p = os.path.normcase(sys.executable) paths = [p] while os.path.islink(p): p = os.path.normcase( os.path.join(os.path.dirname(p), os.readlink(p))) paths.append(p) p_venv = os.path.normcase(str(venv)) if any(p.startswith(p_venv) for p in paths): # Running properly in the virtualenv, don't need to do anything return SystemEnv(Path(sys.prefix), self.get_base_prefix()) return VirtualEnv(venv)
def activate(self, poetry: Poetry, io: IO) -> None: io.write_line("Updating version") poetry.package.set_version("9.9.9")
def activate(self, poetry: Poetry, io: IO) -> None: io.write_line("Setting readmes") poetry.package.readmes = ("README.md", )
def interact(self, io: IO) -> None: io.write_line("interact called")