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
-----------------