1use std::path::Path;
4
5use anyhow::anyhow;
6use tokio_util::sync::CancellationToken;
7use wdl_analysis::document::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
20pub struct Evaluator<'a> {
22 document: &'a Document,
24
25 name: &'a str,
27
28 inputs: Inputs,
30
31 origins: OriginPaths,
33
34 config: Config,
36
37 output_dir: &'a Path,
39}
40
41impl<'a> Evaluator<'a> {
42 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 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 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 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}