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::Events;
12use wdl_engine::Inputs;
13use wdl_engine::Outputs;
14use wdl_engine::config::Config;
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(
63        mut self,
64        token: CancellationToken,
65        events: Events,
66    ) -> EvaluationResult<Outputs> {
67        match self.inputs {
68            Inputs::Task(ref mut inputs) => {
69                let task = self.document.task_by_name(self.name).ok_or_else(|| {
70                    anyhow!(
71                        "document does not contain a task named `{name}`",
72                        name = self.name
73                    )
74                })?;
75
76                // Ensure all the paths specified in the inputs are relative to
77                // their respective origin paths.
78                inputs
79                    .join_paths(task, |key| {
80                        self.origins
81                            .get(key)
82                            .ok_or(anyhow!("unable to find origin path for key `{key}`"))
83                    })
84                    .await?;
85
86                let evaluator = TaskEvaluator::new(self.config, token, events).await?;
87
88                evaluator
89                    .evaluate(self.document, task, inputs, self.output_dir)
90                    .await
91                    .and_then(EvaluatedTask::into_result)
92            }
93            Inputs::Workflow(mut inputs) => {
94                let workflow = self
95                    .document
96                    .workflow()
97                    .ok_or_else(|| anyhow!("document does not contain a workflow"))?;
98
99                if workflow.name() != self.name {
100                    return Err(EvaluationError::Other(anyhow!(
101                        "document does not contain a workflow named `{name}`",
102                        name = self.name
103                    )));
104                }
105
106                // Ensure all the paths specified in the inputs are relative to
107                // their respective origin paths.
108                inputs
109                    .join_paths(workflow, |key| {
110                        self.origins
111                            .get(key)
112                            .ok_or(anyhow!("unable to find origin path for key `{key}`"))
113                    })
114                    .await?;
115
116                let evaluator = WorkflowEvaluator::new(self.config, token, events).await?;
117                evaluator
118                    .evaluate(self.document, inputs, self.output_dir)
119                    .await
120            }
121        }
122    }
123}