| # Copyright 2024 The Bazel Authors. All rights reserved. |
| # |
| # 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 |
| # |
| # http://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. |
| """Builders to make building complex objects easier.""" |
| |
| load("@bazel_skylib//lib:types.bzl", "types") |
| |
| def _DepsetBuilder(): |
| """Create a builder for a depset.""" |
| |
| # buildifier: disable=uninitialized |
| self = struct( |
| _order = [None], |
| add = lambda *a, **k: _DepsetBuilder_add(self, *a, **k), |
| build = lambda *a, **k: _DepsetBuilder_build(self, *a, **k), |
| direct = [], |
| get_order = lambda *a, **k: _DepsetBuilder_get_order(self, *a, **k), |
| set_order = lambda *a, **k: _DepsetBuilder_set_order(self, *a, **k), |
| transitive = [], |
| ) |
| return self |
| |
| def _DepsetBuilder_add(self, *values): |
| """Add value to the depset. |
| |
| Args: |
| self: {type}`DepsetBuilder` implicitly added. |
| *values: {type}`depset | list | object` Values to add to the depset. |
| The values can be a depset, the non-depset value to add, or |
| a list of such values to add. |
| |
| Returns: |
| {type}`DepsetBuilder` |
| """ |
| for value in values: |
| if types.is_list(value): |
| for sub_value in value: |
| if types.is_depset(sub_value): |
| self.transitive.append(sub_value) |
| else: |
| self.direct.append(sub_value) |
| elif types.is_depset(value): |
| self.transitive.append(value) |
| else: |
| self.direct.append(value) |
| return self |
| |
| def _DepsetBuilder_set_order(self, order): |
| """Sets the order to use. |
| |
| Args: |
| self: {type}`DepsetBuilder` implicitly added. |
| order: {type}`str` One of the {obj}`depset` `order` values. |
| |
| Returns: |
| {type}`DepsetBuilder` |
| """ |
| self._order[0] = order |
| return self |
| |
| def _DepsetBuilder_get_order(self): |
| """Gets the depset order that will be used. |
| |
| Args: |
| self: {type}`DepsetBuilder` implicitly added. |
| |
| Returns: |
| {type}`str | None` If not previously set, `None` is returned. |
| """ |
| return self._order[0] |
| |
| def _DepsetBuilder_build(self): |
| """Creates a {obj}`depset` from the accumulated values. |
| |
| Args: |
| self: {type}`DepsetBuilder` implicitly added. |
| |
| Returns: |
| {type}`depset` |
| """ |
| if not self.direct and len(self.transitive) == 1 and self._order[0] == None: |
| return self.transitive[0] |
| else: |
| kwargs = {} |
| if self._order[0] != None: |
| kwargs["order"] = self._order[0] |
| return depset(direct = self.direct, transitive = self.transitive, **kwargs) |
| |
| def _RunfilesBuilder(): |
| """Creates a `RunfilesBuilder`. |
| |
| Returns: |
| {type}`RunfilesBuilder` |
| """ |
| |
| # buildifier: disable=uninitialized |
| self = struct( |
| add = lambda *a, **k: _RunfilesBuilder_add(self, *a, **k), |
| add_targets = lambda *a, **k: _RunfilesBuilder_add_targets(self, *a, **k), |
| build = lambda *a, **k: _RunfilesBuilder_build(self, *a, **k), |
| files = _DepsetBuilder(), |
| root_symlinks = {}, |
| runfiles = [], |
| symlinks = {}, |
| ) |
| return self |
| |
| def _RunfilesBuilder_add(self, *values): |
| """Adds a value to the runfiles. |
| |
| Args: |
| self: {type}`RunfilesBuilder` implicitly added. |
| *values: {type}`File | runfiles | list[File] | depset[File] | list[runfiles]` |
| The values to add. |
| |
| Returns: |
| {type}`RunfilesBuilder` |
| """ |
| for value in values: |
| if types.is_list(value): |
| for sub_value in value: |
| _RunfilesBuilder_add_internal(self, sub_value) |
| else: |
| _RunfilesBuilder_add_internal(self, value) |
| return self |
| |
| def _RunfilesBuilder_add_targets(self, targets): |
| """Adds runfiles from targets |
| |
| Args: |
| self: {type}`RunfilesBuilder` implicitly added. |
| targets: {type}`list[Target]` targets whose default runfiles |
| to add. |
| |
| Returns: |
| {type}`RunfilesBuilder` |
| """ |
| for t in targets: |
| self.runfiles.append(t[DefaultInfo].default_runfiles) |
| return self |
| |
| def _RunfilesBuilder_add_internal(self, value): |
| if _is_file(value): |
| self.files.add(value) |
| elif types.is_depset(value): |
| self.files.add(value) |
| elif _is_runfiles(value): |
| self.runfiles.append(value) |
| else: |
| fail("Unhandled value: type {}: {}".format(type(value), value)) |
| |
| def _RunfilesBuilder_build(self, ctx, **kwargs): |
| """Creates a {obj}`runfiles` from the accumulated values. |
| |
| Args: |
| self: {type}`RunfilesBuilder` implicitly added. |
| ctx: {type}`ctx` The rule context to use to create the runfiles object. |
| **kwargs: additional args to pass along to {obj}`ctx.runfiles`. |
| |
| Returns: |
| {type}`runfiles` |
| """ |
| return ctx.runfiles( |
| transitive_files = self.files.build(), |
| symlinks = self.symlinks, |
| root_symlinks = self.root_symlinks, |
| **kwargs |
| ).merge_all(self.runfiles) |
| |
| # Skylib's types module doesn't have is_file, so roll our own |
| def _is_file(value): |
| return type(value) == "File" |
| |
| def _is_runfiles(value): |
| return type(value) == "runfiles" |
| |
| builders = struct( |
| DepsetBuilder = _DepsetBuilder, |
| RunfilesBuilder = _RunfilesBuilder, |
| ) |