From 4cbbf208acfbeb5111fa91964aa1ae7dba1d40f0 Mon Sep 17 00:00:00 2001 From: tfrench Date: Mon, 8 Jan 2024 15:28:33 +0000 Subject: [PATCH] allow global overrides --- internal/bzlmod/go_deps.bzl | 167 ++++++++++++++++++++++-------------- tests/bcr/MODULE.bazel | 34 ++++++-- tests/bcr/go.mod | 2 - tests/bcr/go.sum | 4 - tests/bcr/pkg/BUILD.bazel | 2 - tests/bcr/pkg/pkg_test.go | 7 -- 6 files changed, 129 insertions(+), 87 deletions(-) diff --git a/internal/bzlmod/go_deps.bzl b/internal/bzlmod/go_deps.bzl index 9eb1c7473..bbf0a788d 100644 --- a/internal/bzlmod/go_deps.bzl +++ b/internal/bzlmod/go_deps.bzl @@ -44,6 +44,36 @@ the required directives to the "default_gazelle_overrides.bzl" file at \ 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 @@ def _fail_on_unmatched_overrides(override_keys, resolutions, override_name): 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,42 @@ def _check_directive(directive): 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. If a specific override is found, + # all of its attributes will be applied (even if left to the tag's default). This is to allow + # users to override the gazelle_default_attributes tag back to the tag's default + specific_override = specific_overrides.get(path) + if specific_override and hasattr(specific_override, attribute_name): + return getattr(specific_override, attribute_name) + + # 2nd. 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 + + # 3rd: Check for default overrides for specific path. + default_path_override = default_path_overrides.get(path) + if default_path_override: + return default_path_override - return DEFAULT_BUILD_FILE_GENERATION_BY_PATH.get(path, "auto") + # 4th. Return the default value if no override was found. + return default_value -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, []) +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_directives(path, gazelle_overrides): - override = gazelle_overrides.get(path) - if override: - return override.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") - return DEFAULT_DIRECTIVES_BY_PATH.get(path, []) +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 +160,32 @@ def _is_dev_dependency(module_ctx, tag): # 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 +204,11 @@ def _process_gazelle_override(gazelle_override_tag): 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 +277,7 @@ def _go_deps_impl(module_ctx): replace_map = {} bazel_deps = {} + gazelle_default_attributes = _process_gazelle_default_attributes(module_ctx) archive_overrides = {} gazelle_overrides = {} module_overrides = {} @@ -341,7 +404,6 @@ def _go_deps_impl(module_ctx): # 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 +471,9 @@ def _go_deps_impl(module_ctx): 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 +513,7 @@ def _go_deps_impl(module_ctx): }, 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 +615,7 @@ _archive_override_tag = tag_class( ) _gazelle_override_tag = tag_class( - attrs = { + attrs = dict({ "path": attr.string( doc = """The Go module path for the repository to be overridden. @@ -561,37 +623,15 @@ _gazelle_override_tag = tag_class( 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 +659,7 @@ go_deps = module_extension( "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 d20340d17..22bc43a6d 100644 --- a/tests/bcr/MODULE.bazel +++ b/tests/bcr/MODULE.bazel @@ -24,6 +24,26 @@ go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps") # Validate a go.mod replace directive works. go_deps.from_file(go_mod = "//:go.mod") +go_deps.gazelle_default_attributes( + build_file_generation = "on", + directives = [ + "gazelle:proto disable", + ], +) + +# By defining `gazelle_default_attributes`, we also must individually +# specify certain overrides from internal/bzlmod/default_gazelle_overrides.bzl +go_deps.gazelle_override( + + # Because this tag is specified, we must specify build_file_generation + # otherwise it will be set to "auto" by default. + build_file_generation = "on", + directives = [ + "gazelle:build_file_name BUILD.bazel", + "gazelle:build_file_proto_mode disable_global", + ], + path = "github.com/google/safetext", +) # Verify that the gazelle:go_naming_convention directive in an override is # respected. @@ -56,16 +76,16 @@ go_deps.gazelle_override( path = "github.com/bazelbuild/buildtools", ) go_deps.archive_override( - urls = [ - "https://github.com/bazelbuild/buildtools/archive/ae8e3206e815d086269eb208b01f300639a4b194.tar.gz", - ], patch_strip = 1, patches = [ "//patches:buildtools.patch", ], - strip_prefix = "buildtools-ae8e3206e815d086269eb208b01f300639a4b194", path = "github.com/bazelbuild/buildtools", sha256 = "05d7c3d2bd3cc0b02d15672fefa0d6be48c7aebe459c1c99dced7ac5e598508f", + strip_prefix = "buildtools-ae8e3206e815d086269eb208b01f300639a4b194", + urls = [ + "https://github.com/bazelbuild/buildtools/archive/ae8e3206e815d086269eb208b01f300639a4b194.tar.gz", + ], ) # Transitive dependencies have to be listed here explicitly. @@ -76,12 +96,12 @@ go_deps.module( version = "v3.0.1", ) go_deps.gazelle_override( - path = "gopkg.in/yaml.v3", directives = [ # Verify that the build naming convention is picked up by Gazelle when it # emits references to this repo. "gazelle:go_naming_convention go_default_library", ], + path = "gopkg.in/yaml.v3", ) go_deps.module( indirect = True, @@ -93,14 +113,10 @@ use_repo( go_deps, "com_github_bazelbuild_buildtools", "com_github_bmatcuk_doublestar_v4", - "com_github_datadog_sketches_go", - "com_github_envoyproxy_protoc_gen_validate", "com_github_fmeum_dep_on_gazelle", "com_github_google_safetext", "com_github_stretchr_testify", "org_golang_x_sys", - # It is not necessary to list transitive dependencies here, only direct ones. - # "in_gopkg_yaml_v3", # Only used for testing. "bazel_gazelle_go_repository_config", ) diff --git a/tests/bcr/go.mod b/tests/bcr/go.mod index 405742d91..31e4108a0 100644 --- a/tests/bcr/go.mod +++ b/tests/bcr/go.mod @@ -7,11 +7,9 @@ go 1.19 replace github.com/bmatcuk/doublestar/v4 => github.com/bmatcuk/doublestar v1.3.4 require ( - github.com/DataDog/sketches-go v1.4.1 github.com/bazelbuild/rules_go v0.39.1 github.com/bmatcuk/doublestar/v4 v4.6.0 github.com/cloudflare/circl v1.3.7 - github.com/envoyproxy/protoc-gen-validate v1.0.1 github.com/fmeum/dep_on_gazelle v1.0.0 github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 golang.org/x/sys v0.15.0 diff --git a/tests/bcr/go.sum b/tests/bcr/go.sum index a82fbd9fd..6d55f3be8 100644 --- a/tests/bcr/go.sum +++ b/tests/bcr/go.sum @@ -1,5 +1,3 @@ -github.com/DataDog/sketches-go v1.4.1 h1:j5G6as+9FASM2qC36lvpvQAj9qsv/jUs3FtO8CwZNAY= -github.com/DataDog/sketches-go v1.4.1/go.mod h1:xJIXldczJyyjnbDop7ZZcLxJdV3+7Kra7H1KMgpgkLk= github.com/bazelbuild/bazel-gazelle v0.30.0 h1:q9XLWQSCA5NZPJ98WFqicHkq6fxrDPnfvMO1XycQBMg= github.com/bazelbuild/bazel-gazelle v0.30.0/go.mod h1:6RxhjM1v/lTpD3JlMpKUCcdus4tvdqsqdfbjYi+czYs= github.com/bazelbuild/rules_go v0.39.1 h1:wkJLUDx59dntWMghuL8++GteoU1To6sRoKJXuyFtmf8= @@ -13,8 +11,6 @@ github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBS github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/protoc-gen-validate v1.0.1 h1:kt9FtLiooDc0vbwTLhdg3dyNX1K9Qwa1EK9LcD4jVUQ= -github.com/envoyproxy/protoc-gen-validate v1.0.1/go.mod h1:0vj8bNkYbSTNS2PIyH87KZaeN4x9zpL9Qt8fQC7d+vs= github.com/fmeum/dep_on_gazelle v1.0.0 h1:7gEtQ2CoD77tYca+1iUnKjIBUZ4mX7mZwjdWp3uuN/E= github.com/fmeum/dep_on_gazelle v1.0.0/go.mod h1:VYCjwfsyRHOJL8oenaEjhIzgM7Oj70iTxgJ2RfXbYr0= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= diff --git a/tests/bcr/pkg/BUILD.bazel b/tests/bcr/pkg/BUILD.bazel index 383211102..0bb578163 100644 --- a/tests/bcr/pkg/BUILD.bazel +++ b/tests/bcr/pkg/BUILD.bazel @@ -55,8 +55,6 @@ go_test( "@circl//dh/x25519", "@com_github_bazelbuild_buildtools//labels:go_default_library", "@com_github_bmatcuk_doublestar_v4//:doublestar", - "@com_github_datadog_sketches_go//ddsketch", - "@com_github_envoyproxy_protoc_gen_validate//validate", "@com_github_fmeum_dep_on_gazelle//:dep_on_gazelle", "@com_github_google_safetext//yamltemplate", "@com_github_stretchr_testify//require:go_default_library", diff --git a/tests/bcr/pkg/pkg_test.go b/tests/bcr/pkg/pkg_test.go index a1ae8cdad..8afe0ea05 100644 --- a/tests/bcr/pkg/pkg_test.go +++ b/tests/bcr/pkg/pkg_test.go @@ -5,7 +5,6 @@ import ( "os" "testing" - "github.com/DataDog/sketches-go/ddsketch" "github.com/bazelbuild/bazel-gazelle/tests/bcr/pkg/data" "github.com/bazelbuild/buildtools/labels" "github.com/bazelbuild/rules_go/go/runfiles" @@ -14,8 +13,6 @@ import ( "github.com/fmeum/dep_on_gazelle" "github.com/google/safetext/yamltemplate" "github.com/stretchr/testify/require" - - _ "github.com/envoyproxy/protoc-gen-validate/validate" ) func TestReplace(t *testing.T) { @@ -37,10 +34,6 @@ func TestBuildFileGeneration(t *testing.T) { yamltemplate.HTMLEscapeString("foo") } -func TestGeneratedFilesPreferredOverProtos(t *testing.T) { - _, _ = ddsketch.NewDefaultDDSketch(0.01) -} - func TestPlatformDependentDep(t *testing.T) { PlatformDependentFunction() }