dockerfile-parser-rs 3.3.0

The ultimate Rust library for parsing, modifying, and generating Dockerfiles
Documentation
use crate::ParseResult;
use crate::ast::Instruction;
use crate::error::ParseError;
use crate::parser::utils::clean_exec_form;
use crate::parser::utils::clean_shell_form;
use crate::parser::utils::get_options_from;
use crate::parser::utils::is_exec_form;
use crate::symbols::strings::HEREDOC_START;
use crate::utils::split_heredoc;

pub fn parse(arguments: &[String]) -> ParseResult<Instruction> {
    let (options, remaining) = get_options_from(arguments);

    if remaining.is_empty() {
        return Err(ParseError::MissingArgument(String::from(
            "RUN requires at least one argument",
        )));
    }

    let mount = options.get("mount").cloned();
    let network = options.get("network").cloned();
    let security = options.get("security").cloned();

    if remaining.iter().any(|arg| arg == HEREDOC_START) {
        let lines = split_heredoc(remaining);

        let command = lines.first().unwrap().clone();
        let heredoc = Some(
            lines[1..]
                .to_vec()
                .iter()
                .map(|v| v.join(" "))
                .collect::<Vec<String>>(),
        );

        return Ok(Instruction::Run {
            mount,
            network,
            security,
            command,
            heredoc,
        });
    }

    let command = if is_exec_form(&remaining) {
        clean_exec_form(&remaining)
    } else {
        clean_shell_form(&remaining)
    };
    let heredoc = None;

    Ok(Instruction::Run {
        mount,
        network,
        security,
        command,
        heredoc,
    })
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_run() {
        let arguments = vec![
            String::from("--mount=type=bind,source=/host/path,target=/container/path"),
            String::from("--network=host"),
            String::from("--security=seccomp"),
            String::from("cat"),
            String::from("/etc/os-release"),
        ];
        let result = parse(&arguments).unwrap();

        assert_eq!(
            result,
            Instruction::Run {
                mount: Some(String::from(
                    "type=bind,source=/host/path,target=/container/path"
                )),
                network: Some(String::from("host")),
                security: Some(String::from("seccomp")),
                command: vec![String::from("cat"), String::from("/etc/os-release")],
                heredoc: None,
            }
        );
    }
}