Ensure store path created if not found
This commit is contained in:
parent
9ba78e7406
commit
f0e4979723
|
@ -8,3 +8,4 @@ edition = "2018"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
ed25519-dalek = "1.0.1"
|
ed25519-dalek = "1.0.1"
|
||||||
|
regex = "1"
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
|
use regex;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::{prelude::*, Error, ErrorKind};
|
use std::io::{prelude::*, Error, ErrorKind};
|
||||||
|
use std::path;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub struct Store {
|
pub struct Store {
|
||||||
|
@ -18,7 +20,7 @@ impl Store {
|
||||||
|
|
||||||
pub fn from(path: String) -> Store {
|
pub fn from(path: String) -> Store {
|
||||||
Store {
|
Store {
|
||||||
path,
|
path: Store::normalize_path(path),
|
||||||
buffer: vec![],
|
buffer: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,11 +29,13 @@ impl Store {
|
||||||
if self.path.is_empty() {
|
if self.path.is_empty() {
|
||||||
return Err(Error::new(ErrorKind::InvalidInput, "empty path for store"));
|
return Err(Error::new(ErrorKind::InvalidInput, "empty path for store"));
|
||||||
}
|
}
|
||||||
|
let p = self.path.clone();
|
||||||
|
Store::ensure_dir(p.clone());
|
||||||
let mut f = fs::OpenOptions::new()
|
let mut f = fs::OpenOptions::new()
|
||||||
.append(true)
|
.append(true)
|
||||||
.create(true)
|
.create(true)
|
||||||
.open(&self.path)?;
|
.open(p.clone())?;
|
||||||
match fs::read(&self.path) {
|
match fs::read(p) {
|
||||||
Ok(buff) => {
|
Ok(buff) => {
|
||||||
self.buffer = buff;
|
self.buffer = buff;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -41,23 +45,48 @@ impl Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn save(&mut self) -> Result<(), Error> {
|
pub fn save(&mut self) -> Result<(), Error> {
|
||||||
fs::write(self.path.clone(), self.buffer.clone())
|
Store::ensure_dir(self.path.clone());
|
||||||
|
fs::write(
|
||||||
|
Store::normalize_path(self.path.clone()),
|
||||||
|
self.buffer.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn normalize_path(p: String) -> String {
|
||||||
|
let re = regex::Regex::new(r"[\\,/]+").unwrap();
|
||||||
|
let sep = path::MAIN_SEPARATOR.to_string();
|
||||||
|
re.replace_all(p.as_str(), sep.as_str()).to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ensure_dir(p: String) {
|
||||||
|
let np = Store::normalize_path(p);
|
||||||
|
let pa = path::PathBuf::from(np);
|
||||||
|
if !pa.exists() {
|
||||||
|
fs::create_dir_all(pa.parent().unwrap());
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::Store;
|
use super::Store;
|
||||||
use std::{fs, io, time::SystemTime};
|
use regex;
|
||||||
|
use std::{fs, io, iter::FromIterator, path, path::MAIN_SEPARATOR, time::SystemTime};
|
||||||
|
|
||||||
const TMP_DIR: &str = "/tmp/pigeon_core/test_data/storage/store";
|
const TMP_DIR: [&'static str; 5] = ["/tmp", "pigeon_core", "test_data", "storage", "store"];
|
||||||
|
|
||||||
fn format_file_name(name: &str) -> String {
|
fn format_file_name(name: &str) -> String {
|
||||||
format!("{}/{}", TMP_DIR, name)
|
let sep = String::from(MAIN_SEPARATOR.clone());
|
||||||
|
let mut pc: Vec<&str> = vec![];
|
||||||
|
for dir in TMP_DIR.to_vec() {
|
||||||
|
pc.push(dir);
|
||||||
|
}
|
||||||
|
pc.push(name);
|
||||||
|
pc.join(&sep)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_tmp_dir() -> Result<(), io::Error> {
|
fn setup_tmp_dir() -> Result<(), io::Error> {
|
||||||
fs::create_dir_all(TMP_DIR)
|
fs::create_dir_all(TMP_DIR.join(MAIN_SEPARATOR.to_string().as_str()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_tmp_file(name: &str, buf: Option<Vec<u8>>) -> Result<String, io::Error> {
|
fn setup_tmp_file(name: &str, buf: Option<Vec<u8>>) -> Result<String, io::Error> {
|
||||||
|
@ -113,18 +142,21 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn store_open_creates_new_file() {
|
fn store_open_creates_new_file() {
|
||||||
setup_tmp_dir().unwrap();
|
fn setup_path() -> String {
|
||||||
|
let name = "store_open_creates_new_file";
|
||||||
let t = SystemTime::now()
|
let t = SystemTime::now()
|
||||||
.duration_since(SystemTime::UNIX_EPOCH)
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let now = format!("{:?}", t);
|
let now = format!("{}-{:?}", name, t);
|
||||||
let path = format_file_name(&now);
|
format_file_name(&now)
|
||||||
let mut s = Store::from(path);
|
}
|
||||||
|
let path = setup_path();
|
||||||
|
let mut s = Store::from(path.clone());
|
||||||
let resp = s.open();
|
let resp = s.open();
|
||||||
assert_eq!(false, resp.is_err());
|
assert_eq!(false, resp.is_err());
|
||||||
let eb: Vec<u8> = vec![];
|
let eb: Vec<u8> = vec![];
|
||||||
assert_eq!(eb, s.buffer);
|
assert_eq!(eb, s.buffer);
|
||||||
teardown_tmp_file(&now);
|
teardown_tmp_file(&*path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -132,10 +164,12 @@ mod tests {
|
||||||
let buf: Vec<u8> = "i exist".as_bytes().to_vec();
|
let buf: Vec<u8> = "i exist".as_bytes().to_vec();
|
||||||
let p = setup_tmp_file("store_load_existing", Some(buf.clone()));
|
let p = setup_tmp_file("store_load_existing", Some(buf.clone()));
|
||||||
assert_eq!(true, p.is_ok());
|
assert_eq!(true, p.is_ok());
|
||||||
let mut s = Store::from(p.unwrap());
|
let path = p.unwrap();
|
||||||
|
let mut s = Store::from(path.clone());
|
||||||
let resp = s.open();
|
let resp = s.open();
|
||||||
assert_eq!(true, resp.is_ok());
|
assert_eq!(true, resp.is_ok());
|
||||||
assert_eq!(buf, s.buffer);
|
assert_eq!(buf, s.buffer);
|
||||||
|
teardown_tmp_file(&*path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -148,25 +182,26 @@ mod tests {
|
||||||
let now = format!("{}-{:?}", name, t);
|
let now = format!("{}-{:?}", name, t);
|
||||||
format_file_name(&now)
|
format_file_name(&now)
|
||||||
}
|
}
|
||||||
let buf = "It's a strange time to be created".as_bytes().to_vec();
|
|
||||||
let path = setup_path();
|
let path = setup_path();
|
||||||
|
let buf = "It's a strange time to be created".as_bytes().to_vec();
|
||||||
let mut s = Store::from(path.clone());
|
let mut s = Store::from(path.clone());
|
||||||
s.buffer = buf.clone();
|
s.buffer = buf.clone();
|
||||||
assert_eq!(buf.clone(), s.buffer);
|
assert_eq!(buf.clone(), s.buffer);
|
||||||
let mut resp = s.save();
|
let mut resp = s.save();
|
||||||
assert_eq!(true, resp.is_ok());
|
assert_eq!(true, resp.is_ok());
|
||||||
|
|
||||||
let mut s = Store::from(path);
|
let mut s = Store::from(path.clone());
|
||||||
let mut resp = s.open();
|
let mut resp = s.open();
|
||||||
assert_eq!(true, resp.is_ok());
|
assert_eq!(true, resp.is_ok());
|
||||||
assert_eq!(buf, s.buffer);
|
assert_eq!(buf, s.buffer);
|
||||||
|
teardown_tmp_file(&*path);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn store_save_updates_existing_file() {
|
fn store_save_updates_existing_file() {
|
||||||
let buf: Vec<u8> = "i exist".as_bytes().to_vec();
|
let buf: Vec<u8> = "i exist".as_bytes().to_vec();
|
||||||
fn setup_buffer(buf: Vec<u8>) -> String {
|
fn setup_buffer(buf: Vec<u8>) -> String {
|
||||||
let p = setup_tmp_file("store_load_existing", Some(buf.clone()));
|
let p = setup_tmp_file("store_save_updates_existing_file", Some(buf.clone()));
|
||||||
assert_eq!(true, p.is_ok());
|
assert_eq!(true, p.is_ok());
|
||||||
p.unwrap()
|
p.unwrap()
|
||||||
}
|
}
|
||||||
|
@ -185,8 +220,25 @@ mod tests {
|
||||||
let resp = s.save();
|
let resp = s.save();
|
||||||
assert_eq!(true, resp.is_ok());
|
assert_eq!(true, resp.is_ok());
|
||||||
|
|
||||||
let mut s = setup_store(path);
|
let mut s = setup_store(path.clone());
|
||||||
assert_ne!(buf, s.buffer);
|
assert_ne!(buf, s.buffer);
|
||||||
assert_eq!(new_buf, s.buffer);
|
assert_eq!(new_buf, s.buffer);
|
||||||
|
teardown_tmp_file(&*path);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn store_normalize_path() {
|
||||||
|
let re = regex::Regex::new(r"[\\,/]+").unwrap();
|
||||||
|
let sep = "\\";
|
||||||
|
let op = format_file_name("store_normalize_path");
|
||||||
|
let e = op.clone();
|
||||||
|
let mut a = op.clone().to_owned();
|
||||||
|
println!("{}, {}, {}", op.clone(), e.clone(), a.clone());
|
||||||
|
a = re.replace_all(a.as_str(), sep).to_string();
|
||||||
|
assert_ne!(e, a);
|
||||||
|
|
||||||
|
let r = Store::normalize_path(a.clone().to_owned());
|
||||||
|
assert_ne!(a, r);
|
||||||
|
assert_eq!(e, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue