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

An ExternalTool subsystem base for downloading external tools. #9625

Merged
merged 19 commits into from
Apr 28, 2020

Conversation

benjyw
Copy link
Contributor

@benjyw benjyw commented Apr 24, 2020

A streamlined replacement for the existing BinaryToolBase.

The existing code has served us really well for a long time, but has over the years evolved to be convoluted, leans on legacy util code, is biased towards pantsbuild-hosted binaries, has too many moving parts, and is no longer ergonomic.

This new code offers a simple and unified interface for version selection, URL computation,
and digest verification (possibly across multiple known versions). It integrates naturally
with the v2 engine, and supports automatic extraction from archives. Its design and functionality is inspired by the existing code, but cuts down the cruft.

The new ExternalTool subsystem base class is backwards compatible with
BinaryToolBase: A subclass of the latter can be rewritten to subclass the former,
and its options will remain compatible (although there may be deprecation warnings).

This change demonstrates its use via the ClocBinary and Protoc subsystems.
A future change can migrate our other uses of BinaryToolBase.

Note: requires #9624

[ci skip-rust-tests]
[ci skip-jvm-tests]

benjyw added 2 commits April 23, 2020 17:36
Useful, e.g., to unpack downloaded external binaries.

[ci skip-rust-tests]
[ci skip-jvm-tests]
A streamlined replacement for the existing BinaryTool.

[ci skip-rust-tests]
[ci skip-jvm-tests]
@benjyw
Copy link
Contributor Author

benjyw commented Apr 24, 2020

Note to reviewers: You can focus on just the second commit. The first is just #9624.

benjyw added 3 commits April 23, 2020 18:21
[ci skip-rust-tests]
[ci skip-jvm-tests]
[ci skip-rust-tests]
[ci skip-jvm-tests]
# Delete this line to force CI to run Clippy and the Rust tests.
[ci skip-rust-tests]
# Delete this line to force CI to run the JVM tests.
[ci skip-jvm-tests]
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.

Very cool. Thank you!

benjyw added 10 commits April 24, 2020 09:52
# Delete this line to force CI to run Clippy and the Rust tests.
[ci skip-rust-tests]
# Delete this line to force CI to run the JVM tests.
[ci skip-jvm-tests]
[ci skip-rust-tests]
[ci skip-jvm-tests]
[ci skip-rust-tests]
[ci skip-jvm-tests]
[ci skip-rust-tests]
[ci skip-jvm-tests]
[ci skip-rust-tests]
[ci skip-jvm-tests]
# Delete this line to force CI to run Clippy and the Rust tests.
[ci skip-rust-tests]
# Delete this line to force CI to run the JVM tests.
[ci skip-jvm-tests]
# Delete this line to force CI to run Clippy and the Rust tests.
[ci skip-rust-tests]
# Delete this line to force CI to run the JVM tests.
[ci skip-jvm-tests]
[ci skip-rust-tests]
[ci skip-jvm-tests]
[ci skip-rust-tests]
[ci skip-jvm-tests]
[ci skip-rust-tests]
[ci skip-jvm-tests]
@benjyw benjyw requested review from Eric-Arellano and stuhood April 25, 2020 07:14
# Delete this line to force CI to run Clippy and the Rust tests.
[ci skip-rust-tests]
# Delete this line to force CI to run the JVM tests.
[ci skip-jvm-tests]
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!

Comment on lines 206 to 214
def get_request(self, plat: Platform) -> ExternalToolRequest:
"""Generate a request for this tool."""
return self.generate_request(
plat, self.get_options().version, self.get_options().known_versions,
)


@rule
async def download_external_tool(request: ExternalToolRequest) -> DownloadedExternalTool:
Copy link
Member

Choose a reason for hiding this comment

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

So, it's currently the case that the Platform is available as a singleton, here:

# TODO We will want to allow users to specify the execution platform for rules,
# which means replacing this singleton rule with a RootRule populated by an option.
@rule
def materialize_platform() -> Platform:
return Platform.current
... that means that you don't need to take the Platform as an argument as part of the Request, and can instead request the platform singleton.

So your rule signature could probably just be:

@rule
async def download_external_tool(request: ExternalToolRequest, platform: Platform) -> DownloadedExternalTool:

The plan shortly (via https://docs.google.com/document/d/1hS0n6vp-hBxy4Xo-q9QA_elofzQtOubjfN4nSeIgp90/edit#heading=h.jj08j7tn7x2d , which I have some initial patches for) is for the Platform to switch from being a singleton to being a Param. That won't change anything from the @rule's perspective, but it will actually allow differentiating requests from one another.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Gotcha. Will make this 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.

Hmm, so we need to know the Platform when we create the request, because it can affect the URL, so this would require more restructuring than I think we want right now?

Copy link
Member

Choose a reason for hiding this comment

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

Not a blocker. Thanks!

@benjyw
Copy link
Contributor Author

benjyw commented Apr 26, 2020

I'll need to add a select() method for proper backwards compat, so I'll ask you to review again once I've done so. Thanks! 🤦

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.

Great! Thank you Benjy!

Subclass this to configure a specific tool.


Idiomatic use:
Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for adding this.

@benjyw benjyw force-pushed the external_tool branch 3 times, most recently from ce0fa04 to d67a3f9 Compare April 27, 2020 20:17
@benjyw benjyw force-pushed the external_tool branch 2 times, most recently from abfea9f to 626ead4 Compare April 27, 2020 22:41
[ci skip-rust-tests]
[ci skip-jvm-tests]
[ci skip-rust-tests]
[ci skip-jvm-tests]
Copy link
Contributor

@cosmicexplorer cosmicexplorer left a comment

Choose a reason for hiding this comment

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

Awesome work!!! binary_util.py is horrible to change (and that's partially my fault). Thanks so much for diving in to repair this.

member_type=str,
default=cls.default_known_versions,
advanced=True,
help=f"Known versions to verify downloads against. Each element is a "
Copy link
Contributor

Choose a reason for hiding this comment

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

Would something like:

      dedent(f"""\
      ...
      """)

Potentially be easier to read and 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.

Sorry I didn't address these comments Danny. I somehow missed them! Will look now and fix in my current change as needed.

Re this, I'm thinking the rendering code should figure this sort of thing out, as needed?

Copy link
Contributor

Choose a reason for hiding this comment

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

Oh sure! I meant for the purposes of development, the result might look cleaner. I agree that the rendering code should be figuring out how to display the text.



A lightweight replacement for the code in binary_tool.py and binary_util.py,
which can be deprecated in favor of this.
Copy link
Contributor

Choose a reason for hiding this comment

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

I would like to add this as a @deprecated_module to those files, then -- we could potentially use deprecation_start_version to delay it if we expect we'll need more than one release cycle to completely remove things.

I know binary_util.py was also used to fetch some tools for rust bootstrapping. We'll probably want to add that before we can remove it entirely.

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 would like to deprecate, but I'm going to transition all current uses first, to see what yelps.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes, sounds great!

) -> ExternalToolRequest:
for known_version in known_versions:
try:
ver, plat_val, sha256, length = (x.strip() for x in known_version.split("|"))
Copy link
Contributor

Choose a reason for hiding this comment

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

It might be useful to split this parsing out into a separate method in the future instead of having to hunt for the logic here.

def my_rule(my_external_tool: MyExternalTool):
downloaded_tool = await Get[DownloadedExternalTool](
ExternalToolRequest, my_external_tool.get_request(Platform.current)
)
Copy link
Contributor

Choose a reason for hiding this comment

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

It would be pretty cool to have this in the official engine README.md. I should also get #9446 in.

[ci skip-rust-tests]
[ci skip-jvm-tests]
@benjyw benjyw merged commit 9760c73 into pantsbuild:master Apr 28, 2020
@benjyw benjyw deleted the external_tool branch April 28, 2020 16:20
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