Skip to content

Commit

Permalink
Dynamic actions API for BXL
Browse files Browse the repository at this point in the history
Summary:
RFC:
https://fb.workplace.com/groups/buck2dev/permalink/3826536414301069/

Reviewed By: cjhopman

Differential Revision: D64564006

fbshipit-source-id: b72c736c270c9137147c3f4259c6cfb446daf477
  • Loading branch information
Nero5023 authored and facebook-github-bot committed Nov 1, 2024
1 parent 16be99a commit 9083fba
Show file tree
Hide file tree
Showing 17 changed files with 269 additions and 58 deletions.
5 changes: 3 additions & 2 deletions app/buck2_action_impl/src/dynamic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
*/

pub(crate) mod attrs;
pub(crate) mod attrs_starlark;
pub mod attrs_starlark;
pub mod bxl;
pub mod calculation;
pub mod deferred;
pub(crate) mod dynamic_actions;
pub(crate) mod dynamic_actions_callable;
pub mod dynamic_actions_callable;
pub(crate) mod dynamic_actions_globals;
pub(crate) mod dynamic_value;
pub mod params;
pub(crate) mod resolved_dynamic_value;
pub(crate) mod storage;
pub use dynamic_actions_globals::new_dynamic_actions_callable;
2 changes: 1 addition & 1 deletion app/buck2_action_impl/src/dynamic/attrs_starlark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use crate::dynamic::attrs::DynamicAttrType;
NoSerialize
)]
#[display("{}", ty)]
pub(crate) struct StarlarkDynamicAttrType {
pub struct StarlarkDynamicAttrType {
pub(crate) ty: DynamicAttrType,
}

Expand Down
17 changes: 17 additions & 0 deletions app/buck2_action_impl/src/dynamic/deferred.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ pub enum DynamicLambdaArgs<'v> {
actions: ValueTyped<'v, AnalysisActions<'v>>,
attr_values: Box<[(String, Value<'v>)]>,
},
DynamicActionsBxlNamed {
// cannot import BxlContext because it bxl is depends on this crate
bxl_ctx: Value<'v>,
attr_values: Box<[(String, Value<'v>)]>,
},
}

pub fn invoke_dynamic_output_lambda<'v>(
Expand Down Expand Up @@ -113,6 +118,15 @@ pub fn invoke_dynamic_output_lambda<'v>(
.collect::<Vec<(&str, Value)>>();
(&[], &named)
}
DynamicLambdaArgs::DynamicActionsBxlNamed {
bxl_ctx,
attr_values,
} => {
named = iter::once(("bxl_ctx", bxl_ctx.dupe()))
.chain(attr_values.iter().map(|(k, v)| (k.as_str(), *v)))
.collect::<Vec<(&str, Value)>>();
(&[], &named)
}
};
let return_value = eval
.eval_function(lambda, pos, named)
Expand All @@ -134,6 +148,9 @@ pub fn invoke_dynamic_output_lambda<'v>(
DynamicLambdaArgs::DynamicActionsNamed { .. } => {
ProviderCollection::try_from_value_dynamic_output(return_value)?
}
DynamicLambdaArgs::DynamicActionsBxlNamed { .. } => {
ProviderCollection::try_from_value_dynamic_output(return_value)?
}
};

Ok(provider_collection)
Expand Down
12 changes: 6 additions & 6 deletions app/buck2_action_impl/src/dynamic/dynamic_actions_callable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ use crate::dynamic::attrs::DynamicAttrValues;
use crate::dynamic::dynamic_actions::StarlarkDynamicActions;
use crate::dynamic::dynamic_actions::StarlarkDynamicActionsData;

pub(crate) struct DynamicActionsCallbackParamSpec;
pub struct DynamicActionsCallbackParamSpec;

pub(crate) struct DynamicActionsCallbackParam {
pub(crate) name: &'static str,
pub(crate) ty: LazyLock<Ty>,
pub struct DynamicActionsCallbackParam {
pub name: &'static str,
pub ty: LazyLock<Ty>,
}

pub(crate) static P_ACTIONS: DynamicActionsCallbackParam = DynamicActionsCallbackParam {
Expand All @@ -79,7 +79,7 @@ impl StarlarkCallableParamSpec for DynamicActionsCallbackParamSpec {
}
}

pub(crate) type DynamicActionsCallbackReturnType = ListType<AbstractProvider>;
pub type DynamicActionsCallbackReturnType = ListType<AbstractProvider>;

#[derive(Debug, thiserror::Error)]
enum DynamicActionCallableError {
Expand All @@ -102,7 +102,7 @@ enum DynamicActionCallableError {
"DynamicActionCallable[{}]",
self.name.get().map(|s| s.as_str()).unwrap_or("(unbound)")
)]
pub(crate) struct DynamicActionsCallable<'v> {
pub struct DynamicActionsCallable<'v> {
pub(crate) self_ty: Ty,
pub(crate) implementation:
StarlarkCallable<'v, DynamicActionsCallbackParamSpec, DynamicActionsCallbackReturnType>,
Expand Down
103 changes: 58 additions & 45 deletions app/buck2_action_impl/src/dynamic/dynamic_actions_globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,68 @@ use crate::dynamic::attrs::DynamicAttrType;
use crate::dynamic::attrs_starlark::StarlarkDynamicAttrType;
use crate::dynamic::dynamic_actions::StarlarkDynamicActions;
use crate::dynamic::dynamic_actions_callable::DynamicActionsCallable;
use crate::dynamic::dynamic_actions_callable::DynamicActionsCallbackParam;
use crate::dynamic::dynamic_actions_callable::DynamicActionsCallbackParamSpec;
use crate::dynamic::dynamic_actions_callable::DynamicActionsCallbackReturnType;
use crate::dynamic::dynamic_actions_callable::FrozenStarlarkDynamicActionsCallable;
use crate::dynamic::dynamic_actions_callable::P_ACTIONS;

pub fn new_dynamic_actions_callable<'v>(
r#impl: StarlarkCallableChecked<
'v,
DynamicActionsCallbackParamSpec,
DynamicActionsCallbackReturnType,
>,
attrs: SmallMap<String, &'v StarlarkDynamicAttrType>,
callback_param: &DynamicActionsCallbackParam,
) -> anyhow::Result<DynamicActionsCallable<'v>> {
if attrs.contains_key(callback_param.name) {
return Err(buck2_error_anyhow!([], "Cannot define `actions` attribute"));
}
let attrs: SmallMap<String, DynamicAttrType> = attrs
.into_iter()
.map(|(name, ty)| (name, ty.ty.clone()))
.collect();

let attr_args = attrs
.iter()
.map(|(name, ty)| (name.as_str(), ty.impl_param_ty()))
.collect::<Vec<_>>();

r#impl
.0
.check_callable_with(
[],
iter::once((callback_param.name, &*callback_param.ty))
.chain(attr_args.iter().map(|(name, ty)| (*name, ty))),
None,
None,
&DynamicActionsCallbackReturnType::starlark_type_repr(),
)
.into_anyhow_result()
.context("`impl` function must be callable with given params")?;

let callable_ty = Ty::function(
ParamSpec::new_named_only(attrs.iter().map(|(name, ty)| {
(
ArcStr::from(name.as_str()),
ParamIsRequired::Yes,
ty.callable_param_ty(),
)
}))
.into_anyhow_result()
.internal_error("Signature must be correct")?,
StarlarkDynamicActions::starlark_type_repr(),
);

Ok(DynamicActionsCallable {
self_ty: callable_ty,
implementation: r#impl.to_unchecked(),
name: OnceCell::new(),
attrs,
})
}

#[starlark_module]
pub(crate) fn register_dynamic_actions(globals: &mut GlobalsBuilder) {
/// Create new dynamic action callable. Returned object will be callable,
Expand All @@ -46,51 +103,7 @@ pub(crate) fn register_dynamic_actions(globals: &mut GlobalsBuilder) {
>,
#[starlark(require = named)] attrs: SmallMap<String, &'v StarlarkDynamicAttrType>,
) -> anyhow::Result<DynamicActionsCallable<'v>> {
if attrs.contains_key(P_ACTIONS.name) {
return Err(buck2_error_anyhow!([], "Cannot define `actions` attribute"));
}
let attrs: SmallMap<String, DynamicAttrType> = attrs
.into_iter()
.map(|(name, ty)| (name, ty.ty.clone()))
.collect();

let attr_args = attrs
.iter()
.map(|(name, ty)| (name.as_str(), ty.impl_param_ty()))
.collect::<Vec<_>>();

r#impl
.0
.check_callable_with(
[],
iter::once((P_ACTIONS.name, &*P_ACTIONS.ty))
.chain(attr_args.iter().map(|(name, ty)| (*name, ty))),
None,
None,
&DynamicActionsCallbackReturnType::starlark_type_repr(),
)
.into_anyhow_result()
.context("`impl` function must be callable with given params")?;

let callable_ty = Ty::function(
ParamSpec::new_named_only(attrs.iter().map(|(name, ty)| {
(
ArcStr::from(name.as_str()),
ParamIsRequired::Yes,
ty.callable_param_ty(),
)
}))
.into_anyhow_result()
.internal_error("Signature must be correct")?,
StarlarkDynamicActions::starlark_type_repr(),
);

Ok(DynamicActionsCallable {
self_ty: callable_ty,
implementation: r#impl.to_unchecked(),
name: OnceCell::new(),
attrs,
})
new_dynamic_actions_callable(r#impl, attrs, &P_ACTIONS)
}

const DynamicActions: StarlarkValueAsType<StarlarkDynamicActions> = StarlarkValueAsType::new();
Expand Down
42 changes: 38 additions & 4 deletions app/buck2_bxl/src/bxl/starlark_defs/context/dynamic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,20 @@
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use std::sync::LazyLock;

use buck2_action_impl::dynamic::attrs_starlark::StarlarkDynamicAttrType;
use buck2_action_impl::dynamic::bxl::EVAL_BXL_FOR_DYNAMIC_OUTPUT;
use buck2_action_impl::dynamic::deferred::dynamic_lambda_ctx_data;
use buck2_action_impl::dynamic::deferred::invoke_dynamic_output_lambda;
use buck2_action_impl::dynamic::deferred::DynamicLambdaArgs;
use buck2_action_impl::dynamic::deferred::DynamicLambdaCtxDataSpec;
use buck2_action_impl::dynamic::deferred::InputArtifactsMaterialized;
use buck2_action_impl::dynamic::dynamic_actions_callable::DynamicActionsCallable;
use buck2_action_impl::dynamic::dynamic_actions_callable::DynamicActionsCallbackParam;
use buck2_action_impl::dynamic::dynamic_actions_callable::DynamicActionsCallbackParamSpec;
use buck2_action_impl::dynamic::dynamic_actions_callable::DynamicActionsCallbackReturnType;
use buck2_action_impl::dynamic::new_dynamic_actions_callable;
use buck2_action_impl::dynamic::params::FrozenDynamicLambdaParams;
use buck2_artifact::dynamic::DynamicLambdaResultsKey;
use buck2_build_api::actions::artifact::get_artifact_fs::GetArtifactFs;
Expand All @@ -39,7 +46,12 @@ use buck2_interpreter::starlark_profiler::profiler::StarlarkProfilerOpt;
use dice::DiceComputations;
use dupe::Dupe;
use itertools::Itertools;
use starlark::collections::SmallMap;
use starlark::environment::GlobalsBuilder;
use starlark::environment::Module;
use starlark::starlark_module;
use starlark::values::type_repr::StarlarkTypeRepr;
use starlark::values::typing::StarlarkCallableChecked;
use starlark::values::OwnedRefFrozenRef;
use starlark::values::ValueTyped;

Expand Down Expand Up @@ -206,10 +218,11 @@ impl BxlDynamicOutputEvaluator<'_> {
artifact_values: *artifact_values,
outputs: *outputs,
},
(Some(_arg), DynamicLambdaCtxDataSpec::New { .. }) => {
return Err(anyhow::anyhow!(
"New `dynamic_actions` API is not implemented for BXL"
));
(Some(_arg), DynamicLambdaCtxDataSpec::New { attr_values }) => {
DynamicLambdaArgs::DynamicActionsBxlNamed {
bxl_ctx: ctx.to_value(),
attr_values: attr_values.clone(),
}
}
(None, DynamicLambdaCtxDataSpec::New { .. })
| (Some(_), DynamicLambdaCtxDataSpec::Old { .. }) => {
Expand Down Expand Up @@ -252,3 +265,24 @@ pub(crate) fn init_eval_bxl_for_dynamic_output() {
},
);
}

static P_BXLCTX: DynamicActionsCallbackParam = DynamicActionsCallbackParam {
name: "bxl_ctx",
ty: LazyLock::new(BxlContext::starlark_type_repr),
};

#[starlark_module]
pub(crate) fn register_dynamic_actions(globals: &mut GlobalsBuilder) {
/// Create new bxl dynamic action callable. Returned object will be callable,
/// and the result of calling it can be passed to `ctx.actions.dynamic_output_new`.
fn dynamic_actions<'v>(
#[starlark(require = named)] r#impl: StarlarkCallableChecked<
'v,
DynamicActionsCallbackParamSpec,
DynamicActionsCallbackReturnType,
>,
#[starlark(require = named)] attrs: SmallMap<String, &'v StarlarkDynamicAttrType>,
) -> anyhow::Result<DynamicActionsCallable<'v>> {
new_dynamic_actions_callable(r#impl, attrs, &P_BXLCTX)
}
}
2 changes: 2 additions & 0 deletions app/buck2_bxl/src/bxl/starlark_defs/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use starlark::environment::GlobalsBuilder;
use crate::bxl::starlark_defs::bxl_function::register_bxl_main_function;
use crate::bxl::starlark_defs::bxl_function::register_bxl_prefixed_main_function;
use crate::bxl::starlark_defs::cli_args;
use crate::bxl::starlark_defs::context::dynamic::register_dynamic_actions;
use crate::bxl::starlark_defs::functions::register_artifact_function;
use crate::bxl::starlark_defs::functions::register_error_handling_function;
use crate::bxl::starlark_defs::functions::register_file_set_function;
Expand All @@ -32,6 +33,7 @@ fn bxl_namespace(g: &mut GlobalsBuilder) {
register_instant_function(g);
register_error_handling_function(g);
register_bxl_type_names_in_bxl_namespace(g);
register_dynamic_actions(g);
}

pub(crate) fn init_bxl_specific_globals() {
Expand Down
9 changes: 9 additions & 0 deletions tests/core/bxl/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ buck2_e2e_test(
],
)

buck2_e2e_test(
name = "test_dynamic_new",
srcs = ["test_dynamic_new.py"],
data_dir = "test_dynamic_new_data",
deps = [
"//buck2/tests/e2e_util:utils",
],
)

buck2_e2e_test(
name = "test_typecheck",
srcs = ["test_typecheck.py"],
Expand Down
23 changes: 23 additions & 0 deletions tests/core/bxl/test_dynamic_new.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# This source code is licensed under both the MIT license found in the
# LICENSE-MIT file in the root directory of this source tree and the Apache
# License, Version 2.0 found in the LICENSE-APACHE file in the root directory
# of this source tree.

# pyre-strict

from pathlib import Path

from buck2.tests.e2e_util.api.buck import Buck
from buck2.tests.e2e_util.buck_workspace import buck_test


@buck_test()
async def test_bxl_dynamic_action_basic(buck: Buck) -> None:

result = await buck.bxl(
"//:dynamic.bxl:basic",
)
outputs = result.stdout.strip()
assert Path(outputs).read_text() == "foobar"
10 changes: 10 additions & 0 deletions tests/core/bxl/test_dynamic_new_data/.buckconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[buildfile]
name=TARGETS.fixture

[repositories]
root = .
prelude = prelude
config = config

[build]
execution_platforms = root//platforms:platforms
Empty file.
Loading

0 comments on commit 9083fba

Please sign in to comment.