From 7951ad0520a2ba4796e4dee8002ae3d9789abf38 Mon Sep 17 00:00:00 2001 From: grimhilt Date: Sun, 25 Feb 2024 17:34:16 +0100 Subject: [PATCH] refactor(tree): create impl Tree --- docs/store.md | 2 +- src/commands/clone.rs | 4 +- src/commands/pull.rs | 4 +- src/commands/push/deleted.rs | 1 + src/commands/push/moved.rs | 1 + src/commands/push/new_dir.rs | 4 +- src/commands/push/rm_dir.rs | 5 +- src/commands/status.rs | 67 +++++++----- src/store/object/blob.rs | 29 +---- src/store/object/object.rs | 207 +++++++++++++++++++++++++++++------ src/store/object/tree.rs | 199 ++++++++++++--------------------- src/utils/into.rs | 8 +- 12 files changed, 306 insertions(+), 225 deletions(-) diff --git a/docs/store.md b/docs/store.md index 382c106..b48542e 100644 --- a/docs/store.md +++ b/docs/store.md @@ -12,4 +12,4 @@ timestamp2: timestamp of file locally to know when the file has changed on the s folder_name timestamp tree hash_path folder_name blob hash_path file_name -``` \ No newline at end of file +``` diff --git a/src/commands/clone.rs b/src/commands/clone.rs index a7aff56..cb31ca1 100644 --- a/src/commands/clone.rs +++ b/src/commands/clone.rs @@ -12,7 +12,7 @@ use crate::global::global::{DIR_PATH, set_dir_path}; use crate::services::api::ApiError; use crate::services::api_call::ApiCall; use crate::services::req_props::{ReqProps, ObjProps}; -use crate::store::object::{tree, blob::Blob}; +use crate::store::object::{tree::Tree, blob::Blob}; use crate::commands::config; use crate::commands::init; @@ -91,7 +91,7 @@ pub fn clone(args: CloneArgs) { // add tree let path_folder = p.strip_prefix(ref_path.clone()).unwrap(); let lastmodified = folder.lastmodified.unwrap().timestamp_millis(); - if let Err(err) = tree::add(path_folder.to_path_buf(), &lastmodified.to_string(), false) { + if let Err(err) = Tree::from_path(path_folder.to_path_buf()).create(&lastmodified.to_string(), false) { eprintln!("err: saving ref of {} ({})", path_folder.display(), err); } } diff --git a/src/commands/pull.rs b/src/commands/pull.rs index acdee0c..f20fc3d 100644 --- a/src/commands/pull.rs +++ b/src/commands/pull.rs @@ -4,7 +4,7 @@ use std::fs::DirBuilder; use crate::services::downloader::Downloader; use crate::services::req_props::ObjProps; use crate::store::object::blob::Blob; -use crate::store::object::tree; +use crate::store::object::tree::Tree; use crate::utils::api::get_api_props; use crate::utils::path; use crate::commands::remote_diff::get_diff; @@ -29,7 +29,7 @@ pub fn pull() { // add tree let path_folder = p.strip_prefix(ref_p.clone()).unwrap(); let lastmodified = folder.lastmodified.unwrap().timestamp_millis(); - if let Err(err) = tree::add(path_folder.to_path_buf(), &lastmodified.to_string(), false) { + if let Err(err) = Tree::from_path(path_folder.clone()).create(&lastmodified.to_string(), false) { eprintln!("err: saving ref of {} ({})", path_folder.display(), err); } } diff --git a/src/commands/push/deleted.rs b/src/commands/push/deleted.rs index 38f53c2..615cadd 100644 --- a/src/commands/push/deleted.rs +++ b/src/commands/push/deleted.rs @@ -7,6 +7,7 @@ use crate::store::index; use crate::store::object::blob::Blob; use crate::commands::status::LocalObj; use crate::commands::push::push_factory::{PushState, PushChange, PushFlowState}; +use crate::store::object::object::ObjMethods; pub struct Deleted { pub obj: LocalObj diff --git a/src/commands/push/moved.rs b/src/commands/push/moved.rs index a5632f1..35e8b4a 100644 --- a/src/commands/push/moved.rs +++ b/src/commands/push/moved.rs @@ -8,6 +8,7 @@ use crate::commands::status::LocalObj; use crate::commands::push::push_factory::{PushState, PushChange, PushFlowState}; use crate::store::object::blob::Blob; use crate::utils::path::path_buf_to_string; +use crate::store::object::object::ObjMethods; pub struct Moved { pub obj: LocalObj, diff --git a/src/commands/push/new_dir.rs b/src/commands/push/new_dir.rs index 5c0f5fe..39d156b 100644 --- a/src/commands/push/new_dir.rs +++ b/src/commands/push/new_dir.rs @@ -5,7 +5,7 @@ use crate::services::api_call::ApiCall; use crate::services::req_props::ReqProps; use crate::services::create_folder::CreateFolder; use crate::store::index; -use crate::store::object::tree; +use crate::store::object::tree::Tree; use crate::commands::status::LocalObj; use crate::commands::push::push_factory::{PushState, PushChange, PushFlowState}; @@ -75,7 +75,7 @@ impl PushChange for NewDir { let lastmodified = prop.lastmodified.unwrap().timestamp_millis(); // update tree - tree::add(obj.path.clone(), &lastmodified.to_string(), true)?; + Tree::from_path(obj.path.clone()).create(&lastmodified.to_string(), true)?; // remove index index::rm_line(obj.path.to_str().unwrap())?; diff --git a/src/commands/push/rm_dir.rs b/src/commands/push/rm_dir.rs index f313258..d29a651 100644 --- a/src/commands/push/rm_dir.rs +++ b/src/commands/push/rm_dir.rs @@ -4,9 +4,10 @@ use crate::services::api::ApiError; use crate::services::api_call::ApiCall; use crate::services::delete_path::DeletePath; use crate::store::index; -use crate::store::object::tree; +use crate::store::object::tree::Tree; use crate::commands::status::LocalObj; use crate::commands::push::push_factory::{PushState, PushChange, PushFlowState}; +use crate::store::object::object::ObjMethods; pub struct RmDir { pub obj: LocalObj @@ -49,7 +50,7 @@ impl PushChange for RmDir { // update tree // todo update date - tree::rm(obj.path.clone())?; + Tree::from_path(obj.path.clone()).rm()?; // remove index index::rm_line(obj.path.to_str().unwrap())?; diff --git a/src/commands/status.rs b/src/commands/status.rs index 28ea6dc..aec850c 100644 --- a/src/commands/status.rs +++ b/src/commands/status.rs @@ -1,15 +1,12 @@ -use std::fs::File; use std::path::PathBuf; -use std::io::{Lines, BufReader}; use std::collections::HashMap; use crypto::digest::Digest; use crypto::sha1::Sha1; use colored::Colorize; use crate::utils::path::{self, path_buf_to_string}; -use crate::store::head; use crate::store::object::blob::Blob; -use crate::utils::read::{read_folder, read_lines}; -use crate::store::object::tree; +use crate::store::object::tree::Tree; +use crate::utils::read::read_folder; use crate::store::index; use crate::store::object::object::ObjMethods; @@ -228,6 +225,12 @@ fn get_staged(hashes: &mut HashMap) -> Vec { staged_objs } +fn read_tree_to_hashmap(tree: &mut Tree, hashes: &mut HashMap, path: PathBuf) { + while let Some(child) = tree.next() { + hashes.insert(String::from(child.get_hash_path()), child.get_local_obj()); + }; +} + fn get_diff() -> (HashMap, HashMap, Vec) { let mut hashes = HashMap::new(); let mut objs: Vec = vec![]; @@ -239,9 +242,10 @@ fn get_diff() -> (HashMap, HashMap, Vec (HashMap, HashMap, Vec String { } } -fn add_to_hashmap(lines: Lines>, hashes: &mut HashMap, path: PathBuf) { - for line in lines { - if let Ok(ip) = line { - if ip.clone().len() > 5 { - let (ftype, hash, name) = tree::parse_line(ip); - let mut p = path.clone(); - p.push(name.clone()); - hashes.insert(String::from(hash), LocalObj{ - otype: String::from(ftype), - name: String::from(name), - path: p, - path_from: None, - state: State::Default, - }); - } - } - } -} +//fn add_to_hashmap(lines: Lines>, hashes: &mut HashMap, path: PathBuf) { +// for line in lines { +// if let Ok(ip) = line { +// if ip.clone().len() > 5 { +// let (ftype, hash, name) = tree::parse_line(ip); +// let mut p = path.clone(); +// p.push(name.clone()); +// hashes.insert(String::from(hash), LocalObj{ +// otype: String::from(ftype), +// name: String::from(name), +// path: p, +// path_from: None, +// state: State::Default, +// }); +// } +// } +// } +//} fn add_to_vec(entries: Vec, objects: &mut Vec, root: PathBuf) { for entry in entries { diff --git a/src/store/object/blob.rs b/src/store/object/blob.rs index 67934ff..ecd84ae 100644 --- a/src/store/object/blob.rs +++ b/src/store/object/blob.rs @@ -262,20 +262,10 @@ impl Blob { Ok(()) } - // 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<()> { // add blob reference to parent - let line = self.get_line(); - if self.get_relative_file_path().iter().count() == 1 { - head::add_line(line)?; - } else { - add_node(self.get_relative_file_path().parent().unwrap(), &line)?; - } + self.add_ref_to_parent(); if let Err(err) = self.create_blob_ref(ts_remote.clone()) { eprintln!("err: saving blob ref of {}: {}", self.get_relative_file_path().display(), err); @@ -295,23 +285,6 @@ impl Blob { Ok(()) } - /// remove object - pub fn rm(&mut self) -> io::Result<()> { - let line = self.get_line(); - - // remove blob reference to parent - if self.get_relative_file_path().iter().count() == 1 { - head::rm_line(&line)?; - } else { - rm_node(self.get_relative_file_path().parent().unwrap(), &line)?; - } - - // remove blob object - fs::remove_file(self.get_obj_path())?; - - Ok(()) - } - pub fn update(&mut self, ts_remote: &str) -> io::Result<()> { // // remove old hash ref diff --git a/src/store/object/object.rs b/src/store/object/object.rs index dfff112..dcd0b82 100644 --- a/src/store/object/object.rs +++ b/src/store/object/object.rs @@ -1,12 +1,15 @@ +use std::io; +use std::fs; use std::path::PathBuf; +use crate::utils::path; +use crate::store::head; +use crate::store::object::{add_node, rm_node}; 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}; - +#[derive(Clone, Copy)] enum ObjType { TREE, BLOB, @@ -21,6 +24,11 @@ pub trait ObjMethods { fn get_name(&self) -> String; fn get_hash_path(&self) -> String; fn get_local_obj(&self) -> LocalObj; + fn get_line(&self) -> String; + fn add_ref_to_parent(&self) -> io::Result<()>; + fn rm(&mut self) -> io::Result<()>; + fn rm_node(&mut self) -> io::Result<()>; + fn rm_node_down(&mut self) -> io::Result<()>; } pub struct Obj { @@ -42,15 +50,15 @@ impl ObjMethods for Obj { } fn get_obj_path(&self) -> PathBuf { - self.obj_path + self.obj_path.clone() } fn get_file_path(&self) -> PathBuf { - self.file_path + self.file_path.clone() } fn get_relative_file_path(&self) -> PathBuf { - self.relative_file_path + self.relative_file_path.clone() } fn get_local_obj(&self) -> LocalObj { @@ -60,18 +68,59 @@ impl ObjMethods for Obj { ObjType::TREE => String::from("tree"), ObjType::DEFAULT => String::from("default"), }, - name: self.name, - path: self.file_path, + name: self.get_name(), + path: self.get_file_path(), path_from: None, state: State::New } } fn get_name(&self) -> String { - self.name + self.name.clone() } + fn get_hash_path(&self) -> String { - self.hash_path + self.hash_path.clone() + } + + // build line for parent reference + fn get_line(&self) -> String { + format!("tree {} {}", self.get_hash_path(), self.get_name()) + } + + fn add_ref_to_parent(&self) -> io::Result<()> { + let line = self.get_line(); + if self.get_relative_file_path().iter().count() == 1 { + head::add_line(line)?; + } else { + add_node(self.get_relative_file_path().parent().unwrap(), &line)?; + } + Ok(()) + } + + fn rm_node(&mut self) -> io::Result<()> { + // remove self object and children object + self.rm_node_down(); + + // remove parent reference to self + let line = self.get_line(); + if self.get_relative_file_path().iter().count() == 1 { + head::rm_line(&line)?; + } else { + rm_node(self.get_relative_file_path().parent().unwrap(), &line)?; + } + + Ok(()) + } + + fn rm_node_down(&mut self) -> io::Result<()> { + eprintln!("rm_node_down: tried to do this on Obj"); + Ok(()) + } + + fn rm(&mut self) -> io::Result<()> { + eprintln!("rm: tried to do this on Obj"); + Ok(()) } } @@ -103,6 +152,33 @@ impl ObjMethods for Blob { fn get_hash_path(&self) -> String { self.obj.get_hash_path() } + + fn get_line(&self) -> String { + self.obj.get_line() + } + + fn add_ref_to_parent(&self) -> io::Result<()> { + self.obj.add_ref_to_parent() + } + + fn rm_node(&mut self) -> io::Result<()> { + self.obj.rm_node() + } + + fn rm_node_down(&mut self) -> io::Result<()> { + // remove reference to self + fs::remove_file(self.get_obj_path())?; + Ok(()) + } + + fn rm(&mut self) -> io::Result<()> { + // remove all references, including children's one + self.rm_node()?; + + // remove file + fs::remove_file(self.get_file_path())?; + Ok(()) + } } impl ObjMethods for Tree { @@ -133,18 +209,57 @@ impl ObjMethods for Tree { fn get_hash_path(&self) -> String { self.obj.get_hash_path() } + + fn get_line(&self) -> String { + self.obj.get_line() + } + + fn add_ref_to_parent(&self) -> io::Result<()> { + self.obj.add_ref_to_parent() + } + + fn rm_node(&mut self) -> io::Result<()> { + self.obj.rm_node() + } + + /// remove objects and children but not parent reference to self + fn rm_node_down(&mut self) -> io::Result<()> { + // remove children + while let Some(mut child) = self.next() { + match child.get_type() { + ObjType::TREE => child.rm_node_down(), + ObjType::BLOB => child.rm_node_down(), + _ => Ok(()) + }?; + }; + + // remove reference to self + fs::remove_file(self.get_obj_path())?; + Ok(()) + } + + fn rm(&mut self) -> io::Result<()> { + // remove all references, including children's one + self.rm_node()?; + + // remove directory and all subfiles + fs::remove_dir_all(self.get_file_path())?; + Ok(()) + } } 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, - // } - //} + fn new() -> Self { + Obj { + name: String::new(), + ref_path: None, + obj_path: PathBuf::new(), + file_path: PathBuf::new(), + obj_type: ObjType::DEFAULT, + hash_path: String::new(), + relative_file_path: PathBuf::new() + } + } pub fn from_path(path: PathBuf) -> Self { let mut hasher = Sha1::new(); @@ -177,9 +292,49 @@ impl Obj { hash_path: hash, } } + pub fn from_line(line: String, base_dir: Option) -> Box { + let mut split = line.rsplit(' '); + if split.clone().count() != 3 { + eprintln!("fatal: invalid object(s)"); + std::process::exit(1); + } - pub fn from_line(line: String) -> Self { - + let name = split.next().unwrap(); + let hash_path = split.next().unwrap(); + let obj_type = split.next().unwrap(); + + let (dir, res) = hash_path.split_at(2); + let mut obj_path = path::objects(); + obj_path.push(dir); + obj_path.push(res); + + let path = match base_dir { + Some(dir) => dir.join(name), + None => PathBuf::from(name), + }; + + let root = path::repo_root(); + let abs_path = root.join(path.clone()); + + let obj = Obj { + name: String::from(name), + ref_path: None, + obj_path, + obj_type: match obj_type { + "tree" => ObjType::TREE, + "blob" => ObjType::BLOB, + _ => ObjType::DEFAULT + }, + file_path: abs_path, + relative_file_path: path, + hash_path: String::from(hash_path), + }; + + match obj.obj_type { + ObjType::TREE => Box::new(Tree::new(obj)), + ObjType::BLOB => Box::new(Blob::new(obj)), + ObjType::DEFAULT => Box::new(Tree::new(obj)) + } } pub fn from_head() -> Self { @@ -193,15 +348,5 @@ impl Obj { hash_path: String::new(), } } - - - - //fn spawn(&self, kind: &str) -> Box { - // match kind { - // "Blob" => Box::new(|_| Blob::new(self.clone())), - // "Tree" => Box::new(|_| Tree::new(self.clone())), - // _ => unreachable!(), - // } - //} } diff --git a/src/store/object/tree.rs b/src/store/object/tree.rs index 414a3c3..06625e1 100644 --- a/src/store/object/tree.rs +++ b/src/store/object/tree.rs @@ -1,161 +1,106 @@ +use crate::utils::into::IntoPathBuf; use crate::store::object::object::Obj; use std::path::PathBuf; -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>>, - pub lines_iter: Option>>>, - + pub file: Option, + pub buf_reader: Option>, + is_head: bool, } impl Tree { + pub fn new(obj: Obj) -> Self { + Tree { + obj, + file: None, + buf_reader: None, + is_head: false, + } + } pub fn from_head() -> Self { Tree { obj: Obj::from_head(), - lines: None, - lines_iter: None + file: None, + buf_reader: None, + is_head: true, } } - pub fn from_path(path: PathBuf) -> Self { + pub fn from_path(r_path: S) -> Tree where S: IntoPathBuf { Tree { - obj: Obj::from_path(path), - lines: None, - lines_iter: None + obj: Obj::from_path(r_path.into()), + file: None, + buf_reader: None, + is_head: false, } } - 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()); + pub fn read(&mut self) { + if self.buf_reader.is_none() { + if let Ok(file) = File::open(self.get_obj_path()) { + //self.file = Some(file); + self.buf_reader = Some(BufReader::new(file)); + + // skip first line if is head + if !self.is_head { + self.next(); + } } } } - fn get_iter(&mut self) -> Iter>> { - if let Some(iter) = self.lines_iter { - iter - } - std::process::exit(4); - } - - pub fn next(&mut self) -> Option { - self.read_data(); - let iter = self.get_iter(); - match iter.next() { - Some(line) => Some(Obj::from_line(line)), + pub fn next(&mut self) -> Option> { + self.read(); + //if let Some(ref mut file) = self.buf_reader { + // let mut line = String::new(); + // match file.read_line(&mut line) { + // Ok(0) => Ok(None), // End of file + // Ok(_) => Ok(Some(line.trim_end().len())), // Return length of line + // Err(e) => Err(e), + // } + //} else { + // Ok(None) // If file is None, return None + //} + match self.buf_reader { + Some(ref mut file) => { + let mut line = String::new(); + match file.read_line(&mut line) { + Ok(0) => None, + Ok(_) => Some(Obj::from_line(line, Some(self.get_relative_file_path()))), + Err(e) => { + eprintln!("tree::next: failed to read next line: {}", e); + None + } + } + }, None => None } } + pub fn create(&self, date: &str, up_parent: bool) -> io::Result<()> { + // add tree reference to parent + self.add_ref_to_parent(); + + // create tree object + let mut content = format!("{} {}", self.get_name(), date); + //create_obj(self.get_hash_path(), &content)?; + todo!(); + + // update date for all parent + todo!(); + //if up_parent { + // update_dates(path, date)?; + //} + + Ok(()) + } + // create } - - -//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>)> { -// 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)) -//} diff --git a/src/utils/into.rs b/src/utils/into.rs index 98a0076..535fd4b 100644 --- a/src/utils/into.rs +++ b/src/utils/into.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +use std::path::{PathBuf, Path}; pub trait IntoPathBuf { fn into(self) -> PathBuf; @@ -10,6 +10,12 @@ impl IntoPathBuf for PathBuf { } } +impl IntoPathBuf for &Path { + fn into(self) -> PathBuf { + PathBuf::from(self) + } +} + impl IntoPathBuf for String { fn into(self) -> PathBuf { PathBuf::from(self)