wdl_ast/v1/task/runtime/item/
container.rs

1//! The `container` item within the `runtime` block.
2
3use wdl_grammar::SyntaxKind;
4use wdl_grammar::SyntaxNode;
5
6use crate::AstNode;
7use crate::AstToken;
8use crate::TreeNode;
9use crate::v1::RuntimeItem;
10use crate::v1::TASK_REQUIREMENT_CONTAINER;
11use crate::v1::TASK_REQUIREMENT_CONTAINER_ALIAS;
12use crate::v1::common::container::value;
13use crate::v1::common::container::value::Value;
14
15/// The `container` item within a `runtime` block.
16#[derive(Debug)]
17pub struct Container<N: TreeNode = SyntaxNode>(RuntimeItem<N>);
18
19impl<N: TreeNode> Container<N> {
20    /// Gets the [`Value`] from a [`Container`] (if it can be parsed).
21    pub fn value(&self) -> value::Result<Value<N>> {
22        Value::try_from(self.0.expr())
23    }
24}
25
26impl<N: TreeNode> AstNode<N> for Container<N> {
27    fn can_cast(kind: SyntaxKind) -> bool {
28        RuntimeItem::<N>::can_cast(kind)
29    }
30
31    fn cast(inner: N) -> Option<Self> {
32        RuntimeItem::cast(inner).and_then(|item| Container::try_from(item).ok())
33    }
34
35    fn inner(&self) -> &N {
36        self.0.inner()
37    }
38}
39
40impl<N: TreeNode> TryFrom<RuntimeItem<N>> for Container<N> {
41    type Error = ();
42
43    fn try_from(value: RuntimeItem<N>) -> Result<Self, Self::Error> {
44        if [TASK_REQUIREMENT_CONTAINER, TASK_REQUIREMENT_CONTAINER_ALIAS]
45            .iter()
46            .any(|key| value.name().text() == *key)
47        {
48            return Ok(Self(value));
49        }
50
51        Err(())
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use crate::Document;
58
59    #[test]
60    fn simple_example() {
61        let (document, diagnostics) = Document::parse(
62            r#"version 1.2
63
64task hello {
65    runtime {
66        container: "ubuntu"
67    }
68}"#,
69        );
70
71        assert!(diagnostics.is_empty());
72
73        let section = document
74            .ast()
75            .as_v1()
76            .expect("v1 ast")
77            .tasks()
78            .next()
79            .expect("the 'hello' task to exist")
80            .runtime()
81            .expect("the 'runtime' block to exist");
82
83        let container = section.items().filter_map(|p| p.into_container());
84
85        assert!(container.count() == 1);
86    }
87
88    #[test]
89    fn missing_container_item() {
90        let (document, diagnostics) = Document::parse(
91            r#"version 1.2
92
93task hello {
94    runtime {
95        foo: "ubuntu"
96    }
97}"#,
98        );
99
100        assert!(diagnostics.is_empty());
101
102        let section = document
103            .ast()
104            .as_v1()
105            .expect("v1 ast")
106            .tasks()
107            .next()
108            .expect("the 'hello' task to exist")
109            .runtime()
110            .expect("the 'runtime' block to exist");
111
112        let container = section.items().filter_map(|p| p.into_container());
113
114        assert!(container.count() == 0);
115    }
116
117    #[test]
118    fn docker_alias() {
119        let (document, diagnostics) = Document::parse(
120            r#"version 1.2
121
122task hello {
123    runtime {
124        docker: "ubuntu"
125    }
126}"#,
127        );
128
129        assert!(diagnostics.is_empty());
130
131        let section = document
132            .ast()
133            .as_v1()
134            .expect("v1 ast")
135            .tasks()
136            .next()
137            .expect("the 'hello' task to exist")
138            .runtime()
139            .expect("the 'runtime' block to exist");
140
141        let container = section.items().filter_map(|p| p.into_container());
142
143        assert!(container.count() == 1);
144    }
145}