From 0896dfa5601fba214818ce6ac2eeb8e61041808f Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Tue, 28 Nov 2023 20:40:48 +0100 Subject: [PATCH 01/16] :allow plugins to provide builtin goals --- .../pants/backend/experimental/bsp/BUILD | 4 +++ .../backend/experimental/bsp/__init__.py | 0 .../backend/experimental/bsp/register.py | 13 +++++++++ .../pants/backend/experimental/java/bsp/BUILD | 4 +++ .../backend/experimental/java/bsp/__init__.py | 0 .../backend/experimental/java/bsp/register.py | 29 +++++++++++++++++++ .../backend/experimental/java/register.py | 2 -- .../backend/experimental/scala/bsp/BUILD | 4 +++ .../experimental/scala/bsp/__init__.py | 0 .../experimental/scala/bsp/register.py | 28 ++++++++++++++++++ .../backend/experimental/scala/register.py | 2 -- .../pants/build_graph/build_configuration.py | 18 ++++++++++++ src/python/pants/core/register.py | 2 -- src/python/pants/goal/builtins.py | 5 ++-- src/python/pants/init/extension_loader.py | 6 ++++ 15 files changed, 108 insertions(+), 9 deletions(-) create mode 100644 src/python/pants/backend/experimental/bsp/BUILD create mode 100644 src/python/pants/backend/experimental/bsp/__init__.py create mode 100644 src/python/pants/backend/experimental/bsp/register.py create mode 100644 src/python/pants/backend/experimental/java/bsp/BUILD create mode 100644 src/python/pants/backend/experimental/java/bsp/__init__.py create mode 100644 src/python/pants/backend/experimental/java/bsp/register.py create mode 100644 src/python/pants/backend/experimental/scala/bsp/BUILD create mode 100644 src/python/pants/backend/experimental/scala/bsp/__init__.py create mode 100644 src/python/pants/backend/experimental/scala/bsp/register.py diff --git a/src/python/pants/backend/experimental/bsp/BUILD b/src/python/pants/backend/experimental/bsp/BUILD new file mode 100644 index 00000000000..3928f7e3ba8 --- /dev/null +++ b/src/python/pants/backend/experimental/bsp/BUILD @@ -0,0 +1,4 @@ +# Copyright 2024 Pants project contributors (see CONTRIBUTORS.md). +# Licensed under the Apache License, Version 2.0 (see LICENSE). + +python_sources() diff --git a/src/python/pants/backend/experimental/bsp/__init__.py b/src/python/pants/backend/experimental/bsp/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/python/pants/backend/experimental/bsp/register.py b/src/python/pants/backend/experimental/bsp/register.py new file mode 100644 index 00000000000..4f804006f14 --- /dev/null +++ b/src/python/pants/backend/experimental/bsp/register.py @@ -0,0 +1,13 @@ +# Copyright 2024 Pants project contributors (see CONTRIBUTORS.md). +# Licensed under the Apache License, Version 2.0 (see LICENSE). + +from pants.bsp.goal import BSPGoal +from pants.bsp.rules import rules as bsp_rules + + +def builtin_goals(): + return (BSPGoal,) + + +def rules(): + return (*bsp_rules(),) diff --git a/src/python/pants/backend/experimental/java/bsp/BUILD b/src/python/pants/backend/experimental/java/bsp/BUILD new file mode 100644 index 00000000000..3928f7e3ba8 --- /dev/null +++ b/src/python/pants/backend/experimental/java/bsp/BUILD @@ -0,0 +1,4 @@ +# Copyright 2024 Pants project contributors (see CONTRIBUTORS.md). +# Licensed under the Apache License, Version 2.0 (see LICENSE). + +python_sources() diff --git a/src/python/pants/backend/experimental/java/bsp/__init__.py b/src/python/pants/backend/experimental/java/bsp/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/python/pants/backend/experimental/java/bsp/register.py b/src/python/pants/backend/experimental/java/bsp/register.py new file mode 100644 index 00000000000..253322bd37b --- /dev/null +++ b/src/python/pants/backend/experimental/java/bsp/register.py @@ -0,0 +1,29 @@ +# Copyright 2024 Pants project contributors (see CONTRIBUTORS.md). +# Licensed under the Apache License, Version 2.0 (see LICENSE). + +from pants.backend.experimental.bsp.register import builtin_goals as bsp_builtin_goals +from pants.backend.experimental.bsp.register import rules as bsp_rules +from pants.backend.experimental.java.register import build_file_aliases as java_build_file_aliases +from pants.backend.experimental.java.register import rules as java_rules +from pants.backend.experimental.java.register import target_types as java_target_types +from pants.backend.java.bsp.rules import rules as java_bsp_rules + + +def builtin_goals(): + return bsp_builtin_goals() + + +def target_types(): + return java_target_types() + + +def rules(): + return ( + *java_rules(), + *bsp_rules(), + *java_bsp_rules(), + ) + + +def build_file_aliases(): + return java_build_file_aliases() diff --git a/src/python/pants/backend/experimental/java/register.py b/src/python/pants/backend/experimental/java/register.py index a3fbed53ab3..0cd9d1729a4 100644 --- a/src/python/pants/backend/experimental/java/register.py +++ b/src/python/pants/backend/experimental/java/register.py @@ -1,7 +1,6 @@ # Copyright 2021 Pants project contributors (see CONTRIBUTORS.md). # Licensed under the Apache License, Version 2.0 (see LICENSE). -from pants.backend.java.bsp import rules as java_bsp_rules from pants.backend.java.compile import javac from pants.backend.java.dependency_inference import java_parser from pants.backend.java.dependency_inference import rules as dependency_inference_rules @@ -39,7 +38,6 @@ def rules(): *java_parser.rules(), *dependency_inference_rules.rules(), *tailor.rules(), - *java_bsp_rules.rules(), *archive.rules(), *target_types_rules(), *jvm_common.rules(), diff --git a/src/python/pants/backend/experimental/scala/bsp/BUILD b/src/python/pants/backend/experimental/scala/bsp/BUILD new file mode 100644 index 00000000000..3928f7e3ba8 --- /dev/null +++ b/src/python/pants/backend/experimental/scala/bsp/BUILD @@ -0,0 +1,4 @@ +# Copyright 2024 Pants project contributors (see CONTRIBUTORS.md). +# Licensed under the Apache License, Version 2.0 (see LICENSE). + +python_sources() diff --git a/src/python/pants/backend/experimental/scala/bsp/__init__.py b/src/python/pants/backend/experimental/scala/bsp/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/src/python/pants/backend/experimental/scala/bsp/register.py b/src/python/pants/backend/experimental/scala/bsp/register.py new file mode 100644 index 00000000000..9ed4ec4d315 --- /dev/null +++ b/src/python/pants/backend/experimental/scala/bsp/register.py @@ -0,0 +1,28 @@ +# Copyright 2024 Pants project contributors (see CONTRIBUTORS.md). +# Licensed under the Apache License, Version 2.0 (see LICENSE). +from pants.backend.experimental.bsp.register import builtin_goals as bsp_builtin_goals +from pants.backend.experimental.bsp.register import rules as bsp_rules +from pants.backend.experimental.scala.register import build_file_aliases as scala_build_file_aliases +from pants.backend.experimental.scala.register import rules as scala_rules +from pants.backend.experimental.scala.register import target_types as scala_target_types +from pants.backend.scala.bsp.rules import rules as scala_bsp_rules + + +def builtin_goals(): + return bsp_builtin_goals() + + +def target_types(): + return scala_target_types() + + +def rules(): + return ( + *scala_rules(), + *bsp_rules(), + *scala_bsp_rules(), + ) + + +def build_file_aliases(): + return scala_build_file_aliases() diff --git a/src/python/pants/backend/experimental/scala/register.py b/src/python/pants/backend/experimental/scala/register.py index 14683063736..315f04f40b5 100644 --- a/src/python/pants/backend/experimental/scala/register.py +++ b/src/python/pants/backend/experimental/scala/register.py @@ -1,6 +1,5 @@ # Copyright 2021 Pants project contributors (see CONTRIBUTORS.md). # Licensed under the Apache License, Version 2.0 (see LICENSE). -from pants.backend.scala.bsp.rules import rules as bsp_rules from pants.backend.scala.compile import scalac from pants.backend.scala.dependency_inference import rules as dep_inf_rules from pants.backend.scala.goals import check, repl, tailor @@ -50,7 +49,6 @@ def rules(): *dep_inf_rules.rules(), *target_types_rules(), *scala_lockfile_rules(), - *bsp_rules(), *jvm_common.rules(), *wrap_scala.rules, ] diff --git a/src/python/pants/build_graph/build_configuration.py b/src/python/pants/build_graph/build_configuration.py index 003c5b58fec..aa28b40e188 100644 --- a/src/python/pants/build_graph/build_configuration.py +++ b/src/python/pants/build_graph/build_configuration.py @@ -269,6 +269,24 @@ def register_target_types( def register_remote_auth_plugin(self, remote_auth_plugin: Callable) -> None: self._remote_auth_plugin = remote_auth_plugin + def register_builtin_goals(self, plugin_or_backend: str, builtin_goals: Iterable[type]): + """Registers the given builtin goals.""" + if not isinstance(builtin_goals, Iterable): + raise TypeError( + f"The entrypoint `builtin_goals` must return an iterable. " + f"Given {repr(builtin_goals)}" + ) + # Import `BuiltinGoal` here to avoid import cycle. + from pants.goal.builtin_goal import BuiltinGoal + + bad_elements = [goal for goal in builtin_goals if not issubclass(goal, BuiltinGoal)] + if bad_elements: + raise TypeError( + "Every element of the entrypoint `builtin_goals` must be a subclass of " + f"{BuiltinGoal.__name__}. Bad elements: {bad_elements}." + ) + self.register_subsystems(plugin_or_backend, builtin_goals) + def allow_unknown_options(self, allow: bool = True) -> None: """Allows overriding whether Options parsing will fail for unrecognized Options. diff --git a/src/python/pants/core/register.py b/src/python/pants/core/register.py index 0c0e19bde4e..e10544ba425 100644 --- a/src/python/pants/core/register.py +++ b/src/python/pants/core/register.py @@ -6,7 +6,6 @@ These are always activated and cannot be disabled. """ from pants.backend.codegen import export_codegen_goal -from pants.bsp.rules import rules as bsp_rules from pants.build_graph.build_file_aliases import BuildFileAliases from pants.core.goals import ( check, @@ -85,7 +84,6 @@ def rules(): *run.rules(), *tailor.rules(), *test.rules(), - *bsp_rules(), # util_rules *adhoc_binaries.rules(), *anonymous_telemetry.rules(), diff --git a/src/python/pants/goal/builtins.py b/src/python/pants/goal/builtins.py index 9b5140d0ca2..ae230fe723b 100644 --- a/src/python/pants/goal/builtins.py +++ b/src/python/pants/goal/builtins.py @@ -3,7 +3,6 @@ from __future__ import annotations -from pants.bsp.goal import BSPGoal from pants.build_graph.build_configuration import BuildConfiguration from pants.goal import help from pants.goal.builtin_goal import BuiltinGoal @@ -13,12 +12,12 @@ def register_builtin_goals(build_configuration: BuildConfiguration.Builder) -> None: - build_configuration.register_subsystems("pants.goal", builtin_goals()) + # build_configuration.register_subsystems("pants.goal", builtin_goals()) + build_configuration.register_builtin_goals("builtin", builtin_goals()) def builtin_goals() -> tuple[type[BuiltinGoal], ...]: return ( - BSPGoal, CompletionBuiltinGoal, ExplorerBuiltinGoal, MigrateCallByNameBuiltinGoal, diff --git a/src/python/pants/init/extension_loader.py b/src/python/pants/init/extension_loader.py index 2fecae4ba86..10cd5395b69 100644 --- a/src/python/pants/init/extension_loader.py +++ b/src/python/pants/init/extension_loader.py @@ -107,6 +107,9 @@ def load_plugins( f"register remote auth function {remote_auth_func.__module__}.{remote_auth_func.__name__} from plugin: {plugin}" ) build_configuration.register_remote_auth_plugin(remote_auth_func) + if "builtin_goals" in entries: + builtin_goals = entries["builtin_goals"].load()() + build_configuration.register_builtin_goals(req.key, builtin_goals) loaded[dist.as_requirement().key] = dist @@ -168,3 +171,6 @@ def invoke_entrypoint(name: str): f"register remote auth function {remote_auth_func.__module__}.{remote_auth_func.__name__} from backend: {backend_package}" ) build_configuration.register_remote_auth_plugin(remote_auth_func) + builtin_goals = getattr(module, "builtin_goals", None) + if builtin_goals: + build_configuration.register_builtin_goals(backend_package, builtin_goals) From 9dee8244565321dd385ae093b14b61645ec8c5c8 Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Mon, 13 May 2024 11:59:27 -0400 Subject: [PATCH 02/16] release notes --- docs/notes/2.22.x.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/notes/2.22.x.md b/docs/notes/2.22.x.md index 46fa44d43d6..37aa2d0567a 100644 --- a/docs/notes/2.22.x.md +++ b/docs/notes/2.22.x.md @@ -13,6 +13,7 @@ We offer [formal sponsorship tiers for companies](https://www.pantsbuild.org/spo ### Highlights - A new implementation of the options system. +- BSP support has been moved out of core rules into separate core and language-specific backends. ### New options system @@ -51,6 +52,16 @@ to fail to execute (since naturally it doesn't match those signatures). Setting the `orphan_files_behaviour = "ignore"` option for [`pants.backend.experimental.scala.lint.scalafix`](https://www.pantsbuild.org/2.22/reference/subsystems/scalafix#orphan_files_behavior) or [`pants.backend.experimental.scala.lint.scalafmt`](https://www.pantsbuild.org/2.22/reference/subsystems/scalafmt#orphan_files_behavior) backend is now properly silent. It previously showed spurious warnings. +##### BSP (Build Server Protocol) + +The BSP (Build Server Protocol) support has been moved out of the Pants core into several new backends to faciliate disabling this support if it is not needed. The new backends are: + +- `pants.backend.experimental.bsp` (core) +- `pants.backend.experimental.java.bsp` (Java support) +- `pants.backend.experimental.scala.bsp` (Scala support) + +Enable the core `pants.backend.experimental.bsp` backend and one or more of the language-specific backends to enable BSP support. + #### OpenAPI The `openapi_document` target will now bundle itself and its `openapi_source` dependencies into a single file when depended on by other targets. Do note that this change will make the `openapi_document` target behave more like a `resource` target rather than a `file` target, which in turn will likely affect which mechanism you need to use when loading it in dependent code. @@ -89,6 +100,8 @@ Setting [the `orphan_files_behaviour = "ignore"` option](https://www.pantsbuild. The `PythonToolRequirementsBase` and `PythonToolBase` classes now have a new `help_short` field. Subclasses should now use `help_short` instead of the `help` field. The `help` field will be automatically generated using `help_short`, and will include the tool's default package version and provide instructions on how to override this version using a custom lockfile. +Plugins may now provide builtin goals by implememting the `builtin_goals` function in their plugin registration module. + ## Full Changelog For the full changelog, see the individual GitHub Releases for this series: https://github.com/pantsbuild/pants/releases From a501625c95d3391d11cd568c22c9e20d35ade728 Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Mon, 13 May 2024 13:12:06 -0400 Subject: [PATCH 03/16] switch back commented code --- src/python/pants/goal/builtins.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/python/pants/goal/builtins.py b/src/python/pants/goal/builtins.py index ae230fe723b..8d242b28823 100644 --- a/src/python/pants/goal/builtins.py +++ b/src/python/pants/goal/builtins.py @@ -12,8 +12,7 @@ def register_builtin_goals(build_configuration: BuildConfiguration.Builder) -> None: - # build_configuration.register_subsystems("pants.goal", builtin_goals()) - build_configuration.register_builtin_goals("builtin", builtin_goals()) + build_configuration.register_subsystems("pants.goal", builtin_goals()) def builtin_goals() -> tuple[type[BuiltinGoal], ...]: From 5b6adef9dc30f6053589a14ab5c41439f49baee4 Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Wed, 19 Jun 2024 22:10:40 -0400 Subject: [PATCH 04/16] move release notes to 2.23.x --- docs/notes/2.22.x.md | 11 ----------- docs/notes/2.23.x.md | 14 ++++++++++++-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/docs/notes/2.22.x.md b/docs/notes/2.22.x.md index a9a9412f4b6..f7f65b0418a 100644 --- a/docs/notes/2.22.x.md +++ b/docs/notes/2.22.x.md @@ -13,7 +13,6 @@ We offer [formal sponsorship tiers for companies](https://www.pantsbuild.org/spo ### Highlights - A new implementation of the options system. -- BSP support has been moved out of core rules into separate core and language-specific backends. - Source globs are now less strict, using a "match any" conjunction rather than the previous "match all". - In-workspace execution of processes via `experimental_workspace_environment` target type. @@ -91,16 +90,6 @@ The internal code for exporting JVM tools was refactored. Setting the `orphan_files_behaviour = "ignore"` option for [`pants.backend.experimental.scala.lint.scalafix`](https://www.pantsbuild.org/2.22/reference/subsystems/scalafix#orphan_files_behavior) or [`pants.backend.experimental.scala.lint.scalafmt`](https://www.pantsbuild.org/2.22/reference/subsystems/scalafmt#orphan_files_behavior) backend is now properly silent. It previously showed spurious warnings. -##### BSP (Build Server Protocol) - -The BSP (Build Server Protocol) support has been moved out of the Pants core into several new backends to faciliate disabling this support if it is not needed. The new backends are: - -- `pants.backend.experimental.bsp` (core) -- `pants.backend.experimental.java.bsp` (Java support) -- `pants.backend.experimental.scala.bsp` (Scala support) - -Enable the core `pants.backend.experimental.bsp` backend and one or more of the language-specific backends to enable BSP support. - #### OpenAPI Added an `openapi_bundle` target that will provide the ability to bundle `openapi_document` and its `openapi_source` dependencies into a single file when depended on by other targets. Do note that the `openapi_bundle` target behaves like a `resource` target rather than a `file` target, which in turn will likely affect which mechanism you need to use when loading it in dependent code. diff --git a/docs/notes/2.23.x.md b/docs/notes/2.23.x.md index 8ecd24852b2..9ef7cb20dc7 100644 --- a/docs/notes/2.23.x.md +++ b/docs/notes/2.23.x.md @@ -14,10 +14,10 @@ We offer [formal sponsorship tiers for companies](https://www.pantsbuild.org/spo ### Overall - - The deprecations for the `--changed-dependees` option and the `dependees` goal have expired. Use the equivalent [`--changed-dependents` option](https://www.pantsbuild.org/2.23/reference/subsystems/changed#dependents) or [`dependents` goal](https://www.pantsbuild.org/2.23/reference/goals/dependents) instead. +BSP support has been moved out of core rules into separate core and language-specific backends. + ### Remote caching/execution @@ -57,6 +57,16 @@ The deprecation for `crossversion="partial"` on `scala_artifact` has expired. Us The Scala dependency inference now understand usages of the `_root_` package name as a marker for disambiguating between colliding dependencies and will try to resolve those symbols as absolute. For instance, `import _root_.io.circe.syntax` will now be understood as an import of `io.circie.syntax`. +##### BSP (Build Server Protocol) + +The BSP (Build Server Protocol) support has been moved out of the Pants core into several new backends to faciliate disabling this support if it is not needed. The new backends are: + +- `pants.backend.experimental.bsp` (core) +- `pants.backend.experimental.java.bsp` (Java support) +- `pants.backend.experimental.scala.bsp` (Scala support) + +Enable the core `pants.backend.experimental.bsp` backend and one or more of the language-specific backends to enable BSP support. + #### NEW: Trufflehog A new experimental `pants.backend.experimental.tools.trufflehog` backend was added to support From d44ac54779d27bb1b8d7b81f1146f805592e886f Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Thu, 20 Jun 2024 11:11:57 -0400 Subject: [PATCH 05/16] checkpoint --- docs/notes/2.22.x.md | 2 - docs/notes/2.23.x.md | 2 + .../backend/experimental/bsp/register.py | 2 +- .../backend/experimental/java/bsp/register.py | 6 +-- .../experimental/scala/bsp/register.py | 6 +-- src/python/pants/bsp/goal.py | 20 +++----- .../pants/build_graph/build_configuration.py | 20 ++++---- src/python/pants/goal/daemon_goal.py | 51 +++++++++++++++++++ src/python/pants/init/extension_loader.py | 12 ++--- src/python/pants/option/arg_splitter.py | 26 +++++----- src/python/pants/option/scope.py | 3 ++ 11 files changed, 100 insertions(+), 50 deletions(-) create mode 100644 src/python/pants/goal/daemon_goal.py diff --git a/docs/notes/2.22.x.md b/docs/notes/2.22.x.md index f7f65b0418a..77fe919d56b 100644 --- a/docs/notes/2.22.x.md +++ b/docs/notes/2.22.x.md @@ -137,8 +137,6 @@ Setting [the `orphan_files_behaviour = "ignore"` option](https://www.pantsbuild. The `PythonToolRequirementsBase` and `PythonToolBase` classes now have a new `help_short` field. Subclasses should now use `help_short` instead of the `help` field. The `help` field will be automatically generated using `help_short`, and will include the tool's default package version and provide instructions on how to override this version using a custom lockfile. -Plugins may now provide builtin goals by implememting the `builtin_goals` function in their plugin registration module. - The process execution intrinsic rule in Rust now contains support for "in workspace" execution. This is local execution from within the repository itself without using an execution sandbox. `ProcessExecutionEnvironment`'s constructor has a new `execute_in_workspace` parameter which enables workspace execution. ### Other minor tweaks diff --git a/docs/notes/2.23.x.md b/docs/notes/2.23.x.md index 9ef7cb20dc7..d21e24c7aa1 100644 --- a/docs/notes/2.23.x.md +++ b/docs/notes/2.23.x.md @@ -125,6 +125,8 @@ Support documenting macro constants using `MY_CONSTANT: Annotated[some_type, Doc Fixed bug where files larger than 512KB were being materialized to a process's sandbox without write permissions if the file was only globbed by `output_directories=(".",)`. +Plugins may now provide "daemon" goals by implememting the `daemon_goals` function in their plugin registration module. + ### Other minor tweaks The "Provided by" information in the documentation now correctly reflects the proper backend to enable to activate a certain feature. diff --git a/src/python/pants/backend/experimental/bsp/register.py b/src/python/pants/backend/experimental/bsp/register.py index 4f804006f14..62055316437 100644 --- a/src/python/pants/backend/experimental/bsp/register.py +++ b/src/python/pants/backend/experimental/bsp/register.py @@ -5,7 +5,7 @@ from pants.bsp.rules import rules as bsp_rules -def builtin_goals(): +def daemon_goals(): return (BSPGoal,) diff --git a/src/python/pants/backend/experimental/java/bsp/register.py b/src/python/pants/backend/experimental/java/bsp/register.py index 253322bd37b..a0f61ddbf8b 100644 --- a/src/python/pants/backend/experimental/java/bsp/register.py +++ b/src/python/pants/backend/experimental/java/bsp/register.py @@ -1,7 +1,7 @@ # Copyright 2024 Pants project contributors (see CONTRIBUTORS.md). # Licensed under the Apache License, Version 2.0 (see LICENSE). -from pants.backend.experimental.bsp.register import builtin_goals as bsp_builtin_goals +from pants.backend.experimental.bsp.register import daemon_goals as bsp_daemon_goals from pants.backend.experimental.bsp.register import rules as bsp_rules from pants.backend.experimental.java.register import build_file_aliases as java_build_file_aliases from pants.backend.experimental.java.register import rules as java_rules @@ -9,8 +9,8 @@ from pants.backend.java.bsp.rules import rules as java_bsp_rules -def builtin_goals(): - return bsp_builtin_goals() +def daemon_goals(): + return bsp_daemon_goals() def target_types(): diff --git a/src/python/pants/backend/experimental/scala/bsp/register.py b/src/python/pants/backend/experimental/scala/bsp/register.py index 9ed4ec4d315..7c58e281891 100644 --- a/src/python/pants/backend/experimental/scala/bsp/register.py +++ b/src/python/pants/backend/experimental/scala/bsp/register.py @@ -1,6 +1,6 @@ # Copyright 2024 Pants project contributors (see CONTRIBUTORS.md). # Licensed under the Apache License, Version 2.0 (see LICENSE). -from pants.backend.experimental.bsp.register import builtin_goals as bsp_builtin_goals +from pants.backend.experimental.bsp.register import daemon_goals as bsp_daemon_goals from pants.backend.experimental.bsp.register import rules as bsp_rules from pants.backend.experimental.scala.register import build_file_aliases as scala_build_file_aliases from pants.backend.experimental.scala.register import rules as scala_rules @@ -8,8 +8,8 @@ from pants.backend.scala.bsp.rules import rules as scala_bsp_rules -def builtin_goals(): - return bsp_builtin_goals() +def daemon_goals(): + return bsp_daemon_goals() def target_types(): diff --git a/src/python/pants/bsp/goal.py b/src/python/pants/bsp/goal.py index 95a5d944877..fa907b04152 100644 --- a/src/python/pants/bsp/goal.py +++ b/src/python/pants/bsp/goal.py @@ -21,6 +21,7 @@ from pants.engine.internals.session import SessionValues from pants.engine.unions import UnionMembership from pants.goal.builtin_goal import BuiltinGoal +from pants.goal.daemon_goal import DaemonGoalContext from pants.init.engine_initializer import GraphSession from pants.option.option_types import BoolOption, FileListOption, StrListOption from pants.option.option_value_container import OptionValueContainer @@ -32,7 +33,7 @@ _logger = logging.getLogger(__name__) -class BSPGoal(BuiltinGoal): +class BSPGoal(DaemonGoal): name = "experimental-bsp" help = "Setup repository for Build Server Protocol (https://build-server-protocol.github.io/)." @@ -102,23 +103,18 @@ class BSPGoal(BuiltinGoal): def run( self, - *, - build_config: BuildConfiguration, - graph_session: GraphSession, - options: Options, - specs: Specs, - union_membership: UnionMembership, + context: DaemonGoalContext, ) -> ExitCode: - goal_options = options.for_scope(self.name) + goal_options = context.options.for_scope(self.name) if goal_options.server: return self._run_server( - graph_session=graph_session, - union_membership=union_membership, + graph_session=context.graph_session, + union_membership=context.union_membership, ) - current_session_values = graph_session.scheduler_session.py_session.session_values + current_session_values = context.graph_session.scheduler_session.py_session.session_values env = current_session_values[CompleteEnvironmentVars] return self._setup_bsp_connection( - union_membership=union_membership, env=env, options=goal_options + union_membership=context.union_membership, env=env, options=goal_options ) def _setup_bsp_connection( diff --git a/src/python/pants/build_graph/build_configuration.py b/src/python/pants/build_graph/build_configuration.py index aa28b40e188..00241fcf355 100644 --- a/src/python/pants/build_graph/build_configuration.py +++ b/src/python/pants/build_graph/build_configuration.py @@ -269,23 +269,23 @@ def register_target_types( def register_remote_auth_plugin(self, remote_auth_plugin: Callable) -> None: self._remote_auth_plugin = remote_auth_plugin - def register_builtin_goals(self, plugin_or_backend: str, builtin_goals: Iterable[type]): + def register_daemon_goals(self, plugin_or_backend: str, daemon_goals: Iterable[type]): """Registers the given builtin goals.""" - if not isinstance(builtin_goals, Iterable): + if not isinstance(daemon_goals, Iterable): raise TypeError( - f"The entrypoint `builtin_goals` must return an iterable. " - f"Given {repr(builtin_goals)}" + f"The entrypoint `daemon_goals` must return an iterable. " + f"Given {repr(daemon_goals)}" ) - # Import `BuiltinGoal` here to avoid import cycle. - from pants.goal.builtin_goal import BuiltinGoal + # Import `DaemonGoal` here to avoid import cycle. + from pants.goal.daemon_goal import DaemonGoal - bad_elements = [goal for goal in builtin_goals if not issubclass(goal, BuiltinGoal)] + bad_elements = [goal for goal in daemon_goals if not issubclass(goal, DaemonGoal)] if bad_elements: raise TypeError( - "Every element of the entrypoint `builtin_goals` must be a subclass of " - f"{BuiltinGoal.__name__}. Bad elements: {bad_elements}." + "Every element of the entrypoint `daemon_goals` must be a subclass of " + f"{DaemonGoal.__name__}. Bad elements: {bad_elements}." ) - self.register_subsystems(plugin_or_backend, builtin_goals) + self.register_subsystems(plugin_or_backend, daemon_goals) def allow_unknown_options(self, allow: bool = True) -> None: """Allows overriding whether Options parsing will fail for unrecognized Options. diff --git a/src/python/pants/goal/daemon_goal.py b/src/python/pants/goal/daemon_goal.py new file mode 100644 index 00000000000..af2180e66fc --- /dev/null +++ b/src/python/pants/goal/daemon_goal.py @@ -0,0 +1,51 @@ +# Copyright 2024 Pants project contributors (see CONTRIBUTORS.md). +# Licensed under the Apache License, Version 2.0 (see LICENSE). + + +from abc import ABC, abstractmethod +from dataclasses import dataclass +from typing import ClassVar + +from pants.base.exiter import ExitCode +from pants.base.specs import Specs +from pants.build_graph.build_configuration import BuildConfiguration +from pants.engine.goal import GoalSubsystem +from pants.engine.unions import UnionMembership +from pants.init.engine_initializer import GraphSession +from pants.option.options import Options + + +@dataclass +class DaemonGoalContext: + """Context passed to a `DaemonGoal.run` implementation.""" + build_config: BuildConfiguration + graph_session: GraphSession + options: Options + specs: Specs + union_membership: UnionMembership + + +class DaemonGoal(ABC, GoalSubsystem): + """Configure a "daemon" goal which allows rules to "take over" Pants client execution. + + Only a single daemon goal is executed per run, any remaining goals/arguments are passed + unaltered to the builtin goal. Daemon goals have precedence over regular goals. + + When multiple daemon goals are presented, the first builtin goal will be used unless there is a + daemon goal that begin with a hyphen (`-`), in which case the last such "option goal" will be + prioritized. This is to support things like `./pants some-builtin-goal --help`. + """ + + # Used by `pants.option.arg_splitter.ArgSplitter()` to optionally allow aliasing builtin goals. + aliases: ClassVar[tuple[str, ...]] = () + + @classmethod + def create_scope_info(cls, **scope_info_kwargs) -> ScopeInfo: + return super().create_scope_info(is_daemon=True, **scope_info_kwargs) + + @abstractmethod + def run( + self, + context: DaemonGoalContext, + ) -> ExitCode: + pass diff --git a/src/python/pants/init/extension_loader.py b/src/python/pants/init/extension_loader.py index 10cd5395b69..1cb7f54c878 100644 --- a/src/python/pants/init/extension_loader.py +++ b/src/python/pants/init/extension_loader.py @@ -107,9 +107,9 @@ def load_plugins( f"register remote auth function {remote_auth_func.__module__}.{remote_auth_func.__name__} from plugin: {plugin}" ) build_configuration.register_remote_auth_plugin(remote_auth_func) - if "builtin_goals" in entries: - builtin_goals = entries["builtin_goals"].load()() - build_configuration.register_builtin_goals(req.key, builtin_goals) + if "daemon_goals" in entries: + daemon_goals = entries["daemon_goals"].load()() + build_configuration.register_daemon_goals(req.key, daemon_goals) loaded[dist.as_requirement().key] = dist @@ -171,6 +171,6 @@ def invoke_entrypoint(name: str): f"register remote auth function {remote_auth_func.__module__}.{remote_auth_func.__name__} from backend: {backend_package}" ) build_configuration.register_remote_auth_plugin(remote_auth_func) - builtin_goals = getattr(module, "builtin_goals", None) - if builtin_goals: - build_configuration.register_builtin_goals(backend_package, builtin_goals) + daemon_goals = getattr(module, "daemon_goals", None) + if daemon_goals: + build_configuration.register_daemon_goals(backend_package, daemon_goals) diff --git a/src/python/pants/option/arg_splitter.py b/src/python/pants/option/arg_splitter.py index e6c07120b65..7ecd40c598d 100644 --- a/src/python/pants/option/arg_splitter.py +++ b/src/python/pants/option/arg_splitter.py @@ -135,7 +135,7 @@ def split_args(self, args: Sequence[str]) -> SplitArgs: specs: list[str] = [] passthru: list[str] = [] unknown_scopes: list[str] = [] - builtin_goal: str | None = None + builtin_or_daemon_goal: str | None = None def add_scope(s: str) -> None: # Force the scope to appear, even if empty. @@ -150,19 +150,19 @@ def add_goal(scope: str) -> str: add_scope(scope) return scope - nonlocal builtin_goal - if scope_info.is_builtin and (not builtin_goal or scope.startswith("-")): - if builtin_goal: - goals.add(builtin_goal) + nonlocal builtin_or_daemon_goal + if (scope_info.is_builtin or scope_info.is_daemon) and (not builtin_or_daemon_goal or scope.startswith("-")): + if builtin_or_daemon_goal: + goals.add(builtin_or_daemon_goal) - # Get scope from info in case we hit an aliased builtin goal. - builtin_goal = scope_info.scope + # Get scope from info in case we hit an aliased builtin/daemon goal. + builtin_or_daemon_goal = scope_info.scope else: goals.add(scope_info.scope) add_scope(scope_info.scope) - # Use builtin goal as default scope for args. - return builtin_goal or scope_info.scope + # Use builtin/daemon goal as default scope for args. + return builtin_or_daemon_goal or scope_info.scope self._unconsumed_args = list(reversed(args)) # The first token is the binary name, so skip it. @@ -198,11 +198,11 @@ def assign_flag_to_scope(flg: str, default_scope: str) -> None: else: add_goal(arg) - if not builtin_goal: + if not builtin_or_daemon_goal: if unknown_scopes and UNKNOWN_GOAL_NAME in self._known_goal_scopes: - builtin_goal = UNKNOWN_GOAL_NAME + builtin_or_daemon_goal = UNKNOWN_GOAL_NAME elif not goals and NO_GOAL_NAME in self._known_goal_scopes: - builtin_goal = NO_GOAL_NAME + builtin_or_daemon_goal = NO_GOAL_NAME if self._at_standalone_double_dash(): self._unconsumed_args.pop() @@ -223,7 +223,7 @@ def assign_flag_to_scope(flg: str, default_scope: str) -> None: ) return SplitArgs( - builtin_goal=builtin_goal, + builtin_goal=builtin_or_daemon_goal, goals=list(goals), unknown_goals=unknown_scopes, scope_to_flags=dict(scope_to_flags), diff --git a/src/python/pants/option/scope.py b/src/python/pants/option/scope.py index c9b9c46f5ec..ffb42bc0191 100644 --- a/src/python/pants/option/scope.py +++ b/src/python/pants/option/scope.py @@ -39,6 +39,9 @@ class ScopeInfo: # Builtin goals, such as `help` and `version` etc. is_builtin: bool = False + # Daemon goals, such as the `experimental-bsp` goal. + is_daemon: bool = False + @property def description(self) -> str: return cast(str, self._subsystem_cls_attr("help")) From 392e1bc438080232a621fc0f41d380024bb58bba Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Thu, 20 Jun 2024 12:34:32 -0400 Subject: [PATCH 06/16] checkpoint --- src/python/pants/option/arg_splitter.py | 4 ++-- src/python/pants/option/arg_splitter_test.py | 12 ++++++------ src/python/pants/option/options.py | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/python/pants/option/arg_splitter.py b/src/python/pants/option/arg_splitter.py index 7ecd40c598d..9a5c330a2e1 100644 --- a/src/python/pants/option/arg_splitter.py +++ b/src/python/pants/option/arg_splitter.py @@ -22,7 +22,7 @@ class ArgSplitterError(Exception): class SplitArgs: """The result of splitting args.""" - builtin_goal: str | None # Requested builtin goal (explicitly or implicitly). + builtin_or_daemon_goal: str | None # Requested builtin goal (explicitly or implicitly). goals: list[str] # Explicitly requested goals. unknown_goals: list[str] # Any unknown goals. scope_to_flags: dict[str, list[str]] # Scope name -> list of flags in that scope. @@ -223,7 +223,7 @@ def assign_flag_to_scope(flg: str, default_scope: str) -> None: ) return SplitArgs( - builtin_goal=builtin_or_daemon_goal, + builtin_or_daemon_goal=builtin_or_daemon_goal, goals=list(goals), unknown_goals=unknown_scopes, scope_to_flags=dict(scope_to_flags), diff --git a/src/python/pants/option/arg_splitter_test.py b/src/python/pants/option/arg_splitter_test.py index ae9230d0c5b..1221797419c 100644 --- a/src/python/pants/option/arg_splitter_test.py +++ b/src/python/pants/option/arg_splitter_test.py @@ -54,16 +54,16 @@ def assert_valid_split( assert expected_passthru == split_args.passthru assert expected_is_help == ( - split_args.builtin_goal + split_args.builtin_or_daemon_goal in ("help", "help-advanced", "help-all", UNKNOWN_GOAL_NAME, NO_GOAL_NAME) ) - assert expected_help_advanced == ("help-advanced" == split_args.builtin_goal) - assert expected_help_all == ("help-all" == split_args.builtin_goal) + assert expected_help_advanced == ("help-advanced" == split_args.builtin_or_daemon_goal) + assert expected_help_all == ("help-all" == split_args.builtin_or_daemon_goal) def assert_unknown_goal(splitter: ArgSplitter, args_str: str, unknown_goals: list[str]) -> None: split_args = splitter.split_args(shlex.split(args_str)) - assert UNKNOWN_GOAL_NAME == split_args.builtin_goal + assert UNKNOWN_GOAL_NAME == split_args.builtin_or_daemon_goal assert set(unknown_goals) == set(split_args.unknown_goals) @@ -424,7 +424,7 @@ def test_help_detection(splitter: ArgSplitter, command_line: str, expected: dict def test_version_request_detection(splitter: ArgSplitter) -> None: def assert_version_request(args_str: str) -> None: split_args = splitter.split_args(shlex.split(args_str)) - assert "version" == split_args.builtin_goal + assert "version" == split_args.builtin_or_daemon_goal assert_version_request("./pants -v") assert_version_request("./pants -V") @@ -452,7 +452,7 @@ def test_unknown_goal_detection( @pytest.mark.parametrize("extra_args", ("", "foo/bar:baz", "f.ext", "-linfo", "--arg")) def test_no_goal_detection(extra_args: str, splitter: ArgSplitter) -> None: split_args = splitter.split_args(shlex.split(f"./pants {extra_args}")) - assert NO_GOAL_NAME == split_args.builtin_goal + assert NO_GOAL_NAME == split_args.builtin_or_daemon_goal def test_subsystem_scope_is_unknown_goal(splitter: ArgSplitter) -> None: diff --git a/src/python/pants/option/options.py b/src/python/pants/option/options.py index 33a73af7fd0..0387f59e552 100644 --- a/src/python/pants/option/options.py +++ b/src/python/pants/option/options.py @@ -166,7 +166,7 @@ def create( native_parser = NativeOptionParser(args, env, config.sources(), allow_pantsrc=True) return cls( - builtin_goal=split_args.builtin_goal, + builtin_goal=split_args.builtin_or_daemon_goal, goals=split_args.goals, unknown_goals=split_args.unknown_goals, scope_to_flags=split_args.scope_to_flags, From e50f12822db5b80dce92a264efa554e6372b0f80 Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Tue, 25 Jun 2024 23:50:10 -0400 Subject: [PATCH 07/16] more progress on DaemonGoal API --- src/python/pants/bsp/goal.py | 5 +---- .../pants/build_graph/build_configuration.py | 2 +- src/python/pants/goal/daemon_goal.py | 15 ++++++++++----- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/python/pants/bsp/goal.py b/src/python/pants/bsp/goal.py index fa907b04152..28023079f71 100644 --- a/src/python/pants/bsp/goal.py +++ b/src/python/pants/bsp/goal.py @@ -12,16 +12,13 @@ from pants.base.build_root import BuildRoot from pants.base.exiter import PANTS_FAILED_EXIT_CODE, PANTS_SUCCEEDED_EXIT_CODE, ExitCode -from pants.base.specs import Specs from pants.bsp.context import BSPContext from pants.bsp.protocol import BSPConnection from pants.bsp.util_rules.lifecycle import BSP_VERSION, BSPLanguageSupport -from pants.build_graph.build_configuration import BuildConfiguration from pants.engine.env_vars import CompleteEnvironmentVars from pants.engine.internals.session import SessionValues from pants.engine.unions import UnionMembership -from pants.goal.builtin_goal import BuiltinGoal -from pants.goal.daemon_goal import DaemonGoalContext +from pants.goal.daemon_goal import DaemonGoal, DaemonGoalContext from pants.init.engine_initializer import GraphSession from pants.option.option_types import BoolOption, FileListOption, StrListOption from pants.option.option_value_container import OptionValueContainer diff --git a/src/python/pants/build_graph/build_configuration.py b/src/python/pants/build_graph/build_configuration.py index 00241fcf355..0a4475c86a7 100644 --- a/src/python/pants/build_graph/build_configuration.py +++ b/src/python/pants/build_graph/build_configuration.py @@ -270,7 +270,7 @@ def register_remote_auth_plugin(self, remote_auth_plugin: Callable) -> None: self._remote_auth_plugin = remote_auth_plugin def register_daemon_goals(self, plugin_or_backend: str, daemon_goals: Iterable[type]): - """Registers the given builtin goals.""" + """Registers the given daemon goals.""" if not isinstance(daemon_goals, Iterable): raise TypeError( f"The entrypoint `daemon_goals` must return an iterable. " diff --git a/src/python/pants/goal/daemon_goal.py b/src/python/pants/goal/daemon_goal.py index af2180e66fc..43e4ee4edb7 100644 --- a/src/python/pants/goal/daemon_goal.py +++ b/src/python/pants/goal/daemon_goal.py @@ -13,6 +13,7 @@ from pants.engine.unions import UnionMembership from pants.init.engine_initializer import GraphSession from pants.option.options import Options +from pants.option.scope import ScopeInfo @dataclass @@ -23,20 +24,24 @@ class DaemonGoalContext: options: Options specs: Specs union_membership: UnionMembership - + class DaemonGoal(ABC, GoalSubsystem): - """Configure a "daemon" goal which allows rules to "take over" Pants client execution. + """Configure a "daemon" goal which allows rules to "take over" Pants client execution in lieu + of executing an ordnary goal. Only a single daemon goal is executed per run, any remaining goals/arguments are passed - unaltered to the builtin goal. Daemon goals have precedence over regular goals. + unaltered to the daemon goal. Daemon goals have precedence over regular goals. - When multiple daemon goals are presented, the first builtin goal will be used unless there is a + When multiple daemon goals are presented, the first daemon goal will be used unless there is a daemon goal that begin with a hyphen (`-`), in which case the last such "option goal" will be prioritized. This is to support things like `./pants some-builtin-goal --help`. + + The intended use for this API is rule code which runs a server (for example, a BSP server) + which provides an alternate interface to the Pants rule engine. """ - # Used by `pants.option.arg_splitter.ArgSplitter()` to optionally allow aliasing builtin goals. + # Used by `pants.option.arg_splitter.ArgSplitter()` to optionally allow aliasing daemon goals. aliases: ClassVar[tuple[str, ...]] = () @classmethod From bb2ebfd7b3dea37d3eb88c918fccba07471f51e8 Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Wed, 24 Jul 2024 21:06:23 -0400 Subject: [PATCH 08/16] rename to AuxillaryGoal --- docs/notes/2.23.x.md | 6 ++--- .../backend/experimental/bsp/register.py | 2 +- .../backend/experimental/java/bsp/register.py | 6 ++--- .../experimental/scala/bsp/register.py | 6 ++--- src/python/pants/bsp/goal.py | 7 +++-- .../pants/build_graph/build_configuration.py | 20 +++++++------- .../{daemon_goal.py => auxillary_goal.py} | 24 +++++++++-------- src/python/pants/init/extension_loader.py | 12 ++++----- src/python/pants/option/arg_splitter.py | 26 ++++++++++--------- src/python/pants/option/arg_splitter_test.py | 12 ++++----- src/python/pants/option/options.py | 2 +- src/python/pants/option/scope.py | 4 +-- 12 files changed, 64 insertions(+), 63 deletions(-) rename src/python/pants/goal/{daemon_goal.py => auxillary_goal.py} (61%) diff --git a/docs/notes/2.23.x.md b/docs/notes/2.23.x.md index b13bd98b13c..f514f84351e 100644 --- a/docs/notes/2.23.x.md +++ b/docs/notes/2.23.x.md @@ -206,11 +206,9 @@ Support documenting macro constants using `MY_CONSTANT: Annotated[some_type, Doc Fixed bug where files larger than 512KB were being materialized to a process's sandbox without write permissions if the file was only globbed by `output_directories=(".",)`. -<<<<<<< HEAD -Plugins may now provide "daemon" goals by implememting the `daemon_goals` function in their plugin registration module. -======= Fixed bug where using `RuleRunner` in plugin tests caused `ValueError` that complains about not finding build root sentinel files. Note that you may have to adjust your tests to account for the new `BUILDROOT` file that `RuleRunner` now injects in the sandbox it creates for each test. For example, a test that uses a `**` glob might have to add `!BUILDROOT` to exclude the `BUILDROOT` file, or otherwise account for its presence when inspecting a sandbox or its digest. ->>>>>>> refs/heads/main + +Plugins may now provide "auxillary" goals by implememting the `auxillary_goals` function in their plugin registration module and returning one or more subclasses of `pants.goal.auxillary_goal.AuxillaryGoal`. The BSP (Build Server Protocol) support now uses this mechanism to move the `experimental-bsp` goal out of the Pants core rules. ### Other minor tweaks diff --git a/src/python/pants/backend/experimental/bsp/register.py b/src/python/pants/backend/experimental/bsp/register.py index 62055316437..07e7c1d7e23 100644 --- a/src/python/pants/backend/experimental/bsp/register.py +++ b/src/python/pants/backend/experimental/bsp/register.py @@ -5,7 +5,7 @@ from pants.bsp.rules import rules as bsp_rules -def daemon_goals(): +def auxillary_goals(): return (BSPGoal,) diff --git a/src/python/pants/backend/experimental/java/bsp/register.py b/src/python/pants/backend/experimental/java/bsp/register.py index a0f61ddbf8b..effac16db13 100644 --- a/src/python/pants/backend/experimental/java/bsp/register.py +++ b/src/python/pants/backend/experimental/java/bsp/register.py @@ -1,7 +1,7 @@ # Copyright 2024 Pants project contributors (see CONTRIBUTORS.md). # Licensed under the Apache License, Version 2.0 (see LICENSE). -from pants.backend.experimental.bsp.register import daemon_goals as bsp_daemon_goals +from pants.backend.experimental.bsp.register import auxillary_goals as bsp_auxillary_goals from pants.backend.experimental.bsp.register import rules as bsp_rules from pants.backend.experimental.java.register import build_file_aliases as java_build_file_aliases from pants.backend.experimental.java.register import rules as java_rules @@ -9,8 +9,8 @@ from pants.backend.java.bsp.rules import rules as java_bsp_rules -def daemon_goals(): - return bsp_daemon_goals() +def auxillary_goals(): + return bsp_auxillary_goals() def target_types(): diff --git a/src/python/pants/backend/experimental/scala/bsp/register.py b/src/python/pants/backend/experimental/scala/bsp/register.py index 7c58e281891..335f2a82e62 100644 --- a/src/python/pants/backend/experimental/scala/bsp/register.py +++ b/src/python/pants/backend/experimental/scala/bsp/register.py @@ -1,6 +1,6 @@ # Copyright 2024 Pants project contributors (see CONTRIBUTORS.md). # Licensed under the Apache License, Version 2.0 (see LICENSE). -from pants.backend.experimental.bsp.register import daemon_goals as bsp_daemon_goals +from pants.backend.experimental.bsp.register import auxillary_goals as bsp_auxillary_goals from pants.backend.experimental.bsp.register import rules as bsp_rules from pants.backend.experimental.scala.register import build_file_aliases as scala_build_file_aliases from pants.backend.experimental.scala.register import rules as scala_rules @@ -8,8 +8,8 @@ from pants.backend.scala.bsp.rules import rules as scala_bsp_rules -def daemon_goals(): - return bsp_daemon_goals() +def auxillary_goals(): + return bsp_auxillary_goals() def target_types(): diff --git a/src/python/pants/bsp/goal.py b/src/python/pants/bsp/goal.py index 28023079f71..2d1fae968b4 100644 --- a/src/python/pants/bsp/goal.py +++ b/src/python/pants/bsp/goal.py @@ -18,11 +18,10 @@ from pants.engine.env_vars import CompleteEnvironmentVars from pants.engine.internals.session import SessionValues from pants.engine.unions import UnionMembership -from pants.goal.daemon_goal import DaemonGoal, DaemonGoalContext +from pants.goal.auxillary_goal import AuxillaryGoal, AuxillaryGoalContext from pants.init.engine_initializer import GraphSession from pants.option.option_types import BoolOption, FileListOption, StrListOption from pants.option.option_value_container import OptionValueContainer -from pants.option.options import Options from pants.util.docutil import bin_name from pants.util.strutil import softwrap from pants.version import VERSION @@ -30,7 +29,7 @@ _logger = logging.getLogger(__name__) -class BSPGoal(DaemonGoal): +class BSPGoal(AuxillaryGoal): name = "experimental-bsp" help = "Setup repository for Build Server Protocol (https://build-server-protocol.github.io/)." @@ -100,7 +99,7 @@ class BSPGoal(DaemonGoal): def run( self, - context: DaemonGoalContext, + context: AuxillaryGoalContext, ) -> ExitCode: goal_options = context.options.for_scope(self.name) if goal_options.server: diff --git a/src/python/pants/build_graph/build_configuration.py b/src/python/pants/build_graph/build_configuration.py index 0a4475c86a7..61ab5bffdaa 100644 --- a/src/python/pants/build_graph/build_configuration.py +++ b/src/python/pants/build_graph/build_configuration.py @@ -269,23 +269,23 @@ def register_target_types( def register_remote_auth_plugin(self, remote_auth_plugin: Callable) -> None: self._remote_auth_plugin = remote_auth_plugin - def register_daemon_goals(self, plugin_or_backend: str, daemon_goals: Iterable[type]): + def register_auxillary_goals(self, plugin_or_backend: str, auxillary_goals: Iterable[type]): """Registers the given daemon goals.""" - if not isinstance(daemon_goals, Iterable): + if not isinstance(auxillary_goals, Iterable): raise TypeError( - f"The entrypoint `daemon_goals` must return an iterable. " - f"Given {repr(daemon_goals)}" + f"The entrypoint `auxillary_goals` must return an iterable. " + f"Given {repr(auxillary_goals)}" ) - # Import `DaemonGoal` here to avoid import cycle. - from pants.goal.daemon_goal import DaemonGoal + # Import `AuxillaryGoal` here to avoid import cycle. + from pants.goal.auxillary_goal import AuxillaryGoal - bad_elements = [goal for goal in daemon_goals if not issubclass(goal, DaemonGoal)] + bad_elements = [goal for goal in auxillary_goals if not issubclass(goal, AuxillaryGoal)] if bad_elements: raise TypeError( - "Every element of the entrypoint `daemon_goals` must be a subclass of " - f"{DaemonGoal.__name__}. Bad elements: {bad_elements}." + "Every element of the entrypoint `auxillary_goals` must be a subclass of " + f"{AuxillaryGoal.__name__}. Bad elements: {bad_elements}." ) - self.register_subsystems(plugin_or_backend, daemon_goals) + self.register_subsystems(plugin_or_backend, auxillary_goals) def allow_unknown_options(self, allow: bool = True) -> None: """Allows overriding whether Options parsing will fail for unrecognized Options. diff --git a/src/python/pants/goal/daemon_goal.py b/src/python/pants/goal/auxillary_goal.py similarity index 61% rename from src/python/pants/goal/daemon_goal.py rename to src/python/pants/goal/auxillary_goal.py index 43e4ee4edb7..c15da7b1880 100644 --- a/src/python/pants/goal/daemon_goal.py +++ b/src/python/pants/goal/auxillary_goal.py @@ -17,8 +17,9 @@ @dataclass -class DaemonGoalContext: - """Context passed to a `DaemonGoal.run` implementation.""" +class AuxillaryGoalContext: + """Context passed to a `AuxillaryGoal.run` implementation.""" + build_config: BuildConfiguration graph_session: GraphSession options: Options @@ -26,19 +27,20 @@ class DaemonGoalContext: union_membership: UnionMembership -class DaemonGoal(ABC, GoalSubsystem): - """Configure a "daemon" goal which allows rules to "take over" Pants client execution in lieu +class AuxillaryGoal(ABC, GoalSubsystem): + """Configure a "auxillary" goal which allows rules to "take over" Pants client execution in lieu of executing an ordnary goal. - Only a single daemon goal is executed per run, any remaining goals/arguments are passed - unaltered to the daemon goal. Daemon goals have precedence over regular goals. + Only a single auxillary goal is executed per run, any remaining goals/arguments are passed + unaltered to the auxillary goal. Auxillary goals have precedence over regular goals. - When multiple daemon goals are presented, the first daemon goal will be used unless there is a - daemon goal that begin with a hyphen (`-`), in which case the last such "option goal" will be + When multiple auxillary goals are presented, the first auxillary goal will be used unless there is a + auxillary goal that begin with a hyphen (`-`), in which case the last such "option goal" will be prioritized. This is to support things like `./pants some-builtin-goal --help`. The intended use for this API is rule code which runs a server (for example, a BSP server) - which provides an alternate interface to the Pants rule engine. + which provides an alternate interface to the Pants rule engine, or other kinds of goals + which must run "outside" of the usual engine processing to function. """ # Used by `pants.option.arg_splitter.ArgSplitter()` to optionally allow aliasing daemon goals. @@ -46,11 +48,11 @@ class DaemonGoal(ABC, GoalSubsystem): @classmethod def create_scope_info(cls, **scope_info_kwargs) -> ScopeInfo: - return super().create_scope_info(is_daemon=True, **scope_info_kwargs) + return super().create_scope_info(is_auxillary=True, **scope_info_kwargs) @abstractmethod def run( self, - context: DaemonGoalContext, + context: AuxillaryGoalContext, ) -> ExitCode: pass diff --git a/src/python/pants/init/extension_loader.py b/src/python/pants/init/extension_loader.py index 1cb7f54c878..f9dd44271da 100644 --- a/src/python/pants/init/extension_loader.py +++ b/src/python/pants/init/extension_loader.py @@ -107,9 +107,9 @@ def load_plugins( f"register remote auth function {remote_auth_func.__module__}.{remote_auth_func.__name__} from plugin: {plugin}" ) build_configuration.register_remote_auth_plugin(remote_auth_func) - if "daemon_goals" in entries: - daemon_goals = entries["daemon_goals"].load()() - build_configuration.register_daemon_goals(req.key, daemon_goals) + if "auxillary_goals" in entries: + auxillary_goals = entries["auxillary_goals"].load()() + build_configuration.register_auxillary_goals(req.key, auxillary_goals) loaded[dist.as_requirement().key] = dist @@ -171,6 +171,6 @@ def invoke_entrypoint(name: str): f"register remote auth function {remote_auth_func.__module__}.{remote_auth_func.__name__} from backend: {backend_package}" ) build_configuration.register_remote_auth_plugin(remote_auth_func) - daemon_goals = getattr(module, "daemon_goals", None) - if daemon_goals: - build_configuration.register_daemon_goals(backend_package, daemon_goals) + auxillary_goals = invoke_entrypoint("auxillary_goals") + if auxillary_goals: + build_configuration.register_auxillary_goals(backend_package, auxillary_goals) diff --git a/src/python/pants/option/arg_splitter.py b/src/python/pants/option/arg_splitter.py index 9a5c330a2e1..797092a0b75 100644 --- a/src/python/pants/option/arg_splitter.py +++ b/src/python/pants/option/arg_splitter.py @@ -22,7 +22,7 @@ class ArgSplitterError(Exception): class SplitArgs: """The result of splitting args.""" - builtin_or_daemon_goal: str | None # Requested builtin goal (explicitly or implicitly). + builtin_or_auxillary_goal: str | None # Requested builtin goal (explicitly or implicitly). goals: list[str] # Explicitly requested goals. unknown_goals: list[str] # Any unknown goals. scope_to_flags: dict[str, list[str]] # Scope name -> list of flags in that scope. @@ -135,7 +135,7 @@ def split_args(self, args: Sequence[str]) -> SplitArgs: specs: list[str] = [] passthru: list[str] = [] unknown_scopes: list[str] = [] - builtin_or_daemon_goal: str | None = None + builtin_or_auxillary_goal: str | None = None def add_scope(s: str) -> None: # Force the scope to appear, even if empty. @@ -150,19 +150,21 @@ def add_goal(scope: str) -> str: add_scope(scope) return scope - nonlocal builtin_or_daemon_goal - if (scope_info.is_builtin or scope_info.is_daemon) and (not builtin_or_daemon_goal or scope.startswith("-")): - if builtin_or_daemon_goal: - goals.add(builtin_or_daemon_goal) + nonlocal builtin_or_auxillary_goal + if (scope_info.is_builtin or scope_info.is_auxillary) and ( + not builtin_or_auxillary_goal or scope.startswith("-") + ): + if builtin_or_auxillary_goal: + goals.add(builtin_or_auxillary_goal) # Get scope from info in case we hit an aliased builtin/daemon goal. - builtin_or_daemon_goal = scope_info.scope + builtin_or_auxillary_goal = scope_info.scope else: goals.add(scope_info.scope) add_scope(scope_info.scope) # Use builtin/daemon goal as default scope for args. - return builtin_or_daemon_goal or scope_info.scope + return builtin_or_auxillary_goal or scope_info.scope self._unconsumed_args = list(reversed(args)) # The first token is the binary name, so skip it. @@ -198,11 +200,11 @@ def assign_flag_to_scope(flg: str, default_scope: str) -> None: else: add_goal(arg) - if not builtin_or_daemon_goal: + if not builtin_or_auxillary_goal: if unknown_scopes and UNKNOWN_GOAL_NAME in self._known_goal_scopes: - builtin_or_daemon_goal = UNKNOWN_GOAL_NAME + builtin_or_auxillary_goal = UNKNOWN_GOAL_NAME elif not goals and NO_GOAL_NAME in self._known_goal_scopes: - builtin_or_daemon_goal = NO_GOAL_NAME + builtin_or_auxillary_goal = NO_GOAL_NAME if self._at_standalone_double_dash(): self._unconsumed_args.pop() @@ -223,7 +225,7 @@ def assign_flag_to_scope(flg: str, default_scope: str) -> None: ) return SplitArgs( - builtin_or_daemon_goal=builtin_or_daemon_goal, + builtin_or_auxillary_goal=builtin_or_auxillary_goal, goals=list(goals), unknown_goals=unknown_scopes, scope_to_flags=dict(scope_to_flags), diff --git a/src/python/pants/option/arg_splitter_test.py b/src/python/pants/option/arg_splitter_test.py index 1221797419c..a3bc6474dee 100644 --- a/src/python/pants/option/arg_splitter_test.py +++ b/src/python/pants/option/arg_splitter_test.py @@ -54,16 +54,16 @@ def assert_valid_split( assert expected_passthru == split_args.passthru assert expected_is_help == ( - split_args.builtin_or_daemon_goal + split_args.builtin_or_auxillary_goal in ("help", "help-advanced", "help-all", UNKNOWN_GOAL_NAME, NO_GOAL_NAME) ) - assert expected_help_advanced == ("help-advanced" == split_args.builtin_or_daemon_goal) - assert expected_help_all == ("help-all" == split_args.builtin_or_daemon_goal) + assert expected_help_advanced == ("help-advanced" == split_args.builtin_or_auxillary_goal) + assert expected_help_all == ("help-all" == split_args.builtin_or_auxillary_goal) def assert_unknown_goal(splitter: ArgSplitter, args_str: str, unknown_goals: list[str]) -> None: split_args = splitter.split_args(shlex.split(args_str)) - assert UNKNOWN_GOAL_NAME == split_args.builtin_or_daemon_goal + assert UNKNOWN_GOAL_NAME == split_args.builtin_or_auxillary_goal assert set(unknown_goals) == set(split_args.unknown_goals) @@ -424,7 +424,7 @@ def test_help_detection(splitter: ArgSplitter, command_line: str, expected: dict def test_version_request_detection(splitter: ArgSplitter) -> None: def assert_version_request(args_str: str) -> None: split_args = splitter.split_args(shlex.split(args_str)) - assert "version" == split_args.builtin_or_daemon_goal + assert "version" == split_args.builtin_or_auxillary_goal assert_version_request("./pants -v") assert_version_request("./pants -V") @@ -452,7 +452,7 @@ def test_unknown_goal_detection( @pytest.mark.parametrize("extra_args", ("", "foo/bar:baz", "f.ext", "-linfo", "--arg")) def test_no_goal_detection(extra_args: str, splitter: ArgSplitter) -> None: split_args = splitter.split_args(shlex.split(f"./pants {extra_args}")) - assert NO_GOAL_NAME == split_args.builtin_or_daemon_goal + assert NO_GOAL_NAME == split_args.builtin_or_auxillary_goal def test_subsystem_scope_is_unknown_goal(splitter: ArgSplitter) -> None: diff --git a/src/python/pants/option/options.py b/src/python/pants/option/options.py index 22764a8e7a6..ce8ff2cfe7e 100644 --- a/src/python/pants/option/options.py +++ b/src/python/pants/option/options.py @@ -171,7 +171,7 @@ def create( ) return cls( - builtin_goal=split_args.builtin_or_daemon_goal, + builtin_goal=split_args.builtin_or_auxillary_goal, goals=split_args.goals, unknown_goals=split_args.unknown_goals, scope_to_flags=split_args.scope_to_flags, diff --git a/src/python/pants/option/scope.py b/src/python/pants/option/scope.py index ffb42bc0191..4f2c0202f19 100644 --- a/src/python/pants/option/scope.py +++ b/src/python/pants/option/scope.py @@ -39,8 +39,8 @@ class ScopeInfo: # Builtin goals, such as `help` and `version` etc. is_builtin: bool = False - # Daemon goals, such as the `experimental-bsp` goal. - is_daemon: bool = False + # Auxillary goals, such as the `experimental-bsp` goal. + is_auxillary: bool = False @property def description(self) -> str: From 638a421c74320af798da690b749a30c08d862f1c Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Wed, 24 Jul 2024 22:25:35 -0400 Subject: [PATCH 09/16] fix comment --- src/python/pants/build_graph/build_configuration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/python/pants/build_graph/build_configuration.py b/src/python/pants/build_graph/build_configuration.py index 61ab5bffdaa..34752926862 100644 --- a/src/python/pants/build_graph/build_configuration.py +++ b/src/python/pants/build_graph/build_configuration.py @@ -270,7 +270,7 @@ def register_remote_auth_plugin(self, remote_auth_plugin: Callable) -> None: self._remote_auth_plugin = remote_auth_plugin def register_auxillary_goals(self, plugin_or_backend: str, auxillary_goals: Iterable[type]): - """Registers the given daemon goals.""" + """Registers the given auxillary goals.""" if not isinstance(auxillary_goals, Iterable): raise TypeError( f"The entrypoint `auxillary_goals` must return an iterable. " From 1d31ea5ef7975f82cefda41d1b084a0fbb7f4411 Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Thu, 25 Jul 2024 18:31:54 -0400 Subject: [PATCH 10/16] rename `auxillary` (typo!) to `auxiliary` --- docs/notes/2.23.x.md | 2 +- .../backend/experimental/bsp/register.py | 2 +- .../backend/experimental/java/bsp/register.py | 6 ++--- .../experimental/scala/bsp/register.py | 6 ++--- src/python/pants/bsp/goal.py | 6 ++--- .../pants/build_graph/build_configuration.py | 22 ++++++++-------- .../{auxillary_goal.py => auxiliary_goal.py} | 20 +++++++------- src/python/pants/init/extension_loader.py | 12 ++++----- src/python/pants/option/arg_splitter.py | 26 +++++++++---------- src/python/pants/option/arg_splitter_test.py | 12 ++++----- src/python/pants/option/options.py | 2 +- src/python/pants/option/scope.py | 4 +-- 12 files changed, 60 insertions(+), 60 deletions(-) rename src/python/pants/goal/{auxillary_goal.py => auxiliary_goal.py} (72%) diff --git a/docs/notes/2.23.x.md b/docs/notes/2.23.x.md index f514f84351e..459e5c650b0 100644 --- a/docs/notes/2.23.x.md +++ b/docs/notes/2.23.x.md @@ -208,7 +208,7 @@ Fixed bug where files larger than 512KB were being materialized to a process's s Fixed bug where using `RuleRunner` in plugin tests caused `ValueError` that complains about not finding build root sentinel files. Note that you may have to adjust your tests to account for the new `BUILDROOT` file that `RuleRunner` now injects in the sandbox it creates for each test. For example, a test that uses a `**` glob might have to add `!BUILDROOT` to exclude the `BUILDROOT` file, or otherwise account for its presence when inspecting a sandbox or its digest. -Plugins may now provide "auxillary" goals by implememting the `auxillary_goals` function in their plugin registration module and returning one or more subclasses of `pants.goal.auxillary_goal.AuxillaryGoal`. The BSP (Build Server Protocol) support now uses this mechanism to move the `experimental-bsp` goal out of the Pants core rules. +Plugins may now provide "auxiliary" goals by implememting the `auxiliary_goals` function in their plugin registration module and returning one or more subclasses of `pants.goal.auxiliary_goal.AuxiliaryGoal`. An auxiliary goal is a special kind of goal which is invoked outside of the engine. The BSP (Build Server Protocol) support now uses this mechanism to move the `experimental-bsp` goal out of the Pants core rules. (The BSP rules used this support since running the BSP server cannot be done from within execution of the rules engine.) ### Other minor tweaks diff --git a/src/python/pants/backend/experimental/bsp/register.py b/src/python/pants/backend/experimental/bsp/register.py index 07e7c1d7e23..405345d3f31 100644 --- a/src/python/pants/backend/experimental/bsp/register.py +++ b/src/python/pants/backend/experimental/bsp/register.py @@ -5,7 +5,7 @@ from pants.bsp.rules import rules as bsp_rules -def auxillary_goals(): +def auxiliary_goals(): return (BSPGoal,) diff --git a/src/python/pants/backend/experimental/java/bsp/register.py b/src/python/pants/backend/experimental/java/bsp/register.py index effac16db13..9fb8eb0f912 100644 --- a/src/python/pants/backend/experimental/java/bsp/register.py +++ b/src/python/pants/backend/experimental/java/bsp/register.py @@ -1,7 +1,7 @@ # Copyright 2024 Pants project contributors (see CONTRIBUTORS.md). # Licensed under the Apache License, Version 2.0 (see LICENSE). -from pants.backend.experimental.bsp.register import auxillary_goals as bsp_auxillary_goals +from pants.backend.experimental.bsp.register import auxiliary_goals as bsp_auxiliary_goals from pants.backend.experimental.bsp.register import rules as bsp_rules from pants.backend.experimental.java.register import build_file_aliases as java_build_file_aliases from pants.backend.experimental.java.register import rules as java_rules @@ -9,8 +9,8 @@ from pants.backend.java.bsp.rules import rules as java_bsp_rules -def auxillary_goals(): - return bsp_auxillary_goals() +def auxiliary_goals(): + return bsp_auxiliary_goals() def target_types(): diff --git a/src/python/pants/backend/experimental/scala/bsp/register.py b/src/python/pants/backend/experimental/scala/bsp/register.py index 335f2a82e62..2ffa216cba0 100644 --- a/src/python/pants/backend/experimental/scala/bsp/register.py +++ b/src/python/pants/backend/experimental/scala/bsp/register.py @@ -1,6 +1,6 @@ # Copyright 2024 Pants project contributors (see CONTRIBUTORS.md). # Licensed under the Apache License, Version 2.0 (see LICENSE). -from pants.backend.experimental.bsp.register import auxillary_goals as bsp_auxillary_goals +from pants.backend.experimental.bsp.register import auxiliary_goals as bsp_auxiliary_goals from pants.backend.experimental.bsp.register import rules as bsp_rules from pants.backend.experimental.scala.register import build_file_aliases as scala_build_file_aliases from pants.backend.experimental.scala.register import rules as scala_rules @@ -8,8 +8,8 @@ from pants.backend.scala.bsp.rules import rules as scala_bsp_rules -def auxillary_goals(): - return bsp_auxillary_goals() +def auxiliary_goals(): + return bsp_auxiliary_goals() def target_types(): diff --git a/src/python/pants/bsp/goal.py b/src/python/pants/bsp/goal.py index 2d1fae968b4..2bae132f495 100644 --- a/src/python/pants/bsp/goal.py +++ b/src/python/pants/bsp/goal.py @@ -18,7 +18,7 @@ from pants.engine.env_vars import CompleteEnvironmentVars from pants.engine.internals.session import SessionValues from pants.engine.unions import UnionMembership -from pants.goal.auxillary_goal import AuxillaryGoal, AuxillaryGoalContext +from pants.goal.auxiliary_goal import AuxiliaryGoal, AuxiliaryGoalContext from pants.init.engine_initializer import GraphSession from pants.option.option_types import BoolOption, FileListOption, StrListOption from pants.option.option_value_container import OptionValueContainer @@ -29,7 +29,7 @@ _logger = logging.getLogger(__name__) -class BSPGoal(AuxillaryGoal): +class BSPGoal(AuxiliaryGoal): name = "experimental-bsp" help = "Setup repository for Build Server Protocol (https://build-server-protocol.github.io/)." @@ -99,7 +99,7 @@ class BSPGoal(AuxillaryGoal): def run( self, - context: AuxillaryGoalContext, + context: AuxiliaryGoalContext, ) -> ExitCode: goal_options = context.options.for_scope(self.name) if goal_options.server: diff --git a/src/python/pants/build_graph/build_configuration.py b/src/python/pants/build_graph/build_configuration.py index 34752926862..109f0a4af1b 100644 --- a/src/python/pants/build_graph/build_configuration.py +++ b/src/python/pants/build_graph/build_configuration.py @@ -269,23 +269,23 @@ def register_target_types( def register_remote_auth_plugin(self, remote_auth_plugin: Callable) -> None: self._remote_auth_plugin = remote_auth_plugin - def register_auxillary_goals(self, plugin_or_backend: str, auxillary_goals: Iterable[type]): - """Registers the given auxillary goals.""" - if not isinstance(auxillary_goals, Iterable): + def register_auxiliary_goals(self, plugin_or_backend: str, auxiliary_goals: Iterable[type]): + """Registers the given auxiliary goals.""" + if not isinstance(auxiliary_goals, Iterable): raise TypeError( - f"The entrypoint `auxillary_goals` must return an iterable. " - f"Given {repr(auxillary_goals)}" + f"The entrypoint `auxiliary_goals` must return an iterable. " + f"Given {repr(auxiliary_goals)}" ) - # Import `AuxillaryGoal` here to avoid import cycle. - from pants.goal.auxillary_goal import AuxillaryGoal + # Import `AuxiliaryGoal` here to avoid import cycle. + from pants.goal.auxiliary_goal import AuxiliaryGoal - bad_elements = [goal for goal in auxillary_goals if not issubclass(goal, AuxillaryGoal)] + bad_elements = [goal for goal in auxiliary_goals if not issubclass(goal, AuxiliaryGoal)] if bad_elements: raise TypeError( - "Every element of the entrypoint `auxillary_goals` must be a subclass of " - f"{AuxillaryGoal.__name__}. Bad elements: {bad_elements}." + "Every element of the entrypoint `auxiliary_goals` must be a subclass of " + f"{AuxiliaryGoal.__name__}. Bad elements: {bad_elements}." ) - self.register_subsystems(plugin_or_backend, auxillary_goals) + self.register_subsystems(plugin_or_backend, auxiliary_goals) def allow_unknown_options(self, allow: bool = True) -> None: """Allows overriding whether Options parsing will fail for unrecognized Options. diff --git a/src/python/pants/goal/auxillary_goal.py b/src/python/pants/goal/auxiliary_goal.py similarity index 72% rename from src/python/pants/goal/auxillary_goal.py rename to src/python/pants/goal/auxiliary_goal.py index c15da7b1880..f4ff09a228b 100644 --- a/src/python/pants/goal/auxillary_goal.py +++ b/src/python/pants/goal/auxiliary_goal.py @@ -17,8 +17,8 @@ @dataclass -class AuxillaryGoalContext: - """Context passed to a `AuxillaryGoal.run` implementation.""" +class AuxiliaryGoalContext: + """Context passed to a `AuxiliaryGoal.run` implementation.""" build_config: BuildConfiguration graph_session: GraphSession @@ -27,15 +27,15 @@ class AuxillaryGoalContext: union_membership: UnionMembership -class AuxillaryGoal(ABC, GoalSubsystem): - """Configure a "auxillary" goal which allows rules to "take over" Pants client execution in lieu +class AuxiliaryGoal(ABC, GoalSubsystem): + """Configure a "auxiliary" goal which allows rules to "take over" Pants client execution in lieu of executing an ordnary goal. - Only a single auxillary goal is executed per run, any remaining goals/arguments are passed - unaltered to the auxillary goal. Auxillary goals have precedence over regular goals. + Only a single auxiliary goal is executed per run, any remaining goals/arguments are passed + unaltered to the auxiliary goal. Auxiliary goals have precedence over regular goals. - When multiple auxillary goals are presented, the first auxillary goal will be used unless there is a - auxillary goal that begin with a hyphen (`-`), in which case the last such "option goal" will be + When multiple auxiliary goals are presented, the first auxiliary goal will be used unless there is a + auxiliary goal that begin with a hyphen (`-`), in which case the last such "option goal" will be prioritized. This is to support things like `./pants some-builtin-goal --help`. The intended use for this API is rule code which runs a server (for example, a BSP server) @@ -48,11 +48,11 @@ class AuxillaryGoal(ABC, GoalSubsystem): @classmethod def create_scope_info(cls, **scope_info_kwargs) -> ScopeInfo: - return super().create_scope_info(is_auxillary=True, **scope_info_kwargs) + return super().create_scope_info(is_auxiliary=True, **scope_info_kwargs) @abstractmethod def run( self, - context: AuxillaryGoalContext, + context: AuxiliaryGoalContext, ) -> ExitCode: pass diff --git a/src/python/pants/init/extension_loader.py b/src/python/pants/init/extension_loader.py index f9dd44271da..5a71f2028fe 100644 --- a/src/python/pants/init/extension_loader.py +++ b/src/python/pants/init/extension_loader.py @@ -107,9 +107,9 @@ def load_plugins( f"register remote auth function {remote_auth_func.__module__}.{remote_auth_func.__name__} from plugin: {plugin}" ) build_configuration.register_remote_auth_plugin(remote_auth_func) - if "auxillary_goals" in entries: - auxillary_goals = entries["auxillary_goals"].load()() - build_configuration.register_auxillary_goals(req.key, auxillary_goals) + if "auxiliary_goals" in entries: + auxiliary_goals = entries["auxiliary_goals"].load()() + build_configuration.register_auxiliary_goals(req.key, auxiliary_goals) loaded[dist.as_requirement().key] = dist @@ -171,6 +171,6 @@ def invoke_entrypoint(name: str): f"register remote auth function {remote_auth_func.__module__}.{remote_auth_func.__name__} from backend: {backend_package}" ) build_configuration.register_remote_auth_plugin(remote_auth_func) - auxillary_goals = invoke_entrypoint("auxillary_goals") - if auxillary_goals: - build_configuration.register_auxillary_goals(backend_package, auxillary_goals) + auxiliary_goals = invoke_entrypoint("auxiliary_goals") + if auxiliary_goals: + build_configuration.register_auxiliary_goals(backend_package, auxiliary_goals) diff --git a/src/python/pants/option/arg_splitter.py b/src/python/pants/option/arg_splitter.py index 797092a0b75..9512126272f 100644 --- a/src/python/pants/option/arg_splitter.py +++ b/src/python/pants/option/arg_splitter.py @@ -22,7 +22,7 @@ class ArgSplitterError(Exception): class SplitArgs: """The result of splitting args.""" - builtin_or_auxillary_goal: str | None # Requested builtin goal (explicitly or implicitly). + builtin_or_auxiliary_goal: str | None # Requested builtin goal (explicitly or implicitly). goals: list[str] # Explicitly requested goals. unknown_goals: list[str] # Any unknown goals. scope_to_flags: dict[str, list[str]] # Scope name -> list of flags in that scope. @@ -135,7 +135,7 @@ def split_args(self, args: Sequence[str]) -> SplitArgs: specs: list[str] = [] passthru: list[str] = [] unknown_scopes: list[str] = [] - builtin_or_auxillary_goal: str | None = None + builtin_or_auxiliary_goal: str | None = None def add_scope(s: str) -> None: # Force the scope to appear, even if empty. @@ -150,21 +150,21 @@ def add_goal(scope: str) -> str: add_scope(scope) return scope - nonlocal builtin_or_auxillary_goal - if (scope_info.is_builtin or scope_info.is_auxillary) and ( - not builtin_or_auxillary_goal or scope.startswith("-") + nonlocal builtin_or_auxiliary_goal + if (scope_info.is_builtin or scope_info.is_auxiliary) and ( + not builtin_or_auxiliary_goal or scope.startswith("-") ): - if builtin_or_auxillary_goal: - goals.add(builtin_or_auxillary_goal) + if builtin_or_auxiliary_goal: + goals.add(builtin_or_auxiliary_goal) # Get scope from info in case we hit an aliased builtin/daemon goal. - builtin_or_auxillary_goal = scope_info.scope + builtin_or_auxiliary_goal = scope_info.scope else: goals.add(scope_info.scope) add_scope(scope_info.scope) # Use builtin/daemon goal as default scope for args. - return builtin_or_auxillary_goal or scope_info.scope + return builtin_or_auxiliary_goal or scope_info.scope self._unconsumed_args = list(reversed(args)) # The first token is the binary name, so skip it. @@ -200,11 +200,11 @@ def assign_flag_to_scope(flg: str, default_scope: str) -> None: else: add_goal(arg) - if not builtin_or_auxillary_goal: + if not builtin_or_auxiliary_goal: if unknown_scopes and UNKNOWN_GOAL_NAME in self._known_goal_scopes: - builtin_or_auxillary_goal = UNKNOWN_GOAL_NAME + builtin_or_auxiliary_goal = UNKNOWN_GOAL_NAME elif not goals and NO_GOAL_NAME in self._known_goal_scopes: - builtin_or_auxillary_goal = NO_GOAL_NAME + builtin_or_auxiliary_goal = NO_GOAL_NAME if self._at_standalone_double_dash(): self._unconsumed_args.pop() @@ -225,7 +225,7 @@ def assign_flag_to_scope(flg: str, default_scope: str) -> None: ) return SplitArgs( - builtin_or_auxillary_goal=builtin_or_auxillary_goal, + builtin_or_auxiliary_goal=builtin_or_auxiliary_goal, goals=list(goals), unknown_goals=unknown_scopes, scope_to_flags=dict(scope_to_flags), diff --git a/src/python/pants/option/arg_splitter_test.py b/src/python/pants/option/arg_splitter_test.py index a3bc6474dee..a20ed4bb2b4 100644 --- a/src/python/pants/option/arg_splitter_test.py +++ b/src/python/pants/option/arg_splitter_test.py @@ -54,16 +54,16 @@ def assert_valid_split( assert expected_passthru == split_args.passthru assert expected_is_help == ( - split_args.builtin_or_auxillary_goal + split_args.builtin_or_auxiliary_goal in ("help", "help-advanced", "help-all", UNKNOWN_GOAL_NAME, NO_GOAL_NAME) ) - assert expected_help_advanced == ("help-advanced" == split_args.builtin_or_auxillary_goal) - assert expected_help_all == ("help-all" == split_args.builtin_or_auxillary_goal) + assert expected_help_advanced == ("help-advanced" == split_args.builtin_or_auxiliary_goal) + assert expected_help_all == ("help-all" == split_args.builtin_or_auxiliary_goal) def assert_unknown_goal(splitter: ArgSplitter, args_str: str, unknown_goals: list[str]) -> None: split_args = splitter.split_args(shlex.split(args_str)) - assert UNKNOWN_GOAL_NAME == split_args.builtin_or_auxillary_goal + assert UNKNOWN_GOAL_NAME == split_args.builtin_or_auxiliary_goal assert set(unknown_goals) == set(split_args.unknown_goals) @@ -424,7 +424,7 @@ def test_help_detection(splitter: ArgSplitter, command_line: str, expected: dict def test_version_request_detection(splitter: ArgSplitter) -> None: def assert_version_request(args_str: str) -> None: split_args = splitter.split_args(shlex.split(args_str)) - assert "version" == split_args.builtin_or_auxillary_goal + assert "version" == split_args.builtin_or_auxiliary_goal assert_version_request("./pants -v") assert_version_request("./pants -V") @@ -452,7 +452,7 @@ def test_unknown_goal_detection( @pytest.mark.parametrize("extra_args", ("", "foo/bar:baz", "f.ext", "-linfo", "--arg")) def test_no_goal_detection(extra_args: str, splitter: ArgSplitter) -> None: split_args = splitter.split_args(shlex.split(f"./pants {extra_args}")) - assert NO_GOAL_NAME == split_args.builtin_or_auxillary_goal + assert NO_GOAL_NAME == split_args.builtin_or_auxiliary_goal def test_subsystem_scope_is_unknown_goal(splitter: ArgSplitter) -> None: diff --git a/src/python/pants/option/options.py b/src/python/pants/option/options.py index ce8ff2cfe7e..62fcc27636d 100644 --- a/src/python/pants/option/options.py +++ b/src/python/pants/option/options.py @@ -171,7 +171,7 @@ def create( ) return cls( - builtin_goal=split_args.builtin_or_auxillary_goal, + builtin_goal=split_args.builtin_or_auxiliary_goal, goals=split_args.goals, unknown_goals=split_args.unknown_goals, scope_to_flags=split_args.scope_to_flags, diff --git a/src/python/pants/option/scope.py b/src/python/pants/option/scope.py index 4f2c0202f19..7945a15406e 100644 --- a/src/python/pants/option/scope.py +++ b/src/python/pants/option/scope.py @@ -39,8 +39,8 @@ class ScopeInfo: # Builtin goals, such as `help` and `version` etc. is_builtin: bool = False - # Auxillary goals, such as the `experimental-bsp` goal. - is_auxillary: bool = False + # Auxiliary goals, such as the `experimental-bsp` goal. + is_auxiliary: bool = False @property def description(self) -> str: From 4ab5bd2ae3922071069c3bdc946714882440f075 Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Thu, 25 Jul 2024 18:37:26 -0400 Subject: [PATCH 11/16] cleanup some references to "daemon" goals --- src/python/pants/goal/auxiliary_goal.py | 2 +- src/python/pants/option/arg_splitter.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/python/pants/goal/auxiliary_goal.py b/src/python/pants/goal/auxiliary_goal.py index f4ff09a228b..397f42bfec5 100644 --- a/src/python/pants/goal/auxiliary_goal.py +++ b/src/python/pants/goal/auxiliary_goal.py @@ -43,7 +43,7 @@ class AuxiliaryGoal(ABC, GoalSubsystem): which must run "outside" of the usual engine processing to function. """ - # Used by `pants.option.arg_splitter.ArgSplitter()` to optionally allow aliasing daemon goals. + # Used by `pants.option.arg_splitter.ArgSplitter()` to optionally allow aliasing auxiliary goals. aliases: ClassVar[tuple[str, ...]] = () @classmethod diff --git a/src/python/pants/option/arg_splitter.py b/src/python/pants/option/arg_splitter.py index 9512126272f..beb4c479b52 100644 --- a/src/python/pants/option/arg_splitter.py +++ b/src/python/pants/option/arg_splitter.py @@ -157,13 +157,13 @@ def add_goal(scope: str) -> str: if builtin_or_auxiliary_goal: goals.add(builtin_or_auxiliary_goal) - # Get scope from info in case we hit an aliased builtin/daemon goal. + # Get scope from info in case we hit an aliased builtin/auxiliary goal. builtin_or_auxiliary_goal = scope_info.scope else: goals.add(scope_info.scope) add_scope(scope_info.scope) - # Use builtin/daemon goal as default scope for args. + # Use builtin/auxiliary goal as default scope for args. return builtin_or_auxiliary_goal or scope_info.scope self._unconsumed_args = list(reversed(args)) From c9b96d3249ae93fea19280d63544d89db96f3669 Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Mon, 29 Jul 2024 16:03:39 -0400 Subject: [PATCH 12/16] actually invoke auxiliary goals + integration test --- src/python/pants/bin/BUILD | 3 ++ src/python/pants/bin/local_pants_runner.py | 41 ++++++++++++++++++---- src/python/pants/option/options.py | 12 +++---- src/python/pants/testutil/rule_runner.py | 3 ++ 4 files changed, 46 insertions(+), 13 deletions(-) diff --git a/src/python/pants/bin/BUILD b/src/python/pants/bin/BUILD index 66e86801a8b..8e8874b6524 100644 --- a/src/python/pants/bin/BUILD +++ b/src/python/pants/bin/BUILD @@ -24,6 +24,7 @@ target( "src/python/pants/backend/docker", "src/python/pants/backend/docker/lint/hadolint", "src/python/pants/backend/experimental/adhoc", + "src/python/pants/backend/experimental/bsp", "src/python/pants/backend/experimental/cc", "src/python/pants/backend/experimental/cc/lint/clangformat", "src/python/pants/backend/experimental/codegen/avro/java", @@ -43,6 +44,7 @@ target( "src/python/pants/backend/experimental/helm", "src/python/pants/backend/experimental/helm/check/kubeconform", "src/python/pants/backend/experimental/java", + "src/python/pants/backend/experimental/java/bsp", "src/python/pants/backend/experimental/java/debug_goals", "src/python/pants/backend/experimental/java/lint/google_java_format", "src/python/pants/backend/experimental/javascript", @@ -69,6 +71,7 @@ target( "src/python/pants/backend/experimental/python/typecheck/pytype", "src/python/pants/backend/experimental/rust", "src/python/pants/backend/experimental/scala", + "src/python/pants/backend/experimental/scala/bsp", "src/python/pants/backend/experimental/scala/debug_goals", "src/python/pants/backend/experimental/scala/lint/scalafix", "src/python/pants/backend/experimental/scala/lint/scalafmt", diff --git a/src/python/pants/bin/local_pants_runner.py b/src/python/pants/bin/local_pants_runner.py index c7e5550d464..6057c96184d 100644 --- a/src/python/pants/bin/local_pants_runner.py +++ b/src/python/pants/bin/local_pants_runner.py @@ -6,6 +6,7 @@ import logging import sys from dataclasses import dataclass +from typing import Any from pants.base.exiter import PANTS_FAILED_EXIT_CODE, PANTS_SUCCEEDED_EXIT_CODE, ExitCode from pants.base.specs import Specs @@ -25,6 +26,7 @@ WorkunitsCallbackFactories, ) from pants.engine.unions import UnionMembership +from pants.goal.auxiliary_goal import AuxiliaryGoal, AuxiliaryGoalContext from pants.goal.builtin_goal import BuiltinGoal from pants.goal.run_tracker import RunTracker from pants.init.engine_initializer import EngineInitializer, GraphScheduler, GraphSession @@ -211,13 +213,28 @@ def _get_workunits_callbacks(self) -> tuple[WorkunitsCallback, ...]: ) return tuple(filter(bool, (wcf.callback_factory() for wcf in workunits_callback_factories))) - def _run_builtin_goal(self, builtin_goal: str) -> ExitCode: - scope_info = self.options.known_scope_to_info[builtin_goal] + def _run_builtin_or_auxiliary_goal(self, goal_name: str) -> ExitCode: + scope_info = self.options.known_scope_to_info[goal_name] assert scope_info.subsystem_cls - scoped_options = self.options.for_scope(builtin_goal) + + scoped_options = self.options.for_scope(goal_name) goal = scope_info.subsystem_cls(scoped_options) - assert isinstance(goal, BuiltinGoal) - return goal.run( + + def _run_builtin_goal(context: AuxiliaryGoalContext, goal: Any) -> ExitCode: + assert isinstance(goal, BuiltinGoal) + return goal.run( + build_config=context.build_config, + graph_session=context.graph_session, + options=context.options, + specs=context.specs, + union_membership=context.union_membership, + ) + + def _run_auxiliary_goal(context: AuxiliaryGoalContext, goal: Any) -> ExitCode: + assert isinstance(goal, AuxiliaryGoal) + return goal.run(context) + + context = AuxiliaryGoalContext( build_config=self.build_config, graph_session=self.graph_session, options=self.options, @@ -225,9 +242,19 @@ def _run_builtin_goal(self, builtin_goal: str) -> ExitCode: union_membership=self.union_membership, ) + if scope_info.is_builtin: + return _run_builtin_goal(context, goal) + elif scope_info.is_auxiliary: + return _run_auxiliary_goal(context, goal) + else: + raise AssertionError( + f"Probable builtin or auxiliary goal `{goal_name}` is not configured correctly. " + "Please report this error to the Pants team at https://github.com/pantsbuild/pants/issues/new/choose." + ) + def _run_inner(self) -> ExitCode: - if self.options.builtin_goal: - return self._run_builtin_goal(self.options.builtin_goal) + if self.options.builtin_or_auxiliary_goal: + return self._run_builtin_or_auxiliary_goal(self.options.builtin_or_auxiliary_goal) goals = tuple(self.options.goals) if not goals: diff --git a/src/python/pants/option/options.py b/src/python/pants/option/options.py index 62fcc27636d..569115047e3 100644 --- a/src/python/pants/option/options.py +++ b/src/python/pants/option/options.py @@ -171,7 +171,7 @@ def create( ) return cls( - builtin_goal=split_args.builtin_or_auxiliary_goal, + builtin_or_auxiliary_goal=split_args.builtin_or_auxiliary_goal, goals=split_args.goals, unknown_goals=split_args.unknown_goals, scope_to_flags=split_args.scope_to_flags, @@ -187,7 +187,7 @@ def create( def __init__( self, - builtin_goal: str | None, + builtin_or_auxiliary_goal: str | None, goals: list[str], unknown_goals: list[str], scope_to_flags: dict[str, list[str]], @@ -204,7 +204,7 @@ def __init__( Dependents should use `Options.create` instead. """ - self._builtin_goal = builtin_goal + self._builtin_or_auxiliary_goal = builtin_or_auxiliary_goal self._goals = goals self._unknown_goals = unknown_goals self._scope_to_flags = scope_to_flags @@ -226,12 +226,12 @@ def specs(self) -> list[str]: return self._specs @property - def builtin_goal(self) -> str | None: - """The requested builtin goal, if any. + def builtin_or_auxiliary_goal(self) -> str | None: + """The requested builtin or auxiliary goal, if any. :API: public """ - return self._builtin_goal + return self._builtin_or_auxiliary_goal @property def goals(self) -> list[str]: diff --git a/src/python/pants/testutil/rule_runner.py b/src/python/pants/testutil/rule_runner.py index f3b8be43c01..a55ea7e6dbb 100644 --- a/src/python/pants/testutil/rule_runner.py +++ b/src/python/pants/testutil/rule_runner.py @@ -53,6 +53,7 @@ from pants.engine.rules import QueryRule as QueryRule from pants.engine.target import AllTargets, Target, WrappedTarget, WrappedTargetRequest from pants.engine.unions import UnionMembership, UnionRule +from pants.goal.auxiliary_goal import AuxiliaryGoal from pants.init.engine_initializer import EngineInitializer from pants.init.logging import initialize_stdio, initialize_stdio_raw, stdio_destination from pants.option.global_options import ( @@ -261,6 +262,7 @@ def __init__( max_workunit_verbosity: LogLevel = LogLevel.DEBUG, inherent_environment: EnvironmentName | None = EnvironmentName(None), is_bootstrap: bool = False, + auxiliary_goals: Iterable[type[AuxiliaryGoal]] | None = None, ) -> None: bootstrap_args = [*bootstrap_args] @@ -308,6 +310,7 @@ def rewrite_rule_for_inherent_environment(rule): build_config_builder.register_rules("_dummy_for_test_", all_rules) build_config_builder.register_target_types("_dummy_for_test_", target_types or ()) + build_config_builder.register_auxiliary_goals("_dummy_for_test_", auxiliary_goals or ()) self.build_config = build_config_builder.create() self.environment = CompleteEnvironmentVars({}) From 738285ecc39ff420df76859a0541eea29501fcf5 Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Mon, 5 Aug 2024 22:27:07 -0400 Subject: [PATCH 13/16] integration test --- .../bin/auxiliary_goal_integration_test.py | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/python/pants/bin/auxiliary_goal_integration_test.py diff --git a/src/python/pants/bin/auxiliary_goal_integration_test.py b/src/python/pants/bin/auxiliary_goal_integration_test.py new file mode 100644 index 00000000000..766c0e1cd11 --- /dev/null +++ b/src/python/pants/bin/auxiliary_goal_integration_test.py @@ -0,0 +1,24 @@ +# Copyright 2024 Pants project contributors (see CONTRIBUTORS.md). +# Licensed under the Apache License, Version 2.0 (see LICENSE). + +from pants.testutil.pants_integration_test import run_pants + + +def test_auxiliary_goal_invocation() -> None: + result1 = run_pants( + [ + "experimental-bsp", + ] + ) + result1.assert_failure() + assert "Unknown goal: experimental-bsp" in result1.stdout + + result2 = run_pants( + [ + "--backend-packages=pants.backend.experimental.bsp", + "experimental-bsp", + ] + ) + result2.assert_success() + assert "Wrote BSP runner script" in result2.stderr + assert "Wrote BSP connection file" in result2.stderr From 31fdb33e752f92176b4c3e02a5371e729f130114 Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Mon, 5 Aug 2024 22:30:05 -0400 Subject: [PATCH 14/16] add backends for BSP to docs --- docs/docs/using-pants/key-concepts/backends.mdx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/docs/using-pants/key-concepts/backends.mdx b/docs/docs/using-pants/key-concepts/backends.mdx index 829fa81469e..4895770faf2 100644 --- a/docs/docs/using-pants/key-concepts/backends.mdx +++ b/docs/docs/using-pants/key-concepts/backends.mdx @@ -65,6 +65,7 @@ The list of all backends (both stable and experimental) is also available via `p | Backend | What it does | Docs | | :----------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------- | | `pants.backend.experimental.adhoc` | Enables support for executing arbitrary runnable targets. | [Integrating new tools without plugins](../../ad-hoc-tools/integrating-new-tools-without-plugins.mdx) | +| `pants.backend.experimental.bsp` | Enables core Build Server Protocol ("BSP") support. | | | `pants.backend.experimental.cc` | Enables core C and C++ support. | | | `pants.backend.experimental.cc.lint.clangformat` | Enables clang-format, a C and C++ autoformatter: [https://clang.llvm.org/docs/ClangFormat.html](https://clang.llvm.org/docs/ClangFormat.html) | | | `pants.backend.experimental.codegen.avro.java` | Enables generating Java from Avro | | @@ -83,6 +84,7 @@ The list of all backends (both stable and experimental) is also available via `p | `pants.backend.experimental.helm` | Enables core Helm support: [https://helm.sh](https://helm.sh) | [Helm overview](../../helm/index.mdx) | | `pants.backend.experimental.helm.check.kubeconfirm` | Enables Kubeconform, a fast Kubernetes manifest validator: [https://github.com/yannh/kubeconform](https://github.com/yannh/kubeconform) | [Helm overview](../../helm/index.mdx) | | `pants.backend.experimental.java` | Enables core Java support. | [Java & Scala overview](../../jvm/java-and-scala.mdx) | +| `pants.backend.experimental.java.bsp` | Enable Java-specific support for Build Server Protocol | [Java & Scala overview](../../jvm/java-and-scala.mdx) | | `pants.backend.experimental.java.debug_goals` | Enable additional goals for introspecting Java targets | [Java & Scala overview](../../jvm/java-and-scala.mdx) | | `pants.backend.experimental.java.lint.google_java_format` | Enables Google Java Format. | [Java & Scala overview](../../jvm/java-and-scala.mdx) | | `pants.backend.experimental.javascript` | Enables core JavaScript support. | | @@ -105,6 +107,7 @@ The list of all backends (both stable and experimental) is also available via `p | `pants.backend.experimental.python.typecheck.pytype` | Enables Pytype, a Python type checker: [https://google.github.io/pytype/](https://google.github.io/pytype/) | | | `pants.backend.experimental.rust` | Enables core Rust support. | | | `pants.backend.experimental.scala` | Enables core Scala support. | [Java & Scala overview](../../jvm/java-and-scala.mdx) | +| `pants.backend.experimental.scala.bsp` | Enables Scala-specific support for Build Server Protocol | [Java & Scala overview](../../jvm/java-and-scala.mdx) | | `pants.backend.experimental.scala.debug_goals` | Enables additional goals for introspecting Scala targets | [Java & Scala overview](../../jvm/java-and-scala.mdx) | | `pants.backend.experimental.scala.lint.scalafmt` | Enables the Scalafmt formatter. | [Java & Scala overview](../../jvm/java-and-scala.mdx) | | `pants.backend.experimental.swift` | Enables core Swift support. | | From ef3e98c444b9bf1168d77383768c128fbf821e6c Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Mon, 5 Aug 2024 22:45:49 -0400 Subject: [PATCH 15/16] Update src/python/pants/goal/auxiliary_goal.py Co-authored-by: Jacob Floyd --- src/python/pants/goal/auxiliary_goal.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/python/pants/goal/auxiliary_goal.py b/src/python/pants/goal/auxiliary_goal.py index 397f42bfec5..ecb8bc3063c 100644 --- a/src/python/pants/goal/auxiliary_goal.py +++ b/src/python/pants/goal/auxiliary_goal.py @@ -28,8 +28,8 @@ class AuxiliaryGoalContext: class AuxiliaryGoal(ABC, GoalSubsystem): - """Configure a "auxiliary" goal which allows rules to "take over" Pants client execution in lieu - of executing an ordnary goal. + """Configure an "auxiliary" goal which allows rules to "take over" Pants client execution in lieu + of executing an ordinary goal. Only a single auxiliary goal is executed per run, any remaining goals/arguments are passed unaltered to the auxiliary goal. Auxiliary goals have precedence over regular goals. From 6dc5d7defa2d255ee6148790fc3ba5c91c49e6d5 Mon Sep 17 00:00:00 2001 From: Tom Dyas Date: Mon, 5 Aug 2024 23:21:13 -0400 Subject: [PATCH 16/16] fmt --- src/python/pants/goal/auxiliary_goal.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/python/pants/goal/auxiliary_goal.py b/src/python/pants/goal/auxiliary_goal.py index ecb8bc3063c..66912467d89 100644 --- a/src/python/pants/goal/auxiliary_goal.py +++ b/src/python/pants/goal/auxiliary_goal.py @@ -28,8 +28,8 @@ class AuxiliaryGoalContext: class AuxiliaryGoal(ABC, GoalSubsystem): - """Configure an "auxiliary" goal which allows rules to "take over" Pants client execution in lieu - of executing an ordinary goal. + """Configure an "auxiliary" goal which allows rules to "take over" Pants client execution in + lieu of executing an ordinary goal. Only a single auxiliary goal is executed per run, any remaining goals/arguments are passed unaltered to the auxiliary goal. Auxiliary goals have precedence over regular goals.