allow global overrides
diff --git a/internal/bzlmod/default_gazelle_overrides.bzl b/internal/bzlmod/default_gazelle_overrides.bzl
index 21e74e0..75b3c74 100644
--- a/internal/bzlmod/default_gazelle_overrides.bzl
+++ b/internal/bzlmod/default_gazelle_overrides.bzl
@@ -14,64 +14,29 @@
visibility("private")
+# This file should ONLY specify default overrides for
+# repos explicitly required to build gazelle or rules_go.
+#
+# Otherwise, users should should specify these overrides themselves
+# in their MODULE.bazel file.
+#
+# Gazelle should not be hard coupled to any specific group of
+# Go dependencies.
+
DEFAULT_BUILD_FILE_GENERATION_BY_PATH = {
- "github.com/envoyproxy/protoc-gen-validate": "on",
- "github.com/google/safetext": "on",
- "github.com/grpc-ecosystem/grpc-gateway/v2": "on",
"google.golang.org/grpc": "on",
}
DEFAULT_DIRECTIVES_BY_PATH = {
- "github.com/census-instrumentation/opencensus-proto": [
- "gazelle:proto disable",
- ],
- "github.com/envoyproxy/protoc-gen-validate": [
- "gazelle:build_file_name BUILD.bazel",
- ],
"github.com/gogo/googleapis": [
"gazelle:proto disable",
],
"github.com/gogo/protobuf": [
"gazelle:proto disable",
],
- "github.com/google/gnostic": [
- "gazelle:proto disable",
- ],
- "github.com/google/gnostic-models": [
- "gazelle:proto disable",
- ],
- "github.com/google/safetext": [
- "gazelle:build_file_name BUILD.bazel",
- "gazelle:build_file_proto_mode disable_global",
- ],
- "github.com/googleapis/gax-go/v2": [
- "gazelle:proto disable",
- ],
- "github.com/googleapis/gnostic": [
- "gazelle:proto disable",
- ],
- "github.com/pseudomuto/protoc-gen-doc": [
- # The build file in github.com/mwitkow/go-proto-validators has both go_proto and gogo_proto targets, but the checked
- # in go files are generated by gogo proto. Resolving to the gogo proto target preserves the behavior of Go modules.
- "gazelle:resolve go github.com/mwitkow/go-proto-validators @com_github_mwitkow_go_proto_validators//:validators_gogo",
- ],
"google.golang.org/grpc": [
"gazelle:proto disable",
],
- "k8s.io/api": [
- "gazelle:proto disable",
- ],
- "k8s.io/apiextensions-apiserver": [
- "gazelle:proto disable",
- ],
- "k8s.io/apimachinery": [
- "gazelle:go_generate_proto false",
- "gazelle:proto_import_prefix k8s.io/apimachinery",
- ],
}
-DEFAULT_BUILD_EXTRA_ARGS_BY_PATH = {
- "github.com/census-instrumentation/opencensus-proto": [
- "-exclude=src",
- ],
-}
+DEFAULT_BUILD_EXTRA_ARGS_BY_PATH = {}
diff --git a/internal/bzlmod/go_deps.bzl b/internal/bzlmod/go_deps.bzl
index 9eb1c74..fa50849 100644
--- a/internal/bzlmod/go_deps.bzl
+++ b/internal/bzlmod/go_deps.bzl
@@ -44,6 +44,36 @@
https://github.com/bazelbuild/bazel-gazelle/tree/master/internal/bzlmod/default_gazelle_overrides.bzl.
"""
+_GAZELLE_ATTRS = {
+ "build_file_generation": attr.string(
+ default = "auto",
+ doc = """One of `"auto"` (default), `"on"`, `"off"`.
+
+ Whether Gazelle should generate build files for the Go module. In
+ `"auto"` mode, Gazelle will run if there is no build file in the Go
+ module's root directory.""",
+ values = [
+ "auto",
+ "off",
+ "on",
+ ],
+ ),
+ "build_extra_args": attr.string_list(
+ default = [],
+ doc = """
+ A list of additional command line arguments to pass to Gazelle when generating build files.
+ """,
+ ),
+ "directives": attr.string_list(
+ doc = """Gazelle configuration directives to use for this Go module's external repository.
+
+ Each directive uses the same format as those that Gazelle
+ accepts as comments in Bazel source files, with the
+ directive name followed by optional arguments separated by
+ whitespace.""",
+ ),
+}
+
def _fail_on_non_root_overrides(module_ctx, module, tag_class):
if module.is_root:
return
@@ -68,7 +98,8 @@
unmatched_overrides = [path for path in override_keys if path not in resolutions]
if unmatched_overrides:
fail("Some {} did not target a Go module with a matching path: {}".format(
- override_name, ", ".join(unmatched_overrides)
+ override_name,
+ ", ".join(unmatched_overrides),
))
def _check_directive(directive):
@@ -76,37 +107,40 @@
return
fail("Invalid Gazelle directive: \"{}\". Gazelle directives must be of the form \"gazelle:key value\".".format(directive))
-def _get_build_file_generation(path, gazelle_overrides):
- override = gazelle_overrides.get(path)
- if override:
- return override.build_file_generation
+def _get_override_or_default(specific_overrides, gazelle_default_attributes, default_path_overrides, path, default_value, attribute_name):
+ # 1st: Check for user-provided specific overrides.
+ specific_override = specific_overrides.get(path)
+ if specific_override and hasattr(specific_override, attribute_name):
+ return getattr(specific_override, attribute_name)
- return DEFAULT_BUILD_FILE_GENERATION_BY_PATH.get(path, "auto")
+ # 2nd: Check for default overrides for specific path.
+ default_path_override = default_path_overrides.get(path)
+ if default_path_override:
+ return default_path_override
-def _get_build_extra_args(path, gazelle_overrides):
- override = gazelle_overrides.get(path)
- if override:
- return override.build_extra_args
- return DEFAULT_BUILD_EXTRA_ARGS_BY_PATH.get(path, [])
+ # 3rd. Check for default attributes provided by the user.
+ global_override_value = getattr(gazelle_default_attributes, attribute_name, None)
+ if global_override_value:
+ return global_override_value
-def _get_directives(path, gazelle_overrides):
- override = gazelle_overrides.get(path)
- if override:
- return override.directives
+ # 4th. Return the default value if no override was found.
+ return default_value
- return DEFAULT_DIRECTIVES_BY_PATH.get(path, [])
+def _get_directives(path, gazelle_overrides, gazelle_default_attributes):
+ return _get_override_or_default(gazelle_overrides, gazelle_default_attributes, DEFAULT_DIRECTIVES_BY_PATH, path, [], "directives")
+
+def _get_build_file_generation(path, gazelle_overrides, gazelle_default_attributes):
+ return _get_override_or_default(gazelle_overrides, gazelle_default_attributes, DEFAULT_BUILD_FILE_GENERATION_BY_PATH, path, "auto", "build_file_generation")
+
+def _get_build_extra_args(path, gazelle_overrides, gazelle_default_attributes):
+ return _get_override_or_default(gazelle_overrides, gazelle_default_attributes, DEFAULT_BUILD_EXTRA_ARGS_BY_PATH, path, [], "build_extra_args")
def _get_patches(path, module_overrides):
- override = module_overrides.get(path)
- if override:
- return override.patches
- return []
+ return _get_override_or_default(module_overrides, struct(), {}, path, [], "patches")
def _get_patch_args(path, module_overrides):
- override = module_overrides.get(path)
- if override:
- return ["-p{}".format(override.patch_strip)]
- return []
+ override = _get_override_or_default(module_overrides, struct(), {}, path, None, "patch_strip")
+ return ["-p{}".format(override)] if override else []
def _repo_name(importpath):
path_segments = importpath.split("/")
@@ -124,6 +158,32 @@
# not available.
return module_ctx.is_dev_dependency(tag) if hasattr(module_ctx, "is_dev_dependency") else False
+# This function processes the gazelle_default_attributes tag for a given module and returns a struct
+# containing the attributes from _GAZELLE_ATTRS that are defined in the tag.
+def _process_gazelle_default_attributes(module_ctx):
+ for module in module_ctx.modules:
+ _fail_on_non_root_overrides(module_ctx, module, "gazelle_default_attributes")
+
+ for module in module_ctx.modules:
+ tags = module.tags.gazelle_default_attributes
+ if not tags:
+ continue
+
+ if len(tags) > 1:
+ fail(
+ "go_deps.gazelle_default_attributes: only one tag can be specified per module, got:\n",
+ *[t for p in zip(module.tags.gazelle_default_attributes, len(module.tags.gazelle_default_attributes) * ["\n"]) for t in p]
+ )
+
+ tag = tags[0]
+ return struct(**{
+ attr: getattr(tag, attr)
+ for attr in _GAZELLE_ATTRS.keys()
+ if hasattr(tag, attr)
+ })
+
+ return None
+
# This function processes a given override type for a given module, checks for duplicate overrides
# and inserts the override returned from the process_override_func into the overrides dict.
def _process_overrides(module_ctx, module, override_type, overrides, process_override_func, additional_overrides = None):
@@ -142,11 +202,11 @@
for directive in gazelle_override_tag.directives:
_check_directive(directive)
- return struct(
- directives = gazelle_override_tag.directives,
- build_file_generation = gazelle_override_tag.build_file_generation,
- build_extra_args = gazelle_override_tag.build_extra_args,
- )
+ return struct(**{
+ attr: getattr(gazelle_override_tag, attr)
+ for attr in _GAZELLE_ATTRS.keys()
+ if hasattr(gazelle_override_tag, attr)
+ })
def _process_module_override(module_override_tag):
return struct(
@@ -215,6 +275,7 @@
replace_map = {}
bazel_deps = {}
+ gazelle_default_attributes = _process_gazelle_default_attributes(module_ctx)
archive_overrides = {}
gazelle_overrides = {}
module_overrides = {}
@@ -341,7 +402,6 @@
# in the module resolutions and swapping out the entry.
for path, replace in replace_map.items():
if path in module_resolutions:
-
# If the replace directive specified a version then we only
# apply it if the versions match.
if replace.from_version:
@@ -409,9 +469,9 @@
go_repository_args = {
"name": module.repo_name,
"importpath": path,
- "build_directives": _get_directives(path, gazelle_overrides),
- "build_file_generation": _get_build_file_generation(path, gazelle_overrides),
- "build_extra_args": _get_build_extra_args(path, gazelle_overrides),
+ "build_directives": _get_directives(path, gazelle_overrides, gazelle_default_attributes),
+ "build_file_generation": _get_build_file_generation(path, gazelle_overrides, gazelle_default_attributes),
+ "build_extra_args": _get_build_extra_args(path, gazelle_overrides, gazelle_default_attributes),
"patches": _get_patches(path, module_overrides),
"patch_args": _get_patch_args(path, module_overrides),
}
@@ -451,7 +511,7 @@
},
build_naming_conventions = drop_nones({
module.repo_name: get_directive_value(
- _get_directives(path, gazelle_overrides),
+ _get_directives(path, gazelle_overrides, gazelle_default_attributes),
"go_naming_convention",
)
for path, module in module_resolutions.items()
@@ -553,7 +613,7 @@
)
_gazelle_override_tag = tag_class(
- attrs = {
+ attrs = dict({
"path": attr.string(
doc = """The Go module path for the repository to be overridden.
@@ -561,37 +621,15 @@
extension within this Bazel module.""",
mandatory = True,
),
- "build_file_generation": attr.string(
- default = "auto",
- doc = """One of `"auto"` (default), `"on"`, `"off"`.
-
- Whether Gazelle should generate build files for the Go module. In
- `"auto"` mode, Gazelle will run if there is no build file in the Go
- module's root directory.""",
- values = [
- "auto",
- "off",
- "on",
- ],
- ),
- "build_extra_args": attr.string_list(
- default = [],
- doc = """
- A list of additional command line arguments to pass to Gazelle when generating build files.
- """,
- ),
- "directives": attr.string_list(
- doc = """Gazelle configuration directives to use for this Go module's external repository.
-
- Each directive uses the same format as those that Gazelle
- accepts as comments in Bazel source files, with the
- directive name followed by optional arguments separated by
- whitespace.""",
- ),
- },
+ }, **_GAZELLE_ATTRS),
doc = "Override Gazelle's behavior on a given Go module defined by other tags in this extension.",
)
+_gazelle_default_attributes_tag = tag_class(
+ attrs = _GAZELLE_ATTRS,
+ doc = "Override Gazelle's default attribute values for all modules in this extension.",
+)
+
_module_override_tag = tag_class(
attrs = {
"path": attr.string(
@@ -619,6 +657,7 @@
"config": _config_tag,
"from_file": _from_file_tag,
"gazelle_override": _gazelle_override_tag,
+ "gazelle_default_attributes": _gazelle_default_attributes_tag,
"module": _module_tag,
"module_override": _module_override_tag,
},
diff --git a/tests/bcr/MODULE.bazel b/tests/bcr/MODULE.bazel
index d20340d..87a9bed 100644
--- a/tests/bcr/MODULE.bazel
+++ b/tests/bcr/MODULE.bazel
@@ -24,6 +24,11 @@
# Validate a go.mod replace directive works.
go_deps.from_file(go_mod = "//:go.mod")
+go_deps.gazelle_default_attributes(
+ directives = [
+ "gazelle:proto disable",
+ ],
+)
# Verify that the gazelle:go_naming_convention directive in an override is
# respected.