From 7cfd572ad01bcb91368cb3b2d47e49501665df60 Mon Sep 17 00:00:00 2001 From: grimhilt Date: Sat, 17 Jun 2023 15:36:18 +0200 Subject: [PATCH] cleaning clone --- docs/conventions/variables.md | 21 +++++++++++++ src/commands/clone.rs | 55 +++++++++++++++++----------------- src/services/api.rs | 16 +++++----- src/services/download_files.rs | 17 ++++++----- src/services/list_folders.rs | 31 +++++++++++++++---- src/utils/api.rs | 26 ++++++++++++++++ 6 files changed, 118 insertions(+), 48 deletions(-) create mode 100644 docs/conventions/variables.md diff --git a/docs/conventions/variables.md b/docs/conventions/variables.md new file mode 100644 index 0000000..1e94ff3 --- /dev/null +++ b/docs/conventions/variables.md @@ -0,0 +1,21 @@ +# Conventions + +## Path Variables + +Considering cloning: +* ``https://nextcloud.example.com/remote.php/dav/files/grimhilt/dir/dir_to_clone`` + +We have (in ``ApiProps`` for example): +* ``host``: ``https://nextcloud.example.com`` +* ``username``: ``grimhilt`` +* ``root``: ``/dir/dir_to_clone`` + +Concerning paths we have: +* ``remote_p``: ``/remote.php/dav/files/grimhilt/dir/dir_to_clone/D1/D1_F1.md`` +* ``ref_p``: ``/home/grimhilt/dir_cloned`` +* ``relative_p``: ``D1/D1_F1.md`` +* ``abs_p``: ``/home/grimhilt/dir_cloned/D1_D1_F1.md`` + +Use prefix: +* ``p`` for Path or PathBuffer +* ``ps`` for String diff --git a/src/commands/clone.rs b/src/commands/clone.rs index 07354ff..76bf13e 100644 --- a/src/commands/clone.rs +++ b/src/commands/clone.rs @@ -7,14 +7,14 @@ use crate::services::list_folders::ListFolders; use crate::services::download_files::DownloadFiles; use crate::store::object; use crate::commands; -use crate::utils::api::{get_local_path, get_local_path_t}; +use crate::utils::api::{get_local_path_t, ApiProps}; use crate::global::global::{DIR_PATH, set_dir_path}; pub fn clone(remote: Values<'_>) { let d = DIR_PATH.lock().unwrap().clone(); let url = remote.clone().next().unwrap(); - let (domain, tmp_user, dist_path_str) = get_url_props(url); + let (host, tmp_user, dist_path_str) = get_url_props(url); let username = match tmp_user { Some(u) => u, None => { @@ -22,6 +22,12 @@ pub fn clone(remote: Values<'_>) { todo!(); } }; + let api_props = ApiProps { + host: host.clone(), + username: username.to_string(), + root: dist_path_str.to_string(), + }; + dbg!(dist_path_str.clone()); let ref_path = match d.clone() { Some(dir) => Path::new(&dir).to_owned(), @@ -34,23 +40,18 @@ pub fn clone(remote: Values<'_>) { }, }; - let mut folders = vec![String::from(dist_path_str)]; - let mut url_request; + let mut folders = vec![String::from("")]; let mut files: Vec = vec![]; let mut first_iter = true; while folders.len() > 0 { let folder = folders.pop().unwrap(); - url_request = String::from(domain.clone()); - if first_iter { - url_request.push_str("/remote.php/dav/files/"); - url_request.push_str(username); - } - url_request.push_str(folder.as_str()); // request folder content let mut objs = vec![]; tokio::runtime::Runtime::new().unwrap().block_on(async { - let res = ListFolders::new(url_request.as_str()) + dbg!(folder.clone()); + let res = ListFolders::new() + .set_request(folder.as_str(), &api_props) .gethref() .send_with_res() .await; @@ -83,13 +84,13 @@ pub fn clone(remote: Values<'_>) { } } else { // create folder - let local_folder = get_local_path(folder, ref_path.clone(), username, dist_path_str); - if let Err(err) = DirBuilder::new().recursive(true).create(local_folder.clone()) { - eprintln!("error: cannot create directory {}: {}", local_folder.display(), err); + let p = ref_path.clone().join(Path::new(&folder.clone())); + if let Err(err) = DirBuilder::new().recursive(true).create(p.clone()) { + eprintln!("error: cannot create directory {}: {}", p.display(), err); } // add tree - let path_folder = local_folder.strip_prefix(ref_path.clone()).unwrap(); + let path_folder = p.strip_prefix(ref_path.clone()).unwrap(); if object::add_tree(&path_folder).is_err() { eprintln!("error: cannot store object {}", path_folder.display()); } @@ -99,37 +100,35 @@ pub fn clone(remote: Values<'_>) { let mut iter = objs.iter(); iter.next(); // jump first element which is the folder cloned for object in iter { + dbg!(object.clone()); if object.href.clone().unwrap().chars().last().unwrap() == '/' { - folders.push(object.href.clone().unwrap().to_string()); + folders.push(object.relative_s.clone().unwrap().to_string()); } else { - files.push(object.href.clone().unwrap().to_string()); + files.push(object.relative_s.clone().unwrap().to_string()); } } first_iter = false; } - download_files(ref_path.clone(), files); + download_files(ref_path.clone(), files, &api_props); } -fn download_files(local_p: PathBuf, files: Vec) { - for remote_file in files { +fn download_files(ref_p: PathBuf, files: Vec, api_props: &ApiProps) { + for relative_file in files { tokio::runtime::Runtime::new().unwrap().block_on(async { let res = DownloadFiles::new() - .set_url_with_remote(remote_file.as_str()) - .save(local_p.clone()).await; + .set_url(relative_file.as_str(), api_props) + .save(ref_p.clone()).await; match res { Ok(()) => { - - let s = &get_local_path_t(&remote_file.clone()); - let ss = s.strip_prefix("/").unwrap(); - let relative_p = Path::new(ss); + let relative_p = Path::new(&relative_file); if let Err(_) = object::add_blob(relative_p, "tmpdate") { - eprintln!("error saving reference of {}", remote_file.clone()); + eprintln!("error saving reference of {}", relative_file.clone()); } }, Err(ApiError::Unexpected(_)) => { - eprintln!("error writing {}", remote_file); + eprintln!("error writing {}", relative_file); }, Err(ApiError::IncorrectRequest(err)) => { eprintln!("fatal: {}", err.status()); diff --git a/src/services/api.rs b/src/services/api.rs index 3f08be5..fa9e849 100644 --- a/src/services/api.rs +++ b/src/services/api.rs @@ -1,6 +1,7 @@ use reqwest::Client; use reqwest::RequestBuilder; use reqwest::{Response, Error, IntoUrl, Method}; +use crate::utils::api::ApiProps; use std::env; use dotenv::dotenv; @@ -25,7 +26,7 @@ impl ApiBuilder { } } - pub fn set_request(mut self, method: Method, url: U) -> ApiBuilder { + pub fn set_request(&mut self, method: Method, url: U) -> &mut ApiBuilder { self.request = Some(self.client.request(method, url)); self } @@ -48,13 +49,14 @@ impl ApiBuilder { self } - pub fn build_request_remote(&mut self, meth: Method, path: &str) -> &mut ApiBuilder { - dotenv().ok(); - let host = env::var("HOST").unwrap(); - let mut url = String::from(host); + pub fn set_req(&mut self, meth: Method, p: &str, api_props: &ApiProps) -> &mut ApiBuilder { + let mut url = String::from(&api_props.host); + url.push_str("/remote.php/dav/files/"); url.push_str("/"); - url.push_str(path); - dbg!(url.clone()); + url.push_str(&api_props.username); + url.push_str(&api_props.root); + url.push_str("/"); + url.push_str(p); self.request = Some(self.client.request(meth, url)); self } diff --git a/src/services/download_files.rs b/src/services/download_files.rs index 0aac3cc..6007cae 100644 --- a/src/services/download_files.rs +++ b/src/services/download_files.rs @@ -1,26 +1,26 @@ use crate::services::api::{ApiBuilder, ApiError}; use std::path::PathBuf; use reqwest::{Method, Response, Error}; -use crate::utils::api::get_local_path_t; +use crate::utils::api::{get_local_path_t, ApiProps}; use std::fs::OpenOptions; use std::io::{self, Write}; pub struct DownloadFiles { api_builder: ApiBuilder, - path: String, + relative_ps: String, } impl DownloadFiles { pub fn new() -> Self { DownloadFiles { api_builder: ApiBuilder::new(), - path: String::from(""), + relative_ps: String::from(""), } } - pub fn set_url_with_remote(&mut self, url: &str) -> &mut DownloadFiles { - self.path = get_local_path_t(url.clone()).strip_prefix("/").unwrap().to_string(); - self.api_builder.build_request_remote(Method::GET, url); + pub fn set_url(&mut self, relative_ps: &str, api_props: &ApiProps) -> &mut DownloadFiles { + self.relative_ps = relative_ps.to_string(); + self.api_builder.set_req(Method::from_bytes(b"PROPFIND").unwrap(), relative_ps, api_props); self } @@ -38,8 +38,8 @@ impl DownloadFiles { } } - pub async fn save(&mut self, local_path: PathBuf) -> Result<(), ApiError> { - let p = local_path.join(PathBuf::from(self.path.clone())); + pub async fn save(&mut self, ref_p: PathBuf) -> Result<(), ApiError> { + let p = ref_p.join(PathBuf::from(self.relative_ps.clone())); let res = self.send().await.map_err(ApiError::RequestError)?; if res.status().is_success() { let body = res.bytes().await.map_err(ApiError::EmptyError)?; @@ -53,6 +53,7 @@ impl DownloadFiles { } fn write_file(path: PathBuf, content: &Vec) -> io::Result<()> { + dbg!(path.clone()); let mut f = OpenOptions::new() .write(true) .create(true) diff --git a/src/services/list_folders.rs b/src/services/list_folders.rs index ff8dc63..c7dd0af 100644 --- a/src/services/list_folders.rs +++ b/src/services/list_folders.rs @@ -1,16 +1,20 @@ use crate::services::api::{ApiBuilder, ApiError}; +use crate::utils::api::{ApiProps, get_relative_s}; use xml::reader::{EventReader, XmlEvent}; use std::io::Cursor; -use reqwest::{Method, IntoUrl, Response, Error}; +use reqwest::{Method, Response, Error}; +#[derive(Debug)] pub struct FolderContent { pub href: Option, + pub relative_s: Option, } impl Clone for FolderContent { fn clone(&self) -> Self { FolderContent { href: self.href.clone(), + relative_s: self.relative_s.clone(), } } } @@ -19,6 +23,7 @@ impl FolderContent { fn new() -> Self { FolderContent { href: None, + relative_s: None, } } } @@ -26,17 +31,29 @@ impl FolderContent { pub struct ListFolders { api_builder: ApiBuilder, xml_balises: Vec, + api_props: Option } impl ListFolders { - pub fn new(url: U) -> Self { + pub fn new() -> Self { ListFolders { - api_builder: ApiBuilder::new() - .set_request(Method::from_bytes(b"PROPFIND").unwrap(), url), + api_builder: ApiBuilder::new(), xml_balises: vec![], + api_props: None, } } + pub fn set_url(&mut self, url: &str) -> &mut ListFolders { + self.api_builder.build_request(Method::from_bytes(b"PROPFIND").unwrap(), url); + self + } + + pub fn set_request(&mut self, p: &str, api_props: &ApiProps) -> &mut ListFolders { + self.api_props = Some(api_props.clone()); + self.api_builder.set_req(Method::from_bytes(b"PROPFIND").unwrap(), p, api_props); + self + } + pub fn gethref(&mut self) -> &mut ListFolders { self.xml_balises.push(String::from("href")); self @@ -93,7 +110,11 @@ impl ListFolders { Ok(XmlEvent::Characters(text)) => { if !text.trim().is_empty() && should_get { match val.unwrap().as_str() { - "href" => content.href = Some(text), + "href" => { + content.href = Some(text.clone()); + content.relative_s = Some(get_relative_s(text, &(self.api_props.clone().unwrap()))); + dbg!(content.relative_s.clone()); + }, _ => (), } val = iter.next() diff --git a/src/utils/api.rs b/src/utils/api.rs index 82dc5c4..c2831de 100644 --- a/src/utils/api.rs +++ b/src/utils/api.rs @@ -1,6 +1,32 @@ use std::path::{PathBuf, Path}; use std::env; +#[derive(Debug)] +pub struct ApiProps { + pub host: String, // nextcloud.example.com + pub username: String, + pub root: String, // /dir/cloned +} + +impl Clone for ApiProps { + fn clone(&self) -> Self { + ApiProps { + host: self.host.to_string(), + username: self.username.to_string(), + root: self.root.to_string(), + } + } +} + +pub fn get_relative_s(p: String, api_props: &ApiProps) -> String { + let mut final_p = p.clone(); + final_p = final_p.strip_prefix("/remote.php/dav/files/").unwrap().to_string(); + final_p = final_p.strip_prefix(&api_props.username).unwrap().to_string(); + final_p = final_p.strip_prefix(&api_props.root).unwrap().to_string(); + final_p = final_p.strip_prefix("/").unwrap().to_string(); + final_p +} + pub fn get_local_path(p: String, local_p: PathBuf, username: &str, dist_p: &str) -> PathBuf { let mut final_p = Path::new(p.as_str()); final_p = final_p.strip_prefix("/remote.php/dav/files/").unwrap();