Skip to content

Commit

Permalink
lock: allow for no-update refresh of lock files
Browse files Browse the repository at this point in the history
Relates-to: #3028
  • Loading branch information
abn committed Oct 2, 2020
1 parent 9408eff commit a8678e4
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 5 deletions.
10 changes: 9 additions & 1 deletion poetry/console/commands/lock.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from cleo import option

from .installer_command import InstallerCommand


Expand All @@ -6,6 +8,12 @@ class LockCommand(InstallerCommand):
name = "lock"
description = "Locks the project dependencies."

options = [
option(
"no-update", None, "Do not update locked versions, only refresh lock file."
),
]

help = """
The <info>lock</info> command reads the <comment>pyproject.toml</> file from the
current directory, processes it, and locks the dependencies in the <comment>poetry.lock</>
Expand All @@ -21,6 +29,6 @@ def handle(self):
self.poetry.config.get("experimental.new-installer", False)
)

self._installer.lock()
self._installer.lock(update=not self.option("no-update"))

return self._installer.run()
26 changes: 22 additions & 4 deletions poetry/installation/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ def set_locker(self, locker): # type: (Locker) -> Installer
return self

def run(self):
# Check if refresh
if not self._update and self._lock and self._locker.is_locked():
return self._do_refresh()

# Force update if there is no lock file present
if not self._update and not self._locker.is_locked():
self._update = True
Expand Down Expand Up @@ -137,11 +141,11 @@ def update(self, update=True): # type: (bool) -> Installer

return self

def lock(self): # type: () -> Installer
def lock(self, update=True): # type: (bool) -> Installer
"""
Prepare the installer for locking only.
"""
self.update()
self.update(update=update)
self.execute_operations(False)
self._lock = True

Expand Down Expand Up @@ -173,6 +177,20 @@ def use_executor(self, use_executor=True): # type: (bool) -> Installer

return self

def _do_refresh(self):
# Checking extras
for extra in self._extras:
if extra not in self._package.extras:
raise ValueError("Extra [{}] is not specified.".format(extra))

ops = self._get_operations_from_lock(self._locker.locked_repository(True))
local_repo = Repository()
self._populate_local_repo(local_repo, ops)

self._write_lock_file(local_repo, force=True)

return 0

def _do_install(self, local_repo):
from poetry.puzzle import Solver

Expand Down Expand Up @@ -285,8 +303,8 @@ def _do_install(self, local_repo):
# Execute operations
return self._execute(ops)

def _write_lock_file(self, repo): # type: (Repository) -> None
if self._update and self._write_lock:
def _write_lock_file(self, repo, force=True): # type: (Repository, bool) -> None
if force or (self._update and self._write_lock):
updated_lock = self._locker.set_lock_data(self._package, repo.packages)

if updated_lock:
Expand Down
119 changes: 119 additions & 0 deletions tests/installation/fixtures/old-lock-refresh.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
[[package]]
name = "attrs"
version = "17.4.0"
description = "Classes Without Boilerplate"
category = "dev"
optional = false
python-versions = "*"

[package.extras]
dev = ["coverage", "hypothesis", "pympler", "pytest", "six", "zope.interface", "sphinx", "zope.interface"]
docs = ["sphinx", "zope.interface"]
tests = ["coverage", "hypothesis", "pympler", "pytest", "six", "zope.interface"]

[[package]]
name = "colorama"
version = "0.3.9"
description = "Cross-platform colored terminal text."
category = "dev"
optional = false
python-versions = "*"

[[package]]
name = "funcsigs"
version = "1.0.2"
description = "Python function signatures from PEP362 for Python 2.6, 2.7 and 3.2+"
category = "dev"
optional = false
python-versions = "*"

[[package]]
name = "more-itertools"
version = "4.1.0"
description = "More routines for operating on iterables, beyond itertools"
category = "dev"
optional = false
python-versions = "*"

[package.dependencies]
six = ">=1.0.0,<2.0.0"

[[package]]
name = "pluggy"
version = "0.6.0"
description = "plugin and hook calling mechanisms for python"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"

[[package]]
name = "py"
version = "1.5.3"
description = "library with cross-python path, ini-parsing, io, code, log facilities"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"

[[package]]
name = "pytest"
version = "3.5.0"
description = "pytest: simple powerful testing with Python"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"

[package.dependencies]
attrs = ">=17.4.0"
colorama = "*"
funcsigs = {version = "*", markers = "python_version < \"3.0\""}
more-itertools = ">=4.0.0"
pluggy = ">=0.5,<0.7"
py = ">=1.5.0"
six = ">=1.10.0"

[[package]]
name = "six"
version = "1.11.0"
description = "Python 2 and 3 compatibility utilities"
category = "dev"
optional = false
python-versions = "*"

[metadata]
lock-version = "1.1"
python-versions = "*"
content-hash = "123456789"

[metadata.files]
attrs = [
{file = "attrs-17.4.0-py2.py3-none-any.whl", hash = "sha256:a17a9573a6f475c99b551c0e0a812707ddda1ec9653bed04c13841404ed6f450"},
{file = "attrs-17.4.0.tar.gz", hash = "sha256:1c7960ccfd6a005cd9f7ba884e6316b5e430a3f1a6c37c5f87d8b43f83b54ec9"},
]
colorama = [
{file = "colorama-0.3.9-py2.py3-none-any.whl", hash = "sha256:463f8483208e921368c9f306094eb6f725c6ca42b0f97e313cb5d5512459feda"},
{file = "colorama-0.3.9.tar.gz", hash = "sha256:48eb22f4f8461b1df5734a074b57042430fb06e1d61bd1e11b078c0fe6d7a1f1"},
]
funcsigs = [
{file = "funcsigs-1.0.2-py2.py3-none-any.whl", hash = "sha256:330cc27ccbf7f1e992e69fef78261dc7c6569012cf397db8d3de0234e6c937ca"},
{file = "funcsigs-1.0.2.tar.gz", hash = "sha256:a7bb0f2cf3a3fd1ab2732cb49eba4252c2af4240442415b4abce3b87022a8f50"},
]
more-itertools = [
{file = "more-itertools-4.1.0.tar.gz", hash = "sha256:c9ce7eccdcb901a2c75d326ea134e0886abfbea5f93e91cc95de9507c0816c44"},
{file = "more_itertools-4.1.0-py2-none-any.whl", hash = "sha256:11a625025954c20145b37ff6309cd54e39ca94f72f6bb9576d1195db6fa2442e"},
{file = "more_itertools-4.1.0-py3-none-any.whl", hash = "sha256:0dd8f72eeab0d2c3bd489025bb2f6a1b8342f9b198f6fc37b52d15cfa4531fea"},
]
pluggy = [
{file = "pluggy-0.6.0.tar.gz", hash = "sha256:7f8ae7f5bdf75671a718d2daf0a64b7885f74510bcd98b1a0bb420eb9a9d0cff"},
]
py = [
{file = "py-1.5.3-py2.py3-none-any.whl", hash = "sha256:983f77f3331356039fdd792e9220b7b8ee1aa6bd2b25f567a963ff1de5a64f6a"},
{file = "py-1.5.3.tar.gz", hash = "sha256:29c9fab495d7528e80ba1e343b958684f4ace687327e6f789a94bf3d1915f881"},
]
pytest = [
{file = "pytest-3.5.0-py2.py3-none-any.whl", hash = "sha256:6266f87ab64692112e5477eba395cfedda53b1933ccd29478e671e73b420c19c"},
{file = "pytest-3.5.0.tar.gz", hash = "sha256:fae491d1874f199537fd5872b5e1f0e74a009b979df9d53d1553fd03da1703e1"},
]
six = [
{file = "six-1.11.0-py2.py3-none-any.whl", hash = "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb"},
{file = "six-1.11.0.tar.gz", hash = "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9"},
]
38 changes: 38 additions & 0 deletions tests/installation/test_installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1772,6 +1772,44 @@ def test_installer_uses_prereleases_if_they_are_compatible(
assert 2 == installer.executor.installations_count


def test_installer_can_refresh_old_lock_files(locker, package, repo, installed, config):
pool = Pool()
pool.add_repository(repo)

locker.locked(True)
locker.mock_lock_data(fixture("old-lock"))

for pkg in locker.locked_repository(with_dev_reqs=True).packages:
dependency = Factory.create_dependency(
name=pkg.name,
constraint=pkg.to_dependency().constraint,
category=pkg.category,
)
package.add_dependency(dependency)
repo.add_package(pkg)

installer = Installer(
NullIO(),
MockEnv(),
package,
locker,
pool,
config,
installed=None,
executor=Executor(MockEnv(), pool, config, NullIO()),
)
installer.use_executor()

installer.lock(update=False)
installer.run()

assert 0 == installer.executor.installations_count
assert 0 == installer.executor.updates_count
assert 0 == installer.executor.removals_count

assert locker.written_data == fixture("old-lock-refresh")


def test_installer_can_handle_old_lock_files(
installer, locker, package, repo, installed, config
):
Expand Down

0 comments on commit a8678e4

Please sign in to comment.