use serde_json::Value as Json;
use std::fs::File;
use std::io::prelude::*;
use std::path::{Path, PathBuf};
pub fn parse_filepath(
filepath_str: &str,
expected_extension: Option<&str>,
) -> Result<PathBuf, Box<dyn std::error::Error>> {
let mut path = PathBuf::from(filepath_str);
if let Some(ext) = expected_extension {
match path.extension() {
Some(ext2) => {
if ext2 != ext {
return Err(
format!("Incorrect extension: {:?}. Expected: {}", ext2, ext).into(),
);
}
}
None => {
path.set_extension(ext);
}
}
}
if !path.is_file() {
return Err("File not found".into());
}
Ok(path)
}
pub fn get_lines_and_output_path(
input_str: &str,
output_path: Option<&str>,
) -> Result<(Vec<String>, PathBuf), Box<dyn std::error::Error>> {
let filepath: PathBuf;
let lines: Vec<String>;
if input_str.trim() == "-" {
lines = match read_tex_from_stdin() {
Ok(l) => l,
Err(e) => return Err(e),
};
filepath = PathBuf::from("main.tex");
} else {
filepath = match parse_filepath(&input_str, Some("tex")) {
Ok(fp) => fp,
Err(e) => return Err(e),
};
lines = match crate::merge_tex(&filepath) {
Ok(l) => l,
Err(e) => return Err(e),
};
}
let pdf_filepath = match output_path {
Some(x) => PathBuf::from(x),
None => {
let mut fp = PathBuf::from(filepath.file_name().unwrap());
fp.set_extension("pdf");
fp
}
};
Ok((lines, pdf_filepath))
}
pub fn get_data_from_str(input_str: &str) -> Result<Json, Box<dyn std::error::Error>> {
match input_str.trim() == "-" {
true => read_data_from_stdin(),
false => read_data(&PathBuf::from(input_str)),
}
}
fn read_data_from_stdin() -> Result<Json, Box<dyn std::error::Error>> {
let mut buf = String::new();
std::io::stdin().read_to_string(&mut buf)?;
Ok(serde_json::from_str(&buf)?)
}
pub fn read_tex(filepath: &Path) -> Result<Vec<String>, Box<dyn std::error::Error>> {
if !filepath.is_file() {
return Err(format!("File not found: {}", filepath.to_str().unwrap()).into());
};
let file = File::open(&filepath)?;
let mut reader = std::io::BufReader::new(file);
let mut buffer = String::new();
reader.read_to_string(&mut buffer)?;
let lines: Vec<String> = buffer.lines().map(|s| s.to_owned()).collect();
Ok(lines)
}
pub fn read_tex_from_stdin() -> Result<Vec<String>, Box<dyn std::error::Error>> {
let mut buf = String::new();
std::io::stdin().read_to_string(&mut buf)?;
let lines: Vec<String> = buf.lines().map(|s| s.to_owned()).collect();
Ok(lines)
}
pub fn read_data(filepath: &Path) -> Result<serde_json::Value, Box<dyn std::error::Error>> {
let file = File::open(filepath)?;
let mut reader = std::io::BufReader::new(file);
let mut buf = String::new();
reader.read_to_string(&mut buf)?;
let extension = filepath
.extension()
.expect("Data file read with no extension!")
.to_str()
.unwrap();
let data: Json = match extension {
"json" => serde_json::from_str(&buf)?,
"toml" => toml::from_str(&buf)?,
s => return Err(format!("Could not read data type: {}", s).into()),
};
Ok(data)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_filepath() {
parse_filepath("tests/data/case1/main.tex", Some("tex")).expect("This should exist");
parse_filepath("tests/data/case1/main.tex", Some("text")).expect_err("This should fail");
parse_filepath("tests/data/case1/main", Some("tex")).expect("This should pass");
parse_filepath("Cargo.toml", Some("toml")).expect("This should pass");
}
}