Commit e677299e by Sébastien Eustace

Add a remove command

parent 40569558
...@@ -10,6 +10,7 @@ from .commands import AddCommand ...@@ -10,6 +10,7 @@ from .commands import AddCommand
from .commands import InstallCommand from .commands import InstallCommand
from .commands import LockCommand from .commands import LockCommand
from .commands import NewCommand from .commands import NewCommand
from .commands import RemoveCommand
from .commands import UpdateCommand from .commands import UpdateCommand
...@@ -46,6 +47,7 @@ class Application(BaseApplication): ...@@ -46,6 +47,7 @@ class Application(BaseApplication):
InstallCommand(), InstallCommand(),
LockCommand(), LockCommand(),
NewCommand(), NewCommand(),
RemoveCommand(),
UpdateCommand(), UpdateCommand(),
] ]
......
...@@ -3,4 +3,5 @@ from .add import AddCommand ...@@ -3,4 +3,5 @@ from .add import AddCommand
from .install import InstallCommand from .install import InstallCommand
from .lock import LockCommand from .lock import LockCommand
from .new import NewCommand from .new import NewCommand
from .remove import RemoveCommand
from .update import UpdateCommand from .update import UpdateCommand
import toml
from poetry.installation import Installer
from .command import Command
class RemoveCommand(Command):
"""
Removes a package from the project dependencies.
remove
{ packages* : Packages that should be removed. }
{--D|dev : Removes a package from the development dependencies. }
{--dry-run : Outputs the operations but will not execute anything
(implicitly enables --verbose). }
"""
help = """The <info>remove</info> command removes a package from the current
list of installed packages
<info>poetry remove</info>"""
def handle(self):
packages = [p.lower() for p in self.argument('packages')]
is_dev = self.option('dev')
with self.poetry.locker.original.path.open() as fd:
content = fd.read().split('\n')
# Trying to figure out where are our dependencies
# If we find a toml library that keeps comments
# We could remove this whole section
section = '[dependencies]'
if is_dev:
section = '[dev-dependencies]'
# Searching for package in
in_section = False
indices = []
requirements = {}
for i, line in enumerate(content):
line = line.strip()
if line == section:
in_section = True
continue
if in_section:
if not line:
# End of section
break
requirement = toml.loads(line)
name = list(requirement.keys())[0].lower()
version = requirement[name]
if name in packages:
requirements[name] = version
indices.append(i)
break
if not indices or len(indices) != len(packages):
raise RuntimeError(
'Packages are not present in your poetry.toml file'
)
new_content = []
for i, line in enumerate(content):
if i in indices:
continue
new_content.append(line)
new_content = '\n'.join(new_content)
with self.poetry.locker.original.path.open('w') as fd:
fd.write(new_content)
# Update packages
self.reset_poetry()
installer = Installer(
self.output,
self.poetry.package,
self.poetry.locker,
self.poetry.repository
)
installer.dry_run(self.option('dry-run'))
installer.update(True)
installer.whitelist(requirements)
try:
status = installer.run()
except Exception:
with self.poetry.locker.original.path.open('w') as fd:
fd.write('\n'.join(content))
raise
if status != 0 or self.option('dry-run'):
# Revert changes
if not self.option('dry-run'):
self.error(
'\n'
'Removal failed, reverting poetry.toml '
'to its original content.'
)
with self.poetry.locker.original.path.open('w') as fd:
fd.write('\n'.join(content))
return status
...@@ -127,8 +127,7 @@ class Installer: ...@@ -127,8 +127,7 @@ class Installer:
solver = Solver(locked_repository, self._io) solver = Solver(locked_repository, self._io)
request = self._package.requires request = self._package.requires
if self.is_dev_mode(): request += self._package.dev_requires
request += self._package.dev_requires
ops = solver.solve(request, self._repository, fixed=fixed) ops = solver.solve(request, self._repository, fixed=fixed)
else: else:
...@@ -136,7 +135,19 @@ class Installer: ...@@ -136,7 +135,19 @@ class Installer:
# If we are installing from lock # If we are installing from lock
# Filter the operations by comparing it with what is # Filter the operations by comparing it with what is
# currently installed # currently installed
ops = self._get_operations_from_lock(locked_repository) ops = []
for package in locked_repository.packages:
ops.append(Install(package))
for op in ops:
if op.job_type == 'install':
local_repo.add_package(op.package)
elif op.job_type == 'update':
local_repo.add_package(op.target_package)
elif op.job_type == 'uninstall':
local_repo.remove_package(op.package)
ops = self._filter_operations(ops)
self._io.new_line() self._io.new_line()
...@@ -174,24 +185,6 @@ class Installer: ...@@ -174,24 +185,6 @@ class Installer:
) )
self._io.new_line() self._io.new_line()
for op in ops:
if op.job_type == 'install':
local_repo.add_package(op.package)
elif op.job_type == 'update':
local_repo.add_package(op.target_package)
# Adding untouched locked package
# to local_repo
if self._update:
for locked in locked_repository.packages:
untouched = True
for local_pkg in local_repo.packages:
if locked.name == local_pkg.name:
untouched = False
if untouched:
local_repo.add_package(locked)
# Writing lock before installing # Writing lock before installing
if self._update and self._write_lock: if self._update and self._write_lock:
updated_lock = self._locker.set_lock_data( updated_lock = self._locker.set_lock_data(
...@@ -254,28 +247,44 @@ class Installer: ...@@ -254,28 +247,44 @@ class Installer:
self._installer.remove(operation.package) self._installer.remove(operation.package)
def _get_operations_from_lock(self, def _filter_operations(self,
locked_repository: Repository ops: List[Operation]
) -> List[Operation]: ) -> List[Operation]:
installed_repo = InstalledRepository.load(self._io.venv) installed_repo = InstalledRepository.load(self._io.venv)
ops = [] new_ops = []
for op in ops:
if isinstance(op, Update):
package = op.target_package
else:
package = op.package
for locked in locked_repository.packages:
is_installed = False is_installed = False
for installed in installed_repo.packages: for installed in installed_repo.packages:
if locked.name == installed.name: if package.name == installed.name:
is_installed = True is_installed = True
if locked.category == 'dev' and not self.is_dev_mode(): if op.job_type == 'uninstall':
ops.append(Uninstall(locked)) new_ops.append(op)
elif locked.version != installed.version: break
ops.append(Update(
installed, locked if package.version != installed.version:
)) new_ops.append(Update(installed, package))
elif package.category == 'dev' and not self.is_dev_mode():
if op.job_type == 'uninstall':
new_ops.append(op)
else:
new_ops.append(Uninstall(installed))
else:
# Nothing to do
break
if not is_installed: if not is_installed:
ops.append(Install(locked)) if op.job_type in ['update', 'uninstall']:
continue
new_ops.append(op)
return ops return new_ops
...@@ -46,17 +46,17 @@ class Solver: ...@@ -46,17 +46,17 @@ class Solver:
operations = [] operations = []
for package in packages: for package in packages:
installed = False processed = False
for pkg in self._installed.packages: for pkg in self._installed.packages:
if package.name == pkg.name: if package.name == pkg.name:
installed = True
# Checking version # Checking version
if package.version != pkg.version: if package.version != pkg.version:
processed = True
operations.append(Update(pkg, package)) operations.append(Update(pkg, package))
break break
if not installed: if not processed:
operations.append(Install(package)) operations.append(Install(package))
# Checking for removals # Checking for removals
......
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