2022-11-10 14:54:12 +00:00
pub mod base ;
2022-10-28 16:29:15 +00:00
pub mod common ;
pub mod darwin ;
pub mod linux ;
2022-09-15 19:11:46 +00:00
2022-10-26 22:13:42 +00:00
use serde ::{ Deserialize , Serialize } ;
2022-09-20 18:42:20 +00:00
2022-11-23 17:18:38 +00:00
/// An action which can be reverted or completed, with an action state
///
/// This trait interacts with [`ActionImplementation`] which does the [`ActionState`] manipulation and provides some tracing facilities.
///
/// Instead of calling [`execute`][Action::execute] or [`revert`][Action::revert], you should prefer [`try_execute`][ActionImplementation::try_execute] and [`try_revert`][ActionImplementation::try_revert]
2022-10-26 21:14:53 +00:00
#[ async_trait::async_trait ]
#[ typetag::serde(tag = " action " ) ]
2022-10-26 22:13:42 +00:00
pub trait Action : Send + Sync + std ::fmt ::Debug + dyn_clone ::DynClone {
2022-11-23 17:18:38 +00:00
fn tracing_synopsis ( & self ) -> String ;
fn execute_description ( & self ) -> Vec < ActionDescription > ;
fn revert_description ( & self ) -> Vec < ActionDescription > ;
/// Instead of calling [`execute`][Action::execute], you should prefer [`try_execute`][ActionImplementation::try_execute], so [`ActionState`] is handled correctly and tracing is done.
2022-10-26 21:14:53 +00:00
async fn execute ( & mut self ) -> Result < ( ) , Box < dyn std ::error ::Error + Send + Sync > > ;
2022-11-23 17:18:38 +00:00
/// Instead of calling [`revert`][Action::revert], you should prefer [`try_revert`][ActionImplementation::try_revert], so [`ActionState`] is handled correctly and tracing is done.
2022-10-26 21:14:53 +00:00
async fn revert ( & mut self ) -> Result < ( ) , Box < dyn std ::error ::Error + Send + Sync > > ;
2022-11-08 18:18:05 +00:00
fn action_state ( & self ) -> ActionState ;
2022-11-23 17:18:38 +00:00
fn set_action_state ( & mut self , new_state : ActionState ) ;
// They should also have an `async fn plan(args...) -> Result<ActionState<Self>, Box<dyn std::error::Error + Send + Sync>>;`
2022-09-15 19:11:46 +00:00
}
2022-11-23 17:18:38 +00:00
/// The main wrapper around [`Action`], handling [`ActionState`] and tracing.
#[ async_trait::async_trait ]
pub trait ActionImplementation : Action {
fn describe_execute ( & self ) -> Vec < ActionDescription > {
if self . action_state ( ) = = ActionState ::Completed {
return vec! [ ] ;
}
return self . execute_description ( ) ;
}
fn describe_revert ( & self ) -> Vec < ActionDescription > {
if self . action_state ( ) = = ActionState ::Uncompleted {
return vec! [ ] ;
}
return self . revert_description ( ) ;
}
/// You should prefer this ([`try_execute`][ActionImplementation::try_execute]) over [`execute`][Action::execute] as it handles [`ActionState`] and does tracing.
async fn try_execute ( & mut self ) -> Result < ( ) , Box < dyn std ::error ::Error + Send + Sync > > {
if self . action_state ( ) = = ActionState ::Completed {
tracing ::trace! ( " Completed: (Already done) {} " , self . tracing_synopsis ( ) ) ;
return Ok ( ( ) ) ;
}
self . set_action_state ( ActionState ::Progress ) ;
tracing ::debug! ( " Executing: {} " , self . tracing_synopsis ( ) ) ;
self . execute ( ) . await ? ;
self . set_action_state ( ActionState ::Completed ) ;
tracing ::debug! ( " Completed: {} " , self . tracing_synopsis ( ) ) ;
Ok ( ( ) )
}
/// You should prefer this ([`try_revert`][ActionImplementation::try_revert]) over [`revert`][Action::revert] as it handles [`ActionState`] and does tracing.
async fn try_revert ( & mut self ) -> Result < ( ) , Box < dyn std ::error ::Error + Send + Sync > > {
if self . action_state ( ) = = ActionState ::Uncompleted {
tracing ::trace! ( " Reverted: (Already done) {} " , self . tracing_synopsis ( ) ) ;
return Ok ( ( ) ) ;
}
self . set_action_state ( ActionState ::Progress ) ;
tracing ::debug! ( " Reverting: {} " , self . tracing_synopsis ( ) ) ;
self . revert ( ) . await ? ;
tracing ::debug! ( " Reverted: {} " , self . tracing_synopsis ( ) ) ;
self . set_action_state ( ActionState ::Uncompleted ) ;
Ok ( ( ) )
}
}
impl ActionImplementation for dyn Action { }
impl < A > ActionImplementation for A where A : Action { }
2022-10-26 22:13:42 +00:00
dyn_clone ::clone_trait_object! ( Action ) ;
2022-10-26 21:14:53 +00:00
2022-11-08 18:18:05 +00:00
#[ derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Copy) ]
2022-09-23 23:22:50 +00:00
pub enum ActionState {
Completed ,
2022-09-28 20:20:11 +00:00
// Only applicable to meta-actions that start multiple sub-actions.
Progress ,
2022-09-26 23:14:25 +00:00
Uncompleted ,
2022-09-15 19:11:46 +00:00
}
2022-09-14 22:18:13 +00:00
2022-09-15 17:29:22 +00:00
#[ derive(Debug, serde::Deserialize, serde::Serialize, Clone) ]
pub struct ActionDescription {
pub description : String ,
pub explanation : Vec < String > ,
}
impl ActionDescription {
fn new ( description : String , explanation : Vec < String > ) -> Self {
2022-09-15 19:11:46 +00:00
Self {
description ,
explanation ,
}
2022-09-15 17:29:22 +00:00
}
}