blob: 50aa3ed91aff1126ec7fdded5db0a110a5d269e2 [file] [log] [blame]
# 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,
)