github.com/bazelbuild/bazel-gazelle@v0.36.1-0.20240520142334-61b277ba6fed/internal/go_repository.bzl (about)

     1  # Copyright 2014 The Bazel Authors. All rights reserved.
     2  #
     3  # Licensed under the Apache License, Version 2.0 (the "License");
     4  # you may not use this file except in compliance with the License.
     5  # You may obtain a copy of the License at
     6  #
     7  #    http://www.apache.org/licenses/LICENSE-2.0
     8  #
     9  # Unless required by applicable law or agreed to in writing, software
    10  # distributed under the License is distributed on an "AS IS" BASIS,
    11  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  # See the License for the specific language governing permissions and
    13  # limitations under the License.
    14  
    15  load("@bazel_tools//tools/build_defs/repo:utils.bzl", "patch", "read_user_netrc", "use_netrc")
    16  load("//internal:common.bzl", "env_execute", "executable_extension")
    17  load("//internal:go_repository_cache.bzl", "read_cache_env")
    18  
    19  _DOC = """
    20  `go_repository` downloads a Go project and generates build files with Gazelle
    21  if they are not already present. This is the simplest way to depend on
    22  external Go projects.
    23  
    24  When `go_repository` is in module mode, it saves downloaded modules in a shared,
    25  internal cache within Bazel's cache. It may be cleared with `bazel clean --expunge`.
    26  By setting the environment variable `GO_REPOSITORY_USE_HOST_CACHE=1`, you can
    27  force `go_repository` to use the module cache on the host system in the location
    28  returned by `go env GOPATH`. Alternatively, by setting the environment variable
    29  `GO_REPOSITORY_USE_HOST_MODCACHE=1`, you can force `go_repository` to use only
    30  the module cache on the host system in the location returned by `go env GOMODCACHE`.
    31  
    32  **Example**
    33  
    34  ```starlark
    35  load("@bazel_gazelle//:deps.bzl", "go_repository")
    36  
    37  # Download using "go mod download"
    38  go_repository(
    39      name = "com_github_pkg_errors",
    40      importpath = "github.com/pkg/errors",
    41      sum = "h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=",
    42      version = "v0.8.1",
    43  )
    44  
    45  # Download automatically via git
    46  go_repository(
    47      name = "com_github_pkg_errors",
    48      commit = "816c9085562cd7ee03e7f8188a1cfd942858cded",
    49      importpath = "github.com/pkg/errors",
    50  )
    51  
    52  # Download from git fork
    53  go_repository(
    54      name = "com_github_pkg_errors",
    55      commit = "816c9085562cd7ee03e7f8188a1cfd942858cded",
    56      importpath = "github.com/pkg/errors",
    57      remote = "https://example.com/fork/github.com/pkg/errors",
    58      vcs = "git",
    59  )
    60  
    61  # Download via HTTP
    62  go_repository(
    63      name = "com_github_pkg_errors",
    64      importpath = "github.com/pkg/errors",
    65      urls = ["https://codeload.github.com/pkg/errors/zip/816c9085562cd7ee03e7f8188a1cfd942858cded"],
    66      strip_prefix = "errors-816c9085562cd7ee03e7f8188a1cfd942858cded",
    67      type = "zip",
    68  )
    69  
    70  # Download major version suffixed via git
    71  go_repository(
    72      name = "com_github_thediveo_enumflag_v2",
    73      commit = "0217df583bf3d37b92798602e5061b36556bcd38",
    74      importpath = "github.com/thediveo/enumflag/v2",
    75      remote = "https://github.com/thediveo/enumflag",
    76      vcs = "git",
    77  )
    78  ```
    79  
    80  """
    81  
    82  # copied from
    83  # https://github.com/bazelbuild/bazel/blob/d273cb62f43ef8169415cf60fc96e503ea2ad823/tools/build_defs/repo/http.bzl#L76
    84  _AUTH_PATTERN_DOC = """An optional dict mapping host names to custom authorization patterns.
    85  
    86  If a URL's host name is present in this dict the value will be used as a pattern when
    87  generating the authorization header for the http request. This enables the use of custom
    88  authorization schemes used in a lot of common cloud storage providers.
    89  
    90  The pattern currently supports 2 tokens: <code>&lt;login&gt;</code> and
    91  <code>&lt;password&gt;</code>, which are replaced with their equivalent value
    92  in the netrc file for the same host name. After formatting, the result is set
    93  as the value for the <code>Authorization</code> field of the HTTP request.
    94  
    95  Example attribute and netrc for a http download to an oauth2 enabled API using a bearer token:
    96  
    97  <pre>
    98  auth_patterns = {
    99      "storage.cloudprovider.com": "Bearer &lt;password&gt;"
   100  }
   101  </pre>
   102  
   103  netrc:
   104  
   105  <pre>
   106  machine storage.cloudprovider.com
   107          password RANDOM-TOKEN
   108  </pre>
   109  
   110  The final HTTP request would have the following header:
   111  
   112  <pre>
   113  Authorization: Bearer RANDOM-TOKEN
   114  </pre>
   115  """
   116  
   117  # We can't disable timeouts on Bazel, but we can set them to large values.
   118  _GO_REPOSITORY_TIMEOUT = 86400
   119  
   120  def _go_repository_impl(ctx):
   121      # TODO(#549): vcs repositories are not cached and still need to be fetched.
   122      # Download the repository or module.
   123      fetch_repo_args = None
   124      gazelle_path = None
   125  
   126      # Declare Label dependencies at the top of function to avoid unnecessary fetching:
   127      # https://docs.bazel.build/versions/main/skylark/repository_rules.html#when-is-the-implementation-function-executed
   128      go_env_cache = str(ctx.path(Label("@bazel_gazelle_go_repository_cache//:go.env")))
   129      if not ctx.attr.urls:
   130          fetch_repo = str(ctx.path(Label("@bazel_gazelle_go_repository_tools//:bin/fetch_repo{}".format(executable_extension(ctx)))))
   131      generate = ctx.attr.build_file_generation == "on"
   132      _gazelle = "@bazel_gazelle_go_repository_tools//:bin/gazelle{}".format(executable_extension(ctx))
   133      if generate:
   134          gazelle_path = ctx.path(Label(_gazelle))
   135  
   136      if ctx.attr.local_path:
   137          pass
   138      elif ctx.attr.urls:
   139          # HTTP mode
   140          for key in ("commit", "tag", "vcs", "remote", "version", "sum", "replace"):
   141              if getattr(ctx.attr, key):
   142                  fail("cannot specifiy both urls and %s" % key, key)
   143          result = ctx.download_and_extract(
   144              url = ctx.attr.urls,
   145              sha256 = ctx.attr.sha256,
   146              canonical_id = ctx.attr.canonical_id,
   147              stripPrefix = ctx.attr.strip_prefix,
   148              type = ctx.attr.type,
   149              auth = use_netrc(read_user_netrc(ctx), ctx.attr.urls, ctx.attr.auth_patterns),
   150          )
   151          if not ctx.attr.sha256:
   152              print("For Go module \"{path}\", integrity not specified, calculated sha256 = \"{sha256}\"".format(
   153                  path = ctx.attr.importpath,
   154                  sha256 = result.sha256,
   155              ))
   156      elif ctx.attr.commit or ctx.attr.tag:
   157          # repository mode
   158          if ctx.attr.commit:
   159              rev = ctx.attr.commit
   160              rev_key = "commit"
   161          elif ctx.attr.tag:
   162              rev = ctx.attr.tag
   163              rev_key = "tag"
   164          for key in ("urls", "strip_prefix", "type", "sha256", "version", "sum", "replace", "canonical_id"):
   165              if getattr(ctx.attr, key):
   166                  fail("cannot specify both %s and %s" % (rev_key, key), key)
   167  
   168          if ctx.attr.vcs and not ctx.attr.remote:
   169              fail("if vcs is specified, remote must also be")
   170  
   171          fetch_repo_args = ["-dest", ctx.path(""), "-importpath", ctx.attr.importpath]
   172          if ctx.attr.remote:
   173              fetch_repo_args.extend(["--remote", ctx.attr.remote])
   174          if rev:
   175              fetch_repo_args.extend(["--rev", rev])
   176          if ctx.attr.vcs:
   177              fetch_repo_args.extend(["--vcs", ctx.attr.vcs])
   178      elif ctx.attr.version:
   179          # module mode
   180          for key in ("urls", "strip_prefix", "type", "sha256", "commit", "tag", "vcs", "remote"):
   181              if getattr(ctx.attr, key):
   182                  fail("cannot specify both version and %s" % key)
   183          if ctx.attr.version and not ctx.attr.sum:
   184              fail("if version is specified, sum must also be")
   185  
   186          fetch_path = ctx.attr.replace if ctx.attr.replace else ctx.attr.importpath
   187          fetch_repo_args = [
   188              "-dest=" + str(ctx.path("")),
   189              "-importpath=" + fetch_path,
   190              "-version=" + ctx.attr.version,
   191              "-sum=" + ctx.attr.sum,
   192          ]
   193      else:
   194          fail("one of urls, commit, tag, or version must be specified")
   195  
   196      env = read_cache_env(ctx, go_env_cache)
   197      env_keys = [
   198          # keep sorted
   199  
   200          # Respect user proxy and sumdb settings for privacy.
   201          # TODO(jayconrod): gazelle in go_repository mode should probably
   202          # not go out to the network at all. This means *the build*
   203          # goes out to the network. We tolerate this for downloading
   204          # archives, but finding module roots is a bit much.
   205          "GONOPROXY",
   206          "GONOSUMDB",
   207          "GOPRIVATE",
   208          "GOPROXY",
   209          "GOSUMDB",
   210  
   211          # PATH is needed to locate git and other vcs tools.
   212          "PATH",
   213  
   214          # HOME is needed to locate vcs configuration files (.gitconfig).
   215          "HOME",
   216  
   217          # Settings below are used by vcs tools.
   218          "GIT_CONFIG",
   219          "GIT_CONFIG_COUNT",
   220          "GIT_CONFIG_GLOBAL",
   221          "GIT_CONFIG_NOSYSTEM",
   222          "GIT_CONFIG_SYSTEM",
   223          "GIT_SSH",
   224          "GIT_SSH_COMMAND",
   225          "GIT_SSL_CAINFO",
   226          "HTTPS_PROXY",
   227          "HTTP_PROXY",
   228          "NO_PROXY",
   229          "SSH_AUTH_SOCK",
   230          "SSL_CERT_DIR",
   231          "SSL_CERT_FILE",
   232          "http_proxy",
   233          "https_proxy",
   234          "no_proxy",
   235      ]
   236  
   237      # Git allows passing configuration through environmental variables, this will be picked
   238      # by go get properly: https://www.git-scm.com/docs/git-config/#Documentation/git-config.txt-GITCONFIGCOUNT
   239      if "GIT_CONFIG_COUNT" in ctx.os.environ:
   240          count = ctx.os.environ["GIT_CONFIG_COUNT"]
   241          if count:
   242              if not count.isdigit or int(count) < 1:
   243                  fail("GIT_CONFIG_COUNT has to be a positive integer")
   244              count = int(count)
   245              for i in range(count):
   246                  key = "GIT_CONFIG_KEY_%d" % i
   247                  value = "GIT_CONFIG_VALUE_%d" % i
   248                  for j in [key, value]:
   249                      if j not in ctx.os.environ:
   250                          fail("%s is not defined as an environment variable, but you asked for GIT_COUNT_COUNT=%d" % (j, count))
   251                  env_keys = env_keys + [key, value]
   252  
   253      env.update({k: ctx.os.environ[k] for k in env_keys if k in ctx.os.environ})
   254  
   255      if ctx.attr.local_path:
   256          local_path_env = dict(env)
   257          local_path_env["GOSUMDB"] = "off"
   258  
   259          # Override external GO111MODULE, because it is needed by module mode, no-op in repository mode
   260          local_path_env["GO111MODULE"] = "on"
   261  
   262          if hasattr(ctx, "watch_tree"):
   263              # https://github.com/bazelbuild/bazel/commit/fffa0affebbacf1961a97ef7cd248be64487d480
   264              ctx.watch_tree(ctx.attr.local_path)
   265          else:
   266              print("""
   267    WARNING: go.mod replace directives to module paths is only supported in bazel 7.1.0-rc1 or later,
   268            Because of this changes to %s will not be detected by your version of Bazel.""" % ctx.attr.local_path)
   269  
   270          command = [fetch_repo, "--path", ctx.attr.local_path, "--dest", ctx.path("")]
   271          result = env_execute(
   272              ctx,
   273              command,
   274              environment = local_path_env,
   275              timeout = _GO_REPOSITORY_TIMEOUT,
   276          )
   277  
   278          if result.return_code:
   279              fail(command)
   280  
   281      if fetch_repo_args:
   282          # Disable sumdb in fetch_repo. In module mode, the sum is a mandatory
   283          # attribute of go_repository, so we don't need to look it up.
   284          fetch_repo_env = dict(env)
   285          fetch_repo_env["GOSUMDB"] = "off"
   286  
   287          # Override external GO111MODULE, because it is needed by module mode, no-op in repository mode
   288          fetch_repo_env["GO111MODULE"] = "on"
   289  
   290          result = env_execute(
   291              ctx,
   292              [fetch_repo] + fetch_repo_args,
   293              environment = fetch_repo_env,
   294              timeout = _GO_REPOSITORY_TIMEOUT,
   295          )
   296          if result.return_code:
   297              fail("%s: %s" % (ctx.name, result.stderr))
   298  
   299      # Repositories are fetched. Determine if build file generation is needed.
   300      build_file_names = ctx.attr.build_file_name.split(",")
   301      existing_build_file = ""
   302      for name in build_file_names:
   303          path = ctx.path(name)
   304          if path.exists and not env_execute(ctx, ["test", "-f", path]).return_code:
   305              existing_build_file = name
   306              break
   307  
   308      generate = generate or (not existing_build_file and ctx.attr.build_file_generation == "auto")
   309  
   310      if generate:
   311          # Build file generation is needed. Populate Gazelle directive at root build file
   312          build_file_name = existing_build_file or build_file_names[0]
   313          if len(ctx.attr.build_directives) > 0:
   314              ctx.file(
   315                  build_file_name,
   316                  "\n".join(["# " + d for d in ctx.attr.build_directives]),
   317              )
   318  
   319          # Run Gazelle
   320          if gazelle_path == None:
   321              gazelle_path = ctx.path(Label(_gazelle))
   322  
   323          # ctx.attr.name is the canonical name of this repository, which contains a '~' if and only
   324          # if this repository is generated by a module extension rather than an invocation in
   325          # WORKSPACE.
   326          is_module_extension_repo = "~" in ctx.attr.name
   327          if is_module_extension_repo:
   328              # TODO: In Bazel 6.3.0 and earlier, there is no way to obtain a label referencing a repo
   329              # generated by an extension from within that extension. We thus have to manually
   330              # construct such a label pointing to the sibling `_go_repository_config` repo created by
   331              # the `go_deps` extension. All extension-generated repos have names of the form
   332              # `<prefix>~<name set by the extension>`.
   333              extension_repo_prefix = ctx.attr.name.rpartition("~")[0] + "~"
   334              repo_config = ctx.path(Label("@@" + extension_repo_prefix + "bazel_gazelle_go_repository_config//:WORKSPACE"))
   335          else:
   336              repo_config = ctx.path(ctx.attr.build_config)
   337          cmd = [
   338              gazelle_path,
   339              "-go_repository_mode",
   340              "-go_prefix",
   341              ctx.attr.importpath,
   342              "-mode",
   343              "fix",
   344              "-repo_root",
   345              ctx.path(""),
   346              "-repo_config",
   347              repo_config,
   348          ]
   349          if ctx.attr.version or ctx.attr.local_path:
   350              cmd.append("-go_repository_module_mode")
   351          if ctx.attr.build_file_name:
   352              cmd.extend(["-build_file_name", ctx.attr.build_file_name])
   353          if ctx.attr.build_tags:
   354              cmd.extend(["-build_tags", ",".join(ctx.attr.build_tags)])
   355          if ctx.attr.build_external:
   356              cmd.extend(["-external", ctx.attr.build_external])
   357          if ctx.attr.build_file_proto_mode:
   358              cmd.extend(["-proto", ctx.attr.build_file_proto_mode])
   359          if ctx.attr.build_naming_convention:
   360              cmd.extend(["-go_naming_convention", ctx.attr.build_naming_convention])
   361          if is_module_extension_repo:
   362              cmd.append("-bzlmod")
   363          cmd.extend(ctx.attr.build_extra_args)
   364          cmd.append(ctx.path(""))
   365          ctx.report_progress("running Gazelle")
   366          result = env_execute(ctx, cmd, environment = env, timeout = _GO_REPOSITORY_TIMEOUT)
   367          if result.return_code:
   368              fail("failed to generate BUILD files for %s: %s" % (
   369                  ctx.attr.importpath,
   370                  result.stderr,
   371              ))
   372          if ctx.attr.debug_mode and result.stderr:
   373              print("%s gazelle.stdout: %s" % (ctx.name, result.stdout))
   374              print("%s gazelle.stderr: %s" % (ctx.name, result.stderr))
   375  
   376      # Apply patches if necessary.
   377      patch(ctx)
   378  
   379  go_repository = repository_rule(
   380      implementation = _go_repository_impl,
   381      doc = _DOC,
   382      attrs = {
   383          # Fundamental attributes of a go repository
   384          "importpath": attr.string(
   385              doc = """The Go import path that matches the root directory of this repository.
   386  
   387              In module mode (when `version` is set), this must be the module path. If
   388              neither `urls` nor `remote` is specified, `go_repository` will
   389              automatically find the true path of the module, applying import path
   390              redirection.
   391  
   392              If build files are generated for this repository, libraries will have their
   393              `importpath` attributes prefixed with this `importpath` string.  """,
   394              mandatory = True,
   395          ),
   396  
   397          # Attributes for a repository that should be checked out from VCS
   398          "commit": attr.string(
   399              doc = """If the repository is downloaded using a version control tool, this is the
   400              commit or revision to check out. With git, this would be a sha1 commit id.
   401              `commit` and `tag` may not both be set.""",
   402          ),
   403          "tag": attr.string(
   404              doc = """If the repository is downloaded using a version control tool, this is the
   405              named revision to check out. `commit` and `tag` may not both be set.""",
   406          ),
   407          "vcs": attr.string(
   408              default = "",
   409              doc = """One of `"git"`, `"hg"`, `"svn"`, `"bzr"`.
   410  
   411              The version control system to use. This is usually determined automatically,
   412              but it may be necessary to set this when `remote` is set and the VCS cannot
   413              be inferred. You must have the corresponding tool installed on your host.""",
   414              values = [
   415                  "",
   416                  "git",
   417                  "hg",
   418                  "svn",
   419                  "bzr",
   420              ],
   421          ),
   422          "remote": attr.string(
   423              doc = """The VCS location where the repository should be downloaded from. This is
   424              usually inferred from `importpath`, but you can set `remote` to download
   425              from a private repository or a fork.""",
   426          ),
   427  
   428          # Attributes for a repository that should be downloaded via HTTP.
   429          "urls": attr.string_list(
   430              doc = """A list of HTTP(S) URLs where an archive containing the project can be
   431              downloaded. Bazel will attempt to download from the first URL; the others
   432              are mirrors.""",
   433          ),
   434          "strip_prefix": attr.string(
   435              doc = """If the repository is downloaded via HTTP (`urls` is set), this is a
   436              directory prefix to strip. See [`http_archive.strip_prefix`].""",
   437          ),
   438          "type": attr.string(
   439              doc = """One of `"zip"`, `"tar.gz"`, `"tgz"`, `"tar.bz2"`, `"tar.xz"`.
   440  
   441              If the repository is downloaded via HTTP (`urls` is set), this is the
   442              file format of the repository archive. This is normally inferred from the
   443              downloaded file name.""",
   444          ),
   445          "sha256": attr.string(
   446              doc = """If the repository is downloaded via HTTP (`urls` is set), this is the
   447              SHA-256 sum of the downloaded archive. When set, Bazel will verify the archive
   448              against this sum before extracting it.
   449  
   450              **CAUTION:** Do not use this with services that prepare source archives on
   451              demand, such as codeload.github.com. Any minor change in the server software
   452              can cause differences in file order, alignment, and compression that break
   453              SHA-256 sums.""",
   454          ),
   455          "canonical_id": attr.string(
   456              doc = """If the repository is downloaded via HTTP (`urls` is set) and this is set, restrict cache hits to those cases where the
   457              repository was added to the cache with the same canonical id.""",
   458          ),
   459          "auth_patterns": attr.string_dict(
   460              doc = _AUTH_PATTERN_DOC,
   461          ),
   462  
   463          # Attributes for a module that should be loaded from the local file system.
   464          "local_path": attr.string(
   465              doc = """ If specified, `go_repository` will load the module from this local directory""",
   466          ),
   467  
   468          # Attributes for a module that should be downloaded with the Go toolchain.
   469          "version": attr.string(
   470              doc = """If specified, `go_repository` will download the module at this version
   471              using `go mod download`. `sum` must also be set. `commit`, `tag`,
   472              and `urls` may not be set. """,
   473          ),
   474          "sum": attr.string(
   475              doc = """A hash of the module contents. In module mode, `go_repository` will verify
   476              the downloaded module matches this sum. May only be set when `version`
   477              is also set.
   478  
   479              A value for `sum` may be found in the `go.sum` file or by running
   480              `go mod download -json <module>@<version>`.""",
   481          ),
   482          "replace": attr.string(
   483              doc = """A replacement for the module named by `importpath`. The module named by
   484              `replace` will be downloaded at `version` and verified with `sum`.
   485  
   486              NOTE: There is no `go_repository` equivalent to file path `replace`
   487              directives. Use `local_repository` instead.""",
   488          ),
   489  
   490          # Attributes for a repository that needs automatic build file generation
   491          "build_external": attr.string(
   492              default = "static",
   493              doc = """One of `"external"`, `"static"` or `"vendored"`.
   494  
   495              This sets Gazelle's `-external` command line flag. In `"static"` mode,
   496              Gazelle will not call out to the network to resolve imports.
   497  
   498              **NOTE:** This cannot be used to ignore the `vendor` directory in a
   499              repository. The `-external` flag only controls how Gazelle resolves
   500              imports which are not present in the repository. Use
   501              `build_extra_args = ["-exclude=vendor"]` instead.""",
   502              values = [
   503                  "",
   504                  "external",
   505                  "static",
   506                  "vendored",
   507              ],
   508          ),
   509          "build_file_name": attr.string(
   510              default = "BUILD.bazel,BUILD",
   511              doc = """Comma-separated list of names Gazelle will consider to be build files.
   512              If a repository contains files named `build` that aren't related to Bazel,
   513              it may help to set this to `"BUILD.bazel"`, especially on case-insensitive
   514              file systems.""",
   515          ),
   516          "build_file_generation": attr.string(
   517              default = "auto",
   518              doc = """One of `"auto"`, `"on"`, `"off"`.
   519  
   520              Whether Gazelle should generate build files in the repository. In `"auto"`
   521              mode, Gazelle will run if there is no build file in the repository root
   522              directory.""",
   523              values = [
   524                  "on",
   525                  "auto",
   526                  "off",
   527              ],
   528          ),
   529          "build_naming_convention": attr.string(
   530              values = [
   531                  "go_default_library",
   532                  "import",
   533                  "import_alias",
   534              ],
   535              default = "import_alias",
   536              doc = """Sets the library naming convention to use when resolving dependencies against this external
   537              repository. If unset, the convention from the external workspace is used.
   538              Legal values are `go_default_library`, `import`, and `import_alias`.
   539  
   540              See the `gazelle:go_naming_convention` directive in [Directives] for more information.""",
   541          ),
   542          "build_tags": attr.string_list(
   543              doc = "This sets Gazelle's `-build_tags` command line flag.",
   544          ),
   545          "build_file_proto_mode": attr.string(
   546              doc = """One of `"default"`, `"legacy"`, `"disable"`, `"disable_global"` or `"package"`.
   547  
   548              This sets Gazelle's `-proto` command line flag. See [Directives] for more
   549              information on each mode.""",
   550              values = [
   551                  "",
   552                  "default",
   553                  "package",
   554                  "disable",
   555                  "disable_global",
   556                  "legacy",
   557              ],
   558          ),
   559          "build_extra_args": attr.string_list(
   560              doc = "A list of additional command line arguments to pass to Gazelle when generating build files.",
   561          ),
   562          "build_config": attr.label(
   563              default = "@bazel_gazelle_go_repository_config//:WORKSPACE",
   564              doc = """A file that Gazelle should read to learn about external repositories before
   565              generating build files. This is useful for dependency resolution. For example,
   566              a `go_repository` rule in this file establishes a mapping between a
   567              repository name like `golang.org/x/tools` and a workspace name like
   568              `org_golang_x_tools`. Workspace directives like
   569              `# gazelle:repository_macro` are recognized.
   570  
   571              `go_repository` rules will be re-evaluated when parts of WORKSPACE related
   572              to Gazelle's configuration are changed, including Gazelle directives and
   573              `go_repository` `name` and `importpath` attributes.
   574              Their content should still be fetched from a local cache, but build files
   575              will be regenerated. If this is not desirable, `build_config` may be set
   576              to a less frequently updated file or `None` to disable this functionality.""",
   577          ),
   578          "build_directives": attr.string_list(
   579              default = [],
   580              doc = """A list of directives to be written to the root level build file before
   581              Calling Gazelle to generate build files. Each string in the list will be
   582              prefixed with `#` automatically. A common use case is to pass a list of
   583              Gazelle directives.""",
   584          ),
   585  
   586          # Patches to apply after running gazelle.
   587          "patches": attr.label_list(
   588              doc = "A list of patches to apply to the repository after gazelle runs.",
   589          ),
   590          "patch_tool": attr.string(
   591              default = "",
   592              doc = """The patch tool used to apply `patches`. If this is specified, Bazel will
   593              use the specifed patch tool instead of the Bazel-native patch implementation.""",
   594          ),
   595          "patch_args": attr.string_list(
   596              default = ["-p0"],
   597              doc = "Arguments passed to the patch tool when applying patches.",
   598          ),
   599          "patch_cmds": attr.string_list(
   600              default = [],
   601              doc = "Commands to run in the repository after patches are applied.",
   602          ),
   603  
   604          # Attributes that affect the verbosity of logging:
   605          "debug_mode": attr.bool(
   606              default = False,
   607              doc = """Enables logging of fetch_repo and Gazelle output during succcesful runs. Gazelle can be noisy
   608              so this defaults to `False`. However, setting to `True` can be useful for debugging build failures and
   609              unexpected behavior for the given rule.
   610              """,
   611          ),
   612      },
   613  )
   614  """See repository.md#go-repository for full documentation."""