refactor(tree): create impl Tree

This commit is contained in:
grimhilt 2024-02-25 17:34:16 +01:00
parent faf7341525
commit 7951ad0520
12 changed files with 306 additions and 225 deletions

View File

@ -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
```
```

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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,

View File

@ -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())?;

View File

@ -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())?;

View File

@ -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<String, LocalObj>) -> Vec<LocalObj> {
staged_objs
}
fn read_tree_to_hashmap(tree: &mut Tree, hashes: &mut HashMap<String, LocalObj>, path: PathBuf) {
while let Some(child) = tree.next() {
hashes.insert(String::from(child.get_hash_path()), child.get_local_obj());
};
}
fn get_diff() -> (HashMap<String, LocalObj>, HashMap<String, LocalObj>, Vec<String>) {
let mut hashes = HashMap::new();
let mut objs: Vec<String> = vec![];
@ -239,9 +242,10 @@ fn get_diff() -> (HashMap<String, LocalObj>, HashMap<String, LocalObj>, Vec<Stri
// todo use repo_root instead of current
let dist_path = current_p.strip_prefix(root.clone()).unwrap().to_path_buf();
if let Ok(lines) = read_lines(head::path()) {
add_to_hashmap(lines, &mut hashes, dist_path.clone());
}
read_tree_to_hashmap(&mut Tree::from_head(), &mut hashes, dist_path.clone());
//if let Ok(lines) = read_lines(head::path()) {
// add_to_hashmap(lines, &mut hashes, dist_path.clone());
//}
if let Ok(entries) = read_folder(root.clone()) {
add_to_vec(entries, &mut objs, root.clone());
@ -256,14 +260,19 @@ fn get_diff() -> (HashMap<String, LocalObj>, HashMap<String, LocalObj>, Vec<Stri
let obj_path = root.clone().join(cur_path.clone());
if obj_path.is_dir() {
if let Some((_, lines)) = tree::read(cur_obj.clone()) {
add_to_hashmap(lines, &mut hashes, cur_path.clone());
}
// read virtual tree
read_tree_to_hashmap(&mut Tree::from_path(cur_obj.clone()), &mut hashes, dist_path.clone());
//let mut tree = Tree::from_path(cur_obj.clone());
//if let Some(lines) = tree.get_children() {
//add_to_hashmap(lines, &mut hashes, cur_path.clone());
//}
// read physical tree
if let Ok(entries) = read_folder(obj_path.clone()) {
add_to_vec(entries, &mut objs, root.clone());
}
// remove duplicate
let diff = remove_duplicate(&mut hashes, &mut objs, RemoveSide::Both);
obj_to_analyse.append(&mut diff.clone());
} else {
@ -309,24 +318,24 @@ fn get_otype(p: PathBuf) -> String {
}
}
fn add_to_hashmap(lines: Lines<BufReader<File>>, hashes: &mut HashMap<String, LocalObj>, 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<BufReader<File>>, hashes: &mut HashMap<String, LocalObj>, 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<PathBuf>, objects: &mut Vec<String>, root: PathBuf) {
for entry in entries {

View File

@ -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

View File

@ -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<PathBuf>) -> Box<dyn ObjMethods> {
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<dyn FnOnce(Self)> {
// match kind {
// "Blob" => Box::new(|_| Blob::new(self.clone())),
// "Tree" => Box::new(|_| Tree::new(self.clone())),
// _ => unreachable!(),
// }
//}
}

View File

@ -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<Lines<BufReader<File>>>,
pub lines_iter: Option<Iter<String, Lines<BufReader<File>>>>,
pub file: Option<File>,
pub buf_reader: Option<BufReader<File>>,
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<S>(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<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)),
pub fn next(&mut self) -> Option<Box<dyn ObjMethods>> {
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<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))
//}

View File

@ -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)