pw_env_setup: Adds CIPD Bazel rules Adds a set of Bazel rules for fetching the cipd client and downloading CIPD based dependencies as Bazel remote repositories. Change-Id: Id15641be7dcac33ddd4bf17f807d8b7f197078ac Reviewed-on: https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/45140 Reviewed-by: Rob Mohr <mohrr@google.com> Commit-Queue: Rob Mohr <mohrr@google.com> Pigweed-Auto-Submit: Rob Mohr <mohrr@google.com>
diff --git a/pw_env_setup/BUILD b/pw_env_setup/BUILD new file mode 100644 index 0000000..32015da --- /dev/null +++ b/pw_env_setup/BUILD
@@ -0,0 +1,18 @@ +# Copyright 2021 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +exports_files([ + "py/pw_env_setup/cipd_setup/.cipd_version", + "py/pw_env_setup/cipd_setup/.cipd_version.digests", +])
diff --git a/pw_env_setup/bazel/cipd_setup/BUILD b/pw_env_setup/bazel/cipd_setup/BUILD new file mode 100644 index 0000000..e3edb0b --- /dev/null +++ b/pw_env_setup/bazel/cipd_setup/BUILD
@@ -0,0 +1,16 @@ +# Copyright 2021 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +# This file is intentionally left empty, but it is required to mark this +# directory as a package for 'cipd_rules.bzl'.
diff --git a/pw_env_setup/bazel/cipd_setup/cipd_rules.bzl b/pw_env_setup/bazel/cipd_setup/cipd_rules.bzl new file mode 100644 index 0000000..65c2a90 --- /dev/null +++ b/pw_env_setup/bazel/cipd_setup/cipd_rules.bzl
@@ -0,0 +1,73 @@ +# Copyright 2021 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +load( + "//pw_env_setup/bazel/cipd_setup/internal:cipd_internal.bzl", + _cipd_client_impl = "cipd_client_impl", + _cipd_repository_impl = "cipd_repository_impl", +) + +_cipd_client_repository = repository_rule( + _cipd_client_impl, + attrs = { + "_cipd_version_file": attr.label(default = "@pigweed//pw_env_setup:py/pw_env_setup/cipd_setup/.cipd_version"), + "_cipd_digest_file": attr.label(default = "@pigweed//pw_env_setup:py/pw_env_setup/cipd_setup/.cipd_version.digests"), + }, + doc = """ +Fetches the cipd client. + +This rule should not be used directly and instead should be called via +the cipd_client_repository macro. +""", +) + +def cipd_client_repository(): + """Fetches the cipd client. + + Fetches the cipd client to the prescribed remote repository target + prefix 'cipd_client'. This rule should be called before a + cipd_repository rule is instantiated. + """ + _cipd_client_repository( + name = "cipd_client", + ) + +cipd_repository = repository_rule( + _cipd_repository_impl, + attrs = { + "_cipd_client": attr.label(default = "@cipd_client//:cipd"), + "path": attr.string(), + "tag": attr.string(), + }, + doc = """ +Downloads a singular CIPD dependency to the root of a remote repository. + +Example: + + load( + "//pw_env_setup/bazel/cipd_setup:cipd_rules.bzl", + "cipd_client_repository", + "cipd_repository", + ) + + # Must be called before cipd_repository + cipd_client_repository() + + cipd_repository( + name = "bloaty", + path = "pigweed/third_party/bloaty-embedded/${os=linux,mac}-${arch=amd64}", + tag = "git_revision:2d87d204057b419f5290f8d38b61b9c2c5b4fb52-2", + ) +""", +)
diff --git a/pw_env_setup/bazel/cipd_setup/ensure.tpl b/pw_env_setup/bazel/cipd_setup/ensure.tpl new file mode 100644 index 0000000..07e3fd1 --- /dev/null +++ b/pw_env_setup/bazel/cipd_setup/ensure.tpl
@@ -0,0 +1,18 @@ +# Copyright 2021 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. +$VerifiedPlatform linux-amd64 +$VerifiedPlatform mac-amd64 +$ParanoidMode CheckPresence +@Subdir +%{path} %{tag} \ No newline at end of file
diff --git a/pw_env_setup/bazel/cipd_setup/internal/BUILD b/pw_env_setup/bazel/cipd_setup/internal/BUILD new file mode 100644 index 0000000..d3c52e1 --- /dev/null +++ b/pw_env_setup/bazel/cipd_setup/internal/BUILD
@@ -0,0 +1,16 @@ +# Copyright 2021 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +# This file is intentionally left empty to mark this as a package for +# cipd_internal.bzl
diff --git a/pw_env_setup/bazel/cipd_setup/internal/cipd_internal.bzl b/pw_env_setup/bazel/cipd_setup/internal/cipd_internal.bzl new file mode 100644 index 0000000..c328bb3 --- /dev/null +++ b/pw_env_setup/bazel/cipd_setup/internal/cipd_internal.bzl
@@ -0,0 +1,123 @@ +# Copyright 2021 The Pigweed Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may not +# use this file except in compliance with the License. You may obtain a copy of +# the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations under +# the License. + +_CIPD_HOST = "https://chrome-infra-packages.appspot.com" + +def platform_normalized(rctx): + """Normalizes the platform to match CIPDs naming system. + + Args: + rctx: Repository context. + + Returns: + str: Normalized string. + """ + + # Chained if else used because Bazel's rctx.os.name is not stable + # between different versions of windows i.e. windows 10 vs windows + # server. + if "windows" in rctx.os.name: + return "windows" + elif "linux" == rctx.os.name: + return "linux" + elif "mac os x" == rctx.os.name: + return "mac" + else: + fail("Could not normalize os:", rctx.os.name) + +def arch_normalized(rctx): + """Normalizes the architecture string to match CIPDs naming system. + + Args: + rctx: Repository context. + + Returns: + str: Normalized architecture. + """ + + # TODO(pwbug/388): Find a way to get host architecture information from a + # repository context. + return "amd64" + +def get_client_cipd_version(rctx): + """Gets the CIPD client version from the config file. + + Args: + rctx: Repository context. + + Returns: + str: The CIPD client version tag to use. + """ + return rctx.read(rctx.attr._cipd_version_file).strip() + +def _platform(rctx): + return "{}-{}".format(platform_normalized(rctx), arch_normalized(rctx)) + +def get_client_cipd_digest(rctx): + """Gets the CIPD client digest from the digest file. + + Args: + rctx: Repository context. + + Returns: + str: The CIPD client digest. + """ + platform = _platform(rctx) + digest_file = rctx.read(rctx.attr._cipd_digest_file) + digest_lines = [ + digest + for digest in digest_file.splitlines() + # Remove comments from version file + if not digest.startswith("#") and digest + ] + + for line in digest_lines: + (digest_platform, digest_type, digest) = \ + [element for element in line.split(" ") if element] + if digest_platform == platform: + if digest_type != "sha256": + fail("Bazel only supports sha256 type digests.") + return digest + fail("Could not find CIPD digest that matches this platform.") + +def cipd_client_impl(rctx): + platform = _platform(rctx) + path = "/client?platform={}&version={}".format( + platform, + get_client_cipd_version(rctx), + ) + rctx.download( + output = "cipd", + url = _CIPD_HOST + path, + sha256 = get_client_cipd_digest(rctx), + executable = True, + ) + rctx.file("BUILD", "exports_files([\"cipd\"])") + +def cipd_repository_base(rctx): + cipd_path = rctx.path(rctx.attr._cipd_client).basename + ensure_path = rctx.name + ".ensure" + rctx.template( + ensure_path, + Label("@pigweed//pw_env_setup/bazel/cipd_setup:ensure.tpl"), + { + "%{path}": rctx.attr.path, + "%{tag}": rctx.attr.tag, + }, + ) + rctx.execute([cipd_path, "ensure", "-root", ".", "-ensure-file", ensure_path]) + +def cipd_repository_impl(rctx): + cipd_repository_base(rctx) + rctx.file("BUILD", "exports_files(glob([\"**/*\"]))")
diff --git a/pw_env_setup/docs.rst b/pw_env_setup/docs.rst index a3216d2..b392a0c 100644 --- a/pw_env_setup/docs.rst +++ b/pw_env_setup/docs.rst
@@ -91,6 +91,38 @@ pw_bootstrap --args... # See below for details about args. pw_finalize bootstrap "$SETUP_SH" + +Bazel Usage +----------- +It is possible to pull in a CIPD dependency into Bazel using WORKSPACE rules +rather than using `bootstrap.sh`. e.g. + +.. code:: python + + # WORKSPACE + + load( + "@pigweed//pw_env_setup/bazel/cipd_setup:cipd_rules.bzl", + "cipd_client_repository", + "cipd_repository", + ) + + # Must be called before cipd_repository + cipd_client_repository() + + cipd_repository( + name = "bloaty", + path = "pigweed/third_party/bloaty-embedded/${os=linux,mac}-${arch=amd64}", + tag = "git_revision:2d87d204057b419f5290f8d38b61b9c2c5b4fb52-2", + ) + +From here it is possible to get access to the Bloaty binaries using the +following command. + +.. code:: sh + + bazel run @bloaty//:bloaty -- --help + User-Friendliness -----------------