Skip to main content

ui_automata/
workflow.rs

1use crate::plan::DEFAULT_TIMEOUT;
2use crate::{
3    AutomataError, Desktop, Executor, Plan, RecoveryHandler, RetryPolicy, Step, WorkflowState,
4};
5use std::time::Duration;
6
7/// Owned data for one phase of a `Workflow`.
8pub struct WorkflowPhase {
9    pub name: String,
10    pub steps: Vec<Step>,
11    pub recovery_handlers: Vec<RecoveryHandler>,
12    pub unmount: Vec<String>,
13    pub default_timeout: Duration,
14    pub default_retry: RetryPolicy,
15}
16
17impl WorkflowPhase {
18    pub fn new(name: impl Into<String>, steps: Vec<Step>) -> Self {
19        Self {
20            name: name.into(),
21            steps,
22            recovery_handlers: vec![],
23            unmount: vec![],
24            default_timeout: DEFAULT_TIMEOUT,
25            default_retry: RetryPolicy::None,
26        }
27    }
28}
29
30/// A sequence of named plans run in order through a single executor.
31pub struct Workflow<D: Desktop> {
32    phases: Vec<WorkflowPhase>,
33    _marker: std::marker::PhantomData<D>,
34}
35
36impl<D: Desktop> Workflow<D> {
37    pub fn new() -> Self {
38        Self {
39            phases: vec![],
40            _marker: std::marker::PhantomData,
41        }
42    }
43
44    /// Add a phase to the workflow.
45    pub fn phase(mut self, phase: WorkflowPhase) -> Self {
46        self.phases.push(phase);
47        self
48    }
49
50    /// Run all phases in order, stopping on the first failure.
51    pub fn run(&self, executor: &mut Executor<D>) -> Result<(), AutomataError> {
52        let mut state = WorkflowState::new(true);
53        for phase in &self.phases {
54            eprintln!("[workflow] phase: {}", phase.name);
55            let plan = Plan {
56                name: &phase.name,
57                steps: &phase.steps,
58                recovery_handlers: phase.recovery_handlers.clone(),
59                max_recoveries: 10,
60                unmount: &phase.unmount,
61                default_timeout: phase.default_timeout,
62                default_retry: phase.default_retry.clone(),
63            };
64            executor.run(&plan, &mut state)?;
65        }
66        Ok(())
67    }
68}
69
70impl<D: Desktop> Default for Workflow<D> {
71    fn default() -> Self {
72        Self::new()
73    }
74}