diff --git a/README.rst b/README.rst index 3b4c2d8f3..0fc0ef0fe 100644 --- a/README.rst +++ b/README.rst @@ -674,7 +674,7 @@ The following flags are accepted: +----------------------------------------------------------------------------------------------------------+----------------------------------------------+ | Sets the ``build_extra_args attribute`` for the generated `go_repository`_ rule(s). | +----------------------------------------------------------------------------------------------------------+----------------------------------------------+ -| :flag:`-build_file_generation auto|on|off` | | +| :flag:`-build_file_generation auto|on|off|clean` | | +----------------------------------------------------------------------------------------------------------+----------------------------------------------+ | Sets the ``build_file_generation`` attribute for the generated `go_repository`_ rule(s). | +----------------------------------------------------------------------------------------------------------+----------------------------------------------+ diff --git a/internal/bzlmod/go_deps.bzl b/internal/bzlmod/go_deps.bzl index 140465860..96c3e410f 100644 --- a/internal/bzlmod/go_deps.bzl +++ b/internal/bzlmod/go_deps.bzl @@ -48,7 +48,7 @@ https://github.com/bazelbuild/bazel-gazelle/tree/master/internal/bzlmod/default_ _GAZELLE_ATTRS = { "build_file_generation": attr.string( default = "on", - doc = """One of `"auto"`, `"on"` (default), `"off"`. + doc = """One of `"auto"`, `"on"` (default), `"off"`, `"clean"`. Whether Gazelle should generate build files for the Go module. @@ -60,11 +60,14 @@ _GAZELLE_ATTRS = { In `"auto"` mode, Gazelle will run if there is no build file in the Go module's root directory. + In `"clean"` mode, Gazelle will not reuse any existing build files. + """, values = [ "auto", "off", "on", + "clean", ], ), "build_extra_args": attr.string_list( diff --git a/internal/go_repository.bzl b/internal/go_repository.bzl index 627a1f9e3..3849f7cdf 100644 --- a/internal/go_repository.bzl +++ b/internal/go_repository.bzl @@ -128,7 +128,7 @@ def _go_repository_impl(ctx): go_env_cache = str(ctx.path(Label("@bazel_gazelle_go_repository_cache//:go.env"))) if not ctx.attr.urls: fetch_repo = str(ctx.path(Label("@bazel_gazelle_go_repository_tools//:bin/fetch_repo{}".format(executable_extension(ctx))))) - generate = ctx.attr.build_file_generation == "on" + generate = ctx.attr.build_file_generation in ["on", "clean"] _gazelle = "@bazel_gazelle_go_repository_tools//:bin/gazelle{}".format(executable_extension(ctx)) if generate: gazelle_path = ctx.path(Label(_gazelle)) @@ -296,8 +296,26 @@ def _go_repository_impl(ctx): if result.return_code: fail("%s: %s" % (ctx.name, result.stderr)) - # Repositories are fetched. Determine if build file generation is needed. build_file_names = ctx.attr.build_file_name.split(",") + + # Clean existing build files if requested + if ctx.attr.build_file_generation == "clean": + # Pure-starlark way of doing the equivalent of "find . -type f -name BUILD -delete". + # Since Windows doesn't have the "find" command we have to do it here, and since + # Starlark doesn't let us write a while loop, we have to hope the user has less + # than a billion files. + paths = [ctx.path("")] + for i in range(1000000000): + if len(paths) == 0: + break + path = paths.pop() + if path.is_dir: + paths += path.readdir(watch = 'no') + else: + if path.basename in build_file_names: + ctx.delete(path) + + # Repositories are fetched. Determine if build file generation is needed. existing_build_file = "" for name in build_file_names: path = ctx.path(name) @@ -515,15 +533,17 @@ go_repository = repository_rule( ), "build_file_generation": attr.string( default = "auto", - doc = """One of `"auto"`, `"on"`, `"off"`. + doc = """One of `"auto"`, `"on"`, `"off"`, `"clean"`. Whether Gazelle should generate build files in the repository. In `"auto"` mode, Gazelle will run if there is no build file in the repository root - directory.""", + directory. In `"clean"` mode, Gazelle will not reuse any existing build + files.""", values = [ "on", "auto", "off", + "clean", ], ), "build_naming_convention": attr.string( diff --git a/repository.md b/repository.md index 5fa4f192d..727fd2f62 100644 --- a/repository.md +++ b/repository.md @@ -178,7 +178,7 @@ go_repository( | build_directives | A list of directives to be written to the root level build file before Calling Gazelle to generate build files. Each string in the list will be prefixed with `#` automatically. A common use case is to pass a list of Gazelle directives. | List of strings | optional | `[]` | | build_external | One of `"external"`, `"static"` or `"vendored"`.

This sets Gazelle's `-external` command line flag. In `"static"` mode, Gazelle will not call out to the network to resolve imports.

**NOTE:** This cannot be used to ignore the `vendor` directory in a repository. The `-external` flag only controls how Gazelle resolves imports which are not present in the repository. Use `build_extra_args = ["-exclude=vendor"]` instead. | String | optional | `"static"` | | build_extra_args | A list of additional command line arguments to pass to Gazelle when generating build files. | List of strings | optional | `[]` | -| build_file_generation | One of `"auto"`, `"on"`, `"off"`.

Whether Gazelle should generate build files in the repository. In `"auto"` mode, Gazelle will run if there is no build file in the repository root directory. | String | optional | `"auto"` | +| build_file_generation | One of `"auto"`, `"on"`, `"off"`, `"clean"`.

Whether Gazelle should generate build files in the repository. In `"auto"` mode, Gazelle will run if there is no build file in the repository root directory. In `"clean"` mode, Gazelle will not reuse any existing build files. | String | optional | `"auto"` | | build_file_name | Comma-separated list of names Gazelle will consider to be build files. If a repository contains files named `build` that aren't related to Bazel, it may help to set this to `"BUILD.bazel"`, especially on case-insensitive file systems. | String | optional | `"BUILD.bazel,BUILD"` | | build_file_proto_mode | One of `"default"`, `"legacy"`, `"disable"`, `"disable_global"` or `"package"`.

This sets Gazelle's `-proto` command line flag. See [Directives] for more information on each mode. | String | optional | `""` | | build_naming_convention | Sets the library naming convention to use when resolving dependencies against this external repository. If unset, the convention from the external workspace is used. Legal values are `go_default_library`, `import`, and `import_alias`.

See the `gazelle:go_naming_convention` directive in [Directives] for more information. | String | optional | `"import_alias"` | diff --git a/tests/bcr/go_mod/MODULE.bazel b/tests/bcr/go_mod/MODULE.bazel index 858a52782..0690c9b1a 100644 --- a/tests/bcr/go_mod/MODULE.bazel +++ b/tests/bcr/go_mod/MODULE.bazel @@ -102,6 +102,12 @@ go_deps.archive_override( ], ) +# Test a module that ships with its own BUILD files and first needs rewriting +go_deps.gazelle_override( + build_file_generation = "clean", + path = "github.com/google/go-jsonnet", +) + # Transitive dependencies have to be listed here explicitly. go_deps.module( indirect = True, @@ -130,6 +136,7 @@ use_repo( "com_github_datadog_sketches_go", "com_github_envoyproxy_protoc_gen_validate", "com_github_fmeum_dep_on_gazelle", + "com_github_google_go_jsonnet", "com_github_google_safetext", "com_github_stretchr_testify", "org_golang_google_protobuf", diff --git a/tests/bcr/go_mod/go.mod b/tests/bcr/go_mod/go.mod index 030865263..96f51e043 100644 --- a/tests/bcr/go_mod/go.mod +++ b/tests/bcr/go_mod/go.mod @@ -23,13 +23,16 @@ require ( require ( github.com/bazelbuild/bazel-gazelle v0.30.0 // indirect github.com/davecgh/go-spew v1.1.0 // indirect + github.com/google/go-jsonnet v0.20.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect golang.org/x/text v0.9.0 // indirect google.golang.org/protobuf v1.32.0 // indirect + gopkg.in/yaml.v2 v2.2.7 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect rsc.io/quote v1.5.2 // indirect rsc.io/sampler v1.3.0 // indirect + sigs.k8s.io/yaml v1.1.0 // indirect ) replace example.org/hello => ../../fixtures/hello diff --git a/tests/bcr/go_mod/go.sum b/tests/bcr/go_mod/go.sum index 9e6056a54..bdbc4f8b0 100644 --- a/tests/bcr/go_mod/go.sum +++ b/tests/bcr/go_mod/go.sum @@ -49,6 +49,8 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-jsonnet v0.20.0 h1:WG4TTSARuV7bSm4PMB4ohjxe33IHT5WVTrJSU33uT4g= +github.com/google/go-jsonnet v0.20.0/go.mod h1:VbgWF9JX7ztlv770x/TolZNGGFfiHEVx9G6ca2eUmeA= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/safetext v0.0.0-20220905092116-b49f7bc46da2 h1:SJ+NtwL6QaZ21U+IrK7d0gGgpjGGvd2kz+FzTHVzdqI= @@ -117,6 +119,8 @@ google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHh gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo= +gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= @@ -126,3 +130,5 @@ rsc.io/quote v1.5.2 h1:w5fcysjrx7yqtD/aO+QwRjYZOKnaM9Uh2b40tElTs3Y= rsc.io/quote v1.5.2/go.mod h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPXsUe+TKr0= rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= +sigs.k8s.io/yaml v1.1.0 h1:4A07+ZFc2wgJwo8YNlQpr1rVlgUDlxXHhPJciaPY5gs= +sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o= diff --git a/tests/bcr/go_mod/pkg/BUILD.bazel b/tests/bcr/go_mod/pkg/BUILD.bazel index ab8a846cd..66dc22d24 100644 --- a/tests/bcr/go_mod/pkg/BUILD.bazel +++ b/tests/bcr/go_mod/pkg/BUILD.bazel @@ -58,6 +58,7 @@ go_test( "@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_go_jsonnet//:go-jsonnet", "@com_github_google_safetext//yamltemplate", "@com_github_stretchr_testify//require:go_default_library", "@my_rules_go//go/runfiles", diff --git a/tests/bcr/go_mod/pkg/pkg_test.go b/tests/bcr/go_mod/pkg/pkg_test.go index 05d873a84..f742a3d34 100644 --- a/tests/bcr/go_mod/pkg/pkg_test.go +++ b/tests/bcr/go_mod/pkg/pkg_test.go @@ -13,6 +13,7 @@ import ( "github.com/bmatcuk/doublestar/v4" "github.com/cloudflare/circl/dh/x25519" "github.com/fmeum/dep_on_gazelle" + "github.com/google/go-jsonnet" "github.com/google/safetext/yamltemplate" "github.com/stretchr/testify/require" @@ -38,6 +39,11 @@ func TestBuildFileGeneration(t *testing.T) { yamltemplate.HTMLEscapeString("foo") } +func TestCleanBuildFileGeneration(t *testing.T) { + // github.com/google/go-jsonnet@v0.20.0 requires fully replacing the BUILD files it provides + jsonnet.Version() +} + func TestGeneratedFilesPreferredOverProtos(t *testing.T) { _, _ = ddsketch.NewDefaultDDSketch(0.01) }