From febf909428153c24c25e6fc0d0fc5cf7232b4561 Mon Sep 17 00:00:00 2001 From: Jade Lovelace Date: Mon, 14 Jul 2025 11:55:35 -0700 Subject: [PATCH 1/2] flake: add yarn This is useful for the web site. We should probably document how to build the website a little better, but it's mostly okay. --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index a873c1dc19a27..1f4792bafa760 100644 --- a/flake.nix +++ b/flake.nix @@ -38,7 +38,7 @@ # properly find libatomic.so, but harmless elsewhere pkgs.stdenv.cc.cc ]; - packages = [ my-rust-bin pkgs.dotslash pkgs.python3 pkgs.lld_20 pkgs.clang_20 ]; + packages = [ my-rust-bin pkgs.dotslash pkgs.python3 pkgs.lld_20 pkgs.clang_20 pkgs.yarn ]; shellHook = '' export BUCK2_BUILD_PROTOC=${pkgs.protobuf}/bin/protoc From 61104f1e2f484b404553f9a3c2e146ecafec94e4 Mon Sep 17 00:00:00 2001 From: Jade Lovelace Date: Mon, 14 Jul 2025 11:55:35 -0700 Subject: [PATCH 2/2] docs: add a bunch of docs to dynamic outputs There's a bunch of boilerplate due to https://github.com/facebook/buck2/issues/1046. Documents the problem mentioned in https://github.com/facebook/buck2/issues/1041, but a more ideal fix would involve the tool itself handling the mixup for you. Fixes: https://github.com/facebook/buck2/issues/1038 --- .../src/context/dynamic_output.rs | 29 +++++++++++++++++++ .../src/dynamic/attrs_starlark.rs | 19 ++++++++++++ .../src/dynamic/dynamic_actions.rs | 20 ++++++++++++- .../src/dynamic/dynamic_actions_callable.rs | 18 +++++++++++- .../src/dynamic/dynamic_actions_globals.rs | 5 ++++ .../artifact/starlark_output_artifact.rs | 1 + .../src/bxl/starlark_defs/context/dynamic.rs | 5 ++++ 7 files changed, 95 insertions(+), 2 deletions(-) diff --git a/app/buck2_action_impl/src/context/dynamic_output.rs b/app/buck2_action_impl/src/context/dynamic_output.rs index 0919c85385538..9e8c041f09d4c 100644 --- a/app/buck2_action_impl/src/context/dynamic_output.rs +++ b/app/buck2_action_impl/src/context/dynamic_output.rs @@ -202,6 +202,35 @@ pub(crate) fn analysis_actions_methods_dynamic_output(methods: &mut MethodsBuild /// New version of `dynamic_output`. /// /// This is work in progress, and will eventually replace the old `dynamic_output`. + /// In contrast to the old `dynamic_output`, `dynamic_output_new()` allows calling dynamic + /// actions similarly to normal rules as function calls. + /// + /// This function allows defining deferred analysis actions that are executed in the action + /// graph on demand rather than at normal analysis time. Using `dynamic_output_new`, one can + /// write rules which can read the contents of artifacts built by other rules while determining + /// which actions to register. + /// + /// It takes as input a `DynamicActions` obtained from calling a dynamic action defined with + /// [`dynamic_actions()`](../#dynamic_actions) or + /// [`bxl.dynamic_actions()`](../../bxl/#dynamic_actions). + /// + /// This function is typically used in two distinct ways: + /// - Binding an artifact: passing in an unbound artifact to a + /// [`dynattrs.output()`](../dynattrs#output) attr of a dynamic action. That dynamic action is + /// then analyzed at build time when the artifact is required by another rule, then the + /// actions bound to the artifact are executed. In this case, the return value of + /// `dynamic_output_new()` is not used. + /// - Using the returned opaque [`DynamicValue`](../DynamicValue) as input to other dynamic + /// actions' [`dynattrs.dynamic_value()`](../dynattrs/#dynamic_value) attrs. + /// + /// The invoked dynamic actions will be analyzed at build time when a dependency requires them + /// through an artifact bound by [`dynattrs.output()`](../dynattrs#output) or if they are + /// required by other dynamic actions that use the returned `DynamicValue`. + /// + /// See [Dynamic Dependencies](../../../rule_authors/dynamic_dependencies) for an overall + /// overview of dynamic dependencies in buck2. + /// + /// For a guide on using this with BXL, see [How to run actions based on the content of artifacts](../../../bxl/how_tos/how_to_run_actions_based_on_the_content_of_artifact). fn dynamic_output_new<'v>( this: &'v AnalysisActions<'v>, #[starlark(require = pos)] dynamic_actions: ValueTyped<'v, StarlarkDynamicActions<'v>>, diff --git a/app/buck2_action_impl/src/dynamic/attrs_starlark.rs b/app/buck2_action_impl/src/dynamic/attrs_starlark.rs index db163a155f655..f020c9e3416a4 100644 --- a/app/buck2_action_impl/src/dynamic/attrs_starlark.rs +++ b/app/buck2_action_impl/src/dynamic/attrs_starlark.rs @@ -49,26 +49,41 @@ impl<'v> AllocValue<'v> for StarlarkDynamicAttrType { } } +/// Attributes declared for [`dynamic_actions()`](../#dynamic_actions) functions. #[starlark_module] fn struct_dynattrs(globals: &mut GlobalsBuilder) { + /// Unbound output to be bound by this dynamic action. + /// Accepts an [`OutputArtifact`](../OutputArtifact/). + /// + /// The impl function receives an [`OutputArtifact`](../OutputArtifact/) value. fn output() -> starlark::Result { Ok(StarlarkDynamicAttrType { ty: DynamicAttrType::Output, }) } + /// Artifact to use the contents of in this dynamic action. + /// Accepts an [`OutputArtifact`](../OutputArtifact/). + /// + /// The impl function receives an [`ArtifactValue`](../ArtifactValue). fn artifact_value() -> starlark::Result { Ok(StarlarkDynamicAttrType { ty: DynamicAttrType::ArtifactValue, }) } + /// Dynamic value generated by another dynamic action, which is resolved before calling the + /// dynamic action. + /// Accepts a [`DynamicValue`](../DynamicValue/). + /// + /// The impl function receives a [`ResolvedDynamicValue`](../ResolvedDynamicValue/). fn dynamic_value() -> starlark::Result { Ok(StarlarkDynamicAttrType { ty: DynamicAttrType::DynamicValue, }) } + /// Plain value of a given type. fn value<'v>( #[starlark(require = pos)] ty: ValueOf<'v, TypeType>, eval: &mut Evaluator<'v, '_, '_>, @@ -82,6 +97,7 @@ fn struct_dynattrs(globals: &mut GlobalsBuilder) { }) } + /// Takes a list of values and gives a list to the impl function. fn list<'v>( #[starlark(require = pos)] ty: &'v StarlarkDynamicAttrType, ) -> starlark::Result { @@ -91,6 +107,7 @@ fn struct_dynattrs(globals: &mut GlobalsBuilder) { }) } + /// Takes a dict of values and gives it to the impl function. fn dict<'v>( #[starlark(require = pos)] key: ValueOf<'v, TypeType>, #[starlark(require = pos)] value: &'v StarlarkDynamicAttrType, @@ -105,6 +122,7 @@ fn struct_dynattrs(globals: &mut GlobalsBuilder) { }) } + /// Takes a tuple and gives it to the impl function. fn tuple<'v>( #[starlark(args)] args: UnpackTuple<&'v StarlarkDynamicAttrType>, ) -> starlark::Result { @@ -114,6 +132,7 @@ fn struct_dynattrs(globals: &mut GlobalsBuilder) { }) } + /// Takes either a value or `None` and gives it to the impl function. fn option<'v>( #[starlark(require = pos)] ty: &'v StarlarkDynamicAttrType, ) -> starlark::Result { diff --git a/app/buck2_action_impl/src/dynamic/dynamic_actions.rs b/app/buck2_action_impl/src/dynamic/dynamic_actions.rs index a48bb11466069..9383f36be72f3 100644 --- a/app/buck2_action_impl/src/dynamic/dynamic_actions.rs +++ b/app/buck2_action_impl/src/dynamic/dynamic_actions.rs @@ -13,6 +13,10 @@ use std::cell::RefCell; use allocative::Allocative; use buck2_artifact::artifact::artifact_type::OutputArtifact; use starlark::any::ProvidesStaticType; +use starlark::environment::Methods; +use starlark::environment::MethodsBuilder; +use starlark::environment::MethodsStatic; +use starlark::starlark_module; use starlark::values::AllocValue; use starlark::values::FrozenValueTyped; use starlark::values::Heap; @@ -45,7 +49,13 @@ pub(crate) struct StarlarkDynamicActions<'v> { } #[starlark_value(type = "DynamicAction")] -impl<'v> StarlarkValue<'v> for StarlarkDynamicActions<'v> {} +impl<'v> StarlarkValue<'v> for StarlarkDynamicActions<'v> { + // Used to add type documentation to the generated documentation + fn get_methods() -> Option<&'static Methods> { + static RES: MethodsStatic = MethodsStatic::new(); + RES.methods(dynamic_actions_methods) + } +} impl<'v> AllocValue<'v> for StarlarkDynamicActions<'v> { fn alloc_value(self, heap: &'v Heap) -> Value<'v> { @@ -54,3 +64,11 @@ impl<'v> AllocValue<'v> for StarlarkDynamicActions<'v> { heap.alloc_complex_no_freeze(self) } } + +/// Opaque thunk type returned from calling the returned value of a `dynamic_actions` or +/// `bxl.dynamic_actions` invocation. Conceptually, a tuple of (function, args). +/// +/// Must be passed to +/// [`AnalysisActions.dynamic_output_new`](../AnalysisActions#analysisactionsdynamic_output_new). +#[starlark_module] +fn dynamic_actions_methods(builder: &mut MethodsBuilder) {} diff --git a/app/buck2_action_impl/src/dynamic/dynamic_actions_callable.rs b/app/buck2_action_impl/src/dynamic/dynamic_actions_callable.rs index 4c6a11be18e61..eaf1b65f54591 100644 --- a/app/buck2_action_impl/src/dynamic/dynamic_actions_callable.rs +++ b/app/buck2_action_impl/src/dynamic/dynamic_actions_callable.rs @@ -19,10 +19,14 @@ use buck2_build_api::interpreter::rule_defs::provider::ty::abstract_provider::Ab use buck2_error::BuckErrorContext; use dupe::Dupe; use starlark::any::ProvidesStaticType; +use starlark::environment::Methods; +use starlark::environment::MethodsBuilder; +use starlark::environment::MethodsStatic; use starlark::eval::Arguments; use starlark::eval::Evaluator; use starlark::eval::ParametersSpec; use starlark::eval::ParametersSpecParam; +use starlark::starlark_module; use starlark::typing::ParamIsRequired; use starlark::typing::ParamSpec; use starlark::typing::Ty; @@ -92,7 +96,6 @@ enum DynamicActionCallableError { NotExported, } -/// Result of `dynamic_actions` rule invocation. #[derive( Debug, NoSerialize, @@ -164,6 +167,12 @@ impl<'v> StarlarkValue<'v> for DynamicActionsCallable<'v> { impl<'v> StarlarkValue<'v> for FrozenStarlarkDynamicActionsCallable { type Canonical = Self; + // Used to add type documentation to the generated documentation + fn get_methods() -> Option<&'static Methods> { + static RES: MethodsStatic = MethodsStatic::new(); + RES.methods(dynamic_actions_callable_methods) + } + fn invoke( &self, me: Value<'v>, @@ -236,3 +245,10 @@ impl<'v> Freeze for DynamicActionsCallable<'v> { }) } } + +/// Result of `dynamic_actions` or `bxl.dynamic_actions` invocation. +/// +/// When called, becomes a [`DynamicActions`](../DynamicActions) value which can then be passed to +/// [`AnalysisActions.dynamic_output_new`](../AnalysisActions#analysisactionsdynamic_output_new) +#[starlark_module] +fn dynamic_actions_callable_methods(builder: &mut MethodsBuilder) {} diff --git a/app/buck2_action_impl/src/dynamic/dynamic_actions_globals.rs b/app/buck2_action_impl/src/dynamic/dynamic_actions_globals.rs index d2cb403b6d8b8..e95e747f6508c 100644 --- a/app/buck2_action_impl/src/dynamic/dynamic_actions_globals.rs +++ b/app/buck2_action_impl/src/dynamic/dynamic_actions_globals.rs @@ -95,6 +95,11 @@ pub fn new_dynamic_actions_callable<'v>( pub(crate) fn register_dynamic_actions(globals: &mut GlobalsBuilder) { /// Create new dynamic action callable. Returned object will be callable, /// and the result of calling it can be passed to `ctx.actions.dynamic_output_new`. + /// + /// Be aware that the context argument of the called impl function differs between + /// [`dynamic_actions`](../#dynamic_actions) where it is [`actions: AnalysisActions`](../AnalysisActions) + /// and [`bxl.dynamic_actions`](../../bxl/#dynamic_actions) + /// where it is [`bxl_ctx: bxl.Context`](../../bxl/Context). fn dynamic_actions<'v>( #[starlark(require = named)] r#impl: StarlarkCallableChecked< 'v, diff --git a/app/buck2_build_api/src/interpreter/rule_defs/artifact/starlark_output_artifact.rs b/app/buck2_build_api/src/interpreter/rule_defs/artifact/starlark_output_artifact.rs index 9740813802e74..c4d45e2d11969 100644 --- a/app/buck2_build_api/src/interpreter/rule_defs/artifact/starlark_output_artifact.rs +++ b/app/buck2_build_api/src/interpreter/rule_defs/artifact/starlark_output_artifact.rs @@ -197,6 +197,7 @@ impl<'v> CommandLineArgLike<'v> for FrozenStarlarkOutputArtifact { } } +/// The result of calling [`Artifact.as_output()`](../Artifact/#artifactas_output). #[starlark_module] pub(crate) fn register_output_artifact(globals: &mut GlobalsBuilder) { const OutputArtifact: StarlarkValueAsType = StarlarkValueAsType::new(); diff --git a/app/buck2_bxl/src/bxl/starlark_defs/context/dynamic.rs b/app/buck2_bxl/src/bxl/starlark_defs/context/dynamic.rs index 8e0cf68bd47ba..12d9b97bc2431 100644 --- a/app/buck2_bxl/src/bxl/starlark_defs/context/dynamic.rs +++ b/app/buck2_bxl/src/bxl/starlark_defs/context/dynamic.rs @@ -281,6 +281,11 @@ static P_BXLCTX: DynamicActionsCallbackParam = DynamicActionsCallbackParam { 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`. + /// + /// Be aware that the context argument of the called impl function differs between + /// [`dynamic_actions`](../#dynamic_actions) where it is [`actions: AnalysisActions`](../AnalysisActions) + /// and [`bxl.dynamic_actions`](../../bxl/#dynamic_actions) + /// where it is [`bxl_ctx: bxl.Context`](../../bxl/Context). fn dynamic_actions<'v>( #[starlark(require = named)] r#impl: StarlarkCallableChecked< 'v,