Skip to content

Commit 029a126

Browse files
Nero5023facebook-github-bot
authored andcommitted
Add bxl.SelectConcat
Summary: rfc: https://fb.workplace.com/groups/buck2dev/permalink/3882274572060586/ https://fb.workplace.com/groups/buck2dev/permalink/3887456818209028/ Reviewed By: JakobDegen Differential Revision: D67996832 fbshipit-source-id: bb41c849172d25551bd0e674d12d20d73aebf553
1 parent 425fd2c commit 029a126

File tree

6 files changed

+155
-5
lines changed

6 files changed

+155
-5
lines changed

app/buck2_bxl/src/bxl/starlark_defs/nodes/unconfigured/attribute.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ use buck2_interpreter::types::configured_providers_label::StarlarkConfiguredProv
2222
use buck2_interpreter::types::configured_providers_label::StarlarkProvidersLabel;
2323
use buck2_interpreter::types::opaque_metadata::OpaqueMetadata;
2424
use buck2_interpreter::types::target_label::StarlarkTargetLabel;
25-
use buck2_interpreter_for_build::interpreter::selector::StarlarkSelector;
2625
use buck2_node::attrs::coerced_attr::CoercedAttr;
2726
use buck2_node::attrs::display::AttrDisplayWithContext;
2827
use buck2_node::attrs::fmt_context::AttrFmtContext;
@@ -53,6 +52,7 @@ use starlark::values::StarlarkValue;
5352
use starlark::values::Value;
5453
use starlark_map::small_map::SmallMap;
5554

55+
use crate::bxl::starlark_defs::select::StarlarkSelectConcat;
5656
use crate::bxl::starlark_defs::select::StarlarkSelectDict;
5757

5858
#[derive(Debug, ProvidesStaticType, From, Allocative)]
@@ -239,10 +239,7 @@ impl CoercedAttrExt for CoercedAttr {
239239
let select_dict = StarlarkSelectDict::new(*selector.clone(), pkg.dupe());
240240
heap.alloc(select_dict)
241241
}
242-
CoercedAttr::Concat(l) => {
243-
let list = l.as_ref().try_map(|attr| attr.to_value(pkg.dupe(), heap))?;
244-
StarlarkSelector::from_concat(list, heap)?
245-
}
242+
CoercedAttr::Concat(c) => heap.alloc(StarlarkSelectConcat::new(c.clone(), pkg.dupe())),
246243
})
247244
}
248245
}

app/buck2_bxl/src/bxl/starlark_defs/select.rs

+112
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use allocative::Allocative;
1111
use buck2_core::package::PackageLabel;
1212
use buck2_interpreter::types::configured_providers_label::StarlarkProvidersLabel;
13+
use buck2_node::attrs::coerced_attr::CoercedConcat;
1314
use buck2_node::attrs::coerced_attr::CoercedSelector;
1415
use buck2_node::attrs::coerced_attr::CoercedSelectorKeyRef;
1516
use buck2_node::attrs::display::AttrDisplayWithContext;
@@ -216,3 +217,114 @@ fn select_dict_methods(builder: &mut MethodsBuilder) {
216217
Ok(this.get(key, heap)?)
217218
}
218219
}
220+
221+
#[derive(ProvidesStaticType, Derivative, Trace, Allocative, Clone, Debug)]
222+
pub(crate) struct StarlarkSelectConcat {
223+
concat: CoercedConcat,
224+
pkg: PackageLabel,
225+
}
226+
227+
impl StarlarkSelectConcat {
228+
pub(crate) fn new(concat: CoercedConcat, pkg: PackageLabel) -> Self {
229+
Self { concat, pkg }
230+
}
231+
}
232+
233+
impl Serialize for StarlarkSelectConcat {
234+
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
235+
where
236+
S: Serializer,
237+
{
238+
let ctx = AttrFmtContext {
239+
package: Some(self.pkg),
240+
options: Default::default(),
241+
};
242+
self.concat.serialize_with_ctx(&ctx, serializer)
243+
}
244+
}
245+
246+
impl Display for StarlarkSelectConcat {
247+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
248+
let ctx = AttrFmtContext {
249+
package: Some(self.pkg),
250+
options: Default::default(),
251+
};
252+
self.concat.fmt(&ctx, f)
253+
}
254+
}
255+
256+
starlark_simple_value!(StarlarkSelectConcat);
257+
258+
#[starlark_value(type = "bxl.SelectConcat")]
259+
impl<'v> StarlarkValue<'v> for StarlarkSelectConcat {
260+
fn get_methods() -> Option<&'static Methods> {
261+
static RES: MethodsStatic = MethodsStatic::new();
262+
RES.methods(select_concat_methods)
263+
}
264+
265+
fn length(&self) -> starlark::Result<i32> {
266+
Ok(self.concat.0.len() as i32)
267+
}
268+
}
269+
270+
/// In bxl, `Select = bxl.SelectDict | bxl.SelectConcat`. `bxl.SelectConcat` is a list-like object that represents a select.
271+
/// One example of this type is:
272+
/// ```
273+
/// ["--flags"] + select({
274+
// "root//constraints:a": ["--foo"],
275+
// "root//constraints:b": ["--bar"],
276+
// "DEFAULT": ["baz"]
277+
// })
278+
/// ```
279+
/// You can:
280+
/// * Iterate over the values of this object (e.g. `for item in select_concat.select_iter():`)
281+
/// * Get the length (e.g. `len(select_concat)`)
282+
/// * Check its type using `isinstance(select_concat, bxl.SelectConcat)`.
283+
///
284+
/// Simple usage:
285+
/// ```python
286+
/// def _impl_select_concat(ctx):
287+
/// node = ctx.lazy.unconfigured_target_node("root//:select_concat").resolve()
288+
/// attr = node.get_attr("select_attr")
289+
/// for value in attr:
290+
/// if isinstance(value, bxl.SelectDict):
291+
/// for key, value in value.items():
292+
/// ctx.output.print(f"{key} -> {value}")
293+
/// else:
294+
/// ctx.output.print(value)
295+
/// ctx.output.print(attr[0])
296+
/// ```
297+
#[starlark_module]
298+
fn select_concat_methods(builder: &mut MethodsBuilder) {
299+
/// Return the values of the SelectConcat.
300+
///
301+
/// Sample usage:
302+
/// ```python
303+
/// def _impl_select_concat(ctx):
304+
/// node = ctx.lazy.unconfigured_target_node("root//:select_concat").resolve()
305+
/// attr = node.get_attr("select_attr")
306+
/// for value in attr.select_iter():
307+
/// ctx.output.print(value)
308+
/// ```
309+
fn select_iter<'v>(
310+
this: &'v StarlarkSelectConcat,
311+
heap: &'v Heap,
312+
) -> anyhow::Result<Vec<Value<'v>>> {
313+
let list = this
314+
.concat
315+
.iter()
316+
.map(|a| a.to_value(this.pkg.dupe(), heap))
317+
.collect::<buck2_error::Result<_>>()?;
318+
Ok(list)
319+
}
320+
321+
/// Returns the length of a SelectConcat, defined as the number of items being concatenated
322+
/// at the select level (not the total number of elements across all lists).
323+
///
324+
/// For example, `[1, 2] + select({"DEFAULT": [3, 4]}` returns 2 instead of 4.
325+
/// Note: You can use `len()` to get the length too.
326+
#[starlark(attribute)]
327+
fn length(this: &StarlarkSelectConcat) -> starlark::Result<i32> {
328+
Ok(this.concat.0.len() as i32)
329+
}
330+
}

app/buck2_bxl/src/bxl/starlark_defs/type_names.rs

+2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ use crate::bxl::starlark_defs::nodes::configured::StarlarkLazyResolvedAttrs;
3737
use crate::bxl::starlark_defs::nodes::unconfigured::StarlarkTargetNode;
3838
use crate::bxl::starlark_defs::result::StarlarkError;
3939
use crate::bxl::starlark_defs::result::StarlarkResult;
40+
use crate::bxl::starlark_defs::select::StarlarkSelectConcat;
4041
use crate::bxl::starlark_defs::select::StarlarkSelectDict;
4142
use crate::bxl::starlark_defs::target_universe::StarlarkTargetUniverse;
4243
use crate::bxl::starlark_defs::targetset::StarlarkTargetSet;
@@ -78,4 +79,5 @@ pub(crate) fn register_bxl_type_names_in_bxl_namespace(globals: &mut GlobalsBuil
7879
const LazyCqueryContext: StarlarkValueAsType<StarlarkLazyCqueryCtx> =
7980
StarlarkValueAsType::new();
8081
const SelectDict: StarlarkValueAsType<StarlarkSelectDict> = StarlarkValueAsType::new();
82+
const SelectConcat: StarlarkValueAsType<StarlarkSelectConcat> = StarlarkValueAsType::new();
8183
}

tests/core/bxl/test_selector_concat_dict.py

+7
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,10 @@ async def test_selector_dict_attr(buck: Buck) -> None:
2121
await buck.bxl(
2222
"//:selector_concat_dict.bxl:selector_dict_attr",
2323
)
24+
25+
26+
@buck_test()
27+
async def test_selector_concat_attr(buck: Buck) -> None:
28+
await buck.bxl(
29+
"//:selector_concat_dict.bxl:selector_concat_attr",
30+
)

tests/core/bxl/test_selector_concat_dict_data/selector_concat_dict.bxl

+27
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,30 @@ selector_dict_attr = bxl_main(
5757
impl = _selector_dict_attr,
5858
cli_args = {},
5959
)
60+
61+
def _selector_concat_attr(ctx):
62+
node = ctx.lazy.unconfigured_target_node("root//:select_concat").resolve()
63+
flags = node.get_attr("flags")
64+
65+
asserts.true(isinstance(flags, bxl.SelectConcat))
66+
asserts.equals(str(flags), '["--flag", "--baz"]+select({"root//constraints:macos": ["--foo-macos", "--bar-macos"], "root//constraints:x86": ["--foo-x86", "--bar-x86"], "DEFAULT": ["--foo", "--bar"]})')
67+
68+
# test for iterator
69+
for v in flags.select_iter():
70+
if isinstance(v, bxl.SelectDict):
71+
asserts.equals(str(v), 'select({"root//constraints:macos": ["--foo-macos", "--bar-macos"], "root//constraints:x86": ["--foo-x86", "--bar-x86"], "DEFAULT": ["--foo", "--bar"]})')
72+
for key, val in v.select_items():
73+
print(key)
74+
print(val)
75+
else:
76+
asserts.true(isinstance(v, list))
77+
asserts.equals(v, ["--flag", "--baz"])
78+
79+
asserts.equals(len(flags), 2)
80+
asserts.equals(flags.select_iter()[0], ["--flag", "--baz"])
81+
asserts.true(isinstance(flags.select_iter()[1], bxl.SelectDict))
82+
83+
selector_concat_attr = bxl_main(
84+
impl = _selector_concat_attr,
85+
cli_args = {},
86+
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# This file is @generated, regenerate by re-running test with `-- --env BUCK2_UPDATE_GOLDEN=1` appended to the test command
2+
3+
# SelectConcat
4+
## SelectConcat.length
5+
## SelectConcat.select\_iter

0 commit comments

Comments
 (0)