1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use crate::image::ImageRef;
use crate::parser::{Pair, Rule};
use crate::splicer::*;
use crate::error::*;
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct FromInstruction {
pub span: Span,
pub image: String,
pub image_span: Span,
pub image_parsed: ImageRef,
pub index: usize,
pub alias: Option<String>,
pub alias_span: Option<Span>
}
impl FromInstruction {
pub(crate) fn from_record(record: Pair, index: usize) -> Result<FromInstruction> {
let span = Span::from_pair(&record);
let mut image_field = None;
let mut alias_field = None;
for field in record.into_inner() {
match field.as_rule() {
Rule::from_image => image_field = Some(field),
Rule::from_alias => alias_field = Some(field),
_ => return Err(unexpected_token(field))
};
}
let (image, image_span) = if let Some(image_field) = image_field {
(image_field.as_str().to_string(), Span::from_pair(&image_field))
} else {
return Err(Error::GenericParseError {
message: "missing from image".into()
});
};
let image_parsed = ImageRef::parse(&image);
let (alias, alias_span) = if let Some(alias_field) = alias_field {
(
Some(alias_field.as_str().to_string()),
Some(Span::from_pair(&alias_field))
)
} else {
(None, None)
};
Ok(FromInstruction {
span, index,
image, image_span, image_parsed,
alias, alias_span,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::test_util::*;
#[test]
fn from_no_alias() -> Result<()> {
let from = parse_direct(
"from alpine:3.10",
Rule::from,
|p| FromInstruction::from_record(p, 0)
)?;
assert_eq!(from, FromInstruction {
span: Span { start: 0, end: 16 },
index: 0,
image: "alpine:3.10".into(),
image_span: Span { start: 5, end: 16 },
image_parsed: ImageRef {
registry: None,
image: "alpine".into(),
tag: Some("3.10".into())
},
alias: None,
alias_span: None
});
Ok(())
}
#[test]
fn from_no_newline() -> Result<()> {
assert!(parse_single(
"from alpine:3.10 from example",
Rule::dockerfile,
).is_err());
Ok(())
}
#[test]
fn from_missing_alias() -> Result<()> {
assert!(parse_single(
"from alpine:3.10 as",
Rule::dockerfile,
).is_err());
Ok(())
}
}