Make fconv delete faulty files
This commit is contained in:
@@ -1,221 +1,225 @@
|
||||
use colored::*;
|
||||
use envmnt::{ExpandOptions, ExpansionType};
|
||||
use std::{boxed::Box, io::{BufRead, BufReader, BufWriter, Read, Write}, path::PathBuf};
|
||||
|
||||
pub mod bits;
|
||||
pub mod compress;
|
||||
pub mod raw;
|
||||
|
||||
pub type BufferedInputFile = BufReader<std::fs::File>;
|
||||
pub type Output = Box<dyn Write>;
|
||||
pub type Input = Box<dyn BufRead>;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! format_if_error {
|
||||
($result:expr, $format_text:literal) => {
|
||||
tool_helper::callback_if_any_error($result, |error_text| {
|
||||
format!($format_text, error_text=error_text)
|
||||
})
|
||||
};
|
||||
($result:expr, $format_text:literal, $($arg:expr)*) => {
|
||||
tool_helper::callback_if_any_error($result, |error_text| {
|
||||
format!($format_text, $($arg),*, error_text=error_text)
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! format_if_error_drop_cause {
|
||||
($result:expr, $format_text:literal) => {
|
||||
tool_helper::callback_if_any_error($result, |error_text| {
|
||||
format!($format_text)
|
||||
})
|
||||
};
|
||||
($result:expr, $format_text:literal, $($arg:expr)*) => {
|
||||
tool_helper::callback_if_any_error($result, |error_text| {
|
||||
format!($format_text, $($arg),*)
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
pub struct Error {
|
||||
pub exit_code: i32,
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
const DEFAULT_EXITCODE:i32 = -1;
|
||||
|
||||
pub fn from_str(str: &str) -> Error {
|
||||
Self::from_text(str.to_owned())
|
||||
}
|
||||
|
||||
pub fn from_text(text: String) -> Error {
|
||||
Error{exit_code: Self::DEFAULT_EXITCODE, text}
|
||||
}
|
||||
|
||||
pub fn from_error<T>(error: T) -> Error where T: std::fmt::Display {
|
||||
Error::from_text(error.to_string())
|
||||
}
|
||||
|
||||
pub fn from_core_error<T>(error: T) -> Error where T: core::fmt::Display {
|
||||
Error::from_text(error.to_string())
|
||||
}
|
||||
|
||||
pub fn from_callback<F>(callback: F) -> Error where F: Fn() -> String {
|
||||
Error::from_text(callback())
|
||||
}
|
||||
|
||||
pub fn not_implemented(function: &str) -> Error {
|
||||
Error::from_text(format!("{} not implemented yet", function))
|
||||
}
|
||||
|
||||
pub fn try_or_new<T, S>(result: std::result::Result<T, S>) -> Result<T, Error> where S: std::fmt::Display {
|
||||
match result {
|
||||
Ok(value) => Ok(value),
|
||||
Err(error) => Err(Error{exit_code: Self::DEFAULT_EXITCODE, text: error.to_string()}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ok_or_new<T, F>(option: Option<T>, error_text: F) -> Result<T, Error> where F: Fn () -> String{
|
||||
Ok(option.ok_or(Error::from_callback(error_text))?)
|
||||
}
|
||||
|
||||
pub fn print_generic_to_std_err<T: std::fmt::Display>(object: &T) {
|
||||
eprintln!("{}", format!("ERROR: {}", object).red());
|
||||
}
|
||||
|
||||
pub fn print_to_std_err(&self) {
|
||||
Self::print_generic_to_std_err(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.text)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<std::io::Error> for Error {
|
||||
fn from(error: std::io::Error) -> Self {
|
||||
Error{exit_code: -1, text: error.to_string()}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<cdtypes::Error> for Error {
|
||||
fn from(error: cdtypes::Error) -> Self {
|
||||
Error::from_error(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<std::convert::Infallible> for Error {
|
||||
fn from(error: std::convert::Infallible) -> Self {
|
||||
Error::from_error(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<std::sync::mpsc::RecvError> for Error {
|
||||
fn from(error: std::sync::mpsc::RecvError) -> Self {
|
||||
Error::from_error(error)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exit_with_error(error: Error) {
|
||||
error.print_to_std_err();
|
||||
std::process::exit(error.exit_code);
|
||||
}
|
||||
|
||||
pub fn prefix_if_error<T>(prefix: &str, result: Result<T, Error>) -> Result<T, Error> {
|
||||
match result {
|
||||
Ok(value) => Ok(value),
|
||||
Err(mut error) => {
|
||||
let mut new_text = String::from(prefix);
|
||||
|
||||
new_text.push_str(error.text.as_str());
|
||||
error.text = new_text;
|
||||
Err(error)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn callback_if_error<F: Fn(String) -> String, T>(result: Result<T, Error>, callback: F) -> Result<T, Error> {
|
||||
match result {
|
||||
Ok(value) => Ok(value),
|
||||
Err(mut error) => {
|
||||
error.text = callback(error.text);
|
||||
|
||||
Err(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn callback_if_any_error<F: Fn(String) -> String, T, E: std::string::ToString>(result: Result<T, E>, callback: F) -> Result<T, Error> {
|
||||
match result {
|
||||
Ok(value) => Ok(value),
|
||||
Err(error) => {
|
||||
Err(Error::from_text(callback(error.to_string())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn path_with_env_from(path: &str) -> PathBuf {
|
||||
PathBuf::from(envmnt::expand(path, Some(ExpandOptions{expansion_type: Some(ExpansionType::All), default_to_empty: false})))
|
||||
}
|
||||
|
||||
pub fn open_output_file(output_path: &PathBuf) -> Result<BufWriter<std::fs::File>, Error> {
|
||||
Ok(std::io::BufWriter::new(std::fs::File::create(output_path)?))
|
||||
}
|
||||
|
||||
pub fn open_output(output_file: Option<PathBuf>) -> Result<Output, Error> {
|
||||
match output_file {
|
||||
Some(output_path) => Ok(Box::new(open_output_file(&output_path)?)),
|
||||
None => Ok(Box::new(BufWriter::new(std::io::stdout()))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open_input(input_file: Option<PathBuf>) -> Result<Input, Error> {
|
||||
match input_file {
|
||||
Some(input_path) => Ok(Box::new(open_input_file_buffered(&input_path)?)),
|
||||
None => Ok(Box::new(BufReader::new(std::io::stdin()))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open_input_file_buffered(input_path: &PathBuf) -> Result<BufferedInputFile, Error> {
|
||||
Ok(BufReader::new(std::fs::File::open(input_path)?))
|
||||
}
|
||||
|
||||
pub fn os_str_to_string(input: &std::ffi::OsStr, name: &str) -> Result<String, Error> {
|
||||
Ok(Error::ok_or_new(input.to_str(), ||format!("Converting {} to UTF-8 failed", name))?.to_owned())
|
||||
}
|
||||
|
||||
pub fn get_file_name_from_path_buf(input: &PathBuf, name: &str) -> Result<String, Error> {
|
||||
os_str_to_string(Error::ok_or_new(input.file_name(), ||format!("No {} file name found", name))?, name)
|
||||
}
|
||||
|
||||
pub fn input_to_vec(input: Input) -> Result<Vec<u8>, Error> {
|
||||
let mut data = Vec::new();
|
||||
|
||||
for byte in input.bytes() {
|
||||
data.push(byte?);
|
||||
}
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub fn read_file(file_path: &PathBuf) -> Result<Vec<u8>, Error> {
|
||||
match std::fs::read(file_path) {
|
||||
Ok(data) => Ok(data),
|
||||
Err(error) => create_file_read_error(file_path, error),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_file_to_string(file_path: &PathBuf) -> Result<String, Error> {
|
||||
match std::fs::read_to_string(file_path) {
|
||||
Ok(string) => Ok(string),
|
||||
Err(error) => create_file_read_error(file_path, error),
|
||||
}
|
||||
}
|
||||
|
||||
fn create_file_read_error<T>(file_path: &PathBuf, error: std::io::Error) -> Result<T, Error> {
|
||||
Err(Error::from_text(format!("Failed reading file {} with error: \"{}\"", file_path.display(), error)))
|
||||
use colored::*;
|
||||
use envmnt::{ExpandOptions, ExpansionType};
|
||||
use std::{boxed::Box, io::{BufRead, BufReader, BufWriter, Read, Write}, path::PathBuf};
|
||||
|
||||
pub mod bits;
|
||||
pub mod compress;
|
||||
pub mod raw;
|
||||
|
||||
pub type BufferedInputFile = BufReader<std::fs::File>;
|
||||
pub type Output = Box<dyn Write>;
|
||||
pub type Input = Box<dyn BufRead>;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! format_if_error {
|
||||
($result:expr, $format_text:literal) => {
|
||||
tool_helper::callback_if_any_error($result, |error_text| {
|
||||
format!($format_text, error_text=error_text)
|
||||
})
|
||||
};
|
||||
($result:expr, $format_text:literal, $($arg:expr)*) => {
|
||||
tool_helper::callback_if_any_error($result, |error_text| {
|
||||
format!($format_text, $($arg),*, error_text=error_text)
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! format_if_error_drop_cause {
|
||||
($result:expr, $format_text:literal) => {
|
||||
tool_helper::callback_if_any_error($result, |error_text| {
|
||||
format!($format_text)
|
||||
})
|
||||
};
|
||||
($result:expr, $format_text:literal, $($arg:expr)*) => {
|
||||
tool_helper::callback_if_any_error($result, |error_text| {
|
||||
format!($format_text, $($arg),*)
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
pub struct Error {
|
||||
pub exit_code: i32,
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
const DEFAULT_EXITCODE:i32 = -1;
|
||||
|
||||
pub fn from_str(str: &str) -> Error {
|
||||
Self::from_text(str.to_owned())
|
||||
}
|
||||
|
||||
pub fn from_text(text: String) -> Error {
|
||||
Error{exit_code: Self::DEFAULT_EXITCODE, text}
|
||||
}
|
||||
|
||||
pub fn from_error<T>(error: T) -> Error where T: std::fmt::Display {
|
||||
Error::from_text(error.to_string())
|
||||
}
|
||||
|
||||
pub fn from_core_error<T>(error: T) -> Error where T: core::fmt::Display {
|
||||
Error::from_text(error.to_string())
|
||||
}
|
||||
|
||||
pub fn from_callback<F>(callback: F) -> Error where F: Fn() -> String {
|
||||
Error::from_text(callback())
|
||||
}
|
||||
|
||||
pub fn not_implemented(function: &str) -> Error {
|
||||
Error::from_text(format!("{} not implemented yet", function))
|
||||
}
|
||||
|
||||
pub fn try_or_new<T, S>(result: std::result::Result<T, S>) -> Result<T, Error> where S: std::fmt::Display {
|
||||
match result {
|
||||
Ok(value) => Ok(value),
|
||||
Err(error) => Err(Error{exit_code: Self::DEFAULT_EXITCODE, text: error.to_string()}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ok_or_new<T, F>(option: Option<T>, error_text: F) -> Result<T, Error> where F: Fn () -> String{
|
||||
Ok(option.ok_or(Error::from_callback(error_text))?)
|
||||
}
|
||||
|
||||
pub fn print_generic_to_std_err<T: std::fmt::Display>(object: &T) {
|
||||
eprintln!("{}", format!("ERROR: {}", object).red());
|
||||
}
|
||||
|
||||
pub fn print_to_std_err(&self) {
|
||||
Self::print_generic_to_std_err(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.text)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<std::io::Error> for Error {
|
||||
fn from(error: std::io::Error) -> Self {
|
||||
Error{exit_code: -1, text: error.to_string()}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<cdtypes::Error> for Error {
|
||||
fn from(error: cdtypes::Error) -> Self {
|
||||
Error::from_error(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<std::convert::Infallible> for Error {
|
||||
fn from(error: std::convert::Infallible) -> Self {
|
||||
Error::from_error(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<std::sync::mpsc::RecvError> for Error {
|
||||
fn from(error: std::sync::mpsc::RecvError) -> Self {
|
||||
Error::from_error(error)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exit_with_error(error: Error) {
|
||||
error.print_to_std_err();
|
||||
std::process::exit(error.exit_code);
|
||||
}
|
||||
|
||||
pub fn print_warning(str: String) {
|
||||
eprintln!("{}", str.yellow());
|
||||
}
|
||||
|
||||
pub fn prefix_if_error<T>(prefix: &str, result: Result<T, Error>) -> Result<T, Error> {
|
||||
match result {
|
||||
Ok(value) => Ok(value),
|
||||
Err(mut error) => {
|
||||
let mut new_text = String::from(prefix);
|
||||
|
||||
new_text.push_str(error.text.as_str());
|
||||
error.text = new_text;
|
||||
Err(error)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn callback_if_error<F: Fn(String) -> String, T>(result: Result<T, Error>, callback: F) -> Result<T, Error> {
|
||||
match result {
|
||||
Ok(value) => Ok(value),
|
||||
Err(mut error) => {
|
||||
error.text = callback(error.text);
|
||||
|
||||
Err(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn callback_if_any_error<F: Fn(String) -> String, T, E: std::string::ToString>(result: Result<T, E>, callback: F) -> Result<T, Error> {
|
||||
match result {
|
||||
Ok(value) => Ok(value),
|
||||
Err(error) => {
|
||||
Err(Error::from_text(callback(error.to_string())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn path_with_env_from(path: &str) -> PathBuf {
|
||||
PathBuf::from(envmnt::expand(path, Some(ExpandOptions{expansion_type: Some(ExpansionType::All), default_to_empty: false})))
|
||||
}
|
||||
|
||||
pub fn open_output_file(output_path: &PathBuf) -> Result<BufWriter<std::fs::File>, Error> {
|
||||
Ok(std::io::BufWriter::new(std::fs::File::create(output_path)?))
|
||||
}
|
||||
|
||||
pub fn open_output(output_file: &Option<PathBuf>) -> Result<Output, Error> {
|
||||
match output_file {
|
||||
Some(output_path) => Ok(Box::new(open_output_file(&output_path)?)),
|
||||
None => Ok(Box::new(BufWriter::new(std::io::stdout()))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open_input(input_file: Option<PathBuf>) -> Result<Input, Error> {
|
||||
match input_file {
|
||||
Some(input_path) => Ok(Box::new(open_input_file_buffered(&input_path)?)),
|
||||
None => Ok(Box::new(BufReader::new(std::io::stdin()))),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open_input_file_buffered(input_path: &PathBuf) -> Result<BufferedInputFile, Error> {
|
||||
Ok(BufReader::new(std::fs::File::open(input_path)?))
|
||||
}
|
||||
|
||||
pub fn os_str_to_string(input: &std::ffi::OsStr, name: &str) -> Result<String, Error> {
|
||||
Ok(Error::ok_or_new(input.to_str(), ||format!("Converting {} to UTF-8 failed", name))?.to_owned())
|
||||
}
|
||||
|
||||
pub fn get_file_name_from_path_buf(input: &PathBuf, name: &str) -> Result<String, Error> {
|
||||
os_str_to_string(Error::ok_or_new(input.file_name(), ||format!("No {} file name found", name))?, name)
|
||||
}
|
||||
|
||||
pub fn input_to_vec(input: Input) -> Result<Vec<u8>, Error> {
|
||||
let mut data = Vec::new();
|
||||
|
||||
for byte in input.bytes() {
|
||||
data.push(byte?);
|
||||
}
|
||||
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub fn read_file(file_path: &PathBuf) -> Result<Vec<u8>, Error> {
|
||||
match std::fs::read(file_path) {
|
||||
Ok(data) => Ok(data),
|
||||
Err(error) => create_file_read_error(file_path, error),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_file_to_string(file_path: &PathBuf) -> Result<String, Error> {
|
||||
match std::fs::read_to_string(file_path) {
|
||||
Ok(string) => Ok(string),
|
||||
Err(error) => create_file_read_error(file_path, error),
|
||||
}
|
||||
}
|
||||
|
||||
fn create_file_read_error<T>(file_path: &PathBuf, error: std::io::Error) -> Result<T, Error> {
|
||||
Err(Error::from_text(format!("Failed reading file {} with error: \"{}\"", file_path.display(), error)))
|
||||
}
|
Reference in New Issue
Block a user