extern crate std;
use std::error::Error as FmtError;
use self::Error::*;
use subprocess;
macro_rules! foreach_fetch {
($mac:ident) => {
$mac!(tar);
$mac!(bzip2);
$mac!(xz);
$mac!(gzip);
}
}
macro_rules! declare_mod {
($name:ident) => { pub mod $name; }
}
foreach_fetch!(declare_mod);
#[derive(Debug)]
pub enum Error {
NotAnAbsolutePath,
NotAFile,
NotADirectory,
IOError(std::io::Error),
ProcessError(subprocess::Error),
PathError,
UnknownUnpackingMethod,
}
impl From<std::io::Error> for Error {
fn from(error: std::io::Error) -> Self {
IOError(error)
}
}
impl From<subprocess::Error> for Error {
fn from(error: subprocess::Error) -> Self {
ProcessError(error)
}
}
impl std::error::Error for Error {
fn description(&self) -> &str {
match *self {
NotAnAbsolutePath => "Path must be absolute",
NotAFile => "Path must be an existing file",
NotADirectory => "Path must be an existing directory",
IOError(ref err) => err.description(),
ProcessError(ref err) => err.description(),
PathError => "Path failed to be processed",
UnknownUnpackingMethod => "Unknown unpacking method",
}
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}", self.description())
}
}
pub trait Unpacker {
fn unpack(&self, in_file: &std::path::Path, out_dir: &std::path::Path) -> Result<std::path::PathBuf, Error>;
}
pub fn check_unpack_args(in_file: &std::path::Path, out_dir: &std::path::Path) -> Result<(), Error> {
if ! in_file.is_absolute() || ! out_dir.is_absolute() {
error!("Unpacker paths must be absolute");
return Err(NotAnAbsolutePath);
}
if ! in_file.is_file() {
error!("Input path is not an existing file archive");
return Err(NotAFile);
}
if out_dir.exists() && ! out_dir.is_dir() {
error!("Output path exists but is not a directory");
return Err(NotADirectory);
}
Ok(())
}
pub fn get_for_archive(formats: &[String]) -> Result<Vec<Box<Unpacker>>, Error> {
let mut unpackers = Vec::new();
for format in formats.iter().rev() {
macro_rules! match_unpacker {
($name:ident) => {
if format == $name::name_get() {
unpackers.push($name::new());
trace!("Using unpack method {}", format);
continue;
}
}
}
foreach_fetch!(match_unpacker);
error!("Unknown unpacking method: \"{}\"", format);
return Err(UnknownUnpackingMethod);
}
Ok(unpackers)
}