use std::{fs, path::PathBuf};
use crate::commands::{generate::DEFAULT_DOCKERFILE, get_file_path};
pub use clap::{Args, ValueEnum};
use dofigen_lib::{Dofigen, Error, Result};
use crate::CliCommand;
#[derive(Debug, Clone, Copy, ValueEnum, Default)]
enum OutputFormat {
#[default]
Yaml,
Yml,
Json,
Jsonc,
}
#[derive(Args, Debug, Default, Clone)]
pub struct Parse {
#[clap(short, long, default_value = DEFAULT_DOCKERFILE)]
pub file: Option<String>,
#[clap(short, long, alias = "out")]
output: Option<String>,
#[clap(long, value_enum, ignore_case = true)]
format: Option<OutputFormat>,
}
impl CliCommand for Parse {
fn run(self) -> Result<()> {
let path = get_file_path(&self.file)?;
let format = match (self.format, self.output.as_deref()) {
(Some(f), _) => f,
(None, Some(output)) if output.ends_with(".json") => OutputFormat::Jsonc,
(None, _) => OutputFormat::Yaml,
};
let (dockerfile_content, dockerignore_content): (String, Option<String>) = if path == "-" {
let content = std::io::read_to_string(std::io::stdin())
.map_err(|err| Error::Custom(format!("Unable to read stdin: {}", err)))?;
(content, None)
} else {
let dockerfile = PathBuf::from(&path);
if !dockerfile.exists() {
return Err(Error::Custom(format!(
"No Dockerfile file found at path: {}",
dockerfile.display()
)));
}
let filename = dockerfile.file_name().unwrap().to_str().unwrap();
let mut ignorefile = dockerfile.with_file_name(format!("{}.dockerignore", filename));
if filename == "Dockerfile" && !ignorefile.exists() {
ignorefile = dockerfile.clone().with_file_name(".dockerignore");
}
let dockerfile_content = fs::read_to_string(&dockerfile).map_err(|err| {
Error::Custom(format!("Unable to read the Dockerfile file: {}", err))
})?;
let dockerignore_content = if ignorefile.exists() {
Some(fs::read_to_string(&ignorefile).map_err(|err| {
Error::Custom(format!("Unable to read the .dockerignore file: {}", err))
})?)
} else {
None
};
(dockerfile_content, dockerignore_content)
};
let dockerfile = dockerfile_content
.parse()
.map_err(|err| Error::Custom(format!("Unable to parse the Dockerfile: {}", err)))?;
let dockerignore = if let Some(content) = dockerignore_content {
Some(content.parse()?)
} else {
None
};
let dofigen = Dofigen::from_dockerfile(dockerfile, dockerignore)?;
let dofigen_content = match format {
OutputFormat::Yaml | OutputFormat::Yml => serde_yaml::to_string(&dofigen)?,
OutputFormat::Json => serde_json::to_string_pretty(&dofigen)?,
OutputFormat::Jsonc => serde_json::to_string_pretty(&dofigen)?,
};
let output = self.output.unwrap_or_else(|| match format {
OutputFormat::Yaml | OutputFormat::Yml => "dofigen.yml".to_string(),
OutputFormat::Json | OutputFormat::Jsonc => "dofigen.json".to_string(),
});
if output == "-" {
print!("{}", dofigen_content);
} else {
fs::write(PathBuf::from(&output), dofigen_content)
.expect("Unable to write the Dofigen file");
};
Ok(())
}
}