Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lockfile invalidation consumption #12448

Merged

Conversation

chrisjrn
Copy link
Contributor

@chrisjrn chrisjrn commented Jul 28, 2021

Addresses #12415

This adds tools for consuming the lockfile invalidation digests that were added in #12427, both for lockfiles specified for the project, and for individual build tools.

Behavior on invalid lockfiles can be configured to either be a warning or an error.

@chrisjrn chrisjrn marked this pull request as draft July 28, 2021 21:37
@chrisjrn chrisjrn force-pushed the chrisjrn/12415-invalidation-consumption branch 3 times, most recently from 27f13b1 to 020777d Compare July 30, 2021 15:45
@chrisjrn chrisjrn marked this pull request as ready for review July 30, 2021 15:46
@chrisjrn chrisjrn marked this pull request as draft July 30, 2021 15:46
Christopher Neugebauer added 18 commits August 9, 2021 08:51
[ci skip-rust]

[ci skip-build-wheels]
# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
[ci skip-rust]

[ci skip-build-wheels]
# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
[ci skip-rust]

[ci skip-build-wheels]
Fmt
# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
[ci skip-rust]

[ci skip-build-wheels]
# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
[ci skip-rust]

[ci skip-build-wheels]
# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
@chrisjrn chrisjrn force-pushed the chrisjrn/12415-invalidation-consumption branch from ed70791 to 0d691ad Compare August 9, 2021 16:48
Christopher Neugebauer added 2 commits August 9, 2021 15:43
# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
@chrisjrn chrisjrn marked this pull request as ready for review August 10, 2021 16:50
@chrisjrn
Copy link
Contributor Author

@Eric-Arellano this is ready for review now

@chrisjrn chrisjrn changed the title [WIP] lockfile invalidation consumption Lockfile invalidation consumption Aug 10, 2021
Christopher Neugebauer added 2 commits August 10, 2021 11:50
# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
Copy link
Contributor

@Eric-Arellano Eric-Arellano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome change!

Comment on lines 90 to 93
lockfile_digest = None
if lambdex.lockfile != "<none>":
lockfile_request = await Get(PythonLockfileRequest, LambdexLockfileSentinel())
lockfile_digest = lockfile_request.hex_digest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe lockfile_hash? Now that I see this in an @rule, the word "digest" is overloaded to think "directory digest" from pants.engine.fs.

I think this could get really confusing, e.g. people accidentally using it with MergeDigests

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still think that throwing around the word hash in a Python database is likely to bring up similar confusion. That said, these lines from our JVM support make digest on its own a non-starter for our lockfile support.

wheeeeeeeeeeeee

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yeah true. Then, maybe being explicit is the key. invalidation_digest or invalidation_hash, but never just hash or just digest.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll go with hex_digest, since that's what I'm using elsewhere.

Comment on lines 446 to 448
raise ValueError("Invalid lockfile provided. [TODO: Improve message]")
else:
logger.warning("%s", "Invalid lockfile provided. [TODO: Improve message]")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean to address this here, or it will be a followup?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It wasn't clear to me how to provide a really meaningful error here. I'll discuss this with you out-of-band

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sg! Because this is experimental, it's fine to land in this state imo.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great. Let's follow up in a separate PR.

Comment on lines 450 to +453
requirements_file_digest = await Get(
Digest,
PathGlobs(
[request.requirements.file_path],
glob_match_error_behavior=GlobMatchErrorBehavior.error,
description_of_origin=request.requirements.file_path_description_of_origin,
),
PathGlobs,
globs,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI this is split over 3 lines because there was a trailing comma so Black forces it to be split. You can get back to one line by removing the comma and rerunning Black.

You don't need to fix as that's what Black did, only an FYI. (can't remember if I've mentioned this already)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment on lines 463 to 465
raise ValueError("Invalid lockfile provided. [TODO: Improve message]")
else:
logger.warning("%s", "Invalid lockfile provided. [TODO: Improve message]")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will likely want this error message to differ from the one above. This is currently always the <default> lockfile, whereas the above are always lockfiles checked in by the user. Our guidance is different depending on those two edge cases.

To formalize that implicit association, we may in a followup want to change PexRequirements to be less generic than it is now, e.g. change the field to be "default_requirements_file: FileContentrather thanfile_content: FileContent`.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressing in a follow-up

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, fair enough. I do think we have some tests using this style out there and iirc Benjy prefers your style - not blocking

@@ -535,3 +536,67 @@ def assert_description(
use_repo_pex=True,
expected="Extracting all requirements in lock.txt from repo.pex to build new.pex",
)


def test_error_on_invalid_lockfile_with_path(rule_runner: RuleRunner) -> None:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subjective style suggestion, feel free to disagree. It may be more readable to have this in a single test that puts _run_pex_for_lockfile_test as an inner helper function. These are all the same functionality, so I think makes sense to be in the same test as they're simply different edge cases of the same functionality. Kind of like pytest.parametrize.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about doing it that way, but my preferred behaviour is to match what pytest.parametrize does, which is to run every case and report every failure. Each one of these tests is running a completely different code path, and the behaviour has to be tested in a different way, otherwise I'd have done it with parametrize

src/python/pants/backend/python/util_rules/pex_test.py Outdated Show resolved Hide resolved
src/python/pants/backend/python/util_rules/pex_test.py Outdated Show resolved Hide resolved
src/python/pants/python/python_setup.py Outdated Show resolved Hide resolved
"--invalid-lockfile-behavior",
advanced=True,
type=InvalidLockfileBehavior,
default=InvalidLockfileBehavior.warn,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we talked about this a couple times, what the default should be. I can't remember what the conclusion was, but I'm thinking we should probably default to error for now, at least until we get feedback from users it's an annoying default. We want to encourage people to do the right thing, and warnings are too easy to miss (e.g. in CI).

Lockfiles are feature gated, so this is fine to change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fine by me.

Christopher Neugebauer and others added 3 commits August 10, 2021 13:06
Co-authored-by: Eric Arellano <14852634+Eric-Arellano@users.noreply.github.com>
# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
Copy link
Contributor

@Eric-Arellano Eric-Arellano left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Comment on lines 463 to 465
raise ValueError("Invalid lockfile provided. [TODO: Improve message]")
else:
logger.warning("%s", "Invalid lockfile provided. [TODO: Improve message]")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, fair enough. I do think we have some tests using this style out there and iirc Benjy prefers your style - not blocking

@Eric-Arellano
Copy link
Contributor

Needs a new commit because of GitHub outage yesterday

Christopher Neugebauer added 2 commits August 12, 2021 07:56
# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
Turns out our lockfiles aren't quite valid: https://github.com/pantsbuild/pants/pull/12448/checks

# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
Copy link
Member

@stuhood stuhood left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation looks good, but there is a lot of redundancy for consumers. It will be important to make doing the right thing easy, so it's possible that fixing some of that redundancy before landing would be good.

@@ -86,10 +87,15 @@ async def package_python_awslambda(
],
)

lockfile_hex_digest = None
if lambdex.lockfile != "<none>":
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This magic string ended up peppered a lot of places. Would be good to have def lockfile convert "<none>" to str | None instead.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Imo fine to do in a followup. This code path is still changing frequently.

Comment on lines +101 to +103
if python_protobuf_mypy_plugin.lockfile != "<none>":
lockfile_request = await Get(PythonLockfileRequest, MypyProtobufLockfileSentinel())
lockfile_hex_digest = lockfile_request.hex_digest
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is very redundant...

Could PexRequest take the sentinel type + lockfile and make this request for you instead? Or could the sentinel type be converted into a wrapper around the filename (i.e., no longer just a sentinel)?

Or, more fundamentally, should PexRequest.requirements become a union of PexRequirements | PythonToolRequirementsBase?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that we will absolutely want to fix this, but it's fine in a followup.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I recommend we wait to fix this. For example, #12542 will make lots of changes to these call sites.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I don't particularly like this code, and I'd be happy to take suggestions on how to make the improvement.

# Rust tests and lints will be skipped. Delete if not intended.
[ci skip-rust]

# Building wheels and fs_util will be skipped. Delete if not intended.
[ci skip-build-wheels]
@Eric-Arellano Eric-Arellano merged commit 4ad7b46 into pantsbuild:main Aug 12, 2021
@stuhood stuhood mentioned this pull request Aug 14, 2021
Eric-Arellano added a commit that referenced this pull request Aug 17, 2021
These were missed in #12448.

To reduce the risk of this happening again, we remove the default argument for `PythonToolBase.pex_requirements(expected_lockfile_hex_digest)`.

In the process, I realized that Pylint is not actually consuming it's lockfile at all because of how we handle first-party plugins. I'll address that in a followup that adds lockfile support to MyPy.

[ci skip-rust]
[ci skip-build-wheels]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants