Skip to content

Commit

Permalink
Add logic to skip dependency resolution if --lock is up-to-date
Browse files Browse the repository at this point in the history
  • Loading branch information
lfdebrux committed Feb 19, 2020
1 parent cf44da7 commit 47ec35c
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 1 deletion.
10 changes: 9 additions & 1 deletion piptools/scripts/compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from ..cache import DependencyCache
from ..exceptions import PipToolsError
from ..locations import CACHE_DIR
from ..lock import read_locks
from ..lock import check, read_locks
from ..logging import log
from ..repositories import LocalRequirementsRepository, PyPIRepository
from ..resolver import Resolver
Expand Down Expand Up @@ -186,6 +186,8 @@
@click.option(
"--lock",
help="Add input file locks to generated file. "
"If output file already exists and has a valid lock, "
"resolving dependencies is skipped.",
is_flag=True,
default=False,
)
Expand Down Expand Up @@ -274,6 +276,12 @@ def cli(
)
)

valid_lock = check(existing_locks)
if lock and not (upgrade or upgrade_packages):
if valid_lock:
log.info("locks are up-to-date, nothing to do :)")
sys.exit(0)

###
# Setup
###
Expand Down
94 changes: 94 additions & 0 deletions tests/test_cli_compile.py
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,100 @@ def test_locked_file_is_always_locked(pip_conf, runner):
)


def test_lock_skips_resolve_if_lock_up_to_date(pip_conf, runner):
"""
Tests pip-compile --lock doesn't do dependency resolution or touch
requirements.txt if the input file has not changed since the lock.
"""
with open("requirements.in", "w") as req_in:
req_in.write("small-fake-a")

with open("requirements.txt", "w") as req_txt:
req_txt.write(
"# sha256:ddc021cb85916175da3f7efa0043501be399f2bce1d3ae4b833cdcb348f0755b"
" requirements.in\n"
)
req_txt.write("small-fake-a==0.1")

before_compile_mtime = os.stat("requirements.txt").st_mtime

out = runner.invoke(cli, ["--lock"])

assert out.exit_code == 0, out.stderr
assert "small-fake-a" not in out.stderr
assert "locks are up-to-date" in out.stderr

# The package version must NOT be updated in the output file
with open("requirements.txt", "r") as req_txt:
assert "small-fake-a==0.1" in req_txt.read().splitlines()

# The output file must not be touched
after_compile_mtime = os.stat("requirements.txt").st_mtime
assert after_compile_mtime == before_compile_mtime


def test_lock_option_does_not_skip_dependency_resolution_if_lock_not_up_to_date(
pip_conf, runner
):
"""
Tests pip-compile --lock does dependency resolution and updates
requirements.txt if the input file has changed since the lock.
"""
with open("requirements.in", "w") as req_in:
req_in.write("small-fake-b<0.3")

runner.invoke(cli, ["--lock"])

with open("requirements.in", "w") as req_in:
req_in.write("small-fake-b<0.2")

out = runner.invoke(cli, ["--lock"])

assert out.exit_code == 0, out.stderr
assert (
"ecb4d0f00fe312b666652c46c39c108e6ae7f9ebbbef1ba5f415768d6445149a" in out.stderr
)
assert "small-fake-b==0.1" in out.stderr


@pytest.mark.parametrize(
"add_options, expected_cli_output_package",
[
(["--upgrade"], "small-fake-b==0.3"),
(["--upgrade-package", "small-fake-b"], "small-fake-b==0.3"),
(["--upgrade-package", "small-fake-b==0.1"], "small-fake-b==0.1"),
],
)
def test_lock_option_does_not_skip_dependency_resolution_if_upgrade_option(
pip_conf, runner, add_options, expected_cli_output_package
):
"""
Tests pip-compile --lock does dependency resolution and updates
requirements.txt if the --upgrade or --upgrade-package options are present,
even if the input file has not changed since the lock.
"""
with open("requirements.in", "w") as req_in:
req_in.write("small-fake-b")

runner.invoke(cli, ["--lock"])

# downgrade small-fake-b
with open("requirements.txt") as req_txt:
textlines = req_txt.read().splitlines()
textlines[-1] = "small-fake-b==0.2"

with open("requirements.txt", "w") as req_txt:
req_txt.write("\n".join(textlines))

out = runner.invoke(cli, ["--lock"] + add_options)

assert out.exit_code == 0, out.stderr
assert (
"ff69e9c25ac4dfa733c8a7b5c0035f080a2780e73bea363e21b9eb4d849fdc8d" in out.stderr
)
assert expected_cli_output_package in out.stderr


@pytest.mark.parametrize(
"empty_input_pkg, prior_output_pkg",
[
Expand Down

0 comments on commit 47ec35c

Please sign in to comment.