Merge branch 'add-store' into rewrite
This commit is contained in:
commit
52787f5108
7 changed files with 182 additions and 113 deletions
|
@ -2,12 +2,14 @@ use std::convert::{From, Into};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt::{Debug, Display, Formatter};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::hash::Hash;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
#[derive(Eq)]
|
#[derive(Eq)]
|
||||||
|
#[derive(Hash)]
|
||||||
pub struct FileHash {
|
pub struct FileHash {
|
||||||
hash: String,
|
hash: String,
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ use std::convert::{From, Into};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt::{Debug, Display, Formatter};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use std::hash::Hash;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::result::Result;
|
use std::result::Result;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
@ -12,6 +13,9 @@ use storage::file::id_type::FileIDType;
|
||||||
use storage::file::hash::FileHash;
|
use storage::file::hash::FileHash;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
#[derive(Hash)]
|
||||||
|
#[derive(Eq)]
|
||||||
|
#[derive(PartialEq)]
|
||||||
pub struct FileID {
|
pub struct FileID {
|
||||||
id: FileHash,
|
id: FileHash,
|
||||||
id_type: FileIDType,
|
id_type: FileIDType,
|
||||||
|
@ -101,7 +105,7 @@ impl Into<String> for FileID {
|
||||||
fn into(self) -> String {
|
fn into(self) -> String {
|
||||||
let typestr : String = self.id_type.into();
|
let typestr : String = self.id_type.into();
|
||||||
let idstr : String = self.id.into();
|
let idstr : String = self.id.into();
|
||||||
typestr + &idstr[..]
|
typestr + "-" + &idstr[..]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
use std::convert::{From, Into};
|
use std::convert::{From, Into};
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
#[derive(Eq)]
|
#[derive(Eq)]
|
||||||
// #[derive(Display)]
|
// #[derive(Display)]
|
||||||
|
#[derive(Hash)]
|
||||||
pub enum FileIDType {
|
pub enum FileIDType {
|
||||||
UUID,
|
UUID,
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,130 +23,42 @@ use self::header::data::*;
|
||||||
* Internal abstract view on a file. Does not exist on the FS and is just kept
|
* Internal abstract view on a file. Does not exist on the FS and is just kept
|
||||||
* internally until it is written to disk.
|
* internally until it is written to disk.
|
||||||
*/
|
*/
|
||||||
pub struct File<'a> {
|
pub struct File {
|
||||||
owning_module : &'a Module<'a>,
|
pub owning_module_name : &'static str,
|
||||||
header : FileHeaderData,
|
pub header : FileHeaderData,
|
||||||
data : String,
|
pub data : String,
|
||||||
id : FileID,
|
pub id : FileID,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> File<'a> {
|
impl File {
|
||||||
|
|
||||||
pub fn new(module: &'a Module<'a>) -> File<'a> {
|
pub fn owner_name(&self) -> &'static str {
|
||||||
let f = File {
|
self.owning_module_name
|
||||||
owning_module: module,
|
|
||||||
header: FileHeaderData::Null,
|
|
||||||
data: String::from(""),
|
|
||||||
id: File::get_new_file_id(),
|
|
||||||
};
|
|
||||||
debug!("Create new File object: {:?}", f);
|
|
||||||
f
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_parser_result(module: &'a Module<'a>, id: FileID, header: FileHeaderData, data: String) -> File<'a> {
|
pub fn header(&self) -> &FileHeaderData {
|
||||||
let f = File {
|
&self.header
|
||||||
owning_module: module,
|
|
||||||
header: header,
|
|
||||||
data: data,
|
|
||||||
id: id,
|
|
||||||
};
|
|
||||||
debug!("Create new File object from parser result: {:?}", f);
|
|
||||||
f
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_with_header(module: &'a Module<'a>, h: FileHeaderData) -> File<'a> {
|
pub fn data(&self) -> &String {
|
||||||
let f = File {
|
&self.data
|
||||||
owning_module: module,
|
|
||||||
header: h,
|
|
||||||
data: String::from(""),
|
|
||||||
id: File::get_new_file_id(),
|
|
||||||
};
|
|
||||||
debug!("Create new File object with header: {:?}", f);
|
|
||||||
f
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_with_data(module: &'a Module<'a>, d: String) -> File<'a> {
|
pub fn contents(&self) -> (&FileHeaderData, &String) {
|
||||||
let f = File {
|
|
||||||
owning_module: module,
|
|
||||||
header: FileHeaderData::Null,
|
|
||||||
data: d,
|
|
||||||
id: File::get_new_file_id(),
|
|
||||||
};
|
|
||||||
debug!("Create new File object with data: {:?}", f);
|
|
||||||
f
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_with_content(module: &'a Module<'a>, h: FileHeaderData, d: String) -> File<'a> {
|
|
||||||
let f = File {
|
|
||||||
owning_module: module,
|
|
||||||
header: h,
|
|
||||||
data: d,
|
|
||||||
id: File::get_new_file_id(),
|
|
||||||
};
|
|
||||||
debug!("Create new File object with content: {:?}", f);
|
|
||||||
f
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call editor on the file
|
|
||||||
*
|
|
||||||
* Return true if exit code from editor was good (and content was changed), false otherwise.
|
|
||||||
*/
|
|
||||||
pub fn edit(rt: &Runtime) {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Call editor on the file contents, but don't include the header inside the editor call.
|
|
||||||
*
|
|
||||||
* Return true if exit code from editor was good (and content was changed), false otherwise.
|
|
||||||
*/
|
|
||||||
pub fn edit_contents(rt: &Runtime) -> bool {
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make file persistent.
|
|
||||||
*
|
|
||||||
* Retreive store path from the runtime, file id is already available in self.
|
|
||||||
*
|
|
||||||
* Return true if action succeeded, false otherwise.
|
|
||||||
*/
|
|
||||||
pub fn persist(rt: &Runtime) -> bool {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn header(&self) -> FileHeaderData {
|
|
||||||
self.header.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn data(&self) -> String {
|
|
||||||
self.data.clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn contents(&self) -> (FileHeaderData, String) {
|
|
||||||
(self.header(), self.data())
|
(self.header(), self.data())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn id(&self) -> FileID {
|
pub fn id(&self) -> &FileID {
|
||||||
self.id.clone()
|
&self.id
|
||||||
}
|
|
||||||
|
|
||||||
pub fn owner(&self) -> &'a Module<'a> {
|
|
||||||
self.owning_module
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn matches_with(&self, r: &Regex) -> bool {
|
pub fn matches_with(&self, r: &Regex) -> bool {
|
||||||
r.is_match(&self.data[..]) || self.header.matches_with(r)
|
r.is_match(&self.data[..]) || self.header.matches_with(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_new_file_id() -> FileID {
|
|
||||||
use uuid::Uuid;
|
|
||||||
let hash = FileHash::from(Uuid::new_v4().to_hyphenated_string());
|
|
||||||
FileID::new(FileIDType::UUID, hash)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Display for File<'a> {
|
impl Display for File {
|
||||||
|
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
||||||
write!(fmt,
|
write!(fmt,
|
||||||
|
@ -154,7 +66,7 @@ impl<'a> Display for File<'a> {
|
||||||
FileID: '{:?}'
|
FileID: '{:?}'
|
||||||
Header: '{:?}'
|
Header: '{:?}'
|
||||||
Data : '{:?}'",
|
Data : '{:?}'",
|
||||||
self.owning_module,
|
self.owning_module_name,
|
||||||
self.header,
|
self.header,
|
||||||
self.data,
|
self.data,
|
||||||
self.id);
|
self.id);
|
||||||
|
@ -163,7 +75,7 @@ impl<'a> Display for File<'a> {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Debug for File<'a> {
|
impl Debug for File {
|
||||||
|
|
||||||
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
|
||||||
write!(fmt,
|
write!(fmt,
|
||||||
|
@ -171,7 +83,7 @@ impl<'a> Debug for File<'a> {
|
||||||
FileID: '{:?}'
|
FileID: '{:?}'
|
||||||
Header: '{:?}'
|
Header: '{:?}'
|
||||||
Data : '{:?}'",
|
Data : '{:?}'",
|
||||||
self.owning_module,
|
self.owning_module_name,
|
||||||
self.header,
|
self.header,
|
||||||
self.data,
|
self.data,
|
||||||
self.id);
|
self.id);
|
||||||
|
|
|
@ -1,4 +1,153 @@
|
||||||
|
use std::rc::Rc;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::fs::File as FSFile;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::io::Write;
|
||||||
|
|
||||||
pub mod path;
|
pub mod path;
|
||||||
pub mod file;
|
pub mod file;
|
||||||
pub mod parser;
|
pub mod parser;
|
||||||
pub mod json;
|
pub mod json;
|
||||||
|
|
||||||
|
use module::Module;
|
||||||
|
use runtime::Runtime;
|
||||||
|
use storage::file::File;
|
||||||
|
use storage::file::id::FileID;
|
||||||
|
use storage::file::id_type::FileIDType;
|
||||||
|
use storage::file::hash::FileHash;
|
||||||
|
use storage::parser::{FileHeaderParser, Parser, ParserError};
|
||||||
|
use storage::file::header::data::FileHeaderData;
|
||||||
|
|
||||||
|
type Cache = HashMap<FileID, Rc<RefCell<File>>>;
|
||||||
|
|
||||||
|
pub struct Store {
|
||||||
|
cache : RefCell<Cache>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Store {
|
||||||
|
|
||||||
|
pub fn new() -> Store {
|
||||||
|
Store {
|
||||||
|
cache: RefCell::new(HashMap::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn put_in_cache(&self, f: File) -> FileID {
|
||||||
|
let res = f.id().clone();
|
||||||
|
self.cache.borrow_mut().insert(f.id().clone(), Rc::new(RefCell::new(f)));
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_file(&self, module: &Module)
|
||||||
|
-> FileID
|
||||||
|
{
|
||||||
|
let f = File {
|
||||||
|
owning_module_name: module.name(),
|
||||||
|
header: FileHeaderData::Null,
|
||||||
|
data: String::from(""),
|
||||||
|
id: self.get_new_file_id(),
|
||||||
|
};
|
||||||
|
|
||||||
|
debug!("Create new File object: {:?}", &f);
|
||||||
|
self.put_in_cache(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_file_from_parser_result(&self,
|
||||||
|
module: &Module,
|
||||||
|
id: FileID,
|
||||||
|
header: FileHeaderData,
|
||||||
|
data: String)
|
||||||
|
-> FileID
|
||||||
|
{
|
||||||
|
let f = File {
|
||||||
|
owning_module_name: module.name(),
|
||||||
|
header: header,
|
||||||
|
data: data,
|
||||||
|
id: id,
|
||||||
|
};
|
||||||
|
debug!("Create new File object from parser result: {:?}", f);
|
||||||
|
self.put_in_cache(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_file_with_header(&self,
|
||||||
|
module: &Module,
|
||||||
|
h: FileHeaderData)
|
||||||
|
-> FileID
|
||||||
|
{
|
||||||
|
let f = File {
|
||||||
|
owning_module_name: module.name(),
|
||||||
|
header: h,
|
||||||
|
data: String::from(""),
|
||||||
|
id: self.get_new_file_id(),
|
||||||
|
};
|
||||||
|
debug!("Create new File object with header: {:?}", f);
|
||||||
|
self.put_in_cache(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_file_with_data(&self, module: &Module, d: String)
|
||||||
|
-> FileID
|
||||||
|
{
|
||||||
|
let f = File {
|
||||||
|
owning_module_name: module.name(),
|
||||||
|
header: FileHeaderData::Null,
|
||||||
|
data: d,
|
||||||
|
id: self.get_new_file_id(),
|
||||||
|
};
|
||||||
|
debug!("Create new File object with data: {:?}", f);
|
||||||
|
self.put_in_cache(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_file_with_content(&self,
|
||||||
|
module: &Module,
|
||||||
|
h: FileHeaderData,
|
||||||
|
d: String)
|
||||||
|
-> FileID
|
||||||
|
{
|
||||||
|
let f = File {
|
||||||
|
owning_module_name: module.name(),
|
||||||
|
header: h,
|
||||||
|
data: d,
|
||||||
|
id: self.get_new_file_id(),
|
||||||
|
};
|
||||||
|
debug!("Create new File object with content: {:?}", f);
|
||||||
|
self.put_in_cache(f)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn persist<HP>(&self,
|
||||||
|
storepath: String,
|
||||||
|
p: &Parser<HP>,
|
||||||
|
f: Rc<RefCell<File>>) -> bool
|
||||||
|
where HP: FileHeaderParser
|
||||||
|
{
|
||||||
|
let file = f.deref().borrow();
|
||||||
|
let text = p.write(file.contents());
|
||||||
|
if text.is_err() {
|
||||||
|
error!("Error: {}", text.err().unwrap());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = {
|
||||||
|
let ids : String = file.id().clone().into();
|
||||||
|
format!("{}/{}-{}.imag", storepath, file.owning_module_name, ids)
|
||||||
|
};
|
||||||
|
|
||||||
|
FSFile::create(&path).map(|mut fsfile| {
|
||||||
|
fsfile.write_all(&text.unwrap().clone().into_bytes()[..])
|
||||||
|
}).map_err(|writeerr| {
|
||||||
|
debug!("Could not create file at '{}'", path);
|
||||||
|
}).and(Ok(true)).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn load(&self, id: &FileID) -> Option<Rc<RefCell<File>>> {
|
||||||
|
debug!("Loading '{:?}'", id);
|
||||||
|
self.cache.borrow().get(id).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_new_file_id(&self) -> FileID {
|
||||||
|
use uuid::Uuid;
|
||||||
|
let hash = FileHash::from(Uuid::new_v4().to_hyphenated_string());
|
||||||
|
FileID::new(FileIDType::UUID, hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -122,7 +122,7 @@ impl<HP: FileHeaderParser> Parser<HP> {
|
||||||
Ok((h_parseres, data.unwrap_or(String::new())))
|
Ok((h_parseres, data.unwrap_or(String::new())))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(&self, tpl : (FileHeaderData, String)) -> Result<String, ParserError> {
|
pub fn write(&self, tpl : (&FileHeaderData, &String)) -> Result<String, ParserError> {
|
||||||
debug!("Parsing internal datastructure to String");
|
debug!("Parsing internal datastructure to String");
|
||||||
let (header, data) = tpl;
|
let (header, data) = tpl;
|
||||||
let h_text = try!(self.headerp.write(&header));
|
let h_text = try!(self.headerp.write(&header));
|
||||||
|
|
|
@ -14,7 +14,7 @@ pub trait FilePrinter {
|
||||||
/*
|
/*
|
||||||
* Print a list of files
|
* Print a list of files
|
||||||
*/
|
*/
|
||||||
fn print_files<'a, I: Iterator<Item = File<'a>>>(&self, files: I) {
|
fn print_files<I: Iterator<Item = File>>(&self, files: I) {
|
||||||
for file in files {
|
for file in files {
|
||||||
self.print_file(&file);
|
self.print_file(&file);
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ impl FilePrinter for TablePrinter {
|
||||||
self.sp.print_file(f);
|
self.sp.print_file(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_files<'a, I: Iterator<Item = File<'a>>>(&self, files: I) {
|
fn print_files<I: Iterator<Item = File>>(&self, files: I) {
|
||||||
use prettytable::Table;
|
use prettytable::Table;
|
||||||
use prettytable::row::Row;
|
use prettytable::row::Row;
|
||||||
use prettytable::cell::Cell;
|
use prettytable::cell::Cell;
|
||||||
|
@ -103,9 +103,9 @@ impl FilePrinter for TablePrinter {
|
||||||
debug!("Printing file: {:?}", file);
|
debug!("Printing file: {:?}", file);
|
||||||
i += 1;
|
i += 1;
|
||||||
let cell_i = Cell::new(&format!("{}", i)[..]);
|
let cell_i = Cell::new(&format!("{}", i)[..]);
|
||||||
let cell_o = Cell::new(&format!("{}", file.owner().name())[..]);
|
let cell_o = Cell::new(&format!("{}", file.owner_name())[..]);
|
||||||
|
|
||||||
let id : String = file.id().into();
|
let id : String = file.id().clone().into();
|
||||||
let cell_id = Cell::new(&id[..]);
|
let cell_id = Cell::new(&id[..]);
|
||||||
let row = Row::new(vec![cell_i, cell_o, cell_id]);
|
let row = Row::new(vec![cell_i, cell_o, cell_id]);
|
||||||
tab.add_row(row);
|
tab.add_row(row);
|
||||||
|
|
Loading…
Reference in a new issue