1# Copyright 2021 The Pigweed Authors 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); you may not 4# use this file except in compliance with the License. You may obtain a copy of 5# the License at 6# 7# https://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, WITHOUT 11# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 12# License for the specific language governing permissions and limitations under 13# the License. 14"""Internal Bazel helpers for downloading CIPD packages.""" 15 16load( 17 ":cipd_repository_list_templates.bzl", 18 "CIPD_INIT_BZL_TEMPLATE", 19 "CIPD_REPOSITORY_TEMPLATE", 20) 21 22_CIPD_HOST = "https://chrome-infra-packages.appspot.com" 23 24def platform_normalized(rctx): 25 """Normalizes the platform to match CIPDs naming system. 26 27 Args: 28 rctx: Repository context. 29 30 Returns: 31 str: Normalized string. 32 """ 33 34 # Chained if else used because Bazel's rctx.os.name is not stable 35 # between different versions of windows i.e. windows 10 vs windows 36 # server. 37 if "windows" in rctx.os.name: 38 return "windows" 39 elif "linux" == rctx.os.name: 40 return "linux" 41 elif "mac os x" == rctx.os.name: 42 return "mac" 43 else: 44 fail("Could not normalize os:", rctx.os.name) 45 46def arch_normalized(rctx): 47 """Normalizes the architecture string to match CIPDs naming system. 48 49 Args: 50 rctx: Repository context. 51 52 Returns: 53 str: Normalized architecture. 54 """ 55 56 if "arm" in rctx.os.name or "aarch" in rctx.os.arch: 57 return "arm64" 58 59 return "amd64" 60 61def get_client_cipd_version(rctx): 62 """Gets the CIPD client version from the config file. 63 64 Args: 65 rctx: Repository context. 66 67 Returns: 68 str: The CIPD client version tag to use. 69 """ 70 return rctx.read(rctx.attr._cipd_version_file).strip() 71 72def _platform(rctx): 73 """Generates a normalized platform string from the host OS/architecture. 74 75 Args: 76 rctx: Repository context. 77 """ 78 return "{}-{}".format(platform_normalized(rctx), arch_normalized(rctx)) 79 80def get_client_cipd_digest(rctx): 81 """Gets the CIPD client digest from the digest file. 82 83 Args: 84 rctx: Repository context. 85 86 Returns: 87 str: The CIPD client digest. 88 """ 89 platform = _platform(rctx) 90 digest_file = rctx.read(rctx.attr._cipd_digest_file) 91 digest_lines = [ 92 digest 93 for digest in digest_file.splitlines() 94 # Remove comments from version file 95 if not digest.startswith("#") and digest 96 ] 97 98 for line in digest_lines: 99 (digest_platform, digest_type, digest) = \ 100 [element for element in line.split(" ") if element] 101 if digest_platform == platform: 102 if digest_type != "sha256": 103 fail("Bazel only supports sha256 type digests.") 104 return digest 105 fail("Could not find CIPD digest that matches this platform.") 106 107def cipd_client_impl(rctx): 108 """Initializes the CIPD client repository. 109 110 Args: 111 rctx: Repository context. 112 """ 113 platform = _platform(rctx) 114 path = "/client?platform={}&version={}".format( 115 platform, 116 get_client_cipd_version(rctx), 117 ) 118 rctx.download( 119 output = "cipd", 120 url = _CIPD_HOST + path, 121 sha256 = get_client_cipd_digest(rctx), 122 executable = True, 123 ) 124 rctx.file("BUILD", "exports_files([\"cipd\"])") 125 126def cipd_repository_base(rctx): 127 """Populates the base contents of a CIPD repository. 128 129 Args: 130 rctx: Repository context. 131 """ 132 cipd_path = rctx.path(rctx.attr._cipd_client) 133 ensure_path = rctx.name + ".ensure" 134 rctx.template( 135 ensure_path, 136 Label("@pigweed//pw_env_setup/bazel/cipd_setup:ensure.tpl"), 137 { 138 "%{path}": rctx.attr.path, 139 "%{tag}": rctx.attr.tag, 140 }, 141 ) 142 result = rctx.execute([cipd_path, "ensure", "-root", ".", "-ensure-file", ensure_path]) 143 144 if result.return_code != 0: 145 fail("Failed to fetch CIPD repository `{}`:\n{}".format(rctx.name, result.stderr)) 146 147def cipd_repository_impl(rctx): 148 """Generates an external repository from a CIPD package. 149 150 Args: 151 rctx: Repository context. 152 """ 153 cipd_repository_base(rctx) 154 155 # Allow the BUILD file to be overriden in the generated repository. 156 # If unspecified, default to a BUILD file that exposes all of its files. 157 if rctx.attr.build_file: 158 rctx.file("BUILD", rctx.read(rctx.attr.build_file)) 159 elif not rctx.path("BUILD").exists and not rctx.path("BUILD.bazel").exists: 160 rctx.file("BUILD", """ 161exports_files(glob(["**"])) 162 163filegroup( 164 name = "all", 165 srcs = glob(["**"]), 166 visibility = ["//visibility:public"], 167) 168 """) 169 170def _cipd_path_to_repository_name(path, platform): 171 """ Converts a cipd path to a repository name 172 173 Args: 174 path: The cipd path. 175 platform: The cipd platform name. 176 177 Example: 178 print(_cipd_path_to_repository_name( 179 "infra/3pp/tools/cpython3/windows-amd64", 180 "linux-amd64" 181 )) 182 >> cipd_infra_3pp_tools_cpython3_windows_amd64 183 """ 184 return "cipd_" + \ 185 path.replace("/", "_") \ 186 .replace("${platform}", platform) \ 187 .replace("-", "_") 188 189def _cipd_dep_to_cipd_repositories_str(dep, indent): 190 """ Converts a CIPD dependency to a CIPD repositories string 191 192 Args: 193 dep: The CIPD dependency. 194 indent: The indentation to use. 195 """ 196 return "\n".join([CIPD_REPOSITORY_TEMPLATE.format( 197 name = _cipd_path_to_repository_name(dep["path"], platform), 198 path = dep["path"].replace("${platform}", platform), 199 tag = dep["tags"][0], 200 indent = indent, 201 ) for platform in dep["platforms"]]) 202 203def cipd_deps_impl(repository_ctx): 204 """ Generates a CIPD dependencies file """ 205 pigweed_deps = json.decode( 206 repository_ctx.read(repository_ctx.attr._pigweed_packages_json), 207 )["packages"] 208 repository_ctx.file("BUILD", "exports_files(glob([\"**/*\"]))\n") 209 210 repository_ctx.file("cipd_init.bzl", CIPD_INIT_BZL_TEMPLATE.format( 211 cipd_deps = "\n".join([ 212 _cipd_dep_to_cipd_repositories_str(dep, indent = " ") 213 for dep in pigweed_deps 214 ]), 215 )) 216