use std::future::IntoFuture;
use futures::{future::LocalBoxFuture, FutureExt};
use interruptible::Interruptibility;
use own::{OwnedOrMutRef, OwnedOrRef};
use peace_flow_rt::Flow;
use peace_item_model::ItemId;
use peace_params::{ParamsSpecs, ParamsValue};
use peace_resource_rt::{
internal::{FlowParamsFile, ProfileParamsFile, WorkspaceParamsFile},
paths::{FlowDir, ParamsSpecsFile, ProfileDir, ProfileHistoryDir, StatesCurrentFile},
resources::ts::Empty,
Resources,
};
use peace_rt_model::{
params::{FlowParamsOpt, ProfileParamsOpt, WorkspaceParamsOpt},
ParamsSpecsSerializer, Workspace, WorkspaceInitializer,
};
use peace_state_rt::StatesSerializer;
use type_reg::untagged::TypeReg;
use typed_builder::TypedBuilder;
use crate::{CmdCtxBuilderSupport, CmdCtxSpsf, CmdCtxSpsfFields, CmdCtxTypes, ProfileSelection};
#[derive(Debug, TypedBuilder)]
#[builder(build_method(vis="", name=build_partial))]
pub struct CmdCtxSpsfParams<'ctx, CmdCtxTypesT>
where
CmdCtxTypesT: CmdCtxTypes,
{
#[builder(setter(prefix = "with_"))]
pub output: OwnedOrMutRef<'ctx, CmdCtxTypesT::Output>,
#[builder(setter(prefix = "with_"), default = Interruptibility::NonInterruptible)]
pub interruptibility: Interruptibility<'static>,
#[builder(setter(prefix = "with_"))]
pub workspace: OwnedOrRef<'ctx, Workspace>,
#[builder(setter(prefix = "with_"))]
pub profile_selection: ProfileSelection<'ctx, CmdCtxTypesT::WorkspaceParamsKey>,
#[builder(setter(prefix = "with_"))]
pub flow: OwnedOrRef<'ctx, Flow<CmdCtxTypesT::AppError>>,
#[builder(
setter(prefix = "with_"),
via_mutators(init = WorkspaceParamsOpt::default()),
mutators(
/// Sets the value at the given workspace params key.
///
/// # Parameters
///
/// * `key`: The key to store the given value against.
/// * `value`: The value to store at the given key. This is an
/// `Option` so that you may remove a value if desired.
///
/// # Type Parameters
///
/// * `V`: The serializable type stored at the given key.
pub fn with_workspace_param<V>(
&mut self,
key: CmdCtxTypesT::WorkspaceParamsKey,
value: Option<V>,
)
where
V: ParamsValue,
{
let _ = self.workspace_params.insert(key, value);
}
)
)]
#[builder(setter(prefix = "with_"))]
pub workspace_params: WorkspaceParamsOpt<<CmdCtxTypesT as CmdCtxTypes>::WorkspaceParamsKey>,
#[builder(
setter(prefix = "with_"),
via_mutators(init = ProfileParamsOpt::default()),
mutators(
/// Sets the value at the given profile params key.
///
/// # Parameters
///
/// * `key`: The key to store the given value against.
/// * `value`: The value to store at the given key. This is an
/// `Option` so that you may remove a value if desired.
///
/// # Type Parameters
///
/// * `V`: The serializable type stored at the given key.
pub fn with_profile_param<V>(
&mut self,
key: CmdCtxTypesT::ProfileParamsKey,
value: Option<V>,
)
where
V: ParamsValue,
{
let _ = self.profile_params.insert(key, value);
}
)
)]
pub profile_params: ProfileParamsOpt<<CmdCtxTypesT as CmdCtxTypes>::ProfileParamsKey>,
#[builder(
setter(prefix = "with_"),
via_mutators(init = FlowParamsOpt::default()),
mutators(
/// Sets the value at the given flow params key.
///
/// # Parameters
///
/// * `key`: The key to store the given value against.
/// * `value`: The value to store at the given key. This is an
/// `Option` so that you may remove a value if desired.
///
/// # Type Parameters
///
/// * `V`: The serializable type stored at the given key.
pub fn with_flow_param<V>(
&mut self,
key: CmdCtxTypesT::FlowParamsKey,
value: Option<V>,
)
where
V: ParamsValue,
{
let _ = self.flow_params.insert(key, value);
}
)
)]
pub flow_params: FlowParamsOpt<<CmdCtxTypesT as CmdCtxTypes>::FlowParamsKey>,
#[builder(
setter(prefix = "with_"),
via_mutators(init = ParamsSpecs::new()),
mutators(
/// Sets an item's parameters.
///
/// Note: this **must** be called for each item in the flow.
pub fn with_item_params<I>(
&mut self,
item_id: ItemId,
params_spec: <I::Params<'_> as peace_params::Params>::Spec,
)
where
I: peace_cfg::Item,
CmdCtxTypesT::AppError: From<I::Error>,
{
self.params_specs.insert(item_id, params_spec);
}
)
)]
pub params_specs: ParamsSpecs,
#[builder(
setter(prefix = "with_"),
via_mutators(init = Resources::<Empty>::new()),
mutators(
/// Adds an object to the in-memory resources.
pub fn with_resource<R>(
&mut self,
resource: R,
)
where
R: peace_resource_rt::Resource,
{
self.resources.insert(resource);
}
)
)]
pub resources: Resources<Empty>,
}
#[allow(non_camel_case_types)]
impl<
'ctx,
CmdCtxTypesT,
__interruptibility: ::typed_builder::Optional<Interruptibility<'static>>,
>
CmdCtxSpsfParamsBuilder<
'ctx,
CmdCtxTypesT,
(
(OwnedOrMutRef<'ctx, CmdCtxTypesT::Output>,),
__interruptibility,
(OwnedOrRef<'ctx, Workspace>,),
(ProfileSelection<'ctx, CmdCtxTypesT::WorkspaceParamsKey>,),
(OwnedOrRef<'ctx, Flow<CmdCtxTypesT::AppError>>,),
(WorkspaceParamsOpt<<CmdCtxTypesT as CmdCtxTypes>::WorkspaceParamsKey>,),
(ProfileParamsOpt<<CmdCtxTypesT as CmdCtxTypes>::ProfileParamsKey>,),
(FlowParamsOpt<<CmdCtxTypesT as CmdCtxTypes>::FlowParamsKey>,),
(ParamsSpecs,),
(Resources<Empty>,),
),
>
where
CmdCtxTypesT: CmdCtxTypes,
{
pub async fn build(self) -> Result<CmdCtxSpsf<'ctx, CmdCtxTypesT>, CmdCtxTypesT::AppError> {
let CmdCtxSpsfParams {
output,
interruptibility,
workspace,
profile_selection,
flow,
workspace_params: workspace_params_provided,
profile_params: profile_params_provided,
flow_params: flow_params_provided,
params_specs: params_specs_provided,
resources: resources_override,
} = self.build_partial();
let mut workspace_params_type_reg = TypeReg::new();
CmdCtxTypesT::workspace_params_register(&mut workspace_params_type_reg);
let mut profile_params_type_reg = TypeReg::new();
CmdCtxTypesT::profile_params_register(&mut profile_params_type_reg);
let mut flow_params_type_reg = TypeReg::new();
CmdCtxTypesT::flow_params_register(&mut flow_params_type_reg);
let workspace_dirs = workspace.dirs();
let storage = workspace.storage();
let workspace_params_file = WorkspaceParamsFile::from(workspace_dirs.peace_app_dir());
let workspace_params = CmdCtxBuilderSupport::workspace_params_merge(
storage,
&workspace_params_type_reg,
workspace_params_provided,
&workspace_params_file,
)
.await?;
let profile = CmdCtxBuilderSupport::profile_from_profile_selection(
profile_selection,
&workspace_params,
storage,
&workspace_params_file,
)
.await?;
let profile_ref = &profile;
let profile_dir = ProfileDir::from((workspace_dirs.peace_app_dir(), profile_ref));
let profile_history_dir = ProfileHistoryDir::from(&profile_dir);
let flow_dir = FlowDir::from((&profile_dir, flow.flow_id()));
let dirs_to_create = [
AsRef::<std::path::Path>::as_ref(workspace_dirs.workspace_dir()),
AsRef::<std::path::Path>::as_ref(workspace_dirs.peace_dir()),
AsRef::<std::path::Path>::as_ref(workspace_dirs.peace_app_dir()),
AsRef::<std::path::Path>::as_ref(&profile_dir),
AsRef::<std::path::Path>::as_ref(&profile_history_dir),
AsRef::<std::path::Path>::as_ref(&flow_dir),
];
let storage = workspace.storage();
let profile_params_file = ProfileParamsFile::from(&profile_dir);
let profile_params = CmdCtxBuilderSupport::profile_params_merge(
storage,
&profile_params_type_reg,
profile_params_provided,
&profile_params_file,
)
.await?;
let flow_params_file = FlowParamsFile::from(&flow_dir);
let flow_params = CmdCtxBuilderSupport::flow_params_merge(
storage,
&flow_params_type_reg,
flow_params_provided,
&flow_params_file,
)
.await?;
#[cfg(target_arch = "wasm32")]
{
WorkspaceInitializer::dirs_create(storage, dirs_to_create).await?;
}
#[cfg(not(target_arch = "wasm32"))]
{
WorkspaceInitializer::dirs_create(dirs_to_create).await?;
let workspace_dir = workspace_dirs.workspace_dir();
std::env::set_current_dir(workspace_dir).map_err(
#[cfg_attr(coverage_nightly, coverage(off))]
|error| {
peace_rt_model::Error::Native(peace_rt_model::NativeError::CurrentDirSet {
workspace_dir: workspace_dir.clone(),
error,
})
},
)?;
}
let interruptibility_state = interruptibility.into();
CmdCtxBuilderSupport::workspace_params_serialize(
&workspace_params,
storage,
&workspace_params_file,
)
.await?;
CmdCtxBuilderSupport::profile_params_serialize(
&profile_params,
storage,
&profile_params_file,
)
.await?;
CmdCtxBuilderSupport::flow_params_serialize(&flow_params, storage, &flow_params_file)
.await?;
let mut resources = peace_resource_rt::Resources::new();
CmdCtxBuilderSupport::workspace_params_insert(workspace_params.clone(), &mut resources);
resources.insert(workspace_params_file);
CmdCtxBuilderSupport::profile_params_insert(profile_params.clone(), &mut resources);
resources.insert(profile_params_file);
CmdCtxBuilderSupport::flow_params_insert(flow_params.clone(), &mut resources);
resources.insert(flow_params_file);
{
let (app_name, workspace_dirs, storage) = (*workspace).clone().into_inner();
let (workspace_dir, peace_dir, peace_app_dir) = workspace_dirs.into_inner();
resources.insert(app_name);
resources.insert(storage);
resources.insert(workspace_dir);
resources.insert(peace_dir);
resources.insert(peace_app_dir);
resources.insert(profile_dir.clone());
resources.insert(profile_history_dir.clone());
resources.insert(profile.clone());
resources.insert(flow_dir.clone());
resources.insert(flow.flow_id().clone());
}
let flow_ref = &flow;
let flow_id = flow_ref.flow_id();
let item_graph = flow_ref.graph();
let (params_specs_type_reg, states_type_reg) =
CmdCtxBuilderSupport::params_and_states_type_reg(item_graph);
let params_specs_type_reg_ref = ¶ms_specs_type_reg;
let params_specs_file = ParamsSpecsFile::from(&flow_dir);
let params_specs_stored = ParamsSpecsSerializer::<peace_rt_model::Error>::deserialize_opt(
&profile,
flow_id,
storage,
params_specs_type_reg_ref,
¶ms_specs_file,
)
.await?;
let params_specs = CmdCtxBuilderSupport::params_specs_merge(
flow_ref,
params_specs_provided,
params_specs_stored,
)?;
CmdCtxBuilderSupport::params_specs_serialize(¶ms_specs, storage, ¶ms_specs_file)
.await?;
let states_type_reg_ref = &states_type_reg;
let states_current_file = StatesCurrentFile::from(&flow_dir);
let states_current_stored =
StatesSerializer::<peace_rt_model::Error>::deserialize_stored_opt(
flow_id,
storage,
states_type_reg_ref,
&states_current_file,
)
.await?;
if let Some(states_current_stored) = states_current_stored {
resources.insert(states_current_stored);
}
let mut resources = CmdCtxBuilderSupport::item_graph_setup(item_graph, resources).await?;
#[cfg(feature = "output_progress")]
let cmd_progress_tracker = {
let multi_progress =
indicatif::MultiProgress::with_draw_target(indicatif::ProgressDrawTarget::hidden());
let progress_trackers = item_graph.iter_insertion().fold(
peace_rt_model::IndexMap::with_capacity(item_graph.node_count()),
|mut progress_trackers, item| {
let progress_bar = multi_progress.add(indicatif::ProgressBar::hidden());
let progress_tracker = peace_progress_model::ProgressTracker::new(progress_bar);
progress_trackers.insert(item.id().clone(), progress_tracker);
progress_trackers
},
);
peace_rt_model::CmdProgressTracker::new(multi_progress, progress_trackers)
};
resources.merge(resources_override.into_inner());
#[cfg(feature = "item_state_example")]
{
let () = flow.graph().iter().try_for_each(|item| {
let _state_example = item.state_example(¶ms_specs, &resources)?;
Ok::<_, CmdCtxTypesT::AppError>(())
})?;
}
let cmd_ctx_spsf = CmdCtxSpsf {
output,
#[cfg(feature = "output_progress")]
cmd_progress_tracker,
fields: CmdCtxSpsfFields {
interruptibility_state,
workspace,
profile,
profile_dir,
profile_history_dir,
flow,
flow_dir,
workspace_params_type_reg,
workspace_params,
profile_params_type_reg,
profile_params,
flow_params_type_reg,
flow_params,
params_specs_type_reg,
params_specs,
states_type_reg,
resources,
},
};
Ok(cmd_ctx_spsf)
}
}
#[allow(non_camel_case_types)]
impl<
'ctx,
CmdCtxTypesT,
__interruptibility: ::typed_builder::Optional<Interruptibility<'static>> + 'ctx,
> IntoFuture
for CmdCtxSpsfParamsBuilder<
'ctx,
CmdCtxTypesT,
(
(OwnedOrMutRef<'ctx, CmdCtxTypesT::Output>,),
__interruptibility,
(OwnedOrRef<'ctx, Workspace>,),
(ProfileSelection<'ctx, CmdCtxTypesT::WorkspaceParamsKey>,),
(OwnedOrRef<'ctx, Flow<CmdCtxTypesT::AppError>>,),
(WorkspaceParamsOpt<<CmdCtxTypesT as CmdCtxTypes>::WorkspaceParamsKey>,),
(ProfileParamsOpt<<CmdCtxTypesT as CmdCtxTypes>::ProfileParamsKey>,),
(FlowParamsOpt<<CmdCtxTypesT as CmdCtxTypes>::FlowParamsKey>,),
(ParamsSpecs,),
(Resources<Empty>,),
),
>
where
CmdCtxTypesT: CmdCtxTypes,
{
type IntoFuture =
LocalBoxFuture<'ctx, Result<CmdCtxSpsf<'ctx, CmdCtxTypesT>, CmdCtxTypesT::AppError>>;
type Output = <Self::IntoFuture as std::future::Future>::Output;
fn into_future(self) -> Self::IntoFuture {
self.build().boxed_local()
}
}