Compare commits

..

6 Commits

Author SHA1 Message Date
grimhilt
b16058b4d3 cleaning imports and warnings 2023-06-17 01:26:13 +02:00
grimhilt
ea2b0772af move parsing into list_folders 2023-06-17 01:20:00 +02:00
grimhilt
b911ad8606 move creation of downloaded file in service 2023-06-17 00:37:12 +02:00
grimhilt
0bf5fb76e0 allow http if forced 2023-06-16 23:30:44 +02:00
grimhilt
7a34b3c79b optimize add 2023-06-16 23:22:18 +02:00
grimhilt
cbbf185b1a use retain 2023-06-16 18:49:08 +02:00
13 changed files with 275 additions and 177 deletions

2
README.md Normal file
View File

@ -0,0 +1,2 @@
## NextSync

View File

@ -1,9 +1,9 @@
use clap::Values; use clap::Values;
use crate::utils::{self, nextsyncignore}; use crate::utils::{self};
use crate::utils::nextsyncignore::{self, ignore_file};
use crate::store; use crate::store;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::io::Write; use std::io::Write;
use glob::glob;
pub struct AddArgs<'a> { pub struct AddArgs<'a> {
pub files: Values<'a>, pub files: Values<'a>,
@ -13,13 +13,21 @@ pub struct AddArgs<'a> {
pub fn add(args: AddArgs) { pub fn add(args: AddArgs) {
let mut index_file = store::index::open(); let mut index_file = store::index::open();
let mut added_files: Vec<String> = vec![]; let mut added_files: Vec<String> = vec![];
let rules = match nextsyncignore::read_lines() {
Ok(r) => r,
Err(_) => vec![],
};
let mut ignored_f = vec![];
let file_vec: Vec<&str> = args.files.collect(); let file_vec: Vec<&str> = args.files.collect();
for file in file_vec { for file in file_vec {
if !args.force && ignore_file(&file.to_string(), rules.clone(), &mut ignored_f) {
continue;
}
let path = Path::new(file); let path = Path::new(file);
match path.exists() { match path.exists() {
true => { true => {
if path.is_dir() { if path.is_dir() {
added_files.push(String::from(path.to_str().unwrap())); added_files.push(String::from(path.to_str().unwrap()));
add_folder_content(path.to_path_buf(), &mut added_files); add_folder_content(path.to_path_buf(), &mut added_files);
} else { } else {
@ -33,19 +41,16 @@ pub fn add(args: AddArgs) {
} }
} }
// check ignored file if not forced if ignored_f.len() > 0 {
if !args.force { // todo multiple nextsyncignore
let (ignored, ignored_files) = nextsyncignore::ignore_files(&mut added_files); println!("The following paths are ignored by your .nextsyncignore file:");
if ignored { for file in ignored_f {
// todo multiple nextsyncignore println!("{}", file);
println!("The following paths are ignored by your .nextsyncignore file:");
for file in ignored_files {
println!("{}", file);
}
} }
} }
// save all added_files in index // save all added_files in index
// todo avoid duplication
for file in added_files { for file in added_files {
match writeln!(index_file, "{}", file) { match writeln!(index_file, "{}", file) {
Ok(()) => (), Ok(()) => (),

View File

@ -1,16 +1,13 @@
use std::fs::OpenOptions;
use std::fs::DirBuilder; use std::fs::DirBuilder;
use std::io::prelude::*;
use std::io::{self, Cursor};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use clap::Values; use clap::Values;
use regex::Regex; use regex::Regex;
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;
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;
use crate::utils::api::{get_local_path, get_local_path_t};
use crate::global::global::{DIR_PATH, set_dir_path}; use crate::global::global::{DIR_PATH, set_dir_path};
pub fn clone(remote: Values<'_>) { pub fn clone(remote: Values<'_>) {
@ -23,11 +20,10 @@ pub fn clone(remote: Values<'_>) {
None => { None => {
eprintln!("No username found"); eprintln!("No username found");
todo!(); todo!();
""
} }
}; };
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();
@ -52,16 +48,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);
@ -70,70 +83,54 @@ 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 the folder fetched
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 get_local_path(p: String, local_p: PathBuf, username: &str, dist_p: &str) -> PathBuf { fn download_files(local_p: PathBuf, files: Vec<String>) {
let mut final_p = Path::new(p.as_str()); for remote_file in files {
final_p = final_p.strip_prefix("/remote.php/dav/files/").unwrap();
final_p = final_p.strip_prefix(username.clone()).unwrap();
let dist_p = Path::new(dist_p).strip_prefix("/");
final_p = final_p.strip_prefix(dist_p.unwrap()).unwrap();
local_p.clone().join(final_p.clone())
}
fn write_file(path: PathBuf, content: &Vec<u8>, local_p: PathBuf) -> io::Result<()> {
let mut f = OpenOptions::new()
.write(true)
.create(true)
.open(path.clone())?;
f.write_all(&content)?;
let relative_p = Path::new(&path).strip_prefix(local_p).unwrap();
object::add_blob(relative_p, "tmpdate")?;
Ok(())
}
fn download_files(domain: &str, local_p: PathBuf, username: &str, dist_p: &str, files: Vec<String>) {
for file in files {
let mut url_request = String::from(domain.clone());
url_request.push_str(file.as_str());
tokio::runtime::Runtime::new().unwrap().block_on(async { tokio::runtime::Runtime::new().unwrap().block_on(async {
match DownloadFiles::new(url_request.as_str()).send_with_err().await { let res = DownloadFiles::new()
Ok(b) => { .set_url_with_remote(remote_file.as_str())
let p_to_save = get_local_path(file.clone(), local_p.clone(), username, dist_p); .save(local_p.clone()).await;
if let Err(_) = write_file(p_to_save, &b, local_p.clone()) { match res {
eprintln!("error writing {}", file); Ok(()) => {
let s = &get_local_path_t(&remote_file.clone());
let ss = s.strip_prefix("/").unwrap();
let relative_p = Path::new(ss);
if let Err(_) = object::add_blob(relative_p, "tmpdate") {
eprintln!("error saving reference of {}", remote_file.clone());
} }
}, },
Err(ApiError::Unexpected(_)) => {
eprintln!("error writing {}", remote_file);
},
Err(ApiError::IncorrectRequest(err)) => { Err(ApiError::IncorrectRequest(err)) => {
eprintln!("fatal: {}", err.status()); eprintln!("fatal: {}", err.status());
std::process::exit(1); std::process::exit(1);
@ -148,37 +145,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
}
// todo allow http
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 = "";
@ -193,7 +159,7 @@ fn get_url_props(url: &str) -> (String, Option<&str>, &str) {
} }
None => (), None => (),
} }
} else if url.find("?").is_some() { } else if url.find("?").is_some() { // from browser url
let re = Regex::new(r"((https?://)?.+?)/.+dir=(.+?)&").unwrap(); let re = Regex::new(r"((https?://)?.+?)/.+dir=(.+?)&").unwrap();
match re.captures_iter(url).last() { match re.captures_iter(url).last() {
Some(cap) => { Some(cap) => {
@ -218,9 +184,13 @@ fn get_url_props(url: &str) -> (String, Option<&str>, &str) {
} }
let re = Regex::new(r"(^https?://)?").unwrap(); let re = Regex::new(r"^http://").unwrap();
let secure_domain = re.replace(domain, "https://").to_string(); if !re.is_match(domain) {
(secure_domain, username, path) let re = Regex::new(r"(^https?://)?").unwrap();
let secure_domain = re.replace(domain, "https://").to_string();
return (secure_domain, username, path);
}
(domain.to_string(), username, path)
} }
#[cfg(test)] #[cfg(test)]
@ -231,21 +201,22 @@ mod tests {
fn test_get_url_props() { fn test_get_url_props() {
let p = "/foo/bar"; let p = "/foo/bar";
let u = Some("user"); let u = Some("user");
let d = String::from("https://nextcloud.com"); let d = String::from("http://nextcloud.com");
let ld = String::from("https://nextcloud.example.com"); let sd = String::from("https://nextcloud.com");
assert_eq!(get_url_props("user@nextcloud.com/remote.php/dav/files/user/foo/bar"), (d.clone(), u, p)); let sld = String::from("https://nextcloud.example.com");
assert_eq!(get_url_props("user@nextcloud.com/foo/bar"), (d.clone(), u, p)); let ld = String::from("http://nextcloud.example.com");
assert_eq!(get_url_props("user@nextcloud.example.com/remote.php/dav/files/user/foo/bar"), (ld.clone(), u, p)); assert_eq!(get_url_props("user@nextcloud.com/remote.php/dav/files/user/foo/bar"), (sd.clone(), u, p));
assert_eq!(get_url_props("user@nextcloud.example.com/foo/bar"), (ld.clone(), u, p)); assert_eq!(get_url_props("user@nextcloud.com/foo/bar"), (sd.clone(), u, p));
assert_eq!(get_url_props("https://nextcloud.example.com/apps/files/?dir=/foo/bar&fileid=166666"), (ld.clone(), None, p)); assert_eq!(get_url_props("user@nextcloud.example.com/remote.php/dav/files/user/foo/bar"), (sld.clone(), u, p));
assert_eq!(get_url_props("https://nextcloud.com/apps/files/?dir=/foo/bar&fileid=166666"), (d.clone(), None, p)); assert_eq!(get_url_props("user@nextcloud.example.com/foo/bar"), (sld.clone(), u, p));
assert_eq!(get_url_props("https://nextcloud.example.com/apps/files/?dir=/foo/bar&fileid=166666"), (sld.clone(), None, p));
assert_eq!(get_url_props("https://nextcloud.com/apps/files/?dir=/foo/bar&fileid=166666"), (sd.clone(), None, p));
assert_eq!(get_url_props("http://nextcloud.example.com/remote.php/dav/files/user/foo/bar"), (ld.clone(), u, p)); assert_eq!(get_url_props("http://nextcloud.example.com/remote.php/dav/files/user/foo/bar"), (ld.clone(), u, p));
assert_eq!(get_url_props("https://nextcloud.example.com/remote.php/dav/files/user/foo/bar"), (ld.clone(), u, p)); assert_eq!(get_url_props("https://nextcloud.example.com/remote.php/dav/files/user/foo/bar"), (sld.clone(), u, p));
assert_eq!(get_url_props("http://nextcloud.example.com/remote.php/dav/files/user/foo/bar"), (ld.clone(), u, p)); assert_eq!(get_url_props("http://nextcloud.example.com/remote.php/dav/files/user/foo/bar"), (ld.clone(), u, p));
assert_eq!(get_url_props("nextcloud.example.com/remote.php/dav/files/user/foo/bar"), (ld.clone(), u, p)); assert_eq!(get_url_props("nextcloud.example.com/remote.php/dav/files/user/foo/bar"), (sld.clone(), u, p));
assert_eq!(get_url_props("https://nextcloud.example.com/foo/bar"), (ld.clone(), None, p)); assert_eq!(get_url_props("https://nextcloud.example.com/foo/bar"), (sld.clone(), None, p));
assert_eq!(get_url_props("http://nextcloud.example.com/foo/bar"), (ld.clone(), None, p)); assert_eq!(get_url_props("http://nextcloud.example.com/foo/bar"), (ld.clone(), None, p));
assert_eq!(get_url_props("nextcloud.example.com/foo/bar"), (ld.clone(), None, p)); assert_eq!(get_url_props("nextcloud.example.com/foo/bar"), (sld.clone(), None, p));
} }
} }

View File

@ -76,23 +76,14 @@ fn get_staged(objs: &mut Vec<Obj>) -> Vec<Obj> {
} }
} }
let mut to_remove: Vec<usize> = vec![]; objs.retain(|obj| {
let mut index = 0;
for obj in &mut *objs {
dbg!(obj.clone().path.to_str().unwrap());
if indexes.contains(obj.clone().path.to_str().unwrap()) { if indexes.contains(obj.clone().path.to_str().unwrap()) {
staged_objs.push(obj.clone()); staged_objs.push(obj.clone());
to_remove.push(index); false
} else {
true
} }
index += 1; });
}
let mut offset = 0;
for i in to_remove {
objs.remove(i + offset.clone());
offset += 1;
}
staged_objs staged_objs
} }
@ -260,35 +251,29 @@ fn print_staged_object(obj: Obj) {
fn remove_duplicate(hashes: &mut HashMap<String, Obj>, objects: &mut Vec<String>, remove_option: RemoveSide) -> Vec<String> { fn remove_duplicate(hashes: &mut HashMap<String, Obj>, objects: &mut Vec<String>, remove_option: RemoveSide) -> Vec<String> {
let mut hasher = Sha1::new(); let mut hasher = Sha1::new();
let mut to_remove: Vec<usize> = vec![];
let mut i = 0;
let mut duplicate = vec![]; let mut duplicate = vec![];
for object in &mut *objects { objects.retain(|obj| {
// hash the object // hash the object
hasher.input_str(object); hasher.input_str(obj);
let hash = hasher.result_str(); let hash = hasher.result_str();
hasher.reset(); hasher.reset();
// find it on the list of hashes // find it on the list of hashes
if hashes.contains_key(&hash) { if hashes.contains_key(&hash) {
duplicate.push(object.clone()); duplicate.push(obj.clone());
// remove from hashes
if remove_option == RemoveSide::Left || remove_option == RemoveSide::Both { if remove_option == RemoveSide::Left || remove_option == RemoveSide::Both {
hashes.remove(&hash); hashes.remove(&hash);
} }
if remove_option == RemoveSide::Right || remove_option == RemoveSide::Both {
to_remove.push(i);
}
}
i += 1;
}
// remove all objects existing in the list of hashes // remove from objects
i = 0; remove_option != RemoveSide::Right && remove_option != RemoveSide::Both
for index in to_remove { } else {
objects.remove(index-i); true
i += 1; }
} });
duplicate duplicate
} }

View File

@ -106,7 +106,7 @@ fn main() {
if let Some(remote) = matches.values_of("remote") { if let Some(remote) = matches.values_of("remote") {
commands::clone::clone(remote); commands::clone::clone(remote);
} }
} else if let Some(matches) = matches.subcommand_matches("push") { } else if let Some(_matches) = matches.subcommand_matches("push") {
commands::push::push(); commands::push::push();
} else if let Some(matches) = matches.subcommand_matches("config") { } else if let Some(matches) = matches.subcommand_matches("config") {
if let Some(mut var) = matches.values_of("variable") { if let Some(mut var) = matches.values_of("variable") {

View File

@ -9,6 +9,7 @@ pub enum ApiError {
IncorrectRequest(reqwest::Response), IncorrectRequest(reqwest::Response),
EmptyError(reqwest::Error), EmptyError(reqwest::Error),
RequestError(reqwest::Error), RequestError(reqwest::Error),
Unexpected(String),
} }
pub struct ApiBuilder { pub struct ApiBuilder {
@ -47,6 +48,17 @@ impl ApiBuilder {
self 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);
url.push_str("/");
url.push_str(path);
dbg!(url.clone());
self.request = Some(self.client.request(meth, url));
self
}
fn set_auth(&mut self) -> &mut ApiBuilder { fn set_auth(&mut self) -> &mut ApiBuilder {
// todo if not exist // todo if not exist
dotenv().ok(); dotenv().ok();

View File

@ -1,23 +1,34 @@
use crate::services::api::{ApiBuilder, ApiError}; use crate::services::api::{ApiBuilder, ApiError};
use reqwest::{Method, IntoUrl, Response, Error}; use std::path::PathBuf;
use reqwest::{Method, Response, Error};
use crate::utils::api::get_local_path_t;
use std::fs::OpenOptions;
use std::io::{self, Write};
pub struct DownloadFiles { pub struct DownloadFiles {
api_builder: ApiBuilder, api_builder: ApiBuilder,
path: String,
} }
impl DownloadFiles { impl DownloadFiles {
pub fn new<U: IntoUrl>(url: U) -> Self { pub fn new() -> Self {
DownloadFiles { DownloadFiles {
api_builder: ApiBuilder::new() api_builder: ApiBuilder::new(),
.set_request(Method::GET, url), path: 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);
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<Vec<u8>, ApiError> { pub async fn _send_with_err(mut self) -> Result<Vec<u8>, 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.bytes().await.map_err(ApiError::EmptyError)?; let body = res.bytes().await.map_err(ApiError::EmptyError)?;
@ -26,4 +37,28 @@ impl DownloadFiles {
Err(ApiError::IncorrectRequest(res)) Err(ApiError::IncorrectRequest(res))
} }
} }
pub async fn save(&mut self, local_path: PathBuf) -> Result<(), ApiError> {
let p = local_path.join(PathBuf::from(self.path.clone()));
let res = self.send().await.map_err(ApiError::RequestError)?;
if res.status().is_success() {
let body = res.bytes().await.map_err(ApiError::EmptyError)?;
match DownloadFiles::write_file(p, &body.to_vec()) {
Err(_) => Err(ApiError::Unexpected(String::from(""))),
Ok(_) => Ok(()),
}
} else {
Err(ApiError::IncorrectRequest(res))
}
}
fn write_file(path: PathBuf, content: &Vec<u8>) -> io::Result<()> {
let mut f = OpenOptions::new()
.write(true)
.create(true)
.open(path.clone())?;
f.write_all(&content)?;
Ok(())
}
} }

View File

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

View File

@ -35,25 +35,25 @@ impl ReqProps {
self self
} }
pub fn getcontenttype(&mut self) -> &mut ReqProps { pub fn _getcontenttype(&mut self) -> &mut ReqProps {
self.xml_list.push(String::from("getcontenttype")); self.xml_list.push(String::from("getcontenttype"));
self.xml_payload.push_str(r#"<d:getcontenttype/>"#); self.xml_payload.push_str(r#"<d:getcontenttype/>"#);
self self
} }
pub fn getpermissions(&mut self) -> &mut ReqProps { pub fn _getpermissions(&mut self) -> &mut ReqProps {
self.xml_list.push(String::from("permissions")); self.xml_list.push(String::from("permissions"));
self.xml_payload.push_str(r#"<oc:permissions/>"#); self.xml_payload.push_str(r#"<oc:permissions/>"#);
self self
} }
pub fn getressourcetype(&mut self) -> &mut ReqProps { pub fn _getressourcetype(&mut self) -> &mut ReqProps {
self.xml_list.push(String::from("resourcetype")); self.xml_list.push(String::from("resourcetype"));
self.xml_payload.push_str(r#"<d:resourcetype/>"#); self.xml_payload.push_str(r#"<d:resourcetype/>"#);
self self
} }
pub fn getetag(&mut self) -> &mut ReqProps { pub fn _getetag(&mut self) -> &mut ReqProps {
self.xml_list.push(String::from("getetag")); self.xml_list.push(String::from("getetag"));
self.xml_payload.push_str(r#"<d:getetag/>"#); self.xml_payload.push_str(r#"<d:getetag/>"#);
self self

View File

@ -57,7 +57,7 @@ pub fn add_tree(path: &Path) -> io::Result<()> {
} }
pub fn rm_blob(path: &Path) -> io::Result<()> { pub fn rm_blob(path: &Path) -> io::Result<()> {
let (line, hash, name) = parse_path(path.clone(), true); let (line, hash, _) = parse_path(path.clone(), true);
// remove blob reference to parent // remove blob reference to parent
if path.iter().count() == 1 { if path.iter().count() == 1 {
@ -84,7 +84,6 @@ pub fn rm_blob(path: &Path) -> io::Result<()> {
pub fn add_blob(path: &Path, date: &str) -> io::Result<()> { pub fn add_blob(path: &Path, date: &str) -> io::Result<()> {
let (line, hash, name) = parse_path(path.clone(), true); let (line, hash, name) = parse_path(path.clone(), true);
// add blob reference to parent // add blob reference to parent
if path.iter().count() == 1 { if path.iter().count() == 1 {
head::add_line(line)?; head::add_line(line)?;
@ -112,7 +111,7 @@ fn hash_obj(obj: &str) -> (String, String) {
(String::from(dir), String::from(res)) (String::from(dir), String::from(res))
} }
fn object_path(obj: &str) -> PathBuf { fn _object_path(obj: &str) -> PathBuf {
let mut root = match path::objects() { let mut root = match path::objects() {
Some(path) => path, Some(path) => path,
None => todo!(), None => todo!(),

View File

@ -1,3 +1,4 @@
pub mod path; pub mod path;
pub mod read; pub mod read;
pub mod nextsyncignore; pub mod nextsyncignore;
pub mod api;

23
src/utils/api.rs Normal file
View File

@ -0,0 +1,23 @@
use std::path::{PathBuf, Path};
use std::env;
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();
final_p = final_p.strip_prefix(username.clone()).unwrap();
let dist_p = Path::new(dist_p).strip_prefix("/");
final_p = final_p.strip_prefix(dist_p.unwrap()).unwrap();
local_p.clone().join(final_p.clone())
}
pub fn get_local_path_t(p: &str) -> String {
dbg!(p.clone());
let username = env::var("USERNAME").unwrap();
let root = env::var("ROOT").unwrap();
let mut final_p = p;
final_p = final_p.strip_prefix("/remote.php/dav/files/").unwrap();
final_p = final_p.strip_prefix(&username).unwrap();
final_p = final_p.strip_prefix("/").unwrap();
final_p = final_p.strip_prefix(&root).unwrap();
final_p.to_string()
}

View File

@ -1,9 +1,9 @@
use crate::utils::{read, path}; use crate::utils::path;
use regex::Regex; use regex::Regex;
use std::fs::File; use std::fs::File;
use std::io::{Cursor, Lines, BufReader, empty, BufRead}; use std::io::{BufReader, BufRead};
fn read_lines() -> Result<Vec<String>, ()> { pub fn read_lines() -> Result<Vec<String>, ()> {
if let Some(path) = path::nextsyncignore() { if let Some(path) = path::nextsyncignore() {
let file = match File::open(path) { let file = match File::open(path) {
Ok(buffer) => buffer, Ok(buffer) => buffer,
@ -23,12 +23,10 @@ fn read_lines() -> Result<Vec<String>, ()> {
Ok(vec![]) Ok(vec![])
} }
pub fn ignore_files(files: &mut Vec<String>) -> (bool, Vec<String>) { pub fn _ignore_files(files: &mut Vec<String>) -> (bool, Vec<String>) {
let mut ignored_f = vec![]; let mut ignored_f = vec![];
if let Some(path) = path::nextsyncignore() { if let Ok(lines) = read_lines() {
if let Ok(lines) = read_lines() { files.retain(|file| !ignore_file(file, lines.clone(), &mut ignored_f));
files.retain(|file| !ignore_file(file, lines.clone(), &mut ignored_f));
}
} }
(ignored_f.len() > 0, ignored_f) (ignored_f.len() > 0, ignored_f)
} }
@ -56,7 +54,7 @@ fn normalize_rule(l: String) -> String {
pub fn ignore_file(path: &String, lines: Vec<String>, ignored_f: &mut Vec<String>) -> bool { pub fn ignore_file(path: &String, lines: Vec<String>, ignored_f: &mut Vec<String>) -> bool {
let mut ignored = false; let mut ignored = false;
for mut line in lines { for line in lines {
if line.starts_with("!") { if line.starts_with("!") {
if !ignored { if !ignored {
continue; continue;