diff --git a/docs/store.md b/docs/store.md index 61c3f3a..e350f16 100644 --- a/docs/store.md +++ b/docs/store.md @@ -2,12 +2,12 @@ ## Blob object ``` -file_name hash timestamp +file_name timestamp size hash ``` ## Tree object ``` -folder_name +folder_name timestamp tree hash_path folder_name blob hash_path file_name ``` \ No newline at end of file diff --git a/src/commands/push.rs b/src/commands/push.rs index cdb05e1..48eb441 100644 --- a/src/commands/push.rs +++ b/src/commands/push.rs @@ -1,7 +1,11 @@ use crate::commands::{status, config}; +use crate::services::req_props::ReqProps; +use crate::services::api::ApiError; +use crate::services::upload_file::UploadFile; +use crate::commands::status::{State, Obj}; pub fn push() { - dbg!(status::get_diff()); + dbg!(status::get_all_staged()); let remote = match config::get("remote") { Some(r) => r, @@ -10,9 +14,149 @@ pub fn push() { std::process::exit(1); } }; - let (staged_obj, new_obj, del_obj) = status::get_diff(); - + + let staged_objs = status::get_all_staged(); + // todo sort folder first + for obj in staged_objs { + if obj.otype == String::from("tree") { + dbg!("should push folder"); + } else { + let push_factory = PushFactory.new(obj.clone()); + match push_factory.can_push() { + PushState::Valid => push_factory.push(), + _ => todo!(), + } + } + } // read index // if dir upload dir } + +#[derive(Debug)] +enum PushState { + Valid, + Conflict, + Error, +} + +trait PushChange { + fn can_push(&self) -> PushState; + fn push(&self); +} + +struct New { + obj: Obj, +} + +impl PushChange for New { + fn can_push(&self) -> PushState { + // check if exist on server + let file_infos = tokio::runtime::Runtime::new().unwrap().block_on(async { + let res = ReqProps::new() + .set_url(&self.obj.path.to_str().unwrap()) + .getlastmodified() + .send_with_err() + .await; + + match res { + Ok(data) => Ok(data), + Err(ApiError::IncorrectRequest(err)) => { + if err.status() == 404 { + Ok(vec![]) + } else { + Err(()) + } + }, + Err(_) => Err(()), + } + }); + + if let Ok(infos) = file_infos { + if infos.len() == 0 { + // file doesn't exist on remote + PushState::Valid + } else { + // check date + PushState::Conflict + } + } else { + PushState::Error + } + } + + fn push(&self) { + let obj = &self.obj; + tokio::runtime::Runtime::new().unwrap().block_on(async { + let res = UploadFile::new() + .set_url(obj.path.to_str().unwrap()) + .set_file(obj.path.clone()) + .send_with_err() + .await; + + match res { + Err(ApiError::IncorrectRequest(err)) => { + eprintln!("fatal: error pushing file {}: {}", obj.name, err.status()); + std::process::exit(1); + }, + Err(ApiError::RequestError(_)) => { + eprintln!("fatal: request error pushing file {}", obj.name); + std::process::exit(1); + } + _ => (), + } + // todo manage err + // todo remove index + }); + } +} + +struct PushFactory; + +impl PushFactory { + fn new(&self, obj: Obj) -> Box { + match obj.state { + State::New => Box::new(New { obj: obj.clone() }), + State::Renamed => todo!(), + State::Modified => todo!(), + State::Deleted => todo!(), + State::Default => todo!(), + } + } +} + +fn can_push_file(obj: Obj) -> PushState { + dbg!(obj.clone()); + // check if exist on server + let file_infos = tokio::runtime::Runtime::new().unwrap().block_on(async { + let res = ReqProps::new() + .set_url(obj.path.to_str().unwrap()) + .getlastmodified() + .send_with_err() + .await; + + match res { + Ok(data) => Ok(data), + Err(ApiError::IncorrectRequest(err)) => { + if err.status() == 404 { + Ok(vec![]) + } else { + Err(()) + } + }, + Err(_) => Err(()), + } + }); + + if let Ok(infos) = file_infos { + if infos.len() == 0 { + // file doesn't exist on remote + PushState::Valid + } else { + // check date + PushState::Conflict + } + } else { + PushState::Error + } +} diff --git a/src/commands/status.rs b/src/commands/status.rs index 87730e0..65a2b42 100644 --- a/src/commands/status.rs +++ b/src/commands/status.rs @@ -18,7 +18,7 @@ enum RemoveSide { #[derive(PartialEq)] #[derive(Debug)] #[derive(Clone)] -enum State { +pub enum State { Default, New, Renamed, @@ -42,10 +42,23 @@ pub fn status() { #[derive(Debug)] #[derive(Clone)] pub struct Obj { - otype: String, - name: String, - path: PathBuf, - state: State, + pub otype: String, + pub name: String, + pub path: PathBuf, + pub state: State, +} + +pub fn get_all_staged() -> Vec { + // todo opti getting staged and then finding differences ? + // todo opti return folder + let (mut new_objs, mut del_objs) = get_diff(); + let mut renamed_objs = get_renamed(&mut new_objs, &mut del_objs); + // get copy, modified + let mut objs = new_objs; + objs.append(&mut del_objs); + objs.append(&mut renamed_objs); + let staged_objs = get_staged(&mut objs); + staged_objs } fn get_renamed(new_obj: &mut Vec, del_obj: &mut Vec) -> Vec { @@ -62,7 +75,6 @@ fn get_staged(objs: &mut Vec) -> Vec { let nextsync_path = utils::path::nextsync().unwrap(); if let Ok(entries) = store::index::read_line(nextsync_path.clone()) { for entry in entries { - // todo hash this indexes.insert(entry.unwrap()); } } @@ -88,7 +100,7 @@ fn get_staged(objs: &mut Vec) -> Vec { staged_objs } -pub fn get_diff() -> (Vec, Vec) { +fn get_diff() -> (Vec, Vec) { let mut hashes = HashMap::new(); let mut objs: Vec = vec![]; @@ -119,7 +131,7 @@ pub fn get_diff() -> (Vec, Vec) { while obj_to_analyse.len() > 0 { let cur_obj = obj_to_analyse.pop().unwrap(); let cur_path = PathBuf::from(&cur_obj); - dbg!(cur_path.clone()); + let obj_path = root.clone().join(cur_path.clone()); if obj_path.is_dir() { @@ -149,17 +161,26 @@ pub fn get_diff() -> (Vec, Vec) { }).collect(); let new_objs: Vec = objs.iter().map(|x| { - // todo otype and name + let p = PathBuf::from(x.to_string()); + // todo name Obj { - otype: String::from(""), + otype: get_type(p.clone()), name: x.to_string(), - path: PathBuf::from(x.to_string()), + path: p, state: State::New } }).collect(); (new_objs, del_objs) } +fn get_type(p: PathBuf) -> String { + if p.is_dir() { + String::from("tree") + } else { + String::from("blob") + } +} + fn add_to_hashmap(lines: Lines>, hashes: &mut HashMap, path: PathBuf) { for line in lines { if let Ok(ip) = line { diff --git a/src/services.rs b/src/services.rs index 0e53ee9..84aab59 100644 --- a/src/services.rs +++ b/src/services.rs @@ -2,3 +2,4 @@ pub mod api; pub mod list_folders; pub mod download_files; pub mod req_props; +pub mod upload_file;