• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
46# TODO(b/234879770): Enable unused variable check.
47# buildifier: disable=unused-variable
48def arch_normalized(rctx):
49    """Normalizes the architecture string to match CIPDs naming system.
50
51    Args:
52        rctx: Repository context.
53
54    Returns:
55        str: Normalized architecture.
56    """
57
58    # TODO(b/234879770): Find a way to get host architecture information from a
59    # repository context.
60    return "amd64"
61
62def get_client_cipd_version(rctx):
63    """Gets the CIPD client version from the config file.
64
65    Args:
66        rctx: Repository context.
67
68    Returns:
69        str: The CIPD client version tag to use.
70    """
71    return rctx.read(rctx.attr._cipd_version_file).strip()
72
73def _platform(rctx):
74    return "{}-{}".format(platform_normalized(rctx), arch_normalized(rctx))
75
76def get_client_cipd_digest(rctx):
77    """Gets the CIPD client digest from the digest file.
78
79    Args:
80        rctx: Repository context.
81
82    Returns:
83        str: The CIPD client digest.
84    """
85    platform = _platform(rctx)
86    digest_file = rctx.read(rctx.attr._cipd_digest_file)
87    digest_lines = [
88        digest
89        for digest in digest_file.splitlines()
90        # Remove comments from version file
91        if not digest.startswith("#") and digest
92    ]
93
94    for line in digest_lines:
95        (digest_platform, digest_type, digest) = \
96            [element for element in line.split(" ") if element]
97        if digest_platform == platform:
98            if digest_type != "sha256":
99                fail("Bazel only supports sha256 type digests.")
100            return digest
101    fail("Could not find CIPD digest that matches this platform.")
102
103def cipd_client_impl(rctx):
104    platform = _platform(rctx)
105    path = "/client?platform={}&version={}".format(
106        platform,
107        get_client_cipd_version(rctx),
108    )
109    rctx.download(
110        output = "cipd",
111        url = _CIPD_HOST + path,
112        sha256 = get_client_cipd_digest(rctx),
113        executable = True,
114    )
115    rctx.file("BUILD", "exports_files([\"cipd\"])")
116
117def cipd_repository_base(rctx):
118    cipd_path = rctx.path(rctx.attr._cipd_client).basename
119    ensure_path = rctx.name + ".ensure"
120    rctx.template(
121        ensure_path,
122        Label("@pigweed//pw_env_setup/bazel/cipd_setup:ensure.tpl"),
123        {
124            "%{path}": rctx.attr.path,
125            "%{tag}": rctx.attr.tag,
126        },
127    )
128    rctx.execute([cipd_path, "ensure", "-root", ".", "-ensure-file", ensure_path])
129
130def cipd_repository_impl(rctx):
131    cipd_repository_base(rctx)
132    rctx.file("BUILD", """
133exports_files(glob([\"**/*\"]))
134
135filegroup(
136    name = "all",
137    srcs = glob(["**/*"]),
138    visibility = ["//visibility:public"],
139)
140""")
141
142def _cipd_path_to_repository_name(path, platform):
143    """ Converts a cipd path to a repository name
144
145    Args:
146        path: The cipd path.
147        platform: The cipd platform name.
148
149    Example:
150        print(_cipd_path_to_repository_name(
151            "infra/3pp/tools/cpython3/windows-amd64",
152            "linux-amd64"
153        ))
154        >> cipd_infra_3pp_tools_cpython3_windows_amd64
155    """
156    return "cipd_" + \
157           path.replace("/", "_") \
158               .replace("${platform}", platform) \
159               .replace("-", "_")
160
161def _cipd_dep_to_cipd_repositories_str(dep, indent):
162    """ Converts a CIPD dependency to a CIPD repositories string
163
164    Args:
165        dep: The CIPD dependency.
166        indent: The indentation to use.
167    """
168    return "\n".join([CIPD_REPOSITORY_TEMPLATE.format(
169        name = _cipd_path_to_repository_name(dep["path"], platform),
170        path = dep["path"].replace("${platform}", platform),
171        tag = dep["tags"][0],
172        indent = indent,
173    ) for platform in dep["platforms"]])
174
175def cipd_deps_impl(repository_ctx):
176    """ Generates a CIPD dependencies file """
177    pigweed_deps = json.decode(
178        repository_ctx.read(repository_ctx.attr._pigweed_packages_json),
179    )["packages"] + json.decode(
180        repository_ctx.read(repository_ctx.attr._python_packages_json),
181    )["packages"]
182    repository_ctx.file("BUILD", "exports_files(glob([\"**/*\"]))\n")
183
184    repository_ctx.file("cipd_init.bzl", CIPD_INIT_BZL_TEMPLATE.format(
185        cipd_deps = "\n".join([
186            _cipd_dep_to_cipd_repositories_str(dep, indent = "    ")
187            for dep in pigweed_deps
188        ]),
189    ))
190