dockerfile_parser_rs/
lib.rs1mod ast;
2mod error;
3mod parser;
4mod symbols;
5mod utils;
6
7use std::fs::File;
8use std::io::Write;
9use std::path::PathBuf;
10
11use crate::parser::instructions::add;
12use crate::parser::instructions::arg;
13use crate::parser::instructions::cmd;
14use crate::parser::instructions::copy;
15use crate::parser::instructions::entrypoint;
16use crate::parser::instructions::env;
17use crate::parser::instructions::expose;
18use crate::parser::instructions::from;
19use crate::parser::instructions::label;
20use crate::parser::instructions::run;
21use crate::parser::instructions::user;
22use crate::parser::instructions::volume;
23use crate::parser::instructions::workdir;
24use crate::symbols::chars::HASHTAG;
25use crate::utils::read_lines;
26use crate::utils::split_instruction_and_arguments;
27
28pub use crate::ast::Instruction;
29pub use crate::error::ParseError;
30
31pub type ParseResult<T> = Result<T, ParseError>;
32
33#[derive(Debug)]
34pub struct Dockerfile {
35 pub path: PathBuf,
36 pub instructions: Vec<Instruction>,
37}
38
39impl Dockerfile {
40 pub fn new(path: PathBuf) -> Self {
41 Dockerfile {
42 path,
43 instructions: Vec::new(),
44 }
45 }
46
47 pub fn from(path: PathBuf) -> ParseResult<Self> {
48 let mut dockerfile = Dockerfile::new(path);
49 dockerfile.instructions = dockerfile.parse()?;
50 Ok(dockerfile)
51 }
52
53 pub fn parse(&self) -> ParseResult<Vec<Instruction>> {
54 let lines = read_lines(&self.path);
55 let mut instructions = Vec::new();
56
57 for line in lines {
58 if line.is_empty() {
60 instructions.push(Instruction::Empty);
61 } else if line.starts_with(HASHTAG) {
63 instructions.push(Instruction::Comment(line.to_owned()));
64 } else {
65 let (instruction, arguments) = split_instruction_and_arguments(&line)?;
66 let instruction = match instruction.as_str() {
67 "ADD" => add::parse(arguments),
68 "ARG" => arg::parse(arguments),
69 "CMD" => cmd::parse(arguments),
70 "COPY" => copy::parse(arguments),
71 "ENTRYPOINT" => entrypoint::parse(arguments),
72 "ENV" => env::parse(arguments),
73 "EXPOSE" => expose::parse(arguments),
74 "LABEL" => label::parse(arguments),
75 "FROM" => from::parse(arguments),
76 "RUN" => run::parse(arguments),
77 "USER" => user::parse(arguments),
78 "VOLUME" => volume::parse(arguments),
79 "WORKDIR" => workdir::parse(arguments),
80 _ => return Err(ParseError::UnknownInstruction(instruction)),
81 }
82 .map_err(|e| ParseError::SyntaxError(e.to_string()))?;
83 instructions.push(instruction);
84 }
85 }
86 Ok(instructions)
87 }
88
89 pub fn dump(&self) -> std::io::Result<()> {
90 let mut file = File::create(&self.path)?;
91 for instruction in &self.instructions {
92 writeln!(file, "{}", instruction)?;
93 }
94 Ok(())
95 }
96}