refactor(blob): use object trait to create blob
This commit is contained in:
parent
642c358737
commit
faf7341525
@ -107,7 +107,7 @@ fn save_blob(obj: ObjProps) {
|
||||
let relative_s = &obj.clone().relative_s.unwrap();
|
||||
let relative_p = PathBuf::from(&relative_s);
|
||||
let lastmodified = obj.clone().lastmodified.unwrap().timestamp_millis();
|
||||
if let Err(err) = Blob::new(relative_p).create(&lastmodified.to_string(), false) {
|
||||
if let Err(err) = Blob::from_path(relative_p).create(&lastmodified.to_string(), false) {
|
||||
eprintln!("err: saving ref of {} ({})", relative_s.clone(), err);
|
||||
}
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ fn update_blob(obj: ObjProps) {
|
||||
let relative_p = PathBuf::from(&relative_s);
|
||||
let lastmodified = obj.clone().lastmodified.unwrap().timestamp_millis();
|
||||
// todo update function
|
||||
if let Err(err) = Blob::new(relative_p).create(&lastmodified.to_string(), false) {
|
||||
if let Err(err) = Blob::from_path(relative_p).create(&lastmodified.to_string(), false) {
|
||||
eprintln!("err: saving ref of {} ({})", relative_s.clone(), err);
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ impl PushChange for Copied {
|
||||
let lastmodified = prop.lastmodified.unwrap().timestamp_millis();
|
||||
|
||||
// create destination blob
|
||||
if let Err(err) = Blob::new(obj.path.clone()).create(&lastmodified.to_string(), false) {
|
||||
if let Err(err) = Blob::from_path(obj.path.clone()).create(&lastmodified.to_string(), false) {
|
||||
eprintln!("err: creating ref of {}: {}", obj.name.clone(), err);
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,7 @@ impl PushChange for Deleted {
|
||||
|
||||
// update tree
|
||||
// todo date
|
||||
Blob::new(obj.path.clone()).rm()?;
|
||||
Blob::from_path(obj.path.clone()).rm()?;
|
||||
|
||||
// remove index
|
||||
index::rm_line(obj.path.to_str().unwrap())?;
|
||||
|
@ -68,7 +68,7 @@ impl PushChange for Modified {
|
||||
let lastmodified = prop.lastmodified.unwrap().timestamp_millis();
|
||||
|
||||
// update blob
|
||||
Blob::new(obj.path.clone()).update(&lastmodified.to_string())?;
|
||||
Blob::from_path(obj.path.clone()).update(&lastmodified.to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -70,10 +70,10 @@ impl PushChange for Moved {
|
||||
let lastmodified = prop.lastmodified.unwrap().timestamp_millis();
|
||||
|
||||
// delete source and create destination blob
|
||||
if let Err(err) = Blob::new(obj.path.clone()).create(&lastmodified.to_string(), false) {
|
||||
if let Err(err) = Blob::from_path(obj.path.clone()).create(&lastmodified.to_string(), false) {
|
||||
eprintln!("err: creating ref of {}: {}", obj.name.clone(), err);
|
||||
}
|
||||
if let Err(err) = Blob::new(obj.path_from.clone().unwrap()).rm() {
|
||||
if let Err(err) = Blob::from_path(obj.path_from.clone().unwrap()).rm() {
|
||||
eprintln!("err: removing ref of {}: {}", obj.name.clone(), err);
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ impl PushChange for New {
|
||||
let lastmodified = prop.lastmodified.unwrap().timestamp_millis();
|
||||
|
||||
// create new blob
|
||||
Blob::new(obj.path.clone()).create(&lastmodified.to_string(), false)?;
|
||||
Blob::from_path(obj.path.clone()).create(&lastmodified.to_string(), false)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ pub trait PushChange {
|
||||
};
|
||||
|
||||
// check if remote is newest
|
||||
let last_sync_ts = Blob::new(obj.path.clone())
|
||||
let last_sync_ts = Blob::from_path(obj.path.clone())
|
||||
.saved_remote_ts()
|
||||
.parse::<i64>().unwrap();
|
||||
let remote_ts = obj_data.lastmodified.unwrap().timestamp_millis();
|
||||
|
@ -11,6 +11,7 @@ use crate::store::object::blob::Blob;
|
||||
use crate::utils::read::{read_folder, read_lines};
|
||||
use crate::store::object::tree;
|
||||
use crate::store::index;
|
||||
use crate::store::object::object::ObjMethods;
|
||||
|
||||
pub struct StatusArgs {
|
||||
pub nostyle: bool,
|
||||
@ -97,7 +98,7 @@ fn should_retain(hasher: &mut Sha1, key: String, obj: LocalObj, move_copy_hashes
|
||||
{
|
||||
return true;
|
||||
}
|
||||
let mut blob = Blob::new(obj.path.clone());
|
||||
let mut blob = Blob::from_path(obj.path.clone());
|
||||
let mut flag = true;
|
||||
let identical_blobs = blob.get_all_identical_blobs();
|
||||
|
||||
@ -172,7 +173,7 @@ pub fn get_all_staged() -> Vec<LocalObj> {
|
||||
let mut staged_objs = vec![];
|
||||
|
||||
for line in lines {
|
||||
let obj = Blob::new(line).get_local_obj();
|
||||
let obj = Blob::from_path(line).get_local_obj();
|
||||
if obj.state != State::Default {
|
||||
staged_objs.push(obj);
|
||||
}
|
||||
@ -266,7 +267,7 @@ fn get_diff() -> (HashMap<String, LocalObj>, HashMap<String, LocalObj>, Vec<Stri
|
||||
let diff = remove_duplicate(&mut hashes, &mut objs, RemoveSide::Both);
|
||||
obj_to_analyse.append(&mut diff.clone());
|
||||
} else {
|
||||
if Blob::new(cur_path).has_change() {
|
||||
if Blob::from_path(cur_path).has_changes() {
|
||||
objs_modified.push(cur_obj);
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ use crate::utils::{read, path};
|
||||
|
||||
pub mod tree;
|
||||
pub mod blob;
|
||||
pub mod object;
|
||||
|
||||
pub struct Object {
|
||||
path: PathBuf,
|
||||
|
@ -4,76 +4,202 @@ use std::io::Write;
|
||||
use std::fs::OpenOptions;
|
||||
use std::path::PathBuf;
|
||||
use std::time::SystemTime;
|
||||
use crypto::sha1::Sha1;
|
||||
use crypto::digest::Digest;
|
||||
use crate::commands::status::{LocalObj, State};
|
||||
use crate::commands::status::{State};
|
||||
use crate::utils::into::IntoPathBuf;
|
||||
use crate::utils::path::path_buf_to_string;
|
||||
use crate::utils::{path, read};
|
||||
use crate::store::head;
|
||||
use crate::store::object::{update_dates, add_node, rm_node};
|
||||
|
||||
use crate::store::object::object::ObjMethods;
|
||||
use crate::store::object::object::Obj;
|
||||
|
||||
const HASH_EMPTY: &str = "d41d8cd98f00b204e9800998ecf8427e";
|
||||
|
||||
pub struct Blob {
|
||||
r_path: PathBuf, // relative path
|
||||
a_path: PathBuf, // absolute path
|
||||
hash: String, // hash of relative path
|
||||
file_hash: Option<String>,
|
||||
obj_p: PathBuf, // path of the object file
|
||||
data: Vec<String>, // content of the blob
|
||||
pub obj: Obj,
|
||||
data: Vec<String>, // content of the ref file
|
||||
file_hash: Option<String>, // hash of the file's content
|
||||
}
|
||||
|
||||
//pub struct Blob {
|
||||
// r_path: PathBuf, // relative path
|
||||
// a_path: PathBuf, // absolute path
|
||||
// hash: String, // hash of relative path
|
||||
// file_hash: Option<String>,
|
||||
// obj_p: PathBuf, // path of the object file
|
||||
// data: Vec<String>, // content of the blob
|
||||
//}
|
||||
|
||||
|
||||
|
||||
impl Blob {
|
||||
pub fn new<S>(r_path: S) -> Blob where S: IntoPathBuf {
|
||||
let r_path = r_path.into();
|
||||
if r_path.is_dir() {
|
||||
eprintln!("{}: is a directory not a blob", r_path.display());
|
||||
}
|
||||
let mut hasher = Sha1::new();
|
||||
hasher.input_str(r_path.to_str().unwrap());
|
||||
let hash = hasher.result_str();
|
||||
|
||||
let (dir, res) = hash.split_at(2);
|
||||
|
||||
let mut obj_p = path::objects();
|
||||
obj_p.push(dir);
|
||||
obj_p.push(res);
|
||||
|
||||
let root = path::repo_root();
|
||||
let a_path = root.join(r_path.clone());
|
||||
|
||||
Blob {
|
||||
r_path,
|
||||
a_path,
|
||||
hash,
|
||||
file_hash: None,
|
||||
obj_p,
|
||||
pub fn new(obj: Obj) -> Self {
|
||||
Self {
|
||||
obj,
|
||||
data: vec![],
|
||||
file_hash: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_line_filename(&mut self) -> (String, String) {
|
||||
let file_name = self.r_path.file_name().unwrap().to_str().unwrap().to_owned();
|
||||
let mut line = String::from("blob");
|
||||
line.push_str(" ");
|
||||
line.push_str(&self.hash);
|
||||
line.push_str(" ");
|
||||
line.push_str(&file_name);
|
||||
(line, file_name)
|
||||
pub fn from_path<S>(r_path: S) -> Blob where S: IntoPathBuf {
|
||||
let r_path = r_path.into();
|
||||
Self {
|
||||
obj: Obj::from_path(r_path),
|
||||
data: vec![],
|
||||
file_hash: None,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_file_hash(&mut self) -> String {
|
||||
if self.file_hash.is_none() {
|
||||
let bytes = std::fs::read(self.a_path.clone()).unwrap();
|
||||
let bytes = std::fs::read(self.get_file_path()).unwrap();
|
||||
let hash = md5::compute(&bytes);
|
||||
self.file_hash = Some(format!("{:x}", hash))
|
||||
}
|
||||
self.file_hash.clone().unwrap()
|
||||
}
|
||||
|
||||
fn create_blob_ref(&mut self, file_name: String, ts_remote: &str) -> io::Result<()> {
|
||||
let metadata = fs::metadata(self.a_path.clone())?;
|
||||
/// read line of blob to get all informations and store them in self.data
|
||||
pub fn read_data(&mut self) {
|
||||
if self.data.len() == 0 {
|
||||
if let Ok(mut file) = File::open(self.get_obj_path()) {
|
||||
let mut buffer = String::new();
|
||||
let _ = file.read_to_string(&mut buffer);
|
||||
let data = buffer.rsplit(' ').collect::<Vec<_>>();
|
||||
for e in data {
|
||||
self.data.push(String::from(e));
|
||||
}
|
||||
self.data.reverse();
|
||||
|
||||
// remove \n of last element
|
||||
if let Some(last) = self.data.last_mut() {
|
||||
if last.ends_with("\n") {
|
||||
last.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_data_index(&mut self, index: usize) -> String {
|
||||
self.read_data();
|
||||
if self.data.len() >= index + 1 {
|
||||
self.data[index].clone()
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn saved_filename(&mut self) -> String {
|
||||
self.get_data_index(0)
|
||||
}
|
||||
|
||||
pub fn saved_remote_ts(&mut self) -> String {
|
||||
self.get_data_index(1)
|
||||
}
|
||||
|
||||
fn saved_local_size(&mut self) -> String {
|
||||
self.get_data_index(2)
|
||||
}
|
||||
|
||||
fn saved_local_ts(&mut self) -> u64 {
|
||||
match self.get_data_index(3).as_str() {
|
||||
"" => 0,
|
||||
str => str.parse::<u64>().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
fn saved_hash(&mut self) -> String {
|
||||
self.get_data_index(4)
|
||||
}
|
||||
|
||||
fn has_same_size(&mut self) -> bool {
|
||||
let metadata = match fs::metadata(self.get_file_path()) {
|
||||
Ok(m) => m,
|
||||
Err(_) => return true,
|
||||
};
|
||||
|
||||
if self.saved_local_size() == String::new() { return true; }
|
||||
metadata.len().to_string() == self.saved_local_size()
|
||||
}
|
||||
|
||||
fn is_newer(&mut self) -> bool {
|
||||
let metadata = match fs::metadata(self.get_file_path()) {
|
||||
Ok(m) => m,
|
||||
Err(_) => return true,
|
||||
};
|
||||
|
||||
let secs = metadata
|
||||
.modified()
|
||||
.unwrap()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
if self.saved_local_ts() == 0 { return true; }
|
||||
secs > self.saved_local_ts()
|
||||
}
|
||||
|
||||
fn has_same_hash(&mut self) -> bool {
|
||||
if self.saved_hash() == String::new() { return false; }
|
||||
let file_hash = self.get_file_hash().clone();
|
||||
self.saved_hash() == file_hash
|
||||
}
|
||||
|
||||
pub fn has_changes(&mut self) -> bool {
|
||||
!self.has_same_size() || (self.is_newer() && !self.has_same_hash())
|
||||
}
|
||||
|
||||
pub fn get_all_identical_blobs(&mut self) -> Vec<String> {
|
||||
// an empty file is a new file not the copy of another empty file
|
||||
if self.get_file_hash() == HASH_EMPTY {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
let refs_p = self.get_obj_path();
|
||||
let mut blobs: Vec<String> = vec![];
|
||||
if let Ok(lines) = read::read_lines(refs_p) {
|
||||
for line in lines {
|
||||
if let Ok(l) = line {
|
||||
blobs.push(l.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
blobs
|
||||
}
|
||||
|
||||
pub fn status(&mut self, path_from: &mut Option<PathBuf>) -> State {
|
||||
let has_obj_ref = self.get_obj_path().exists();
|
||||
let blob_exists = self.get_file_path().exists();
|
||||
|
||||
if has_obj_ref && !blob_exists {
|
||||
State::Deleted
|
||||
} else if !has_obj_ref && blob_exists {
|
||||
let identical_blobs = self.get_all_identical_blobs();
|
||||
if identical_blobs.len() != 0 {
|
||||
let identical_blob = Blob::from_path(identical_blobs[0].clone()).get_local_obj();
|
||||
|
||||
if identical_blob.state == State::Deleted {
|
||||
*path_from = Some(identical_blob.path);
|
||||
State::Moved
|
||||
} else if identical_blob.state == State::Default {
|
||||
*path_from = Some(identical_blob.path);
|
||||
State::Copied
|
||||
} else {
|
||||
State::New
|
||||
}
|
||||
} else {
|
||||
State::New
|
||||
}
|
||||
} else if !has_obj_ref && !blob_exists {
|
||||
State::Default
|
||||
} else if self.has_changes() {
|
||||
State::Modified
|
||||
} else {
|
||||
State::Default
|
||||
}
|
||||
}
|
||||
|
||||
fn create_blob_ref(&mut self, ts_remote: &str) -> io::Result<()> {
|
||||
let metadata = fs::metadata(self.get_file_path())?;
|
||||
let secs = metadata
|
||||
.modified()
|
||||
.unwrap()
|
||||
@ -81,30 +207,28 @@ impl Blob {
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
|
||||
let mut content = file_name.clone();
|
||||
content.push_str(" ");
|
||||
content.push_str(ts_remote);
|
||||
content.push_str(" ");
|
||||
content.push_str(&metadata.len().to_string());
|
||||
content.push_str(" ");
|
||||
content.push_str(&secs.to_string());
|
||||
content.push_str(" ");
|
||||
content.push_str(&self.get_file_hash());
|
||||
// build line with all needed properties
|
||||
let content = format!("{} {} {} {} {}",
|
||||
self.get_name(),
|
||||
ts_remote,
|
||||
metadata.len().to_string(),
|
||||
secs.to_string(),
|
||||
self.get_file_hash());
|
||||
|
||||
let binding = self.obj_p.clone();
|
||||
let child = binding.file_name();
|
||||
self.obj_p.pop();
|
||||
if !self.obj_p.clone().exists() {
|
||||
fs::create_dir_all(self.obj_p.clone())?;
|
||||
// create parent dir if needed
|
||||
let mut obj_path = self.get_obj_path();
|
||||
obj_path.pop();
|
||||
if !obj_path.exists() {
|
||||
fs::create_dir_all(obj_path)?;
|
||||
}
|
||||
self.obj_p.push(child.unwrap().to_str().unwrap());
|
||||
|
||||
// open ref file
|
||||
let mut file = OpenOptions::new()
|
||||
.create_new(true)
|
||||
.write(true)
|
||||
.open(self.obj_p.clone())?;
|
||||
.open(self.get_obj_path())?;
|
||||
|
||||
writeln!(file, "{}", &content)?;
|
||||
writeln!(file, "{}", content)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -134,261 +258,101 @@ impl Blob {
|
||||
.open(refs_p)?;
|
||||
|
||||
// todo deal with duplicate content
|
||||
writeln!(file, "{}", self.r_path.clone().to_str().unwrap())?;
|
||||
writeln!(file, "{}", self.get_relative_file_path().to_str().unwrap())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_all_identical_blobs(&mut self) -> Vec<String> {
|
||||
// an empty file is a new file not the copy of another empty file
|
||||
if self.get_file_hash() == HASH_EMPTY {
|
||||
return vec![];
|
||||
}
|
||||
|
||||
let refs_p = self.get_file_ref();
|
||||
let mut blobs: Vec<String> = vec![];
|
||||
if let Ok(lines) = read::read_lines(refs_p) {
|
||||
for line in lines {
|
||||
if let Ok(l) = line {
|
||||
blobs.push(l.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
blobs
|
||||
// build line for parent reference
|
||||
fn get_line(&mut self) -> String {
|
||||
format!("blob {} {}", self.get_hash_path(), self.get_name())
|
||||
}
|
||||
|
||||
pub fn create(&mut self, ts_remote: &str, up_parent: bool) -> io::Result<()> {
|
||||
let (line, file_name) = self.get_line_filename();
|
||||
|
||||
// add blob reference to parent
|
||||
if self.r_path.iter().count() == 1 {
|
||||
let line = self.get_line();
|
||||
if self.get_relative_file_path().iter().count() == 1 {
|
||||
head::add_line(line)?;
|
||||
} else {
|
||||
add_node(self.r_path.parent().unwrap(), &line)?;
|
||||
add_node(self.get_relative_file_path().parent().unwrap(), &line)?;
|
||||
}
|
||||
|
||||
if let Err(err) = self.create_blob_ref(file_name.clone(), ts_remote.clone()) {
|
||||
eprintln!("err: saving blob ref of {}: {}", self.r_path.clone().display(), err);
|
||||
if let Err(err) = self.create_blob_ref(ts_remote.clone()) {
|
||||
eprintln!("err: saving blob ref of {}: {}", self.get_relative_file_path().display(), err);
|
||||
}
|
||||
|
||||
if let Err(err) = self.create_hash_ref() {
|
||||
eprintln!("err: saving hash ref of {}: {}", self.r_path.clone().display(), err);
|
||||
eprintln!("err: saving hash ref of {}: {}", self.get_relative_file_path().display(), err);
|
||||
}
|
||||
|
||||
// update date for all parent
|
||||
if up_parent {
|
||||
if let Err(err) = update_dates(self.r_path.clone(), ts_remote) {
|
||||
eprintln!("err: updating parent date of {}: {}", self.r_path.clone().display(), err);
|
||||
if let Err(err) = update_dates(self.get_relative_file_path(), ts_remote) {
|
||||
eprintln!("err: updating parent date of {}: {}", self.get_relative_file_path().display(), err);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// remove object
|
||||
pub fn rm(&mut self) -> io::Result<()> {
|
||||
let (line, _) = self.get_line_filename();
|
||||
let line = self.get_line();
|
||||
|
||||
// remove blob reference to parent
|
||||
if self.r_path.iter().count() == 1 {
|
||||
if self.get_relative_file_path().iter().count() == 1 {
|
||||
head::rm_line(&line)?;
|
||||
} else {
|
||||
rm_node(self.r_path.parent().unwrap(), &line)?;
|
||||
rm_node(self.get_relative_file_path().parent().unwrap(), &line)?;
|
||||
}
|
||||
|
||||
// remove blob object
|
||||
fs::remove_file(self.obj_p.clone())?;
|
||||
fs::remove_file(self.get_obj_path())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update(&mut self, ts_remote: &str) -> io::Result<()> {
|
||||
|
||||
// remove old hash ref
|
||||
let mut refs_p = path::refs();
|
||||
let binding = self.saved_hash();
|
||||
let (dir, res) = binding.split_at(2);
|
||||
refs_p.push(dir);
|
||||
refs_p.push(res);
|
||||
if let Err(err) = fs::remove_file(refs_p) {
|
||||
eprintln!("err: removing hash ref of {}: {}", self.r_path.clone().display(), err);
|
||||
}
|
||||
|
||||
// creating new hash ref
|
||||
if let Err(err) = self.create_hash_ref() {
|
||||
eprintln!("err: saving hash ref of {}: {}", self.r_path.clone().display(), err);
|
||||
}
|
||||
|
||||
// updating content of blob's ref
|
||||
let metadata = fs::metadata(self.a_path.clone())?;
|
||||
let secs = metadata
|
||||
.modified()
|
||||
.unwrap()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
|
||||
let mut content = self.saved_filename();
|
||||
content.push_str(" ");
|
||||
content.push_str(ts_remote);
|
||||
content.push_str(" ");
|
||||
content.push_str(&metadata.len().to_string());
|
||||
content.push_str(" ");
|
||||
content.push_str(&secs.to_string());
|
||||
content.push_str(" ");
|
||||
content.push_str(&self.get_file_hash());
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.write(true)
|
||||
.open(self.obj_p.clone())?;
|
||||
|
||||
writeln!(file, "{}", &content)?;
|
||||
// // remove old hash ref
|
||||
// let mut refs_p = path::refs();
|
||||
// let binding = self.saved_hash();
|
||||
// let (dir, res) = binding.split_at(2);
|
||||
// refs_p.push(dir);
|
||||
// refs_p.push(res);
|
||||
// if let Err(err) = fs::remove_file(refs_p) {
|
||||
// eprintln!("err: removing hash ref of {}: {}", self.r_path.clone().display(), err);
|
||||
// }
|
||||
//
|
||||
// // creating new hash ref
|
||||
// if let Err(err) = self.create_hash_ref() {
|
||||
// eprintln!("err: saving hash ref of {}: {}", self.r_path.clone().display(), err);
|
||||
// }
|
||||
//
|
||||
// // updating content of blob's ref
|
||||
// let metadata = fs::metadata(self.a_path.clone())?;
|
||||
// let secs = metadata
|
||||
// .modified()
|
||||
// .unwrap()
|
||||
// .duration_since(SystemTime::UNIX_EPOCH)
|
||||
// .unwrap()
|
||||
// .as_secs();
|
||||
//
|
||||
// let mut content = self.saved_filename();
|
||||
// content.push_str(" ");
|
||||
// content.push_str(ts_remote);
|
||||
// content.push_str(" ");
|
||||
// content.push_str(&metadata.len().to_string());
|
||||
// content.push_str(" ");
|
||||
// content.push_str(&secs.to_string());
|
||||
// content.push_str(" ");
|
||||
// content.push_str(&self.get_file_hash());
|
||||
//
|
||||
// let mut file = OpenOptions::new()
|
||||
// .write(true)
|
||||
// .open(self.obj_p.clone())?;
|
||||
//
|
||||
// writeln!(file, "{}", &content)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read_data(&mut self) {
|
||||
if self.data.len() == 0 {
|
||||
if let Ok(mut file) = File::open(self.obj_p.clone()) {
|
||||
let mut buffer = String::new();
|
||||
let _ = file.read_to_string(&mut buffer);
|
||||
let data = buffer.rsplit(' ').collect::<Vec<_>>();
|
||||
for e in data {
|
||||
self.data.push(String::from(e));
|
||||
}
|
||||
self.data.reverse();
|
||||
|
||||
// remove \n of last element
|
||||
if let Some(last) = self.data.last_mut() {
|
||||
if last.ends_with("\n") {
|
||||
last.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn saved_filename(&mut self) -> String {
|
||||
self.read_data();
|
||||
if self.data.len() >= 1 {
|
||||
self.data[0].clone()
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn saved_remote_ts(&mut self) -> String {
|
||||
self.read_data();
|
||||
if self.data.len() >= 2 {
|
||||
self.data[1].clone()
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn saved_local_size(&mut self) -> String {
|
||||
self.read_data();
|
||||
if self.data.len() >= 3 {
|
||||
self.data[2].clone()
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn saved_local_ts(&mut self) -> u64 {
|
||||
self.read_data();
|
||||
if self.data.len() >= 4 {
|
||||
self.data[3].parse::<u64>().unwrap()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn saved_hash(&mut self) -> String {
|
||||
self.read_data();
|
||||
if self.data.len() >= 5 {
|
||||
self.data[4].clone()
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn has_same_size(&mut self) -> bool {
|
||||
let metadata = match fs::metadata(self.a_path.clone()) {
|
||||
Ok(m) => m,
|
||||
Err(_) => return true,
|
||||
};
|
||||
|
||||
if self.saved_local_size() == String::new() { return true; }
|
||||
metadata.len().to_string() == self.saved_local_size()
|
||||
}
|
||||
|
||||
fn is_newer(&mut self) -> bool {
|
||||
let metadata = match fs::metadata(self.a_path.clone()) {
|
||||
Ok(m) => m,
|
||||
Err(_) => return true,
|
||||
};
|
||||
|
||||
let secs = metadata
|
||||
.modified()
|
||||
.unwrap()
|
||||
.duration_since(SystemTime::UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
if self.saved_local_ts() == 0 { return true; }
|
||||
secs > self.saved_local_ts()
|
||||
}
|
||||
|
||||
fn has_same_hash(&mut self) -> bool {
|
||||
if self.saved_hash() == String::new() { return false; }
|
||||
let file_hash = self.get_file_hash().clone();
|
||||
self.saved_hash() == file_hash
|
||||
}
|
||||
|
||||
pub fn has_change(&mut self) -> bool {
|
||||
!self.has_same_size() || (self.is_newer() && !self.has_same_hash())
|
||||
}
|
||||
|
||||
pub fn status(&mut self, path_from: &mut Option<PathBuf>) -> State {
|
||||
let has_obj_ref = self.obj_p.clone().exists();
|
||||
let blob_exists = self.a_path.clone().exists();
|
||||
|
||||
if has_obj_ref && !blob_exists {
|
||||
State::Deleted
|
||||
} else if !has_obj_ref && blob_exists {
|
||||
let identical_blobs = self.get_all_identical_blobs();
|
||||
if identical_blobs.len() != 0 {
|
||||
let identical_blob = Blob::new(identical_blobs[0].clone())
|
||||
.get_local_obj();
|
||||
if identical_blob.state == State::Deleted {
|
||||
*path_from = Some(identical_blob.path);
|
||||
State::Moved
|
||||
} else if identical_blob.state == State::Default {
|
||||
*path_from = Some(identical_blob.path);
|
||||
State::Copied
|
||||
} else {
|
||||
State::New
|
||||
}
|
||||
} else {
|
||||
State::New
|
||||
}
|
||||
} else if !has_obj_ref && !blob_exists {
|
||||
State::Default
|
||||
} else if self.has_change() {
|
||||
State::Modified
|
||||
} else {
|
||||
State::Default
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_local_obj(&mut self) -> LocalObj {
|
||||
let mut path_from = None;
|
||||
let state = self.status(&mut path_from);
|
||||
|
||||
LocalObj {
|
||||
otype: String::from("blob"),
|
||||
name: path_buf_to_string(self.r_path.clone()),
|
||||
path: self.r_path.clone(),
|
||||
path_from,
|
||||
state
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
207
src/store/object/object.rs
Normal file
207
src/store/object/object.rs
Normal file
@ -0,0 +1,207 @@
|
||||
use std::path::PathBuf;
|
||||
use crypto::sha1::Sha1;
|
||||
use crypto::digest::Digest;
|
||||
use crate::utils::path;
|
||||
use crate::store::object::{blob::Blob, tree::Tree};
|
||||
use crate::store::head;
|
||||
use crate::commands::status::{State, LocalObj};
|
||||
|
||||
|
||||
enum ObjType {
|
||||
TREE,
|
||||
BLOB,
|
||||
DEFAULT
|
||||
}
|
||||
|
||||
pub trait ObjMethods {
|
||||
fn get_type(&self) -> ObjType;
|
||||
fn get_obj_path(&self) -> PathBuf;
|
||||
fn get_file_path(&self) -> PathBuf;
|
||||
fn get_relative_file_path(&self) -> PathBuf;
|
||||
fn get_name(&self) -> String;
|
||||
fn get_hash_path(&self) -> String;
|
||||
fn get_local_obj(&self) -> LocalObj;
|
||||
}
|
||||
|
||||
pub struct Obj {
|
||||
name: String,
|
||||
ref_path: Option<PathBuf>,
|
||||
obj_path: PathBuf,
|
||||
obj_type: ObjType,
|
||||
file_path: PathBuf, // file here is used as both file and directory
|
||||
relative_file_path: PathBuf,
|
||||
hash_path: String, // hash of the relative path of the file
|
||||
//tree: Option<&Tree>,
|
||||
//blob: Option<&Blob>
|
||||
}
|
||||
|
||||
|
||||
impl ObjMethods for Obj {
|
||||
fn get_type(&self) -> ObjType {
|
||||
self.obj_type
|
||||
}
|
||||
|
||||
fn get_obj_path(&self) -> PathBuf {
|
||||
self.obj_path
|
||||
}
|
||||
|
||||
fn get_file_path(&self) -> PathBuf {
|
||||
self.file_path
|
||||
}
|
||||
|
||||
fn get_relative_file_path(&self) -> PathBuf {
|
||||
self.relative_file_path
|
||||
}
|
||||
|
||||
fn get_local_obj(&self) -> LocalObj {
|
||||
LocalObj {
|
||||
otype: match self.obj_type {
|
||||
ObjType::BLOB => String::from("blob"),
|
||||
ObjType::TREE => String::from("tree"),
|
||||
ObjType::DEFAULT => String::from("default"),
|
||||
},
|
||||
name: self.name,
|
||||
path: self.file_path,
|
||||
path_from: None,
|
||||
state: State::New
|
||||
}
|
||||
}
|
||||
|
||||
fn get_name(&self) -> String {
|
||||
self.name
|
||||
}
|
||||
fn get_hash_path(&self) -> String {
|
||||
self.hash_path
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjMethods for Blob {
|
||||
fn get_type(&self) -> ObjType {
|
||||
self.obj.get_type()
|
||||
}
|
||||
|
||||
fn get_obj_path(&self) -> PathBuf {
|
||||
self.obj.get_obj_path()
|
||||
}
|
||||
|
||||
fn get_file_path(&self) -> PathBuf {
|
||||
self.obj.get_file_path()
|
||||
}
|
||||
|
||||
fn get_relative_file_path(&self) -> PathBuf {
|
||||
self.obj.get_relative_file_path()
|
||||
}
|
||||
|
||||
fn get_local_obj(&self) -> LocalObj {
|
||||
self.obj.get_local_obj()
|
||||
}
|
||||
|
||||
fn get_name(&self) -> String {
|
||||
self.obj.get_name()
|
||||
}
|
||||
|
||||
fn get_hash_path(&self) -> String {
|
||||
self.obj.get_hash_path()
|
||||
}
|
||||
}
|
||||
|
||||
impl ObjMethods for Tree {
|
||||
fn get_type(&self) -> ObjType {
|
||||
self.obj.get_type()
|
||||
}
|
||||
|
||||
fn get_obj_path(&self) -> PathBuf {
|
||||
self.obj.get_obj_path()
|
||||
}
|
||||
|
||||
fn get_file_path(&self) -> PathBuf {
|
||||
self.obj.get_file_path()
|
||||
}
|
||||
|
||||
fn get_relative_file_path(&self) -> PathBuf {
|
||||
self.obj.get_relative_file_path()
|
||||
}
|
||||
|
||||
fn get_local_obj(&self) -> LocalObj {
|
||||
self.obj.get_local_obj()
|
||||
}
|
||||
|
||||
fn get_name(&self) -> String {
|
||||
self.obj.get_name()
|
||||
}
|
||||
|
||||
fn get_hash_path(&self) -> String {
|
||||
self.obj.get_hash_path()
|
||||
}
|
||||
}
|
||||
|
||||
impl Obj {
|
||||
//fn new(name: &str) -> Self {
|
||||
// Obj {
|
||||
// name: String::from(name),
|
||||
// ref_path: None,
|
||||
// obj_path: PathBuf::new(),
|
||||
// file_path: PathBuf::new(),
|
||||
// obj_type: ObjType::DEFAULT,
|
||||
// }
|
||||
//}
|
||||
|
||||
pub fn from_path(path: PathBuf) -> Self {
|
||||
let mut hasher = Sha1::new();
|
||||
hasher.input_str(path.to_str().unwrap());
|
||||
let hash = hasher.result_str();
|
||||
|
||||
let (dir, res) = hash.split_at(2);
|
||||
let mut obj_path = path::objects();
|
||||
obj_path.push(dir);
|
||||
obj_path.push(res);
|
||||
|
||||
let root = path::repo_root();
|
||||
let abs_path = root.join(path.clone());
|
||||
Obj {
|
||||
name: match abs_path.file_name() {
|
||||
None => String::new(),
|
||||
Some(name) => name.to_str().unwrap().to_owned()
|
||||
},
|
||||
ref_path: None,
|
||||
obj_path,
|
||||
obj_type: match path.exists() {
|
||||
true => match path.is_dir() {
|
||||
true => ObjType::TREE,
|
||||
false => ObjType::BLOB
|
||||
},
|
||||
false => ObjType::DEFAULT
|
||||
},
|
||||
file_path: abs_path,
|
||||
relative_file_path: path,
|
||||
hash_path: hash,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_line(line: String) -> Self {
|
||||
|
||||
}
|
||||
|
||||
pub fn from_head() -> Self {
|
||||
Obj {
|
||||
name: String::new(),
|
||||
ref_path: None,
|
||||
obj_path: head::path(),
|
||||
obj_type: ObjType::TREE,
|
||||
file_path: PathBuf::new(),
|
||||
relative_file_path: PathBuf::new(),
|
||||
hash_path: String::new(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//fn spawn(&self, kind: &str) -> Box<dyn FnOnce(Self)> {
|
||||
// match kind {
|
||||
// "Blob" => Box::new(|_| Blob::new(self.clone())),
|
||||
// "Tree" => Box::new(|_| Tree::new(self.clone())),
|
||||
// _ => unreachable!(),
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
@ -1,106 +1,161 @@
|
||||
use std::fs::File;
|
||||
use std::io;
|
||||
use crate::store::object::object::Obj;
|
||||
use std::path::PathBuf;
|
||||
use crate::utils::path::path_buf_to_string;
|
||||
use crate::utils::{read, path};
|
||||
use crate::store::head;
|
||||
use crate::store::object::{self, update_dates, parse_path, hash_obj, add_node, create_obj};
|
||||
use crate::store::object::blob::Blob;
|
||||
use std::iter::{Iter, Empty};
|
||||
use crate::store::object::object::ObjMethods;
|
||||
use std::fs::{self, File, OpenOptions};
|
||||
use std::io::{self, BufRead, BufReader, Write, Lines};
|
||||
use crate::utils::read;
|
||||
|
||||
pub struct Tree {
|
||||
pub obj: Obj,
|
||||
pub lines: Option<Lines<BufReader<File>>>,
|
||||
pub lines_iter: Option<Iter<String, Lines<BufReader<File>>>>,
|
||||
|
||||
|
||||
pub fn add(path: PathBuf, date: &str, up_parent: bool) -> io::Result<()> {
|
||||
let (line, hash, name) = parse_path(path.clone(), false);
|
||||
|
||||
// add tree reference to parent
|
||||
if path.iter().count() == 1 {
|
||||
head::add_line(line)?;
|
||||
} else {
|
||||
add_node(path.parent().unwrap(), &line)?;
|
||||
}
|
||||
|
||||
// create tree object
|
||||
let mut content = name;
|
||||
content.push_str(" ");
|
||||
content.push_str(date);
|
||||
create_obj(hash, &content)?;
|
||||
|
||||
// update date for all parent
|
||||
if up_parent {
|
||||
update_dates(path, date)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn rm(path: PathBuf) -> io::Result<()> {
|
||||
let (_, lines) = read(path_buf_to_string(path.to_path_buf())).unwrap();
|
||||
for line in lines {
|
||||
let (ftype, hash, _) = parse_line(line.unwrap());
|
||||
if ftype == String::from("blob") {
|
||||
object::rm(&hash)?;
|
||||
} else {
|
||||
rm_hash(hash)?;
|
||||
|
||||
impl Tree {
|
||||
|
||||
pub fn from_head() -> Self {
|
||||
Tree {
|
||||
obj: Obj::from_head(),
|
||||
lines: None,
|
||||
lines_iter: None
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
||||
pub fn from_path(path: PathBuf) -> Self {
|
||||
Tree {
|
||||
obj: Obj::from_path(path),
|
||||
lines: None,
|
||||
lines_iter: None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read_data(&mut self) {
|
||||
if self.lines.is_none() {
|
||||
if let Ok(mut file) = File::open(self.get_obj_path()) {
|
||||
self.lines = Some(BufReader::new(file).lines());
|
||||
self.lines_iter = Some(self.lines.iter());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_iter(&mut self) -> Iter<String, Lines<BufReader<File>>> {
|
||||
if let Some(iter) = self.lines_iter {
|
||||
iter
|
||||
}
|
||||
std::process::exit(4);
|
||||
}
|
||||
|
||||
pub fn next(&mut self) -> Option<Obj> {
|
||||
self.read_data();
|
||||
let iter = self.get_iter();
|
||||
match iter.next() {
|
||||
Some(line) => Some(Obj::from_line(line)),
|
||||
None => None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// create
|
||||
}
|
||||
|
||||
fn rm_hash(hash: String) -> io::Result<()> {
|
||||
let mut obj_p = path::objects();
|
||||
let (dir, res) = hash.split_at(2);
|
||||
obj_p.push(dir);
|
||||
obj_p.push(res);
|
||||
|
||||
match read::read_lines(obj_p) {
|
||||
Ok(mut reader) => {
|
||||
reader.next();
|
||||
for line in reader {
|
||||
let (ftype, hash, _) = parse_line(line.unwrap());
|
||||
if ftype == String::from("blob") {
|
||||
object::rm(&hash)?;
|
||||
} else {
|
||||
rm_hash(hash)?;
|
||||
}
|
||||
}
|
||||
},
|
||||
Err(err) => {
|
||||
eprintln!("error reading tree: {}", err);
|
||||
},
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn read(tree: String) -> Option<(String, io::Lines<io::BufReader<File>>)> {
|
||||
let mut obj_p = path::objects();
|
||||
|
||||
let (dir, res) = hash_obj(&tree);
|
||||
obj_p.push(dir);
|
||||
obj_p.push(res);
|
||||
|
||||
match read::read_lines(obj_p) {
|
||||
Ok(mut reader) => {
|
||||
let name = match reader.next() {
|
||||
Some(Ok(line)) => line,
|
||||
_ => String::new(),
|
||||
};
|
||||
Some((name, reader))
|
||||
},
|
||||
Err(err) => {
|
||||
eprintln!("error reading tree: {}", err);
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_line(line: String) -> (String, String, String) {
|
||||
let mut split = line.rsplit(' ');
|
||||
if split.clone().count() != 3 {
|
||||
eprintln!("fatal: invalid object(s)");
|
||||
std::process::exit(1);
|
||||
}
|
||||
|
||||
let name = split.next().unwrap();
|
||||
let hash = split.next().unwrap();
|
||||
let ftype = split.next().unwrap();
|
||||
(String::from(ftype), String::from(hash), String::from(name))
|
||||
}
|
||||
//pub fn add(path: PathBuf, date: &str, up_parent: bool) -> io::Result<()> {
|
||||
// let (line, hash, name) = parse_path(path.clone(), false);
|
||||
//
|
||||
// // add tree reference to parent
|
||||
// if path.iter().count() == 1 {
|
||||
// head::add_line(line)?;
|
||||
// } else {
|
||||
// add_node(path.parent().unwrap(), &line)?;
|
||||
// }
|
||||
//
|
||||
// // create tree object
|
||||
// let mut content = name;
|
||||
// content.push_str(" ");
|
||||
// content.push_str(date);
|
||||
// create_obj(hash, &content)?;
|
||||
//
|
||||
// // update date for all parent
|
||||
// if up_parent {
|
||||
// update_dates(path, date)?;
|
||||
// }
|
||||
//
|
||||
// Ok(())
|
||||
//}
|
||||
//
|
||||
//pub fn rm(path: PathBuf) -> io::Result<()> {
|
||||
// let (_, lines) = read(path_buf_to_string(path.to_path_buf())).unwrap();
|
||||
// for line in lines {
|
||||
// let (ftype, hash, _) = parse_line(line.unwrap());
|
||||
// if ftype == String::from("blob") {
|
||||
// object::rm(&hash)?;
|
||||
// } else {
|
||||
// rm_hash(hash)?;
|
||||
// }
|
||||
// }
|
||||
// Ok(())
|
||||
//}
|
||||
//
|
||||
//fn rm_hash(hash: String) -> io::Result<()> {
|
||||
// let mut obj_p = path::objects();
|
||||
// let (dir, res) = hash.split_at(2);
|
||||
// obj_p.push(dir);
|
||||
// obj_p.push(res);
|
||||
//
|
||||
// match read::read_lines(obj_p) {
|
||||
// Ok(mut reader) => {
|
||||
// reader.next();
|
||||
// for line in reader {
|
||||
// let (ftype, hash, _) = parse_line(line.unwrap());
|
||||
// if ftype == String::from("blob") {
|
||||
// object::rm(&hash)?;
|
||||
// } else {
|
||||
// rm_hash(hash)?;
|
||||
// }
|
||||
// }
|
||||
// },
|
||||
// Err(err) => {
|
||||
// eprintln!("error reading tree: {}", err);
|
||||
// },
|
||||
// }
|
||||
// Ok(())
|
||||
//}
|
||||
//
|
||||
//pub fn read(tree: String) -> Option<(String, io::Lines<io::BufReader<File>>)> {
|
||||
// let mut obj_p = path::objects();
|
||||
//
|
||||
// let (dir, res) = hash_obj(&tree);
|
||||
// obj_p.push(dir);
|
||||
// obj_p.push(res);
|
||||
//
|
||||
// match read::read_lines(obj_p) {
|
||||
// Ok(mut reader) => {
|
||||
// let name = match reader.next() {
|
||||
// Some(Ok(line)) => line,
|
||||
// _ => String::new(),
|
||||
// };
|
||||
// Some((name, reader))
|
||||
// },
|
||||
// Err(err) => {
|
||||
// eprintln!("error reading tree: {}", err);
|
||||
// None
|
||||
// },
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//pub fn parse_line(line: String) -> (String, String, String) {
|
||||
// let mut split = line.rsplit(' ');
|
||||
// if split.clone().count() != 3 {
|
||||
// eprintln!("fatal: invalid object(s)");
|
||||
// std::process::exit(1);
|
||||
// }
|
||||
//
|
||||
// let name = split.next().unwrap();
|
||||
// let hash = split.next().unwrap();
|
||||
// let ftype = split.next().unwrap();
|
||||
// (String::from(ftype), String::from(hash), String::from(name))
|
||||
//}
|
||||
|
@ -208,7 +208,7 @@ fn get_non_new_local_element(iter: &mut dyn Iterator<Item = &PathBuf>) -> Option
|
||||
!Object::new(el.unwrap().clone().to_str().unwrap()).exists()
|
||||
} else {
|
||||
// ignore newly created file (not sync)
|
||||
Blob::new(el.unwrap().clone()).status(&mut None) == State::New
|
||||
Blob::from_path(el.unwrap().clone()).status(&mut None) == State::New
|
||||
}
|
||||
} {
|
||||
el = iter.next();
|
||||
|
@ -1,5 +1,4 @@
|
||||
use rand::{distributions::Alphanumeric, Rng};
|
||||
use std::env;
|
||||
|
||||
mod utils;
|
||||
use utils::{server::ServerTest, client::ClientTest};
|
||||
@ -61,4 +60,46 @@ mod push_tests {
|
||||
client.clean();
|
||||
server.clean();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn push_dir() {
|
||||
let id = get_random_test_id();
|
||||
let mut server = ServerTest::new(id.clone()).init();
|
||||
let mut client = ClientTest::new(id).init();
|
||||
|
||||
let _ = client.add_dir("dir");
|
||||
let _ = client.add_file("dir/file2", "bar");
|
||||
|
||||
// push dir and file2
|
||||
client.run_cmd_ok("add file2");
|
||||
client.run_cmd_ok("push");
|
||||
|
||||
// tests
|
||||
assert!(server.has_file("dir/file2", "bar"));
|
||||
|
||||
client.clean();
|
||||
server.clean();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn push_all() {
|
||||
let id = get_random_test_id();
|
||||
let mut server = ServerTest::new(id.clone()).init();
|
||||
let mut client = ClientTest::new(id).init();
|
||||
|
||||
let _ = client.add_file("file1", "foo");
|
||||
let _ = client.add_dir("dir");
|
||||
let _ = client.add_file("dir/file2", "bar");
|
||||
|
||||
// push dir and file2
|
||||
client.run_cmd_ok("add *");
|
||||
client.run_cmd_ok("push");
|
||||
|
||||
// tests
|
||||
assert!(server.has_file("file1", "foo"));
|
||||
assert!(server.has_file("dir/file2", "bar"));
|
||||
|
||||
client.clean();
|
||||
server.clean();
|
||||
}
|
||||
}
|
||||
|
@ -23,8 +23,6 @@ impl ClientTest {
|
||||
let mut exe_path = env::current_dir().unwrap();
|
||||
exe_path = exe_path.join("target/debug/nextsync");
|
||||
|
||||
// let _ = env::set_current_dir(vol.clone());
|
||||
|
||||
// build the client
|
||||
ClientTest {
|
||||
user: String::from("admin"),
|
||||
@ -50,13 +48,8 @@ impl ClientTest {
|
||||
|
||||
}
|
||||
|
||||
pub fn clean(mut self) -> Self {
|
||||
pub fn clean(self) -> Self {
|
||||
let _ = fs::remove_dir_all(&self.volume);
|
||||
|
||||
// set back the current dir
|
||||
self.exe_path.pop();
|
||||
dbg!(self.exe_path.clone());
|
||||
let _ = env::set_current_dir(self.exe_path.clone());
|
||||
self
|
||||
}
|
||||
|
||||
@ -80,6 +73,14 @@ impl ClientTest {
|
||||
return output;
|
||||
}
|
||||
|
||||
pub fn add_dir(&mut self, name: &str) -> std::io::Result<()> {
|
||||
let mut path = self.volume.clone();
|
||||
path.push_str("/");
|
||||
path.push_str(name);
|
||||
let _ = fs::create_dir_all(path)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_file(&mut self, name: &str, content: &str) -> std::io::Result<()> {
|
||||
let mut path = self.volume.clone();
|
||||
path.push_str("/");
|
||||
|
@ -93,7 +93,7 @@ impl ServerTest {
|
||||
let full_path = self.volume.clone().join(file);
|
||||
|
||||
if !full_path.exists() {
|
||||
eprintln!("File '{}' does't exists on the server", file);
|
||||
eprintln!("File '{}' doesn't exists on the server", file);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user