dockerfile_parser_rs/
file.rs1use std::fs::File;
2use std::io::Write;
3use std::path::PathBuf;
4
5use crate::ParseResult;
6use crate::ast::Instruction;
7use crate::error::ParseError;
8use crate::parser::instructions::add;
9use crate::parser::instructions::arg;
10use crate::parser::instructions::cmd;
11use crate::parser::instructions::copy;
12use crate::parser::instructions::entrypoint;
13use crate::parser::instructions::env;
14use crate::parser::instructions::expose;
15use crate::parser::instructions::from;
16use crate::parser::instructions::label;
17use crate::parser::instructions::run;
18use crate::parser::instructions::shell;
19use crate::parser::instructions::user;
20use crate::parser::instructions::volume;
21use crate::parser::instructions::workdir;
22use crate::symbols::chars::HASHTAG;
23use crate::utils::read_lines;
24use crate::utils::split_instruction_and_arguments;
25
26#[derive(Debug)]
28pub struct Dockerfile {
29 pub path: PathBuf,
30 pub instructions: Vec<Instruction>,
31}
32
33impl Dockerfile {
34 pub fn new(path: PathBuf, instructions: Vec<Instruction>) -> Self {
39 Dockerfile { path, instructions }
40 }
41
42 pub fn empty(path: PathBuf) -> Self {
47 Dockerfile::new(path, Vec::new())
48 }
49
50 pub fn from(path: PathBuf) -> ParseResult<Self> {
70 let mut dockerfile = Dockerfile::empty(path);
71 dockerfile.instructions = dockerfile.parse()?;
72 Ok(dockerfile)
73 }
74
75 pub fn parse(&self) -> ParseResult<Vec<Instruction>> {
98 let file = File::open(&self.path).map_err(|e| ParseError::FileError(e.to_string()))?;
99 let lines = read_lines(&file);
100
101 let mut instructions = Vec::new();
102
103 for line in lines {
104 if line.is_empty() {
106 instructions.push(Instruction::Empty);
107 } else if line.starts_with(HASHTAG) {
109 instructions.push(Instruction::Comment(line.to_owned()));
110 } else {
111 let (instruction, arguments) = split_instruction_and_arguments(&line)?;
112 let instruction = match instruction.as_str() {
113 "ADD" => add::parse(arguments),
114 "ARG" => arg::parse(arguments),
115 "CMD" => cmd::parse(arguments),
116 "COPY" => copy::parse(arguments),
117 "ENTRYPOINT" => entrypoint::parse(arguments),
118 "ENV" => env::parse(arguments),
119 "EXPOSE" => expose::parse(arguments),
120 "LABEL" => label::parse(arguments),
121 "FROM" => from::parse(arguments),
122 "RUN" => run::parse(arguments),
123 "SHELL" => shell::parse(arguments),
124 "USER" => user::parse(arguments),
125 "VOLUME" => volume::parse(arguments),
126 "WORKDIR" => workdir::parse(arguments),
127 _ => return Err(ParseError::UnknownInstruction(instruction)),
128 };
129 match instruction {
130 Ok(instruction) => instructions.push(instruction),
131 Err(e) => {
132 return Err(ParseError::SyntaxError(format!("{}: {}", line, e)));
133 }
134 }
135 }
136 }
137 Ok(instructions)
138 }
139
140 pub fn dump(&self) -> std::io::Result<()> {
146 let mut file = File::create(&self.path)?;
147 for instruction in &self.instructions {
148 writeln!(file, "{}", instruction)?;
149 }
150 Ok(())
151 }
152}