move parsing into list_folders
This commit is contained in:
parent
b911ad8606
commit
ea2b0772af
@ -7,7 +7,7 @@ use clap::Values;
|
|||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use xml::reader::{EventReader, XmlEvent};
|
use xml::reader::{EventReader, XmlEvent};
|
||||||
use crate::services::api::ApiError;
|
use crate::services::api::ApiError;
|
||||||
use crate::services::list_folders::ListFolders;
|
use crate::services::list_folders::{ListFolders, FolderContent};
|
||||||
use crate::services::download_files::DownloadFiles;
|
use crate::services::download_files::DownloadFiles;
|
||||||
use crate::store::object;
|
use crate::store::object;
|
||||||
use crate::commands;
|
use crate::commands;
|
||||||
@ -28,7 +28,7 @@ pub fn clone(remote: Values<'_>) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let local_path = match d.clone() {
|
let ref_path = match d.clone() {
|
||||||
Some(dir) => Path::new(&dir).to_owned(),
|
Some(dir) => Path::new(&dir).to_owned(),
|
||||||
None => {
|
None => {
|
||||||
let iter = Path::new(dist_path_str).iter();
|
let iter = Path::new(dist_path_str).iter();
|
||||||
@ -53,16 +53,33 @@ pub fn clone(remote: Values<'_>) {
|
|||||||
url_request.push_str(folder.as_str());
|
url_request.push_str(folder.as_str());
|
||||||
|
|
||||||
// request folder content
|
// request folder content
|
||||||
let mut body = Default::default();
|
let mut objs = vec![];
|
||||||
tokio::runtime::Runtime::new().unwrap().block_on(async {
|
tokio::runtime::Runtime::new().unwrap().block_on(async {
|
||||||
body = ListFolders::new(url_request.as_str())
|
let res = ListFolders::new(url_request.as_str())
|
||||||
|
.gethref()
|
||||||
.send_with_res()
|
.send_with_res()
|
||||||
.await;
|
.await;
|
||||||
|
objs = match res {
|
||||||
|
Ok(o) => o,
|
||||||
|
Err(ApiError::IncorrectRequest(err)) => {
|
||||||
|
eprintln!("fatal: {}", err.status());
|
||||||
|
std::process::exit(1);
|
||||||
|
},
|
||||||
|
Err(ApiError::EmptyError(_)) => {
|
||||||
|
eprintln!("Failed to get body");
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
Err(ApiError::RequestError(err)) => {
|
||||||
|
eprintln!("fatal: {}", err);
|
||||||
|
std::process::exit(1);
|
||||||
|
},
|
||||||
|
Err(ApiError::Unexpected(_)) => todo!()
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// create folder
|
// create folder
|
||||||
if first_iter {
|
if first_iter {
|
||||||
if DirBuilder::new().create(local_path.clone()).is_err() {
|
if DirBuilder::new().create(ref_path.clone()).is_err() {
|
||||||
eprintln!("fatal: directory already exist");
|
eprintln!("fatal: directory already exist");
|
||||||
// destination path 'path' already exists and is not an empty directory.
|
// destination path 'path' already exists and is not an empty directory.
|
||||||
//std::process::exit(1);
|
//std::process::exit(1);
|
||||||
@ -71,56 +88,53 @@ pub fn clone(remote: Values<'_>) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// create folder
|
// create folder
|
||||||
let local_folder = get_local_path(folder, local_path.clone(), username, dist_path_str);
|
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()) {
|
if let Err(err) = DirBuilder::new().recursive(true).create(local_folder.clone()) {
|
||||||
eprintln!("error: cannot create directory {}: {}", local_folder.display(), err);
|
eprintln!("error: cannot create directory {}: {}", local_folder.display(), err);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add tree
|
// add tree
|
||||||
let path_folder = local_folder.strip_prefix(local_path.clone()).unwrap();
|
let path_folder = local_folder.strip_prefix(ref_path.clone()).unwrap();
|
||||||
if object::add_tree(&path_folder).is_err() {
|
if object::add_tree(&path_folder).is_err() {
|
||||||
eprintln!("error: cannot store object {}", path_folder.display());
|
eprintln!("error: cannot store object {}", path_folder.display());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// find folders and files in response
|
// find folders and files in response
|
||||||
let objects = get_objects_xml(body);
|
let mut iter = objs.iter();
|
||||||
let mut iter = objects.iter();
|
|
||||||
iter.next(); // jump first element which is the folder cloned
|
iter.next(); // jump first element which is the folder cloned
|
||||||
for object in iter {
|
for object in iter {
|
||||||
if object.chars().last().unwrap() == '/' {
|
if object.href.clone().unwrap().chars().last().unwrap() == '/' {
|
||||||
folders.push(object.to_string());
|
folders.push(object.href.clone().unwrap().to_string());
|
||||||
} else {
|
} else {
|
||||||
files.push(object.to_string());
|
files.push(object.href.clone().unwrap().to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
first_iter = false;
|
first_iter = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
download_files(&domain, local_path.clone(), username, dist_path_str, files);
|
download_files(ref_path.clone(), files);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn download_files(domain: &str, local_p: PathBuf, username: &str, dist_p: &str, files: Vec<String>) {
|
fn download_files(local_p: PathBuf, files: Vec<String>) {
|
||||||
dbg!(local_p.clone());
|
for remote_file in files {
|
||||||
for dist_file in files {
|
|
||||||
dbg!(dist_file.clone());
|
|
||||||
tokio::runtime::Runtime::new().unwrap().block_on(async {
|
tokio::runtime::Runtime::new().unwrap().block_on(async {
|
||||||
let res = DownloadFiles::new()
|
let res = DownloadFiles::new()
|
||||||
.set_url_with_remote(dist_file.as_str())
|
.set_url_with_remote(remote_file.as_str())
|
||||||
.save(local_p.clone()).await;
|
.save(local_p.clone()).await;
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
|
|
||||||
let s = &get_local_path_t(&dist_file.clone());
|
let s = &get_local_path_t(&remote_file.clone());
|
||||||
let ss = s.strip_prefix("/").unwrap();
|
let ss = s.strip_prefix("/").unwrap();
|
||||||
let relative_p = Path::new(ss);
|
let relative_p = Path::new(ss);
|
||||||
if let Err(_) = object::add_blob(relative_p, "tmpdate") {
|
if let Err(_) = object::add_blob(relative_p, "tmpdate") {
|
||||||
eprintln!("error saving reference of {}", dist_file.clone());
|
eprintln!("error saving reference of {}", remote_file.clone());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(ApiError::Unexpected(_)) => {
|
Err(ApiError::Unexpected(_)) => {
|
||||||
eprintln!("error writing {}", dist_file);
|
eprintln!("error writing {}", remote_file);
|
||||||
},
|
},
|
||||||
Err(ApiError::IncorrectRequest(err)) => {
|
Err(ApiError::IncorrectRequest(err)) => {
|
||||||
eprintln!("fatal: {}", err.status());
|
eprintln!("fatal: {}", err.status());
|
||||||
@ -136,36 +150,6 @@ fn download_files(domain: &str, local_p: PathBuf, username: &str, dist_p: &str,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_objects_xml(xml: String) -> Vec<String> {
|
|
||||||
let cursor = Cursor::new(xml);
|
|
||||||
let parser = EventReader::new(cursor);
|
|
||||||
|
|
||||||
let mut should_get = false;
|
|
||||||
let mut objects: Vec<String> = vec![];
|
|
||||||
|
|
||||||
for event in parser {
|
|
||||||
match event {
|
|
||||||
Ok(XmlEvent::StartElement { name, .. }) => {
|
|
||||||
should_get = name.local_name == "href";
|
|
||||||
}
|
|
||||||
Ok(XmlEvent::Characters(text)) => {
|
|
||||||
if !text.trim().is_empty() && should_get {
|
|
||||||
objects.push(text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(XmlEvent::EndElement { .. }) => {
|
|
||||||
should_get = false;
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Error: {}", e);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
objects
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_url_props(url: &str) -> (String, Option<&str>, &str) {
|
fn get_url_props(url: &str) -> (String, Option<&str>, &str) {
|
||||||
let mut username = None;
|
let mut username = None;
|
||||||
let mut domain = "";
|
let mut domain = "";
|
||||||
@ -241,4 +225,3 @@ mod tests {
|
|||||||
assert_eq!(get_url_props("nextcloud.example.com/foo/bar"), (sld.clone(), None, p));
|
assert_eq!(get_url_props("nextcloud.example.com/foo/bar"), (sld.clone(), None, p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,31 @@
|
|||||||
use crate::services::api::{ApiBuilder, ApiError};
|
use crate::services::api::{ApiBuilder, ApiError};
|
||||||
|
use xml::reader::{EventReader, XmlEvent};
|
||||||
|
use std::io::Cursor;
|
||||||
use reqwest::{Method, IntoUrl, Response, Error};
|
use reqwest::{Method, IntoUrl, Response, Error};
|
||||||
|
|
||||||
|
pub struct FolderContent {
|
||||||
|
pub href: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for FolderContent {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
FolderContent {
|
||||||
|
href: self.href.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FolderContent {
|
||||||
|
fn new() -> Self {
|
||||||
|
FolderContent {
|
||||||
|
href: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ListFolders {
|
pub struct ListFolders {
|
||||||
api_builder: ApiBuilder,
|
api_builder: ApiBuilder,
|
||||||
|
xml_balises: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ListFolders {
|
impl ListFolders {
|
||||||
@ -10,14 +33,20 @@ impl ListFolders {
|
|||||||
ListFolders {
|
ListFolders {
|
||||||
api_builder: ApiBuilder::new()
|
api_builder: ApiBuilder::new()
|
||||||
.set_request(Method::from_bytes(b"PROPFIND").unwrap(), url),
|
.set_request(Method::from_bytes(b"PROPFIND").unwrap(), url),
|
||||||
|
xml_balises: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn gethref(&mut self) -> &mut ListFolders {
|
||||||
|
self.xml_balises.push(String::from("href"));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn send(&mut self) -> Result<Response, Error> {
|
pub async fn send(&mut self) -> Result<Response, Error> {
|
||||||
self.api_builder.send().await
|
self.api_builder.send().await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_with_err(mut self) -> Result<String, ApiError> {
|
pub async fn send_with_err(&mut self) -> Result<String, ApiError> {
|
||||||
let res = self.send().await.map_err(ApiError::RequestError)?;
|
let res = self.send().await.map_err(ApiError::RequestError)?;
|
||||||
if res.status().is_success() {
|
if res.status().is_success() {
|
||||||
let body = res.text().await.map_err(ApiError::EmptyError)?;
|
let body = res.text().await.map_err(ApiError::EmptyError)?;
|
||||||
@ -27,22 +56,59 @@ impl ListFolders {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_with_res(self) -> String {
|
pub async fn send_with_res(&mut self) -> Result<Vec<FolderContent>, ApiError> {
|
||||||
match self.send_with_err().await {
|
match self.send_with_err().await {
|
||||||
Ok(body) => body,
|
Ok(body) => Ok(self.parse(body)),
|
||||||
Err(ApiError::IncorrectRequest(err)) => {
|
Err(err) => Err(err),
|
||||||
eprintln!("fatal: {}", err.status());
|
|
||||||
std::process::exit(1);
|
|
||||||
},
|
|
||||||
Err(ApiError::EmptyError(_)) => {
|
|
||||||
eprintln!("Failed to get body");
|
|
||||||
String::from("")
|
|
||||||
}
|
|
||||||
Err(ApiError::RequestError(err)) => {
|
|
||||||
eprintln!("fatal: {}", err);
|
|
||||||
std::process::exit(1);
|
|
||||||
},
|
|
||||||
_ => todo!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parse(&self, xml: String) -> Vec<FolderContent> {
|
||||||
|
let cursor = Cursor::new(xml);
|
||||||
|
let parser = EventReader::new(cursor);
|
||||||
|
|
||||||
|
let mut should_get = false;
|
||||||
|
let mut values: Vec<FolderContent> = vec![];
|
||||||
|
|
||||||
|
let mut iter = self.xml_balises.iter();
|
||||||
|
let mut val = iter.next();
|
||||||
|
let mut content = FolderContent::new();
|
||||||
|
|
||||||
|
for event in parser {
|
||||||
|
match event {
|
||||||
|
Ok(XmlEvent::StartElement { name, .. }) => {
|
||||||
|
if let Some(v) = val.clone() {
|
||||||
|
should_get = &name.local_name == v;
|
||||||
|
} else {
|
||||||
|
// end of balises to get then start over for next object
|
||||||
|
values.push(content.clone());
|
||||||
|
iter = self.xml_balises.iter();
|
||||||
|
val = iter.next();
|
||||||
|
content = FolderContent::new();
|
||||||
|
if let Some(v) = val.clone() {
|
||||||
|
should_get = &name.local_name == v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(XmlEvent::Characters(text)) => {
|
||||||
|
if !text.trim().is_empty() && should_get {
|
||||||
|
match val.unwrap().as_str() {
|
||||||
|
"href" => content.href = Some(text),
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
val = iter.next()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(XmlEvent::EndElement { .. }) => {
|
||||||
|
should_get = false;
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Error: {}", e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
values
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user