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

[internal] add JvmToolBase for lockfile handling for JVM tools #13777

Merged
merged 7 commits into from
Dec 4, 2021

Conversation

tdyas
Copy link
Contributor

@tdyas tdyas commented Dec 2, 2021

Add JvmToolBase as base class for subsystems that handle lockfiles for JVM tools. Adds jvm-generate-lockfiles goal for rebuilding JVM tool lockfiles.

Port the junit test goal to use JvmToolBase.

@tdyas tdyas force-pushed the jvm_tool_base branch 2 times, most recently from 529bfa3 to 3d40177 Compare December 2, 2021 19:14
@tdyas tdyas changed the title [WIP] [internal] add JvmToolBase for lockfile handling for JVM tools [internal] add JvmToolBase for lockfile handling for JVM tools Dec 2, 2021
@tdyas tdyas marked this pull request as ready for review December 2, 2021 19:18
"""Base class for subsystems that configure a set of artifact requirements for a JVM tool."""

# Default version of the tool. (Subclasses must set.)
default_version: ClassVar[str]
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The intent here is to provide a simpler way for users to configure the tool version. The version is then substituted into default_artifacts via a %VERSION% placeholder.

Copy link
Member

Choose a reason for hiding this comment

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

There has been a growing convention around using Python's default templating for things: so just {version} see abb022b.


default_version = "5.7.2"
default_artifacts = [
"org.junit.platform:junit-platform-console:1.7.2",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unclear to me how best to handle multiple different versions in the artifacts vis-a-vis the --version option.

Copy link
Member

Choose a reason for hiding this comment

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

Do you mean collisions between the tool and the user's classpath? Eventually we'll likely need to implement shading to handle that: #13259.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, just the artifacts having different versions. Note that the "main" version number is 5.7.2 but the junit-platform-console artifact has version 1.7.2. Maybe --version arguments should be defined by the individual tools based on their needs?

Copy link
Member

Choose a reason for hiding this comment

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

Oh, I see what you are saying. Hm. It may be better not to include the version yet then...? It's an easy feature to add later, and it is pretty error prone here (although I do think that this case is a bit exceptional).

@tdyas
Copy link
Contributor Author

tdyas commented Dec 2, 2021

Open question: Should this handle user resolve lockfiles? I wanted to reduce the scope of this change so didn't try to merge coursier-resolve yet into the jvm-generate-lockfiles goal.

Copy link
Contributor

@chrisjrn chrisjrn 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 sound, but I'll wait for tests etc before approving

from pants.util.logging import LogLevel
from pants.util.ordered_set import FrozenOrderedSet

DEFAULT_TOOL_LOCKFILE = "<default>"
Copy link
Contributor

Choose a reason for hiding this comment

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

Now that we're doing this in two places, we should probably extract a config constants file and have python_tool_base draw from it as well.

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 this should probably go in core/goals/generate_lockfiles.py once we unify the langauges


class GenerateJvmLockfilesSubsystem(GoalSubsystem):
name = "jvm-generate-lockfiles"
help = "Generate lockfiles for JVM tools third-party dependencies."
Copy link
Contributor

Choose a reason for hiding this comment

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

Per #13374, we want generate-lockfiles to work on all supported platforms, so this may not just be for third-party dependencies.

Copy link
Contributor

Choose a reason for hiding this comment

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

(if it's possible to remove coursier-resolve during this work, I'd support that!)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See the open question I just posted. #13777 (comment)

Copy link
Contributor Author

@tdyas tdyas Dec 2, 2021

Choose a reason for hiding this comment

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

This PR is an intermediate step toward merging everything. The question is not should we merge everything, but rather how many PRs to get there.

Copy link
Member

Choose a reason for hiding this comment

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

(moving inline)

Open question: Should this handle user resolve lockfiles? I wanted to reduce the scope of this change so didn't try to merge coursier-resolve yet into the jvm-generate-lockfiles goal.

No, it shouldn't merge with user lockfiles (i.e. generate-user-lockfile). But this change should merge with the Python tool lockfile goal: i.e. generate-lockfiles. That would align it with the status quo.

Copy link
Member

Choose a reason for hiding this comment

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

As discussed offline, fine with doing some of this merging as a fast follow.

Copy link
Contributor

Choose a reason for hiding this comment

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

Want me to handle merging the two goals? I'm now working on lockfiles as my main project so the context switch isn't bad for me

@tdyas
Copy link
Contributor Author

tdyas commented Dec 2, 2021

This seems sound, but I'll wait for tests etc before approving

Added test coverage to the same level as the Python goal. There doesn't seem to be much in the way of actual tests of resolving the Python tool lockfiles support. I.e., searching PythonToolLockfileSentinel in tests only shows up in src/python/pants/backend/python/goals/lockfile_test.py.

@tdyas
Copy link
Contributor Author

tdyas commented Dec 2, 2021

The actual testing of tool lockfiles seems to be from the fact that the tools that have been ported to them actually still continue to pass their own tests.

@chrisjrn
Copy link
Contributor

chrisjrn commented Dec 2, 2021

I'm happy to punt on #13374, but it's probably something we want to address sooner than later, now that we have coursier-resolve, jvm-generate-lockfiles and generate-lockfiles. This is probably not a pattern we want to continue.

src/python/pants/backend/java/test/junit.py Outdated Show resolved Hide resolved
"""Base class for subsystems that configure a set of artifact requirements for a JVM tool."""

# Default version of the tool. (Subclasses must set.)
default_version: ClassVar[str]
Copy link
Member

Choose a reason for hiding this comment

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

There has been a growing convention around using Python's default templating for things: so just {version} see abb022b.

Comment on lines +39 to +46
# Default artifacts for the tool in GROUP:NAME format. The `--version` value will be used for the
# artifact version if it has not been specified for a particular requirement. (Subclasses must set.)
default_artifacts: ClassVar[Sequence[str]]
Copy link
Member

Choose a reason for hiding this comment

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

I'm a bit concerned that we'll need to deprecate or complicate this syntax if we add more features to jvm_artifact (excludes, etc)... it would be good to already know what the migration path from this syntax to specifying these arguments with a target will be.

It seems like it should be possible to support both simultaneously, but let's just start by assuming that we will need to add target support, and that maybe this syntax stays around as the "easy mode" way to specify deps?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Should we have a syntax for differentiating between the use cases? Or would we first try to interpret as an address and then fallback to interpreting as a coordinate?

Maybe we should just go right to addresses only to start?

Copy link
Member

Choose a reason for hiding this comment

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

Based on discussion yesterday, I think that we'll always need a way to specify the builtin version, and even if we did have a "synthetic target" based approach, we'd still need options to seed the target. So this seems fine for now.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe we should just go right to addresses only to start?

Maybe, yea? In the absence of synthetic targets though, that would amount to having two codepaths: one for builtin requirements, the other for targets. But probably not too much complexity, honestly.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, would we be fine with deprecating the coordinate syntax later on?

Copy link
Member

Choose a reason for hiding this comment

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

Yes, although obviously easier to do before stabilizing the JVM. Sorry to wobble back and forth, but I do sortof think that accepting addresses here would be straightforward... I think that you could just request classpath entries for them with ClasspathEntryRequest.for_targets, and it would automatically support either compiling a tool or downloading it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No worries. Will implement address support then, with fallback to coordinate syntax.

Copy link
Contributor Author

@tdyas tdyas Dec 3, 2021

Choose a reason for hiding this comment

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

Using ClasspathEntryRequest.for_targets though doesn't seem to generate coordinates needed to invoke Coursier though to obtain a lockfile. Instead it obtains actual jars to form the invokable classpath. Am I missing something?

My thought to support addresses is to scan the transitive dependencies of the user-supplied addresses and extract jvm_artifacts and extract their coordinates. Not sure how this would play with url= option on those targets though.

Copy link
Member

Choose a reason for hiding this comment

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

Oh, doh. Yes, would only be able to consume jvm_artifacts initially. Sorry about that.

Comment on lines 75 to 84
register(
"--extra-artifacts",
type=list,
member_type=str,
advanced=True,
default=cls.default_extra_artifacts,
help="Any additional artifact requirement strings to use with the tool. This is useful if the "
"tool allows you to install plugins or if you need to constrain a dependency to "
"a certain version.",
)
Copy link
Member

Choose a reason for hiding this comment

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

IMO, let's not add this until we know we need it... only some Python tools do, and the option ends up with a different meaning in each case. It's likely that we'd want to add specific options to subclasses with their own help, which could then override an empty method of the superclass to append them, for example.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

will remove

type=str,
default=cls.default_lockfile_path,
advanced=True,
# TODO: Fix up the help text to not be Python-focused.
Copy link
Member

Choose a reason for hiding this comment

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

TODO


class GenerateJvmLockfilesSubsystem(GoalSubsystem):
name = "jvm-generate-lockfiles"
help = "Generate lockfiles for JVM tools third-party dependencies."
Copy link
Member

Choose a reason for hiding this comment

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

(moving inline)

Open question: Should this handle user resolve lockfiles? I wanted to reduce the scope of this change so didn't try to merge coursier-resolve yet into the jvm-generate-lockfiles goal.

No, it shouldn't merge with user lockfiles (i.e. generate-user-lockfile). But this change should merge with the Python tool lockfile goal: i.e. generate-lockfiles. That would align it with the status quo.


default_version = "5.7.2"
default_artifacts = [
"org.junit.platform:junit-platform-console:1.7.2",
Copy link
Member

Choose a reason for hiding this comment

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

Oh, I see what you are saying. Hm. It may be better not to include the version yet then...? It's an easy feature to add later, and it is pretty error prone here (although I do think that this case is a bit exceptional).

Comment on lines +39 to +46
# Default artifacts for the tool in GROUP:NAME format. The `--version` value will be used for the
# artifact version if it has not been specified for a particular requirement. (Subclasses must set.)
default_artifacts: ClassVar[Sequence[str]]
Copy link
Member

Choose a reason for hiding this comment

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

Based on discussion yesterday, I think that we'll always need a way to specify the builtin version, and even if we did have a "synthetic target" based approach, we'd still need options to seed the target. So this seems fine for now.

Comment on lines 78 to 83
# assert_filtered(disabled_tool, resolve_specified=False)
# with pytest.raises(ValueError) as exc:
# assert_filtered(disabled_tool, resolve_specified=True)
# assert f"`[{disabled_tool.resolve_name}].lockfile` is set to `{NO_TOOL_LOCKFILE}`" in str(
# exc.value
# )
Copy link
Member

Choose a reason for hiding this comment

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

TODO

Tom Dyas added 4 commits December 3, 2021 16:24
[ci skip-rust]

[ci skip-build-wheels]
[ci skip-rust]

[ci skip-build-wheels]
[ci skip-rust]

[ci skip-build-wheels]
[ci skip-rust]

[ci skip-build-wheels]
Tom Dyas added 2 commits December 3, 2021 18:32
[ci skip-rust]

[ci skip-build-wheels]
[ci skip-rust]

[ci skip-build-wheels]
@tdyas tdyas requested review from stuhood and chrisjrn December 3, 2021 23:54
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.

Thanks again.

[ci skip-rust]

[ci skip-build-wheels]
@tdyas tdyas merged commit d1486c4 into pantsbuild:main Dec 4, 2021
@tdyas tdyas deleted the jvm_tool_base branch December 4, 2021 06:08
@stuhood stuhood mentioned this pull request Dec 6, 2021
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.

Sweet, thanks. Pardon the delayed review

from pants.util.logging import LogLevel
from pants.util.ordered_set import FrozenOrderedSet

DEFAULT_TOOL_LOCKFILE = "<default>"
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 this should probably go in core/goals/generate_lockfiles.py once we unify the langauges

Comment on lines +116 to +117
with open(lockfile_path, "rb") as f:
return f.read()
Copy link
Contributor

Choose a reason for hiding this comment

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

This doesn't seem safe with caching?

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 didn't really consider the caching aspect. Another thing to fix ...

Copy link
Member

Choose a reason for hiding this comment

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

I'm addressing this as part of #13827.


class GenerateJvmLockfilesSubsystem(GoalSubsystem):
name = "jvm-generate-lockfiles"
help = "Generate lockfiles for JVM tools third-party dependencies."
Copy link
Contributor

Choose a reason for hiding this comment

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

Want me to handle merging the two goals? I'm now working on lockfiles as my main project so the context switch isn't bad for me

illicitonion added a commit that referenced this pull request Dec 7, 2021
Internal changes:

* [internal] Remove superfluous f-string specifiers ([#13821](#13821))

* [internal] scala: extract annotations as consumed types ([#13810](#13810))

* [jvm] Split nailgun digest from input file digests ([#13813](#13813))

* [internal] jvm: add jre_major_version and use stderr to properly extract version ([#13812](#13812))

* [internal] Clean up Go `embed` support's handling of dependencies ([#13801](#13801))

* [internal] scala: handle package object syntax in parser ([#13809](#13809))

* [internal] java: fix junit sentinel rule setup ([#13815](#13815))

* [internal] upgrade to rust v1.57.0 ([#13807](#13807))

* [internal] add failing test for FrozenDict equality issue ([#13389](#13389))

* [internal] Use `PyObject` instead of `Value` in more places ([#13802](#13802))

* Remove MultiPlatform Process abstractions ([#12725](#12725))

* [internal] add `JvmToolBase` for lockfile handling for JVM tools ([#13777](#13777))

* [internal] Port `MergeDigests` to Rust ([#13773](#13773))

* [jvm] Spawn nailgun servers outside the pool lock ([#13796](#13796))

* [internal] DRY loading internal Go binaries ([#13800](#13800))

* [internal] Convert unit tests to use pytest ([#13798](#13798))

* [internal] remove dead code - socket util. ([#13797](#13797))

* [internal] Reorganize Go parser scripts ([#13791](#13791))

* Adds Jackson core/datatype to `JVM_ARTIFACT_MAPPINGS` ([#13792](#13792))

* [internal] go: initial support for embedding resources ([#13743](#13743))

* [internal] Refer to `go.mod` path when downloading packages ([#13786](#13786))

* [internal] More robust Go dependency inference tests ([#13785](#13785))

* [internal] `tailor` doesn't add `go_package` for `testdata` folder ([#13783](#13783))

* [internal] Add Scala backend to dryrun for wheel builds. ([#13772](#13772))

* [internal] Unify JVM thirdparty resolves ([#13771](#13771))

* [internal] scala: infer dependencies from consumed symbols and intermediate scopes ([#13758](#13758))

* [internal] java: infer scala encoded symbols ([#13739](#13739))

* [internal] scala: parse and report package scopes ([#13738](#13738))

* [internal] go: configure included env vars for `GoSdkProcess` ([#13734](#13734))

* Fix some `./cargo audit` vulnerabilities. ([#13728](#13728))

* [internal] fix non-empty __init__.py ([#13730](#13730))

* Compute RepositoryPex directly from addresses. ([#13716](#13716))

* Upgrade to cargo-audit 0.16.0. ([#13729](#13729))

* Simplify `NativeHandler`. ([#13727](#13727))

* [internal] Switch to a maintained fork of the `fuse` crate for `brfs`. ([#13679](#13679))

* [internal] Add infrastructure to support deprecating field names ([#13666](#13666))

* [internal] Introduce OptionalPex/OptionalPexRequest. ([#13712](#13712))

* [internal] tailor adds go_package targets ([#13703](#13703))

* [internal] Remove unused testproject for pants-plugin ([#13704](#13704))

* [internal] Rename ambiguous `subpath` variable for Go code ([#13701](#13701))

* [internal] scala: generate the JVM names seen by Java code for Scala code ([#13696](#13696))

* Use RequirementsPexRequest in run_pex_binary.py. ([#13693](#13693))

* [internal] Refactor finding owning `go_mod` for first-party packages ([#13695](#13695))

* [internal] repl: add append_only_caches / run_in_workspace attributes to ReplRequest ([#13599](#13599))

* [internal] switch back to official `cargo-ensure-prefix` crate ([#13692](#13692))

* [internal] scala: extract type names from all Type.* AST nodes ([#13685](#13685))

* [internal] Convert unit tests to use pytest ([#13652](#13652))

* Unblock codegen support for java export analysis (#13645) ([#13675](#13675))

* [internal] upgrade to Rust 2021 Edition ([#13644](#13644))

* [internal] Don't store derived values on `go_first_party_package` targets ([#13676](#13676))

* Upgrade to py03 0.15.1. ([#13725](#13725))

* Add PyPDF2 to module mapping ([#13717](#13717))

* Upgrade console and indacatif. ([#13726](#13726))
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