Commit 4fe39a33 by Sébastien Eustace Committed by Arun Babu Neelicattu

Add a `plugin remove` command

parent 594697d5
...@@ -72,6 +72,7 @@ COMMANDS = [ ...@@ -72,6 +72,7 @@ COMMANDS = [
"env use", "env use",
# Plugin commands # Plugin commands
"plugin add", "plugin add",
"plugin remove",
"plugin show", "plugin show",
# Self commands # Self commands
"self update", "self update",
......
import os
from typing import TYPE_CHECKING
from typing import cast
from cleo.helpers import argument
from cleo.helpers import option
from poetry.console.commands.command import Command
if TYPE_CHECKING:
from poetry.console.application import Application # noqa
from poetry.console.commands.remove import RemoveCommand
class PluginRemoveCommand(Command):
name = "plugin remove"
description = "Removes installed plugins"
arguments = [
argument("plugins", "The names of the plugins to install.", multiple=True),
]
options = [
option(
"dry-run",
None,
"Output the operations but do not execute anything (implicitly enables --verbose).",
)
]
def handle(self) -> int:
from pathlib import Path
from cleo.io.inputs.string_input import StringInput
from cleo.io.io import IO
from poetry.factory import Factory
from poetry.utils.env import EnvManager
plugins = self.argument("plugins")
system_env = EnvManager.get_system_env()
env_dir = Path(
os.getenv("POETRY_HOME") if os.getenv("POETRY_HOME") else system_env.path
)
# From this point forward, all the logic will be deferred to
# the remove command, by using the global `pyproject.toml` file.
application = cast("Application", self.application)
remove_command: "RemoveCommand" = cast(
"RemoveCommand", application.find("remove")
)
# We won't go through the event dispatching done by the application
# so we need to configure the command manually
remove_command.set_poetry(Factory().create_poetry(env_dir))
remove_command.set_env(system_env)
application._configure_installer(remove_command, self._io)
argv = ["remove"] + plugins
if self.option("dry-run"):
argv.append("--dry-run")
return remove_command.run(
IO(
StringInput(" ".join(argv)),
self._io.output,
self._io.error_output,
)
)
from cleo.helpers import argument from cleo.helpers import argument
from cleo.helpers import option from cleo.helpers import option
from ...utils.helpers import canonicalize_name
from .installer_command import InstallerCommand from .installer_command import InstallerCommand
...@@ -54,12 +55,17 @@ list of installed packages ...@@ -54,12 +55,17 @@ list of installed packages
for key in requirements: for key in requirements:
del poetry_content[section][key] del poetry_content[section][key]
# Write the new content back dependencies = (
self.poetry.file.write(content) self.poetry.package.requires
if section == "dependencies"
else self.poetry.package.dev_requires
)
# Update packages for i, dependency in enumerate(reversed(dependencies)):
self.reset_poetry() if dependency.name == canonicalize_name(key):
del dependencies[-i]
# Update packages
self._installer.use_executor( self._installer.use_executor(
self.poetry.config.get("experimental.new-installer", False) self.poetry.config.get("experimental.new-installer", False)
) )
...@@ -76,15 +82,7 @@ list of installed packages ...@@ -76,15 +82,7 @@ list of installed packages
raise raise
if status != 0 or self.option("dry-run"):
# Revert changes
if not self.option("dry-run"): if not self.option("dry-run"):
self.line_error( self.poetry.file.write(content)
"\n"
"Removal failed, reverting pyproject.toml "
"to its original content."
)
self.poetry.file.write(original_content)
return status return status
import pytest
import tomlkit
from poetry.__version__ import __version__
from poetry.core.packages.package import Package
from poetry.factory import Factory
from poetry.layouts.layout import POETRY_DEFAULT
from poetry.repositories.installed_repository import InstalledRepository
from poetry.repositories.pool import Pool
from poetry.utils.env import EnvManager
@pytest.fixture()
def tester(command_tester_factory):
return command_tester_factory("plugin remove")
@pytest.fixture()
def installed():
repository = InstalledRepository()
repository.add_package(Package("poetry", __version__))
return repository
def configure_sources_factory(repo):
def _configure_sources(poetry, sources, config, io):
pool = Pool()
pool.add_repository(repo)
poetry.set_pool(pool)
return _configure_sources
@pytest.fixture(autouse=True)
def setup_mocks(mocker, env, repo, installed):
mocker.patch.object(EnvManager, "get_system_env", return_value=env)
mocker.patch.object(InstalledRepository, "load", return_value=installed)
mocker.patch.object(
Factory, "configure_sources", side_effect=configure_sources_factory(repo)
)
@pytest.fixture()
def pyproject(env):
pyproject = tomlkit.loads(POETRY_DEFAULT)
content = pyproject["tool"]["poetry"]
content["name"] = "poetry"
content["version"] = __version__
content["description"] = ""
content["authors"] = ["Sébastien Eustace <sebastien@eustace.io>"]
dependency_section = content["dependencies"]
dependency_section["python"] = "^3.6"
env.path.joinpath("pyproject.toml").write_text(
tomlkit.dumps(pyproject), encoding="utf-8"
)
def test_remove_installed_package(app, repo, tester, env, installed, pyproject):
lock_content = {
"package": [
{
"name": "poetry-plugin",
"version": "1.2.3",
"category": "main",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
},
],
"metadata": {
"python-versions": "^3.6",
"platform": "*",
"content-hash": "123456789",
"hashes": {"poetry-plugin": []},
},
}
env.path.joinpath("poetry.lock").write_text(
tomlkit.dumps(lock_content), encoding="utf-8"
)
pyproject = tomlkit.loads(
env.path.joinpath("pyproject.toml").read_text(encoding="utf-8")
)
content = pyproject["tool"]["poetry"]
dependency_section = content["dependencies"]
dependency_section["poetry-plugin"] = "^1.2.3"
env.path.joinpath("pyproject.toml").write_text(
tomlkit.dumps(pyproject), encoding="utf-8"
)
installed.add_package(Package("poetry-plugin", "1.2.3"))
tester.execute("poetry-plugin")
expected = """\
Updating dependencies
Resolving dependencies...
Writing lock file
Package operations: 0 installs, 0 updates, 1 removal
• Removing poetry-plugin (1.2.3)
"""
assert tester.io.fetch_output() == expected
remove_command = app.find("remove")
assert remove_command.poetry.file.parent == env.path
assert remove_command.poetry.locker.lock.parent == env.path
assert remove_command.poetry.locker.lock.exists()
assert not remove_command.installer.executor._dry_run
content = remove_command.poetry.file.read()["tool"]["poetry"]
assert "poetry-plugin" not in content["dependencies"]
def test_remove_installed_package_dry_run(app, repo, tester, env, installed, pyproject):
lock_content = {
"package": [
{
"name": "poetry-plugin",
"version": "1.2.3",
"category": "main",
"optional": False,
"platform": "*",
"python-versions": "*",
"checksum": [],
},
],
"metadata": {
"python-versions": "^3.6",
"platform": "*",
"content-hash": "123456789",
"hashes": {"poetry-plugin": []},
},
}
env.path.joinpath("poetry.lock").write_text(
tomlkit.dumps(lock_content), encoding="utf-8"
)
pyproject = tomlkit.loads(
env.path.joinpath("pyproject.toml").read_text(encoding="utf-8")
)
content = pyproject["tool"]["poetry"]
dependency_section = content["dependencies"]
dependency_section["poetry-plugin"] = "^1.2.3"
env.path.joinpath("pyproject.toml").write_text(
tomlkit.dumps(pyproject), encoding="utf-8"
)
installed.add_package(Package("poetry-plugin", "1.2.3"))
tester.execute("poetry-plugin --dry-run")
expected = """\
Updating dependencies
Resolving dependencies...
Writing lock file
Package operations: 0 installs, 0 updates, 1 removal
• Removing poetry-plugin (1.2.3)
• Removing poetry-plugin (1.2.3)
"""
assert tester.io.fetch_output() == expected
remove_command = app.find("remove")
assert remove_command.poetry.file.parent == env.path
assert remove_command.poetry.locker.lock.parent == env.path
assert remove_command.poetry.locker.lock.exists()
assert remove_command.installer.executor._dry_run
content = remove_command.poetry.file.read()["tool"]["poetry"]
assert "poetry-plugin" in content["dependencies"]
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment