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

Synthesized lockfile targets should never err on missing lockfiles. #18406

Merged
merged 4 commits into from
Mar 8, 2023

Conversation

kaos
Copy link
Member

@kaos kaos commented Mar 4, 2023

Fixes #18404

@kaos kaos added the category:bugfix Bug fixes for released features label Mar 4, 2023
@kaos kaos requested a review from benjyw March 4, 2023 14:33
@kaos kaos added this to the 2.15.x milestone Mar 4, 2023
Copy link
Contributor

@benjyw benjyw left a comment

Choose a reason for hiding this comment

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

This seems like a lot of code, to avoid a one-time problem. Why not just not synthesize the target when the source doesn't exist?

Copy link
Contributor

@benjyw benjyw left a comment

Choose a reason for hiding this comment

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

To clarify my comment - we're carving out some new and non-trivial functionality here (namely a target that can confusingly override global glob matching error behavior) just to handle a situation with a synthetic target the user didn't define or know about to begin with.

The purpose of the target is to track deps on the file when it changes, but since it is allowed to not exist, in that case I think it's better - and simpler - to just not synthesize it in the first place.

@cognifloyd
Copy link
Member

cognifloyd commented Mar 4, 2023

Can you depend on a synthesized target? Eg, if I wanted to include a lockfile in an sdist, could I depend on the synthesized target? Are there better examples of the utility of the synthesized targets?

Logically, the target does exist, but it has to be synthesized from the contents of pants.toml, not from something defined in a BUILD file. So, I would be surprised if a resolve I explicitly defined (in pants.toml) did not get the synthesized target just because I haven't generated the lockfile yet.

From a different angle: lockfiles are like codegen, but unlike codegen, it gets materialized in the workspace, not under dist/. It's not weird for a codegen thing to not exist. Same with the lockfile. So can we use any of the codegen infra here, allowing things to depend on the file without it existing? But instead of transparently ruining the codegen, it displays a message to run generate-lockfiles.

@kaos
Copy link
Member Author

kaos commented Mar 4, 2023

To clarify my comment - we're carving out some new and non-trivial functionality here (namely a target that can confusingly override global glob matching error behavior) just to handle a situation with a synthetic target the user didn't define or know about to begin with.

The fact that the user didn't know about the target to me contradicts the argument that it would be confusing to not adhere to the global glob matching error behavior.

The purpose of the target is to track deps on the file when it changes, but since it is allowed to not exist, in that case I think it's better - and simpler - to just not synthesize it in the first place.

Although the lockfile is allowed to not exist, that is an intermediate broken state of affairs as we know where it is supposed to exist. I agree that the idea with checking for the existence and not synthesize the _lockfile target in that case would also work, but I don't think that would be any easier. Perhaps this only comes down to from which end we look at this problem, but from my side of the field I see the file missing as a temporary situation that unconditionally must be resolved (eventually) -- and taking this case into consideration when the target is synthesized would spill over to every plugin that synthesizes lockfile targets needing to make extra calls only to check for if the target file in question exists before creating targets. To me that feels like a more complex implementation and in potentially more places going forward, then what we have here.

@kaos
Copy link
Member Author

kaos commented Mar 4, 2023

Can you depend on a synthesized target? Eg, if I wanted to include a lockfile in an sdist, could I depend on the synthesized target? Are there better examples of the utility of the synthesized targets?

Yes, that was the primary motivation to introduce synthetic targets, to be able to depend on the generated lockfiles. Not in order to include them, but for identifying targets for changed since when you have regenerated lockfiles.

resolve = request.template.get(
PythonRequirementResolveField.alias, python_setup.default_resolve
)
lockfile = (
python_setup.resolves.get(resolve) if python_setup.enable_synthetic_lockfiles else None
)
if lockfile:
lockfile_address = Address(
os.path.dirname(lockfile),
target_name=resolve,
)
target_adaptor = await Get(
TargetAdaptor,
TargetAdaptorRequest(
description_of_origin=f"{generator.alias} lockfile dep for the {resolve} resolve",
address=lockfile_address,
),
)
if target_adaptor.type_alias == "_lockfiles":
req_deps.append(f"{lockfile}:{resolve}")
else:
logger.warning(
softwrap(
f"""
The synthetic lockfile target for {lockfile} is being shadowed by the
{target_adaptor.type_alias} target {lockfile_address}.
There will not be any dependency to the lockfile.
Resolve by either renaming the shadowing target, the resolve {resolve!r} or
moving the target or the lockfile to another directory.
"""
)
)

Logically, the target does exist, but it has to be synthesized from the contents of pants.toml, not from something defined in a BUILD file. So, I would be surprised if a resolve I explicitly defined (in pants.toml) did not get the synthesized target just because I haven't generated the lockfile yet.

Thank you. Although the connection between the synthesized target and the source file is looser than for codegen, I agree that we have all the pieces to expect the target to exist, also when the actual source file it represents is not there.

From a different angle: lockfiles are like codegen, but unlike codegen, it gets materialized in the workspace, not under dist/. It's not weird for a codegen thing to not exist. Same with the lockfile. So can we use any of the codegen infra here, allowing things to depend on the file without it existing? But instead of transparently ruining the codegen, it displays a message to run generate-lockfiles.

Another difference here is that the synthetic target plays no role in the materialization of the source files, so to me it makes little sense in having codegen involved at all here.

@kaos
Copy link
Member Author

kaos commented Mar 5, 2023

@cognifloyd there's also #17253 for more context (and linked PR #16998)

Copy link
Contributor

@benjyw benjyw left a comment

Choose a reason for hiding this comment

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

I love it - simpler code yet more functionality!

src/python/pants/core/target_types.py Show resolved Hide resolved
@kaos kaos merged commit 376433a into pantsbuild:main Mar 8, 2023
@kaos kaos deleted the missing-synthetic-target-source branch March 8, 2023 01:04
@kaos kaos removed this from the 2.15.x milestone Mar 8, 2023
kaos added a commit that referenced this pull request Mar 8, 2023
kaos added a commit that referenced this pull request Mar 8, 2023
@danxmoran
Copy link
Contributor

@kaos is it possible the changes here have regressed? I'm seeing an error from missing lockfiles on a PANTS_SHA that should include this change (#18933)

@kaos
Copy link
Member Author

kaos commented May 8, 2023

Eh... hrrm. It seems to me that this fix never actually worked to begin with 😞 😬

Thanks for discovering @danxmoran -- I'll look into it right away.

kaos added a commit to kaos/pants that referenced this pull request May 8, 2023
Fixes pantsbuild#18933 (and pantsbuild#18404). Original attempt at fixing this but failed
was in pantsbuild#18406 due to an oversight that it was the `_lockfiles` target
generator with a `sources` field that was being synthesized, not the
`_lockfile` target with a single `source` file only.

Either use should work equally well, and now they do.
kaos added a commit that referenced this pull request May 9, 2023
Fixes #18933 (and #18404). Original attempt at fixing this but failed
was in #18406 due to an oversight that it was the `_lockfiles` target
generator with a `sources` field that was being synthesized, not the
`_lockfile` target with a single `source` file only.

Either use should work equally well, and now they do.
kaos added a commit to kaos/pants that referenced this pull request May 9, 2023
Fixes pantsbuild#18933 (and pantsbuild#18404). Original attempt at fixing this but failed
was in pantsbuild#18406 due to an oversight that it was the `_lockfiles` target
generator with a `sources` field that was being synthesized, not the
`_lockfile` target with a single `source` file only.

Either use should work equally well, and now they do.
kaos added a commit to kaos/pants that referenced this pull request May 9, 2023
Fixes pantsbuild#18933 (and pantsbuild#18404). Original attempt at fixing this but failed
was in pantsbuild#18406 due to an oversight that it was the `_lockfiles` target
generator with a `sources` field that was being synthesized, not the
`_lockfile` target with a single `source` file only.

Either use should work equally well, and now they do.
kaos added a commit that referenced this pull request May 9, 2023
Fixes #18933 (and #18404). Original attempt at fixing this but failed
was in #18406 due to an oversight that it was the `_lockfiles` target
generator with a `sources` field that was being synthesized, not the
`_lockfile` target with a single `source` file only.

Either use should work equally well, and now they do.
kaos added a commit that referenced this pull request May 9, 2023
Fixes #18933 (and #18404). Original attempt at fixing this but failed
was in #18406 due to an oversight that it was the `_lockfiles` target
generator with a `sources` field that was being synthesized, not the
`_lockfile` target with a single `source` file only.

Either use should work equally well, and now they do.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
category:bugfix Bug fixes for released features
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cannot create a new lockfile if unmatched_build_file_globs = "error"
4 participants