Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Code Quality Tool: toml-based backend templating #20270

Open
wants to merge 24 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from pants.backend.adhoc.code_quality_tool import CodeQualityToolRuleBuilder


def rules(backend_package: str, goal: str, target: str, name: str):
cfg = CodeQualityToolRuleBuilder(
goal=goal,
target=target,
name=name,
scope=backend_package,
)
return cfg.rules()
54 changes: 35 additions & 19 deletions src/python/pants/init/extension_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import importlib
import logging
import traceback
from typing import Dict, List, Optional
from typing import Dict, List, Optional, Mapping, Any

from pkg_resources import Requirement, WorkingSet

Expand All @@ -28,12 +28,9 @@ class PluginLoadOrderError(PluginLoadingError):
pass


def load_backends_and_plugins(
plugins: List[str],
working_set: WorkingSet,
backends: List[str],
bc_builder: Optional[BuildConfiguration.Builder] = None,
) -> BuildConfiguration:
def load_backends_and_plugins(plugins: List[str], working_set: WorkingSet, backends: List[str],
bc_builder: Optional[BuildConfiguration.Builder] = None,
templated_backends: Optional[Mapping[str, Any]] = None) -> BuildConfiguration:
gauthamnair marked this conversation as resolved.
Show resolved Hide resolved
"""Load named plugins and source backends.

:param plugins: v2 plugins to load.
Expand All @@ -42,7 +39,7 @@ def load_backends_and_plugins(
:param bc_builder: The BuildConfiguration (for adding aliases).
"""
bc_builder = bc_builder or BuildConfiguration.Builder()
load_build_configuration_from_source(bc_builder, backends)
load_build_configuration_from_source(bc_builder, backends, templated_backends=templated_backends)
load_plugins(bc_builder, plugins, working_set)
register_builtin_goals(bc_builder)
return bc_builder.create()
Expand Down Expand Up @@ -111,9 +108,8 @@ def load_plugins(
loaded[dist.as_requirement().key] = dist


def load_build_configuration_from_source(
build_configuration: BuildConfiguration.Builder, backends: List[str]
) -> None:
def load_build_configuration_from_source(build_configuration: BuildConfiguration.Builder, backends: List[str],
templated_backends=None) -> None:
"""Installs pants backend packages to provide BUILD file symbols and cli goals.

:param build_configuration: The BuildConfiguration (for adding aliases).
Expand All @@ -123,11 +119,15 @@ def load_build_configuration_from_source(
"""
# NB: Backends added here must be explicit dependencies of this module.
backend_packages = FrozenOrderedSet(["pants.core", "pants.backend.project_info", *backends])
templated_backends = templated_backends or {}

for backend_package in backend_packages:
load_backend(build_configuration, backend_package)
load_backend(build_configuration, backend_package,
templating_args=templated_backends.get(backend_package))


def load_backend(build_configuration: BuildConfiguration.Builder, backend_package: str) -> None:
def load_backend(build_configuration: BuildConfiguration.Builder, backend_package: str,
templating_args: Optional[Mapping[str, Any]] = None) -> None:
"""Installs the given backend package into the build configuration.

:param build_configuration: the BuildConfiguration to install the backend plugin into.
Expand All @@ -136,22 +136,38 @@ def load_backend(build_configuration: BuildConfiguration.Builder, backend_packag
:raises: :class:``pants.base.exceptions.BuildConfigurationError`` if there is a problem loading
the build configuration.
"""
backend_module = backend_package + ".register"

if templating_args:
kwargs = {'backend_package': backend_package}
gauthamnair marked this conversation as resolved.
Show resolved Hide resolved
kwargs.update(templating_args)
backend_module = kwargs.pop('template') + ".register"
gauthamnair marked this conversation as resolved.
Show resolved Hide resolved
else:
kwargs = {}
backend_module = backend_package + ".register"
gauthamnair marked this conversation as resolved.
Show resolved Hide resolved

try:
module = importlib.import_module(backend_module)
except ImportError as ex:
traceback.print_exc()
raise BackendConfigurationError(f"Failed to load the {backend_module} backend: {ex!r}")

def return_none(**kwargs):
return None

def invoke_entrypoint(name: str):
entrypoint = getattr(module, name, lambda: None)
entrypoint = getattr(module, name, return_none)
try:
return entrypoint()
return entrypoint(**kwargs)
except TypeError as e:
traceback.print_exc()
raise BackendConfigurationError(
f"Entrypoint {name} in {backend_module} must be a zero-arg callable: {e!r}"
)
if not kwargs:
err_msg = f"Entrypoint {name} in {backend_module} must be a zero-arg callable: {e!r}"
else:
err_msg = (
f"Entrypoint {name} in {backend_module} backend template "
f"must accept {list(kwargs)} as keyword arguments: {e!r}"
)
Copy link
Member

Choose a reason for hiding this comment

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

This could be improved by using inspect.signature(entrypoint) to also present the actual keyword args expected.

Would probably also be helpful to include kwargs["backend_package_alias"] in the error message, to help identify which templating section this was for, as the backend module could be in multiple of them.

raise BackendConfigurationError(err_msg)

target_types = invoke_entrypoint("target_types")
if target_types:
Expand Down
1 change: 1 addition & 0 deletions src/python/pants/init/options_initializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ def _initialize_build_configuration(
bootstrap_options.plugins,
working_set,
bootstrap_options.backend_packages,
templated_backends=bootstrap_options.templated_backends,
)


Expand Down
4 changes: 4 additions & 0 deletions src/python/pants/option/global_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -934,6 +934,10 @@ class BootstrapOptions:
"""
),
)
templated_backends = DictOption(
advanced=True,
help="TODO",
)
plugins = StrListOption(
advanced=True,
help=softwrap(
Expand Down
5 changes: 2 additions & 3 deletions tests/python/pants_test/init/test_extension_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -325,9 +325,8 @@ def reg_alias():
aliases = BuildFileAliases(objects={"override-alias": DummyObject1})
with self.create_register(build_file_aliases=lambda: aliases) as backend_module:
backends = [backend_module]
build_configuration = load_backends_and_plugins(
plugins, self.working_set, backends, bc_builder=self.bc_builder
)
build_configuration = load_backends_and_plugins(plugins, self.working_set, backends,
bc_builder=self.bc_builder)
# The backend should load first, then the plugins, therefore the alias registered in
# the plugin will override the alias registered by the backend
registered_aliases = build_configuration.registered_aliases
Expand Down
Loading