2015-12-02 11:52:04 +00:00
|
|
|
use std::error::Error;
|
|
|
|
use std::fmt::{Debug, Display, Formatter};
|
|
|
|
use std::fmt;
|
|
|
|
use std::result::Result;
|
2015-11-23 17:42:55 +00:00
|
|
|
use std::path::{Path, PathBuf};
|
2015-12-02 12:23:00 +00:00
|
|
|
use std::convert::From;
|
|
|
|
use std::convert::Into;
|
|
|
|
|
2015-12-02 13:41:04 +00:00
|
|
|
use regex::Regex;
|
|
|
|
|
2015-12-02 12:23:00 +00:00
|
|
|
#[derive(Debug)]
|
|
|
|
#[derive(Clone)]
|
2015-12-02 13:41:04 +00:00
|
|
|
#[derive(PartialEq)]
|
|
|
|
#[derive(Eq)]
|
2015-12-02 12:23:00 +00:00
|
|
|
// #[derive(Display)]
|
|
|
|
pub enum FileIDType {
|
2015-12-02 13:41:04 +00:00
|
|
|
NONE,
|
2015-12-02 12:23:00 +00:00
|
|
|
UUID,
|
|
|
|
}
|
|
|
|
|
2015-12-03 16:33:03 +00:00
|
|
|
impl Into<String> for FileIDType {
|
|
|
|
|
|
|
|
fn into(self) -> String {
|
|
|
|
let s = match self {
|
|
|
|
FileIDType::UUID => "UUID",
|
|
|
|
FileIDType::NONE => "",
|
|
|
|
};
|
|
|
|
|
|
|
|
String::from(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-12-02 12:23:00 +00:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub struct FileID {
|
|
|
|
id: Option<String>,
|
|
|
|
id_type: FileIDType,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FileID {
|
|
|
|
|
|
|
|
pub fn new(id_type: FileIDType, id: String) -> FileID {
|
|
|
|
FileID {
|
|
|
|
id: Some(id),
|
|
|
|
id_type: id_type,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn is_valid(&self) -> bool {
|
|
|
|
self.id.is_some()
|
|
|
|
}
|
|
|
|
|
2015-12-02 13:41:04 +00:00
|
|
|
pub fn get_type(&self) -> FileIDType {
|
|
|
|
self.id_type.clone()
|
|
|
|
}
|
|
|
|
|
2015-12-02 12:23:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
impl Debug for FileID {
|
|
|
|
|
|
|
|
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
|
|
|
write!(fmt, "FileID[{:?}]: {:?}",
|
|
|
|
self.id_type,
|
|
|
|
self.id);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for FileID {
|
|
|
|
|
|
|
|
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
|
|
|
write!(fmt, "FileID[{:?}]: {:?}",
|
|
|
|
self.id_type,
|
|
|
|
self.id);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Into<String> for FileID {
|
|
|
|
|
|
|
|
fn into(self) -> String {
|
|
|
|
if let Some(id) = self.id {
|
|
|
|
id.clone()
|
|
|
|
} else {
|
|
|
|
String::from("INVALID")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<String> for FileID {
|
|
|
|
|
|
|
|
fn from(s: String) -> FileID {
|
2015-12-02 13:41:04 +00:00
|
|
|
FileID::from(&s)
|
2015-12-02 12:23:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> From<&'a String> for FileID {
|
|
|
|
|
2015-12-02 13:41:04 +00:00
|
|
|
fn from(string: &'a String) -> FileID {
|
|
|
|
|
|
|
|
let regex = Regex::new(r"([:alnum:]*)-([:upper:]*)-([A-Za-z0-9-_]*)\.(.*)").unwrap();
|
|
|
|
let s = string.split("/").last().unwrap_or("");
|
|
|
|
|
|
|
|
debug!("Regex build: {:?}", regex);
|
|
|
|
debug!("Matching string: '{}'", s);
|
|
|
|
regex.captures(s).and_then(|capts| {
|
|
|
|
// first one is the whole string, index 1-N are the matches.
|
|
|
|
if capts.len() != 5 {
|
|
|
|
debug!("Matches, but not expected number of groups");
|
|
|
|
return None;
|
|
|
|
}
|
|
|
|
debug!("Matches: {}", capts.len());
|
|
|
|
|
|
|
|
let modname = capts.at(1).unwrap();
|
|
|
|
let hashname = capts.at(2).unwrap();
|
|
|
|
let mut hash = capts.at(3).unwrap();
|
|
|
|
|
|
|
|
debug!("Destructure FilePath to ID:");
|
|
|
|
debug!(" FilePath: {:?}", s);
|
|
|
|
debug!(" Module Name: {:?}", modname);
|
|
|
|
debug!(" Hash Name: {:?}", hashname);
|
|
|
|
debug!(" Hash: {:?}", hash);
|
|
|
|
|
|
|
|
let idtype = select_id_type_from_str(hashname);
|
|
|
|
match idtype {
|
|
|
|
FileIDType::NONE => hash = "INVALID",
|
|
|
|
_ => {},
|
|
|
|
}
|
|
|
|
|
|
|
|
Some(FileID::new(idtype, String::from(hash)))
|
|
|
|
}).unwrap_or({
|
|
|
|
debug!("Did not match");
|
|
|
|
FileID {
|
|
|
|
id_type: FileIDType::NONE,
|
|
|
|
id: None,
|
|
|
|
}
|
|
|
|
})
|
2015-12-02 12:23:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<PathBuf> for FileID {
|
2015-11-23 17:42:55 +00:00
|
|
|
|
2015-12-02 12:23:00 +00:00
|
|
|
fn from(s: PathBuf) -> FileID {
|
|
|
|
unimplemented!()
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> From<&'a PathBuf> for FileID {
|
|
|
|
|
|
|
|
fn from(s: &'a PathBuf) -> FileID {
|
|
|
|
unimplemented!()
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2015-11-23 17:42:55 +00:00
|
|
|
|
2015-12-02 11:52:04 +00:00
|
|
|
pub struct FileIDError {
|
|
|
|
summary: String,
|
|
|
|
descrip: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FileIDError {
|
|
|
|
|
|
|
|
pub fn new(s: String, d: String) -> FileIDError {
|
|
|
|
FileIDError {
|
|
|
|
summary: s,
|
|
|
|
descrip: d,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Error for FileIDError {
|
|
|
|
|
|
|
|
fn description(&self) -> &str {
|
|
|
|
&self.summary[..]
|
|
|
|
}
|
|
|
|
|
|
|
|
fn cause(&self) -> Option<&Error> {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Debug for FileIDError {
|
|
|
|
|
|
|
|
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
|
|
|
write!(fmt, "FileIDError: '{}'\n{}", self.summary, self.descrip);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a> Display for FileIDError {
|
|
|
|
|
|
|
|
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
|
|
|
write!(fmt, "FileIDError: '{}'", self.summary);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-12-02 13:41:04 +00:00
|
|
|
fn select_id_type_from_str(s: &str) -> FileIDType {
|
|
|
|
match s {
|
|
|
|
"UUID" => FileIDType::UUID,
|
|
|
|
_ => FileIDType::NONE,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-12-02 11:52:04 +00:00
|
|
|
pub type FileIDResult = Result<FileID, FileIDError>;
|
|
|
|
|
2015-12-02 12:49:19 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
mod test {
|
|
|
|
|
|
|
|
use super::{FileID, FileIDType};
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn file_id_from_string() {
|
|
|
|
setup_logger();
|
|
|
|
|
|
|
|
let s1 = String::from("/home/user/testmodule-UUID-some-id.imag");
|
|
|
|
let s2 = String::from("/home/user/testmodule-UUID-some-id.extension.imag");
|
|
|
|
let s3 = String::from("/home/user/testmodule-NOHASH-some-id.imag");
|
|
|
|
|
|
|
|
let id1 = FileID::from(s1);
|
|
|
|
let id2 = FileID::from(s2);
|
|
|
|
let id3 = FileID::from(s3);
|
|
|
|
|
|
|
|
println!("Id 1 : {:?}", id1);
|
|
|
|
println!("Id 2 : {:?}", id2);
|
|
|
|
println!("Id 3 : {:?}", id3);
|
|
|
|
|
|
|
|
assert_eq!(FileIDType::UUID, id1.get_type());
|
|
|
|
assert_eq!(FileIDType::UUID, id2.get_type());
|
|
|
|
assert_eq!(FileIDType::NONE, id3.get_type());
|
|
|
|
|
|
|
|
let f1 : String = id1.into();
|
|
|
|
let f2 : String = id2.into();
|
|
|
|
let f3 : String = id3.into();
|
|
|
|
|
|
|
|
assert_eq!(String::from("some-id"), f1);
|
|
|
|
assert_eq!(String::from("some-id"), f2);
|
|
|
|
assert_eq!(String::from("INVALID"), f3);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn setup_logger() {
|
|
|
|
extern crate log;
|
|
|
|
use log::{LogLevelFilter, set_logger};
|
|
|
|
use runtime::ImagLogger;
|
|
|
|
|
|
|
|
log::set_logger(|max_log_lvl| {
|
|
|
|
let lvl = LogLevelFilter::Debug;
|
|
|
|
max_log_lvl.set(lvl);
|
|
|
|
Box::new(ImagLogger::new(lvl.to_log_level().unwrap()))
|
|
|
|
});
|
|
|
|
debug!("Init logger for test");
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|