diff --git a/src/commands/clone.rs b/src/commands/clone.rs index 72350bf..80ff2c8 100644 --- a/src/commands/clone.rs +++ b/src/commands/clone.rs @@ -10,11 +10,12 @@ use xml::reader::{EventReader, XmlEvent}; use crate::services::api::ApiError; use crate::services::list_folders::ListFolders; use crate::services::download_files::DownloadFiles; +use crate::utils::object; use crate::commands; pub fn clone(remote: Values<'_>) { let url = remote.clone().next().unwrap(); - let (domain, tmp_user, path_str) = get_url_props(url); + let (domain, tmp_user, path_str) = get_url_props(url); let path = Path::new(path_str); let username = match tmp_user { Some(u) => u, @@ -38,19 +39,21 @@ pub fn clone(remote: Values<'_>) { } url_request.push_str(folder.as_str()); + // request folder content let mut body = Default::default(); tokio::runtime::Runtime::new().unwrap().block_on(async { body = ListFolders::new(url_request.as_str()) .send_with_res() .await; }); + + // create folder if first_iter { - first_iter = false; if DirBuilder::new().create(path.file_name().unwrap()).is_err() { // todo add second parameter to save in a folder eprintln!("fatal: directory already exist"); // destination path 'path' already exists and is not an empty directory. - std::process::exit(1); + //std::process::exit(1); } else { commands::init::init(Some(env::current_dir().unwrap().to_str().unwrap())); } @@ -60,6 +63,17 @@ pub fn clone(remote: Values<'_>) { DirBuilder::new().recursive(true).create(path.unwrap()); } + // add folder to the structure + if !first_iter { + let mut path_folder = Path::new(&folder).strip_prefix("/remote.php/dav/files/"); + path_folder = path_folder.unwrap().strip_prefix(username); + let mut root = path_folder.clone().unwrap().iter(); + let o = root.next(); + path_folder = path_folder.unwrap().strip_prefix(o.unwrap()); + object::add_tree(&path_folder.unwrap()); + } + + // find folders and files in response let objects = get_objects_xml(body); let mut iter = objects.iter(); iter.next(); // jump first element which the folder fetched @@ -70,6 +84,7 @@ pub fn clone(remote: Values<'_>) { files.push(object.to_string()); } } + first_iter = false; } download_files(&domain, username, files); diff --git a/src/commands/init.rs b/src/commands/init.rs index 7dff619..402e5db 100644 --- a/src/commands/init.rs +++ b/src/commands/init.rs @@ -1,6 +1,5 @@ use std::fs::{DirBuilder, File}; use std::path::PathBuf; -use clap::Values; use std::env; pub fn init(directory: Option<&str>) { @@ -18,6 +17,13 @@ pub fn init(directory: Option<&str>) { Err(_) => println!("Error: cannot create directory"), }; + path.push("objects"); + match builder.create(path.clone()) { + Ok(()) => println!("Directory successfuly created"), + Err(_) => println!("Error: cannot create directory"), + }; + path.pop(); + path.push("HEAD"); match File::create(path.clone()) { Ok(_) => println!("File successfuly created"), diff --git a/src/commands/status.rs b/src/commands/status.rs index 4b6cd06..832763e 100644 --- a/src/commands/status.rs +++ b/src/commands/status.rs @@ -107,8 +107,6 @@ fn find_missing_elements(hashes: &mut HashSet, objects: &mut Vec // find it on the list of hashes if hashes.contains(&hash) { - println!("o"); - println!("{}", object.clone()); duplicate.push(object.clone()); if remove_option == RemoveSide::Left || remove_option == RemoveSide::Both { hashes.remove(&hash); diff --git a/src/utils.rs b/src/utils.rs index 305d212..c803f36 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,3 +1,5 @@ pub mod path; pub mod index; +pub mod head; pub mod read; +pub mod object; diff --git a/src/utils/head.rs b/src/utils/head.rs new file mode 100644 index 0000000..3c1f9da --- /dev/null +++ b/src/utils/head.rs @@ -0,0 +1,44 @@ +use std::fs::{File, OpenOptions}; +use std::path::PathBuf; +use crate::utils::{read, path}; +use std::io::{self, Write}; + +pub fn _read_only(mut path: PathBuf) -> File { + path.push("HEAD"); + OpenOptions::new() + .read(true) + .open(path).expect("Cannot open HEAD file") +} + +pub fn _open(mut path: PathBuf) -> File { + path.push("HEAD"); + OpenOptions::new() + .read(true) + .write(true) + .append(true) + .create(true) + .open(path).expect("Cannot open HEAD file") +} + +pub fn _read_line(mut path: PathBuf) -> io::Result>> { + path.push("HEAD"); + read::read_lines(path) +} + +pub fn add_line(line: String) -> io::Result<()> { + let mut root = match path::nextsync_root() { + Some(path) => path, + None => todo!(), + }; + root.push(".nextsync"); + root.push("HEAD"); + + let mut file = OpenOptions::new() + .read(true) + .write(true) + .append(true) + .open(root)?; + + writeln!(file, "{}", line)?; + Ok(()) +} diff --git a/src/utils/index.rs b/src/utils/index.rs index 3d60681..9adca2e 100644 --- a/src/utils/index.rs +++ b/src/utils/index.rs @@ -4,7 +4,7 @@ use std::path::PathBuf; use crate::utils::read; use std::io; -pub fn read_only(mut path: PathBuf) -> File { +pub fn _read_only(mut path: PathBuf) -> File { path.push("index"); OpenOptions::new() .read(true) diff --git a/src/utils/object.rs b/src/utils/object.rs new file mode 100644 index 0000000..35d671f --- /dev/null +++ b/src/utils/object.rs @@ -0,0 +1,78 @@ +use std::path::Path; +use crate::utils::{head, path}; +use crypto::sha1::Sha1; +use crypto::digest::Digest; +use std::fs::{OpenOptions, self}; +use std::io::Write; +use std::io; + +pub fn add_tree(path: &Path) { + dbg!(path.clone()); + let file_name = path.file_name().unwrap().to_str().unwrap(); + let mut hasher = Sha1::new(); + hasher.input_str(path.clone().to_str().unwrap()); + let hash = hasher.result_str(); + let mut line = hash.to_owned(); + line.push_str(" "); + line.push_str(file_name); + if path.iter().count() == 1 { + dbg!(head::add_line(line)); + } else { + dbg!(add_node(path.parent().unwrap(), &line)); + } + dbg!(add_file(hash, file_name)); + dbg!(path.iter().count()); +} + +fn add_node(path: &Path, node: &str) -> io::Result<()> { + let mut root = match path::nextsync_root() { + Some(path) => path, + None => todo!(), + }; + root.push(".nextsync"); + root.push("objects"); + + let mut hasher = Sha1::new(); + hasher.input_str(path.clone().to_str().unwrap()); + let hash = hasher.result_str(); + let (dir, rest) = hash.split_at(2); + + root.push(dir); + if !root.exists() { + todo!(); + } + root.push(rest); + + let mut file = OpenOptions::new() + .read(true) + .write(true) + .append(true) + .open(root)?; + + writeln!(file, "{}", node)?; + Ok(()) +} + +fn add_file(name: String, content: &str) -> io::Result<()> { + let mut root = match path::nextsync_root() { + Some(path) => path, + None => todo!(), + }; + root.push(".nextsync"); + root.push("objects"); + let c = name.clone(); + let (dir, rest) = c.split_at(2); + + root.push(dir); + if !root.exists() { + fs::create_dir_all(root.clone())?; + } + root.push(rest); + dbg!(root.clone()); + let mut file = OpenOptions::new() + .create_new(true) + .write(true) + .open(root)?; + file.write_all(content.as_bytes())?; + Ok(()) +}