Commit 2c53da3f by Sébastien Eustace

Improve locking and installation

parent b6c1c279
......@@ -47,15 +47,6 @@ class Installer:
local_repo = Repository()
self._do_install(local_repo)
if self._update and self._write_lock:
updated_lock = self._locker.set_lock_data(
self._package,
local_repo.packages
)
if updated_lock:
self._io.writeln('<info>Writing lock file</>')
return 0
def dry_run(self, dry_run=True) -> 'Installer':
......@@ -99,7 +90,7 @@ class Installer:
locked_repository = Repository()
# initialize locked repo if we are installing from lock
if not self._update or self._locker.is_locked():
locked_repository = self._locker.locked_repository(self._dev_mode)
locked_repository = self._locker.locked_repository(True)
if self._update:
self._io.writeln('<info>Updating dependencies</>')
......@@ -121,15 +112,9 @@ class Installer:
self._io.new_line()
# Execute operations
if not ops:
if not ops and self._execute_operations:
self._io.writeln('Nothing to install or update')
# extract dev packages and mark them to be skipped
# if it's a --no-dev install or update
# we also force them to be uninstalled
# if they are present in the local repo
# TODO
if ops and (self._execute_operations or self._dry_run):
installs = []
updates = []
......@@ -166,6 +151,30 @@ class Installer:
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
if self._update and self._write_lock:
updated_lock = self._locker.set_lock_data(
self._package,
local_repo.packages
)
if updated_lock:
self._io.writeln('<info>Writing lock file</>')
self._io.writeln('')
for op in ops:
self._execute(op)
def _execute(self, operation: Operation) -> None:
......@@ -177,6 +186,7 @@ class Installer:
getattr(self, f'_execute_{method}')(operation)
def _execute_install(self, operation: Install) -> None:
if self._execute_operations or self.is_dry_run():
self._io.writeln(
f' - Installing <info>{operation.package.name}</> '
f'(<comment>{operation.package.full_pretty_version}</>)'
......@@ -191,6 +201,7 @@ class Installer:
source = operation.target_package
target = operation.target_package
if self._execute_operations or self.is_dry_run():
self._io.writeln(
f' - Updating <info>{target.name}</> '
f'(<comment>{source.pretty_version}</>'
......@@ -203,6 +214,7 @@ class Installer:
self._installer.update(source, target)
def _execute_uninstall(self, operation: Uninstall) -> None:
if self._execute_operations or self.is_dry_run():
self._io.writeln(
f' - Removing <info>{operation.package.name}</> '
f'(<comment>{operation.package.full_pretty_version}</>)'
......@@ -224,7 +236,9 @@ class Installer:
for installed in installed_repo.packages:
if locked.name == installed.name:
is_installed = True
if locked.version != installed.version:
if locked.category == 'dev' and not self.is_dev_mode():
ops.append(Uninstall(locked))
elif locked.version != installed.version:
ops.append(Update(
installed, locked
))
......
......@@ -14,7 +14,7 @@ class PipInstaller:
self.run('install', self.requirement(target), '--no-deps', '-U')
def remove(self, package):
self.run('uninstall', package.name)
self.run('uninstall', package.name, '-y')
def run(self, *args) -> str:
return self._venv.run('pip', *args)
......
......@@ -3,7 +3,7 @@ from poetry.semver.version_parser import VersionParser
class Dependency:
def __init__(self, name, constraint, optional=False):
def __init__(self, name, constraint, optional=False, category='main'):
self._name = name.lower()
try:
self._constraint = VersionParser().parse_constraints(constraint)
......@@ -12,6 +12,7 @@ class Dependency:
self._pretty_constraint = constraint
self._optional = optional
self._category = category
@property
def name(self):
......@@ -29,6 +30,10 @@ class Dependency:
def pretty_name(self):
return '{} ({})'.format(self._name, self._pretty_constraint)
@property
def category(self):
return self._category
def accepts_prereleases(self):
return False
......
......@@ -74,34 +74,35 @@ class Locker:
return packages
for info in locked_packages:
packages.add_package(
poetry.packages.Package(
info['name'], info['version'], info['version']
)
package = poetry.packages.Package(
info['name'],
info['version'],
info['version']
)
package.category = info['category']
package.optional = info['optional']
package.hashes = info['checksum']
package.python_versions = info['python-versions']
packages.add_package(package)
return packages
def set_lock_data(self,
root, packages,
python_versions=None, platform=None) -> bool:
root, packages) -> bool:
lock = {
'root': {
'name': root.name,
'version': root.version,
'python_versions': python_versions or '*'
'python_versions': root.python_versions,
'platform': root.platform
},
'packages': None,
'packages': self._lock_packages(packages),
'metadata': {
'content-hash': self._content_hash
}
}
if platform is not None:
lock['root']['platform'] = platform
lock['packages'] = self._lock_packages(packages)
if not self.is_locked() or lock != self.lock_data:
self._lock.write(lock)
self._lock_data = None
......@@ -156,6 +157,7 @@ class Locker:
'category': package.category,
'optional': package.optional,
'python-versions': package.python_versions,
'platform': package.platform,
'checksum': package.hashes
}
......
......@@ -63,7 +63,7 @@ class Package:
self.hashes = []
self.optional = False
self.python_versions = '*'
self.platform = None
self.platform = '*'
@property
def name(self):
......@@ -111,7 +111,7 @@ class Package:
def is_prerelease(self):
return self._stability != 'stable'
def add_dependency(self, name, constraint=None, dev=False):
def add_dependency(self, name, constraint=None, category='main'):
if constraint is None:
constraint = '*'
......@@ -122,11 +122,11 @@ class Package:
else:
version = constraint['version']
optional = constraint.get('optional', False)
dependency = Dependency(name, version, optional=optional)
dependency = Dependency(name, version, optional=optional, category=category)
else:
dependency = Dependency(name, constraint)
dependency = Dependency(name, constraint, category=category)
if dev:
if category == 'dev':
self.dev_requires.append(dependency)
else:
self.requires.append(dependency)
......
......@@ -61,7 +61,7 @@ class Poetry:
if 'dev-dependencies' in local_config:
for name, constraint in local_config['dev-dependencies'].items():
package.add_dependency(name, constraint, dev=True)
package.add_dependency(name, constraint, category='dev')
locker = Locker(poetry_file.with_suffix('.lock'), poetry_file)
......
......@@ -29,6 +29,14 @@ class Solver:
packages = [v.payload for v in graph.vertices.values()]
# Setting categories
for vertex in graph.vertices.values():
tags = self._get_categories_for_vertex(vertex, requested)
if 'main' in tags:
vertex.payload.category = 'main'
else:
vertex.payload.category = 'dev'
operations = []
for package in packages:
installed = False
......@@ -56,3 +64,16 @@ class Solver:
operations.append(Uninstall(pkg))
return list(reversed(operations))
def _get_categories_for_vertex(self, vertex, requested):
tags = []
if not vertex.incoming_edges:
# Original dependency
for req in requested:
if req.name == vertex.name:
tags.append(req.category)
else:
for edge in vertex.incoming_edges:
tags += self._get_categories_for_vertex(edge.origin, requested)
return tags
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