wdl_cli/
eval.rs

1//! Facilities for performing a typical WDL evaluation using the `wdl-*` crates.
2
3use std::path::Path;
4
5use anyhow::anyhow;
6use tokio_util::sync::CancellationToken;
7use wdl_analysis::Document;
8use wdl_engine::EvaluatedTask;
9use wdl_engine::EvaluationError;
10use wdl_engine::EvaluationResult;
11use wdl_engine::Inputs;
12use wdl_engine::Outputs;
13use wdl_engine::config::Config;
14use wdl_engine::v1::ProgressKind;
15use wdl_engine::v1::TaskEvaluator;
16use wdl_engine::v1::WorkflowEvaluator;
17
18use crate::inputs::OriginPaths;
19
20/// An evaluator for a WDL task or workflow.
21pub struct Evaluator<'a> {
22    /// The document that contains the task or workflow to run.
23    document: &'a Document,
24
25    /// The name of the task or workflow to run.
26    name: &'a str,
27
28    /// The inputs to the task or workflow.
29    inputs: Inputs,
30
31    /// The origin paths for the input keys.
32    origins: OriginPaths,
33
34    /// The configuration for the WDL engine.
35    config: Config,
36
37    /// The output directory.
38    output_dir: &'a Path,
39}
40
41impl<'a> Evaluator<'a> {
42    /// Creates a new task or workflow evaluator.
43    pub fn new(
44        document: &'a Document,
45        name: &'a str,
46        inputs: Inputs,
47        origins: OriginPaths,
48        config: Config,
49        output_dir: &'a Path,
50    ) -> Self {
51        Self {
52            document,
53            name,
54            inputs,
55            origins,
56            config,
57            output_dir,
58        }
59    }
60
61    /// Runs a WDL task or workflow evaluation.
62    pub async fn run<P, R>(
63        mut self,
64        token: CancellationToken,
65        progress: P,
66    ) -> EvaluationResult<Outputs>
67    where
68        P: Fn(ProgressKind<'_>) -> R + Send + Sync + 'static,
69        R: Future<Output = ()> + Send,
70    {
71        match self.inputs {
72            Inputs::Task(ref mut inputs) => {
73                let task = self.document.task_by_name(self.name).ok_or_else(|| {
74                    anyhow!(
75                        "document does not contain a task named `{name}`",
76                        name = self.name
77                    )
78                })?;
79
80                // Ensure all the paths specified in the inputs are relative to
81                // their respective origin paths.
82                inputs.join_paths(task, |key| {
83                    self.origins
84                        .get(key)
85                        .ok_or(anyhow!("unable to find origin path for key `{key}`"))
86                })?;
87
88                let evaluator = TaskEvaluator::new(self.config, token).await?;
89
90                evaluator
91                    .evaluate(self.document, task, inputs, self.output_dir, progress)
92                    .await
93                    .and_then(EvaluatedTask::into_result)
94            }
95            Inputs::Workflow(mut inputs) => {
96                let workflow = self
97                    .document
98                    .workflow()
99                    .ok_or_else(|| anyhow!("document does not contain a workflow"))?;
100
101                if workflow.name() != self.name {
102                    return Err(EvaluationError::Other(anyhow!(
103                        "document does not contain a workflow named `{name}`",
104                        name = self.name
105                    )));
106                }
107
108                // Ensure all the paths specified in the inputs are relative to
109                // their respective origin paths.
110                inputs.join_paths(workflow, |key| {
111                    self.origins
112                        .get(key)
113                        .ok_or(anyhow!("unable to find origin path for key `{key}`"))
114                })?;
115
116                let evaluator = WorkflowEvaluator::new(self.config, token).await?;
117                evaluator
118                    .evaluate(self.document, inputs, self.output_dir, progress)
119                    .await
120            }
121        }
122    }
123}