use std::fmt;
use std::io::Read;
use std::path::Path;
pub const MAX_FILE_INPUT_SIZE: u64 = 10 * 1024 * 1024;
pub fn read_input_file_with<FN, FE>(
path: &Path,
max_size: Option<u64>,
not_found_msg: FN,
read_err_prefix: FE,
) -> Result<String, String>
where
FN: FnOnce() -> String,
FE: FnOnce() -> String,
{
let file = match std::fs::File::open(path) {
Ok(f) => f,
Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Err(not_found_msg()),
Err(e) => {
if std::fs::metadata(path).map(|m| m.is_dir()).unwrap_or(false) {
return Err(format!("'{}' is not a file.", path.display()));
}
return Err(format!("{}: {e}", read_err_prefix()));
}
};
if file.metadata().map(|m| m.is_dir()).unwrap_or(false) {
return Err(format!("'{}' is not a file.", path.display()));
}
let mut buf = String::new();
match max_size {
Some(cap) => {
let limit = cap.saturating_add(1);
file.take(limit)
.read_to_string(&mut buf)
.map_err(|e| format!("{}: {e}", read_err_prefix()))?;
if buf.len() as u64 > cap {
return Err(format!(
"File '{}' exceeds maximum size of {} bytes.",
path.display(),
cap
));
}
}
None => {
let mut file = file;
file.read_to_string(&mut buf)
.map_err(|e| format!("{}: {e}", read_err_prefix()))?;
}
}
Ok(buf)
}
pub fn read_input_file(path: &Path) -> Result<String, String> {
read_input_file_with(
path,
None,
|| format!("'{}' does not exist.", path.display()),
|| format!("Cannot read '{}'", path.display()),
)
}
fn supported_extensions() -> Vec<&'static str> {
openjd_model::ModelExtension::ALL
.iter()
.map(|e| e.as_str())
.collect()
}
pub trait CliResult: fmt::Display {
fn to_json_value(&self) -> serde_json::Value;
}
pub fn print_cli_result(result: &dyn CliResult, format: &str) {
match format {
"json" => println!(
"{}",
serde_json::to_string_pretty(&result.to_json_value()).unwrap()
),
"yaml" => print!(
"{}",
serde_saphyr::to_string(&result.to_json_value()).unwrap()
),
_ => println!("{result}"),
}
}
pub fn parse_extensions(arg: &Option<String>) -> Result<Vec<String>, String> {
let supported = supported_extensions();
match arg {
Some(ext_str) if ext_str.is_empty() => Ok(vec![]),
Some(ext_str) => {
let exts: Vec<String> = ext_str
.split(',')
.map(|s| s.trim().to_uppercase())
.filter(|s| !s.is_empty())
.collect();
let unsupported: Vec<&str> = exts
.iter()
.filter(|e| !supported.contains(&e.as_str()))
.map(|e| e.as_str())
.collect();
if !unsupported.is_empty() {
return Err(format!(
"Unsupported Open Job Description extension(s): {}",
unsupported.join(", ")
));
}
Ok(exts)
}
None => Ok(supported.iter().map(|s| s.to_string()).collect()),
}
}