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

     1  # Copyright 2019 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("//internal:common.bzl", "executable_extension")
    16  
    17  # Change to trigger cache invalidation: 1
    18  
    19  def _go_repository_cache_impl(ctx):
    20      if ctx.attr.go_sdk_name:
    21          go_sdk_name = ctx.attr.go_sdk_name
    22      else:
    23          host_platform = _detect_host_platform(ctx)
    24          matches = [
    25              name
    26              for name, platform in ctx.attr.go_sdk_info.items()
    27              if host_platform == platform or platform == "host"
    28          ]
    29          if len(matches) > 1:
    30              fail('gazelle found more than one suitable Go SDK ({}). Specify which one to use with gazelle_dependencies(go_sdk = "go_sdk").'.format(", ".join(matches)))
    31          if len(matches) == 0:
    32              fail('gazelle could not find a Go SDK. Specify which one to use with gazelle_dependencies(go_sdk = "go_sdk").')
    33          if len(matches) == 1:
    34              go_sdk_name = matches[0]
    35  
    36      go_sdk_label = Label("@" + go_sdk_name + "//:ROOT")
    37  
    38      go_root = str(ctx.path(go_sdk_label).dirname)
    39      go_path = str(ctx.path("."))
    40      go_cache = str(ctx.path("gocache"))
    41      go_mod_cache = ""
    42      if ctx.os.environ.get("GO_REPOSITORY_USE_HOST_MODCACHE", "") == "1":
    43          extension = executable_extension(ctx)
    44          go_tool = go_root + "/bin/go" + extension
    45          go_mod_cache = read_go_env(ctx, go_tool, "GOMODCACHE")
    46          if not go_mod_cache:
    47              fail("GOMODCACHE must be set when GO_REPOSITORY_USE_HOST_MODCACHE is enabled.")
    48      if ctx.os.environ.get("GO_REPOSITORY_USE_HOST_CACHE", "") == "1":
    49          extension = executable_extension(ctx)
    50          go_tool = go_root + "/bin/go" + extension
    51          go_mod_cache = read_go_env(ctx, go_tool, "GOMODCACHE")
    52          go_path = read_go_env(ctx, go_tool, "GOPATH")
    53          if not go_mod_cache and not go_path:
    54              fail("GOPATH or GOMODCACHE must be set when GO_REPOSITORY_USE_HOST_CACHE is enabled.")
    55          go_cache = read_go_env(ctx, go_tool, "GOCACHE")
    56          if not go_cache:
    57              fail("GOCACHE must be set when GO_REPOSITORY_USE_HOST_CACHE is enabled.")
    58  
    59      cache_env = {
    60          "GOROOT": go_root,
    61          "GOCACHE": go_cache,
    62      }
    63      if go_path:
    64          cache_env["GOPATH"] = go_path
    65      if go_mod_cache:
    66          cache_env["GOMODCACHE"] = go_mod_cache
    67  
    68      for key, value in ctx.attr.go_env.items():
    69          if key in cache_env:
    70              fail("{} cannot be set in go_env".format(key))
    71          cache_env[key] = value
    72      env_content = "\n".join(["{k}='{v}'\n".format(k = k, v = v) for k, v in cache_env.items()])
    73  
    74      ctx.file("go.env", env_content)
    75      ctx.file("BUILD.bazel", 'exports_files(["go.env"])')
    76  
    77  go_repository_cache = repository_rule(
    78      _go_repository_cache_impl,
    79      attrs = {
    80          "go_sdk_name": attr.string(),
    81          "go_sdk_info": attr.string_dict(),
    82          "go_env": attr.string_dict(),
    83      },
    84      # Don't put anything in environ. If we switch between the host cache
    85      # and Bazel's cache, it shouldn't actually invalidate Bazel's cache.
    86  )
    87  
    88  def read_go_env(ctx, go_tool, var):
    89      res = ctx.execute([go_tool, "env", var])
    90      if res.return_code:
    91          fail("failed to read go environment: " + res.stderr)
    92      return res.stdout.strip()
    93  
    94  def read_cache_env(ctx, path):
    95      contents = ctx.read(path)
    96      env = {}
    97      lines = contents.split("\n")
    98      for line in lines:
    99          line = line.strip()
   100          if line == "" or line.startswith("#"):
   101              continue
   102          k, sep, v = line.partition("=")
   103          if sep == "":
   104              fail("failed to parse cache environment")
   105          env[k] = v.strip("'")
   106      return env
   107  
   108  # copied from rules_go. Keep in sync.
   109  def _detect_host_platform(ctx):
   110      if ctx.os.name == "linux":
   111          host = "linux_amd64"
   112          res = ctx.execute(["uname", "-p"])
   113          if res.return_code == 0:
   114              uname = res.stdout.strip()
   115              if uname == "s390x":
   116                  host = "linux_s390x"
   117              elif uname == "i686":
   118                  host = "linux_386"
   119  
   120          # uname -p is not working on Aarch64 boards
   121          # or for ppc64le on some distros
   122          res = ctx.execute(["uname", "-m"])
   123          if res.return_code == 0:
   124              uname = res.stdout.strip()
   125              if uname == "aarch64":
   126                  host = "linux_arm64"
   127              elif uname == "armv6l":
   128                  host = "linux_arm"
   129              elif uname == "armv7l":
   130                  host = "linux_arm"
   131              elif uname == "ppc64le":
   132                  host = "linux_ppc64le"
   133  
   134          # Default to amd64 when uname doesn't return a known value.
   135  
   136      elif ctx.os.name == "mac os x":
   137          host = "darwin_amd64"
   138      elif ctx.os.name.startswith("windows"):
   139          host = "windows_amd64"
   140      elif ctx.os.name == "freebsd":
   141          host = "freebsd_amd64"
   142      else:
   143          fail("Unsupported operating system: " + ctx.os.name)
   144  
   145      return host