use std::{
fs::File,
io::{self, BufReader, Write},
process,
};
use anyhow::Context;
use cbor_cli::{
config::{self, Commands},
export::export_from_reader,
files::{get_format_by_file_extension, get_missing_files},
import::import_from_reader,
inspect::inspect_from_reader,
};
fn files_exist_or_exit(input_paths: &[std::path::PathBuf]) {
let missing_files = get_missing_files(input_paths);
if !missing_files.is_empty() {
for missing_file in missing_files {
eprintln!("File does not exist: {}", missing_file.display());
}
process::exit(1);
}
}
fn unescape_delimiter(s: &str) -> String {
let mut out = String::with_capacity(s.len());
let mut chars = s.chars();
while let Some(c) = chars.next() {
if c == '\\' {
match chars.next() {
Some('n') => out.push('\n'),
Some('t') => out.push('\t'),
Some('r') => out.push('\r'),
Some('0') => out.push('\0'),
Some(other) => out.push(other),
None => out.push('\\'),
}
} else {
out.push(c);
}
}
out
}
fn main() -> anyhow::Result<()> {
let cli = config::get_cli();
match &cli.command {
Some(Commands::Inspect { input_paths }) => {
files_exist_or_exit(input_paths);
if input_paths.is_empty() {
let reader = BufReader::new(io::stdin());
inspect_from_reader(reader, io::stdout())?;
return Ok(());
}
for input_path in input_paths {
write!(io::stdout(), "{}", input_path.display())?;
let reader = BufReader::new(File::open(input_path)
.with_context(|| format!("Failed to open {}", input_path.display()))?);
inspect_from_reader(reader, io::stdout())
.with_context(|| format!("Failed to inspect {}", input_path.display()))?;
}
}
Some(Commands::Import { input_paths, format }) => {
files_exist_or_exit(input_paths);
if input_paths.is_empty() {
let input_format = match format {
Some(format) => format.to_owned(),
None => {
eprintln!("Error: No format specified. Use --format to specify the format.");
process::exit(1);
}
};
let reader = BufReader::new(io::stdin());
import_from_reader(&input_format, reader, &mut io::stdout())?;
return Ok(());
}
for input_path in input_paths {
let input_format = match format {
Some(format) => format.to_owned(),
None => match get_format_by_file_extension(input_path) {
Some(format) => format,
None => {
eprintln!("Error: Could not determine format from file extension");
process::exit(1);
}
},
};
let reader = BufReader::new(File::open(input_path)
.with_context(|| format!("Failed to open {}", input_path.display()))?);
import_from_reader(&input_format, reader, &mut io::stdout())
.with_context(|| format!("Failed to import {}", input_path.display()))?;
}
}
Some(Commands::Export { input_paths, format, pretty }) => {
files_exist_or_exit(input_paths);
let delimiter = match &cli.delimiter {
Some(delimiter) => unescape_delimiter(delimiter),
None => {
if format == "yaml" {
"\n---\n".to_string()
} else {
"\n".to_string()
}
}
};
if cli.verbose > 0 {
eprintln!("Files to export: {input_paths:?}");
eprintln!("Exporting to {} format", format);
}
if input_paths.is_empty() {
let reader = BufReader::new(io::stdin());
export_from_reader(format, &delimiter, *pretty, reader, &mut io::stdout())?;
return Ok(());
}
for (i, input_path) in input_paths.iter().enumerate() {
if i > 0 {
io::stdout().write_all(delimiter.as_bytes())?;
}
let reader = BufReader::new(File::open(input_path)
.with_context(|| format!("Failed to open {}", input_path.display()))?);
export_from_reader(format, &delimiter, *pretty, reader, &mut io::stdout())
.with_context(|| format!("Failed to export {}", input_path.display()))?;
}
}
None => {}
}
Ok(())
}