Compare commits
9 Commits
b16058b4d3
...
4842a20024
Author | SHA1 | Date | |
---|---|---|---|
|
4842a20024 | ||
|
8b3ba64e48 | ||
|
f1d552a31c | ||
|
4cde39dffd | ||
|
5d25429546 | ||
|
e0d4c5efac | ||
|
1fd7948122 | ||
|
eabf707844 | ||
|
7cfd572ad0 |
72
Cargo.lock
generated
72
Cargo.lock
generated
@ -11,6 +11,21 @@ dependencies = [
|
|||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android-tzdata"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android_system_properties"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ansi_term"
|
name = "ansi_term"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
@ -73,6 +88,21 @@ version = "1.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "chrono"
|
||||||
|
version = "0.4.26"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
|
||||||
|
dependencies = [
|
||||||
|
"android-tzdata",
|
||||||
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
|
"num-traits",
|
||||||
|
"time",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "clap"
|
name = "clap"
|
||||||
version = "2.34.0"
|
version = "2.34.0"
|
||||||
@ -376,6 +406,29 @@ dependencies = [
|
|||||||
"tokio-native-tls",
|
"tokio-native-tls",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone"
|
||||||
|
version = "0.1.57"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
|
||||||
|
dependencies = [
|
||||||
|
"android_system_properties",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"iana-time-zone-haiku",
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone-haiku"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "idna"
|
name = "idna"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
@ -526,6 +579,7 @@ dependencies = [
|
|||||||
name = "nextsync"
|
name = "nextsync"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"colored",
|
"colored",
|
||||||
"dotenv",
|
"dotenv",
|
||||||
@ -538,6 +592,15 @@ dependencies = [
|
|||||||
"xml-rs",
|
"xml-rs",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "num-traits"
|
||||||
|
version = "0.2.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num_cpus"
|
name = "num_cpus"
|
||||||
version = "1.15.0"
|
version = "1.15.0"
|
||||||
@ -1259,6 +1322,15 @@ version = "0.4.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows"
|
||||||
|
version = "0.48.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
||||||
|
dependencies = [
|
||||||
|
"windows-targets 0.48.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.42.0"
|
version = "0.42.0"
|
||||||
|
@ -16,3 +16,4 @@ xml-rs = "0.8.0"
|
|||||||
regex = "1.8.3"
|
regex = "1.8.3"
|
||||||
lazy_static = "1.4.0"
|
lazy_static = "1.4.0"
|
||||||
glob = "0.3.1"
|
glob = "0.3.1"
|
||||||
|
chrono = "0.4.26"
|
||||||
|
21
docs/conventions/variables.md
Normal file
21
docs/conventions/variables.md
Normal file
@ -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
|
@ -1,9 +1,9 @@
|
|||||||
|
use std::io::Write;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
use clap::Values;
|
use clap::Values;
|
||||||
|
use crate::store;
|
||||||
use crate::utils::{self};
|
use crate::utils::{self};
|
||||||
use crate::utils::nextsyncignore::{self, ignore_file};
|
use crate::utils::nextsyncignore::{self, ignore_file};
|
||||||
use crate::store;
|
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
use std::io::Write;
|
|
||||||
|
|
||||||
pub struct AddArgs<'a> {
|
pub struct AddArgs<'a> {
|
||||||
pub files: Values<'a>,
|
pub files: Values<'a>,
|
||||||
|
@ -2,19 +2,19 @@ use std::fs::DirBuilder;
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use clap::Values;
|
use clap::Values;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use crate::services::api::ApiError;
|
use crate::utils::api::ApiProps;
|
||||||
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::global::global::{DIR_PATH, set_dir_path};
|
use crate::global::global::{DIR_PATH, set_dir_path};
|
||||||
|
use crate::services::api::ApiError;
|
||||||
|
use crate::services::req_props::{ReqProps, ObjProps};
|
||||||
|
use crate::services::download_files::DownloadFiles;
|
||||||
|
use crate::store::object::{self, add_blob, add_tree};
|
||||||
|
use crate::commands::init;
|
||||||
|
|
||||||
pub fn clone(remote: Values<'_>) {
|
pub fn clone(remote: Values<'_>) {
|
||||||
let d = DIR_PATH.lock().unwrap().clone();
|
let d = DIR_PATH.lock().unwrap().clone();
|
||||||
|
|
||||||
let url = remote.clone().next().unwrap();
|
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 {
|
let username = match tmp_user {
|
||||||
Some(u) => u,
|
Some(u) => u,
|
||||||
None => {
|
None => {
|
||||||
@ -22,6 +22,11 @@ pub fn clone(remote: Values<'_>) {
|
|||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
let api_props = ApiProps {
|
||||||
|
host: host.clone(),
|
||||||
|
username: username.to_string(),
|
||||||
|
root: dist_path_str.to_string(),
|
||||||
|
};
|
||||||
|
|
||||||
let ref_path = match d.clone() {
|
let ref_path = match d.clone() {
|
||||||
Some(dir) => Path::new(&dir).to_owned(),
|
Some(dir) => Path::new(&dir).to_owned(),
|
||||||
@ -34,43 +39,40 @@ pub fn clone(remote: Values<'_>) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut folders = vec![String::from(dist_path_str)];
|
let mut folders: Vec<ObjProps> = vec![ObjProps::new()];
|
||||||
let mut url_request;
|
let mut files: Vec<ObjProps> = vec![];
|
||||||
let mut files: Vec<String> = vec![];
|
|
||||||
let mut first_iter = true;
|
let mut first_iter = true;
|
||||||
while folders.len() > 0 {
|
while folders.len() > 0 {
|
||||||
let folder = folders.pop().unwrap();
|
let folder = folders.pop().unwrap();
|
||||||
url_request = String::from(domain.clone());
|
|
||||||
if first_iter {
|
let relative_s = match folder.relative_s {
|
||||||
url_request.push_str("/remote.php/dav/files/");
|
Some(relative_s) => relative_s,
|
||||||
url_request.push_str(username);
|
None => String::from(""),
|
||||||
}
|
};
|
||||||
url_request.push_str(folder.as_str());
|
|
||||||
|
|
||||||
// request folder content
|
// request folder content
|
||||||
let mut objs = vec![];
|
let res = ReqProps::new()
|
||||||
tokio::runtime::Runtime::new().unwrap().block_on(async {
|
.set_request(relative_s.as_str(), &api_props)
|
||||||
let res = ListFolders::new(url_request.as_str())
|
.gethref()
|
||||||
.gethref()
|
.getlastmodified()
|
||||||
.send_with_res()
|
.send_req_multiple();
|
||||||
.await;
|
|
||||||
objs = match res {
|
let mut objs = match res {
|
||||||
Ok(o) => o,
|
Ok(o) => o,
|
||||||
Err(ApiError::IncorrectRequest(err)) => {
|
Err(ApiError::IncorrectRequest(err)) => {
|
||||||
eprintln!("fatal: {}", err.status());
|
eprintln!("fatal: {}", err.status());
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
},
|
},
|
||||||
Err(ApiError::EmptyError(_)) => {
|
Err(ApiError::EmptyError(_)) => {
|
||||||
eprintln!("Failed to get body");
|
eprintln!("Failed to get body");
|
||||||
vec![]
|
vec![]
|
||||||
}
|
|
||||||
Err(ApiError::RequestError(err)) => {
|
|
||||||
eprintln!("fatal: {}", err);
|
|
||||||
std::process::exit(1);
|
|
||||||
},
|
|
||||||
Err(ApiError::Unexpected(_)) => todo!()
|
|
||||||
}
|
}
|
||||||
});
|
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 {
|
||||||
@ -79,19 +81,20 @@ pub fn clone(remote: Values<'_>) {
|
|||||||
// 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);
|
||||||
} else {
|
} else {
|
||||||
commands::init::init();
|
init::init();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// create folder
|
// create folder
|
||||||
let local_folder = get_local_path(folder, ref_path.clone(), username, dist_path_str);
|
let p = ref_path.clone().join(Path::new(&relative_s));
|
||||||
if let Err(err) = DirBuilder::new().recursive(true).create(local_folder.clone()) {
|
if let Err(err) = DirBuilder::new().recursive(true).create(p.clone()) {
|
||||||
eprintln!("error: cannot create directory {}: {}", local_folder.display(), err);
|
eprintln!("err: cannot create directory {} ({})", p.display(), err);
|
||||||
}
|
}
|
||||||
|
|
||||||
// add tree
|
// 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() {
|
let lastmodified = folder.lastmodified.unwrap().timestamp_millis();
|
||||||
eprintln!("error: cannot store object {}", path_folder.display());
|
if let Err(err) = add_tree(&path_folder, &lastmodified.to_string()) {
|
||||||
|
eprintln!("err: saving ref of {} ({})", path_folder.display(), err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,48 +103,45 @@ pub fn clone(remote: Values<'_>) {
|
|||||||
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.href.clone().unwrap().chars().last().unwrap() == '/' {
|
if object.href.clone().unwrap().chars().last().unwrap() == '/' {
|
||||||
folders.push(object.href.clone().unwrap().to_string());
|
folders.push(object.clone());
|
||||||
} else {
|
} else {
|
||||||
files.push(object.href.clone().unwrap().to_string());
|
files.push(object.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
first_iter = false;
|
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<String>) {
|
fn download_files(ref_p: PathBuf, files: Vec<ObjProps>, api_props: &ApiProps) {
|
||||||
for remote_file in files {
|
for obj in files {
|
||||||
tokio::runtime::Runtime::new().unwrap().block_on(async {
|
let relative_s = &obj.clone().relative_s.unwrap();
|
||||||
let res = DownloadFiles::new()
|
let res = DownloadFiles::new()
|
||||||
.set_url_with_remote(remote_file.as_str())
|
.set_url(&relative_s, api_props)
|
||||||
.save(local_p.clone()).await;
|
.save(ref_p.clone());
|
||||||
|
|
||||||
match res {
|
match res {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
|
let relative_p = Path::new(&relative_s);
|
||||||
let s = &get_local_path_t(&remote_file.clone());
|
let lastmodified = obj.clone().lastmodified.unwrap().timestamp_millis();
|
||||||
let ss = s.strip_prefix("/").unwrap();
|
if let Err(err) = add_blob(relative_p, &lastmodified.to_string()) {
|
||||||
let relative_p = Path::new(ss);
|
eprintln!("err: saving ref of {} ({})", relative_s.clone(), err);
|
||||||
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)) => {
|
|
||||||
eprintln!("fatal: {}", err.status());
|
|
||||||
std::process::exit(1);
|
|
||||||
},
|
|
||||||
Err(ApiError::EmptyError(_)) => eprintln!("Failed to get body"),
|
|
||||||
Err(ApiError::RequestError(err)) => {
|
|
||||||
eprintln!("fatal: {}", err);
|
|
||||||
std::process::exit(1);
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
Err(ApiError::Unexpected(_)) => {
|
||||||
|
eprintln!("err: writing {}", relative_s);
|
||||||
|
},
|
||||||
|
Err(ApiError::IncorrectRequest(err)) => {
|
||||||
|
eprintln!("fatal: {}", err.status());
|
||||||
|
std::process::exit(1);
|
||||||
|
},
|
||||||
|
Err(ApiError::EmptyError(_)) => eprintln!("Failed to get body"),
|
||||||
|
Err(ApiError::RequestError(err)) => {
|
||||||
|
eprintln!("fatal: {}", err);
|
||||||
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::utils::{path, read};
|
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
use crate::utils::{path, read};
|
||||||
|
|
||||||
pub fn set(var: &str, val: &str) -> io::Result<()> {
|
pub fn set(var: &str, val: &str) -> io::Result<()> {
|
||||||
let mut root = match path::nextsync() {
|
let mut root = match path::nextsync() {
|
||||||
@ -40,7 +40,6 @@ pub fn get(var: &str) -> Option<String> {
|
|||||||
if let Ok(lines) = read::read_lines(root) {
|
if let Ok(lines) = read::read_lines(root) {
|
||||||
for line in lines {
|
for line in lines {
|
||||||
if let Ok(l) = line {
|
if let Ok(l) = line {
|
||||||
dbg!(l.clone());
|
|
||||||
if l.starts_with(var.clone()) {
|
if l.starts_with(var.clone()) {
|
||||||
let (_, val) = l.split_once(" ").unwrap();
|
let (_, val) = l.split_once(" ").unwrap();
|
||||||
return Some(val.to_owned());
|
return Some(val.to_owned());
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
|
use std::env;
|
||||||
use std::fs::{DirBuilder, File};
|
use std::fs::{DirBuilder, File};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::env;
|
|
||||||
use crate::global::global::DIR_PATH;
|
use crate::global::global::DIR_PATH;
|
||||||
|
|
||||||
pub fn init() {
|
pub fn init() {
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
use crate::commands::{status, config};
|
|
||||||
use crate::services::req_props::ReqProps;
|
|
||||||
use crate::services::api::ApiError;
|
use crate::services::api::ApiError;
|
||||||
use crate::services::upload_file::UploadFile;
|
use crate::services::upload_file::UploadFile;
|
||||||
use crate::services::delete_path::DeletePath;
|
use crate::services::delete_path::DeletePath;
|
||||||
use crate::commands::status::{State, Obj};
|
use crate::services::req_props::{ReqProps, ObjProps};
|
||||||
use crate::store::object::{add_blob, rm_blob};
|
|
||||||
use crate::store::index;
|
use crate::store::index;
|
||||||
|
use crate::store::object::{add_blob, rm_blob};
|
||||||
|
use crate::commands::{status, config};
|
||||||
|
use crate::commands::status::{State, Obj};
|
||||||
|
use crate::commands::push::push_factory::{PushFactory, PushState};
|
||||||
|
|
||||||
|
pub mod push_factory;
|
||||||
|
pub mod new;
|
||||||
|
pub mod deleted;
|
||||||
|
|
||||||
pub fn push() {
|
pub fn push() {
|
||||||
dbg!(status::get_all_staged());
|
dbg!(status::get_all_staged());
|
||||||
@ -36,205 +41,3 @@ pub fn push() {
|
|||||||
// if dir upload dir
|
// if dir upload dir
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
enum PushState {
|
|
||||||
Done,
|
|
||||||
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 {
|
|
||||||
// todo 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);
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// update tree
|
|
||||||
add_blob(&obj.path.clone(), "todo_date");
|
|
||||||
// remove index
|
|
||||||
index::rm_line(obj.path.to_str().unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct Deleted {
|
|
||||||
obj: Obj,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PushChange for Deleted {
|
|
||||||
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::Done
|
|
||||||
} else {
|
|
||||||
// todo check date
|
|
||||||
//PushState::Conflict
|
|
||||||
PushState::Valid
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
PushState::Error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn push(&self) {
|
|
||||||
let obj = &self.obj;
|
|
||||||
tokio::runtime::Runtime::new().unwrap().block_on(async {
|
|
||||||
let res = DeletePath::new()
|
|
||||||
.set_url(obj.path.to_str().unwrap())
|
|
||||||
.send_with_err()
|
|
||||||
.await;
|
|
||||||
|
|
||||||
match res {
|
|
||||||
Err(ApiError::IncorrectRequest(err)) => {
|
|
||||||
eprintln!("fatal: error deleting file {}: {}", obj.name, err.status());
|
|
||||||
std::process::exit(1);
|
|
||||||
},
|
|
||||||
Err(ApiError::RequestError(_)) => {
|
|
||||||
eprintln!("fatal: request error deleting file {}", obj.name);
|
|
||||||
std::process::exit(1);
|
|
||||||
}
|
|
||||||
_ => (),
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// update tree
|
|
||||||
rm_blob(&obj.path.clone());
|
|
||||||
// remove index
|
|
||||||
index::rm_line(obj.path.to_str().unwrap());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct PushFactory;
|
|
||||||
|
|
||||||
impl PushFactory {
|
|
||||||
fn new(&self, obj: Obj) -> Box<dyn PushChange> {
|
|
||||||
match obj.state {
|
|
||||||
State::New => Box::new(New { obj: obj.clone() }),
|
|
||||||
State::Renamed => todo!(),
|
|
||||||
State::Modified => todo!(),
|
|
||||||
State::Deleted => Box::new(Deleted { obj: obj.clone() }),
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
70
src/commands/push/deleted.rs
Normal file
70
src/commands/push/deleted.rs
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
use crate::services::api::ApiError;
|
||||||
|
use crate::services::req_props::ReqProps;
|
||||||
|
use crate::services::delete_path::DeletePath;
|
||||||
|
use crate::store::index;
|
||||||
|
use crate::store::object::rm_blob;
|
||||||
|
use crate::commands::status::Obj;
|
||||||
|
use crate::commands::push::push_factory::{PushState, PushChange};
|
||||||
|
|
||||||
|
pub struct Deleted {
|
||||||
|
pub obj: Obj,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PushChange for Deleted {
|
||||||
|
fn can_push(&self) -> PushState {
|
||||||
|
// check if exist on server
|
||||||
|
let res = ReqProps::new()
|
||||||
|
.set_url(&self.obj.path.to_str().unwrap())
|
||||||
|
.getlastmodified()
|
||||||
|
.send_with_err();
|
||||||
|
|
||||||
|
let file_infos = match res {
|
||||||
|
Ok(obj) => Ok(Some(obj)),
|
||||||
|
Err(ApiError::IncorrectRequest(err)) => {
|
||||||
|
if err.status() == 404 {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(_) => Err(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Ok(infos) = file_infos {
|
||||||
|
if let Some(inf) = infos {
|
||||||
|
// file doesn't exist on remote
|
||||||
|
PushState::Done
|
||||||
|
} else {
|
||||||
|
// todo check date
|
||||||
|
//PushState::Conflict
|
||||||
|
PushState::Valid
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PushState::Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(&self) {
|
||||||
|
let obj = &self.obj;
|
||||||
|
let res = DeletePath::new()
|
||||||
|
.set_url(obj.path.to_str().unwrap())
|
||||||
|
.send_with_err();
|
||||||
|
|
||||||
|
match res {
|
||||||
|
Err(ApiError::IncorrectRequest(err)) => {
|
||||||
|
eprintln!("fatal: error deleting file {}: {}", obj.name, err.status());
|
||||||
|
std::process::exit(1);
|
||||||
|
},
|
||||||
|
Err(ApiError::RequestError(_)) => {
|
||||||
|
eprintln!("fatal: request error deleting file {}", obj.name);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
// update tree
|
||||||
|
rm_blob(&obj.path.clone());
|
||||||
|
// remove index
|
||||||
|
index::rm_line(obj.path.to_str().unwrap());
|
||||||
|
}
|
||||||
|
}
|
71
src/commands/push/new.rs
Normal file
71
src/commands/push/new.rs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
use crate::services::api::ApiError;
|
||||||
|
use crate::services::req_props::ReqProps;
|
||||||
|
use crate::services::upload_file::UploadFile;
|
||||||
|
use crate::store::index;
|
||||||
|
use crate::store::object::add_blob;
|
||||||
|
use crate::commands::status::Obj;
|
||||||
|
use crate::commands::push::push_factory::{PushState, PushChange, PushFactory};
|
||||||
|
|
||||||
|
pub struct New {
|
||||||
|
pub obj: Obj,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PushChange for New {
|
||||||
|
fn can_push(&self) -> PushState {
|
||||||
|
// check if exist on server
|
||||||
|
let res = ReqProps::new()
|
||||||
|
.set_url(&self.obj.path.to_str().unwrap())
|
||||||
|
.getlastmodified()
|
||||||
|
.send_req_single();
|
||||||
|
|
||||||
|
let file_infos = match res {
|
||||||
|
Ok(obj) => Ok(Some(obj)),
|
||||||
|
Err(ApiError::IncorrectRequest(err)) => {
|
||||||
|
if err.status() == 404 {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
Err(())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(_) => Err(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Ok(infos) = file_infos {
|
||||||
|
if let Some(info) = infos {
|
||||||
|
// file doesn't exist on remote
|
||||||
|
PushState::Valid
|
||||||
|
} else {
|
||||||
|
// todo check date
|
||||||
|
PushState::Conflict
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PushState::Error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(&self) {
|
||||||
|
let obj = &self.obj;
|
||||||
|
let res = UploadFile::new()
|
||||||
|
.set_url(obj.path.to_str().unwrap())
|
||||||
|
.set_file(obj.path.clone())
|
||||||
|
.send_with_err();
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
|
||||||
|
// update tree
|
||||||
|
add_blob(&obj.path.clone(), "todo_date");
|
||||||
|
|
||||||
|
// remove index
|
||||||
|
index::rm_line(obj.path.to_str().unwrap());
|
||||||
|
}
|
||||||
|
}
|
32
src/commands/push/push_factory.rs
Normal file
32
src/commands/push/push_factory.rs
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
use crate::commands::status::{State, Obj};
|
||||||
|
use crate::commands::push::new::New;
|
||||||
|
use crate::commands::push::deleted::Deleted;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum PushState {
|
||||||
|
Done,
|
||||||
|
Valid,
|
||||||
|
Conflict,
|
||||||
|
Error,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait PushChange {
|
||||||
|
fn can_push(&self) -> PushState;
|
||||||
|
fn push(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PushFactory;
|
||||||
|
|
||||||
|
impl PushFactory {
|
||||||
|
pub fn new(&self, obj: Obj) -> Box<dyn PushChange> {
|
||||||
|
match obj.state {
|
||||||
|
State::New => Box::new(New { obj: obj.clone() }),
|
||||||
|
State::Renamed => todo!(),
|
||||||
|
State::Modified => todo!(),
|
||||||
|
State::Deleted => Box::new(Deleted { obj: obj.clone() }),
|
||||||
|
State::Default => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use crypto::digest::Digest;
|
|
||||||
use crypto::sha1::Sha1;
|
|
||||||
use std::collections::{HashSet, HashMap};
|
|
||||||
use colored::Colorize;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::io::{self, Lines, BufReader};
|
use std::io::{self, Lines, BufReader};
|
||||||
|
use std::collections::{HashSet, HashMap};
|
||||||
|
use crypto::digest::Digest;
|
||||||
|
use crypto::sha1::Sha1;
|
||||||
|
use colored::Colorize;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
use crate::store::{self, object};
|
use crate::store::{self, object};
|
||||||
|
|
||||||
@ -58,10 +58,9 @@ pub fn get_all_staged() -> Vec<Obj> {
|
|||||||
staged_objs
|
staged_objs
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_renamed(new_obj: &mut Vec<Obj>, del_obj: &mut Vec<Obj>) -> Vec<Obj> {
|
fn get_renamed(_new_obj: &mut Vec<Obj>, _del_obj: &mut Vec<Obj>) -> Vec<Obj> {
|
||||||
// get hash of all new obj, compare to hash of all del
|
// get hash of all new obj, compare to hash of all del
|
||||||
let renamed_objs = vec![];
|
let renamed_objs = vec![];
|
||||||
|
|
||||||
renamed_objs
|
renamed_objs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use clap::{App, Arg, SubCommand};
|
use clap::{App, Arg, SubCommand};
|
||||||
use crate::commands::add::AddArgs;
|
use crate::commands::add::AddArgs;
|
||||||
|
|
||||||
mod commands;
|
mod commands;
|
||||||
mod utils;
|
mod utils;
|
||||||
mod services;
|
mod services;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
pub mod api;
|
pub mod api;
|
||||||
pub mod list_folders;
|
|
||||||
pub mod download_files;
|
pub mod download_files;
|
||||||
pub mod req_props;
|
pub mod req_props;
|
||||||
pub mod upload_file;
|
pub mod upload_file;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
|
use std::env;
|
||||||
|
use dotenv::dotenv;
|
||||||
use reqwest::Client;
|
use reqwest::Client;
|
||||||
use reqwest::RequestBuilder;
|
use reqwest::RequestBuilder;
|
||||||
use reqwest::{Response, Error, IntoUrl, Method};
|
use reqwest::{Response, Error, IntoUrl, Method};
|
||||||
use std::env;
|
use crate::utils::api::ApiProps;
|
||||||
use dotenv::dotenv;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum ApiError {
|
pub enum ApiError {
|
||||||
@ -25,7 +26,7 @@ impl ApiBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_request<U: IntoUrl>(mut self, method: Method, url: U) -> ApiBuilder {
|
pub fn set_request<U: IntoUrl>(&mut self, method: Method, url: U) -> &mut ApiBuilder {
|
||||||
self.request = Some(self.client.request(method, url));
|
self.request = Some(self.client.request(method, url));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -48,13 +49,14 @@ impl ApiBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_request_remote(&mut self, meth: Method, path: &str) -> &mut ApiBuilder {
|
pub fn set_req(&mut self, meth: Method, p: &str, api_props: &ApiProps) -> &mut ApiBuilder {
|
||||||
dotenv().ok();
|
let mut url = String::from(&api_props.host);
|
||||||
let host = env::var("HOST").unwrap();
|
url.push_str("/remote.php/dav/files/");
|
||||||
let mut url = String::from(host);
|
|
||||||
url.push_str("/");
|
url.push_str("/");
|
||||||
url.push_str(path);
|
url.push_str(&api_props.username);
|
||||||
dbg!(url.clone());
|
url.push_str(&api_props.root);
|
||||||
|
url.push_str("/");
|
||||||
|
url.push_str(p);
|
||||||
self.request = Some(self.client.request(meth, url));
|
self.request = Some(self.client.request(meth, url));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::services::api::{ApiBuilder, ApiError};
|
|
||||||
use reqwest::{Method, IntoUrl, Response, Error};
|
use reqwest::{Method, IntoUrl, Response, Error};
|
||||||
|
use crate::services::api::{ApiBuilder, ApiError};
|
||||||
|
|
||||||
pub struct CreateFolder {
|
pub struct CreateFolder {
|
||||||
api_builder: ApiBuilder,
|
api_builder: ApiBuilder,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::services::api::{ApiBuilder, ApiError};
|
|
||||||
use reqwest::{Method, Response, Error};
|
use reqwest::{Method, Response, Error};
|
||||||
|
use crate::services::api::{ApiBuilder, ApiError};
|
||||||
|
|
||||||
pub struct DeletePath {
|
pub struct DeletePath {
|
||||||
api_builder: ApiBuilder,
|
api_builder: ApiBuilder,
|
||||||
@ -21,10 +21,15 @@ impl DeletePath {
|
|||||||
self.api_builder.send().await
|
self.api_builder.send().await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_with_err(&mut self) -> Result<String, ApiError> {
|
pub fn send_with_err(&mut self) -> Result<String, ApiError> {
|
||||||
let res = self.send().await.map_err(ApiError::RequestError)?;
|
let res = tokio::runtime::Runtime::new().unwrap().block_on(async {
|
||||||
|
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 = tokio::runtime::Runtime::new().unwrap().block_on(async {
|
||||||
|
res.text().await
|
||||||
|
}).map_err(ApiError::EmptyError)?;
|
||||||
Ok(body)
|
Ok(body)
|
||||||
} else {
|
} else {
|
||||||
Err(ApiError::IncorrectRequest(res))
|
Err(ApiError::IncorrectRequest(res))
|
||||||
|
@ -1,26 +1,26 @@
|
|||||||
use crate::services::api::{ApiBuilder, ApiError};
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use reqwest::{Method, Response, Error};
|
|
||||||
use crate::utils::api::get_local_path_t;
|
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
use reqwest::{Method, Response, Error};
|
||||||
|
use crate::utils::api::ApiProps;
|
||||||
|
use crate::services::api::{ApiBuilder, ApiError};
|
||||||
|
|
||||||
pub struct DownloadFiles {
|
pub struct DownloadFiles {
|
||||||
api_builder: ApiBuilder,
|
api_builder: ApiBuilder,
|
||||||
path: String,
|
relative_ps: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DownloadFiles {
|
impl DownloadFiles {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
DownloadFiles {
|
DownloadFiles {
|
||||||
api_builder: ApiBuilder::new(),
|
api_builder: ApiBuilder::new(),
|
||||||
path: String::from(""),
|
relative_ps: String::from(""),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_url_with_remote(&mut self, url: &str) -> &mut DownloadFiles {
|
pub fn set_url(&mut self, relative_ps: &str, api_props: &ApiProps) -> &mut DownloadFiles {
|
||||||
self.path = get_local_path_t(url.clone()).strip_prefix("/").unwrap().to_string();
|
self.relative_ps = relative_ps.to_string();
|
||||||
self.api_builder.build_request_remote(Method::GET, url);
|
self.api_builder.set_req(Method::from_bytes(b"PROPFIND").unwrap(), relative_ps, api_props);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,18 +38,20 @@ impl DownloadFiles {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn save(&mut self, local_path: PathBuf) -> Result<(), ApiError> {
|
pub fn save(&mut self, ref_p: PathBuf) -> Result<(), ApiError> {
|
||||||
let p = local_path.join(PathBuf::from(self.path.clone()));
|
tokio::runtime::Runtime::new().unwrap().block_on(async {
|
||||||
let res = self.send().await.map_err(ApiError::RequestError)?;
|
let p = ref_p.join(PathBuf::from(self.relative_ps.clone()));
|
||||||
if res.status().is_success() {
|
let res = self.send().await.map_err(ApiError::RequestError)?;
|
||||||
let body = res.bytes().await.map_err(ApiError::EmptyError)?;
|
if res.status().is_success() {
|
||||||
match DownloadFiles::write_file(p, &body.to_vec()) {
|
let body = res.bytes().await.map_err(ApiError::EmptyError)?;
|
||||||
Err(_) => Err(ApiError::Unexpected(String::from(""))),
|
match DownloadFiles::write_file(p, &body.to_vec()) {
|
||||||
Ok(_) => Ok(()),
|
Err(_) => Err(ApiError::Unexpected(String::from(""))),
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(ApiError::IncorrectRequest(res))
|
||||||
}
|
}
|
||||||
} else {
|
})
|
||||||
Err(ApiError::IncorrectRequest(res))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_file(path: PathBuf, content: &Vec<u8>) -> io::Result<()> {
|
fn write_file(path: PathBuf, content: &Vec<u8>) -> io::Result<()> {
|
||||||
|
@ -1,114 +0,0 @@
|
|||||||
use crate::services::api::{ApiBuilder, ApiError};
|
|
||||||
use xml::reader::{EventReader, XmlEvent};
|
|
||||||
use std::io::Cursor;
|
|
||||||
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 {
|
|
||||||
api_builder: ApiBuilder,
|
|
||||||
xml_balises: Vec<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ListFolders {
|
|
||||||
pub fn new<U: IntoUrl>(url: U) -> Self {
|
|
||||||
ListFolders {
|
|
||||||
api_builder: ApiBuilder::new()
|
|
||||||
.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> {
|
|
||||||
self.api_builder.send().await
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn send_with_err(&mut self) -> Result<String, ApiError> {
|
|
||||||
let res = self.send().await.map_err(ApiError::RequestError)?;
|
|
||||||
if res.status().is_success() {
|
|
||||||
let body = res.text().await.map_err(ApiError::EmptyError)?;
|
|
||||||
Ok(body)
|
|
||||||
} else {
|
|
||||||
Err(ApiError::IncorrectRequest(res))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn send_with_res(&mut self) -> Result<Vec<FolderContent>, ApiError> {
|
|
||||||
match self.send_with_err().await {
|
|
||||||
Ok(body) => Ok(self.parse(body)),
|
|
||||||
Err(err) => Err(err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +1,52 @@
|
|||||||
use crate::services::api::{ApiBuilder, ApiError};
|
|
||||||
use xml::reader::{EventReader, XmlEvent};
|
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
use chrono::{Utc, DateTime};
|
||||||
use reqwest::{Method, Response, Error};
|
use reqwest::{Method, Response, Error};
|
||||||
|
use xml::reader::{EventReader, XmlEvent};
|
||||||
|
use crate::utils::time::parse_timestamp;
|
||||||
|
use crate::utils::api::{get_relative_s, ApiProps};
|
||||||
|
use crate::services::api::{ApiBuilder, ApiError};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ObjProps {
|
||||||
|
pub href: Option<String>,
|
||||||
|
pub relative_s: Option<String>,
|
||||||
|
pub lastmodified: Option<DateTime<Utc>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for ObjProps {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
ObjProps {
|
||||||
|
href: self.href.clone(),
|
||||||
|
relative_s: self.relative_s.clone(),
|
||||||
|
lastmodified: self.lastmodified.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjProps {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
ObjProps {
|
||||||
|
href: None,
|
||||||
|
relative_s: None,
|
||||||
|
lastmodified: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ReqProps {
|
pub struct ReqProps {
|
||||||
api_builder: ApiBuilder,
|
api_builder: ApiBuilder,
|
||||||
xml_list: Vec<String>,
|
xml_balises: Vec<String>,
|
||||||
xml_payload: String,
|
xml_payload: String,
|
||||||
|
api_props: Option<ApiProps>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ReqProps {
|
impl ReqProps {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
ReqProps {
|
ReqProps {
|
||||||
api_builder: ApiBuilder::new(),
|
api_builder: ApiBuilder::new(),
|
||||||
xml_list: vec![],
|
xml_balises: vec![],
|
||||||
xml_payload: String::new(),
|
xml_payload: String::new(),
|
||||||
|
api_props: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,38 +55,49 @@ impl ReqProps {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_request(&mut self, p: &str, api_props: &ApiProps) -> &mut ReqProps {
|
||||||
|
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 ReqProps {
|
||||||
|
self.xml_balises.push(String::from("href"));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn getlastmodified(&mut self) -> &mut ReqProps {
|
pub fn getlastmodified(&mut self) -> &mut ReqProps {
|
||||||
self.xml_list.push(String::from("getlastmodified"));
|
self.xml_balises.push(String::from("getlastmodified"));
|
||||||
self.xml_payload.push_str(r#"<d:getlastmodified/>"#);
|
self.xml_payload.push_str(r#"<d:getlastmodified/>"#);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn getcontentlenght(&mut self) -> &mut ReqProps {
|
pub fn getcontentlenght(&mut self) -> &mut ReqProps {
|
||||||
self.xml_list.push(String::from("getcontentlength"));
|
self.xml_balises.push(String::from("getcontentlength"));
|
||||||
self.xml_payload.push_str(r#"<d:getcontentlength/>"#);
|
self.xml_payload.push_str(r#"<d:getcontentlength/>"#);
|
||||||
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_balises.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_balises.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_balises.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_balises.push(String::from("getetag"));
|
||||||
self.xml_payload.push_str(r#"<d:getetag/>"#);
|
self.xml_payload.push_str(r#"<d:getetag/>"#);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -72,24 +115,49 @@ impl ReqProps {
|
|||||||
self.api_builder.send().await
|
self.api_builder.send().await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_with_err(&mut self) -> Result<Vec<String>, ApiError> {
|
pub fn send_with_err(&mut self) -> Result<String, ApiError> {
|
||||||
let res = self.send().await.map_err(ApiError::RequestError)?;
|
let res = tokio::runtime::Runtime::new().unwrap().block_on(async {
|
||||||
|
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 = tokio::runtime::Runtime::new().unwrap().block_on(async {
|
||||||
Ok(self.parse(body))
|
res.text().await
|
||||||
|
}).map_err(ApiError::EmptyError)?;
|
||||||
|
Ok(body)
|
||||||
} else {
|
} else {
|
||||||
Err(ApiError::IncorrectRequest(res))
|
Err(ApiError::IncorrectRequest(res))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse(&self, xml: String) -> Vec<String> {
|
pub fn send_req_multiple(&mut self) -> Result<Vec<ObjProps>, ApiError> {
|
||||||
|
match self.send_with_err() {
|
||||||
|
Ok(body) => Ok(self.parse(body, true)),
|
||||||
|
Err(err) => Err(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn send_req_single(&mut self) -> Result<ObjProps, ApiError> {
|
||||||
|
match self.send_with_err() {
|
||||||
|
Ok(body) => {
|
||||||
|
let objs = self.parse(body, false);
|
||||||
|
let obj = objs[0].clone();
|
||||||
|
Ok(obj)
|
||||||
|
},
|
||||||
|
Err(err) => Err(err),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(&self, xml: String, multiple: bool) -> Vec<ObjProps> {
|
||||||
let cursor = Cursor::new(xml);
|
let cursor = Cursor::new(xml);
|
||||||
let parser = EventReader::new(cursor);
|
let parser = EventReader::new(cursor);
|
||||||
|
|
||||||
let mut should_get = false;
|
let mut should_get = false;
|
||||||
let mut values: Vec<String> = vec![];
|
let mut values: Vec<ObjProps> = vec![];
|
||||||
let mut iter = self.xml_list.iter();
|
|
||||||
|
let mut iter = self.xml_balises.iter();
|
||||||
let mut val = iter.next();
|
let mut val = iter.next();
|
||||||
|
let mut content = ObjProps::new();
|
||||||
|
|
||||||
for event in parser {
|
for event in parser {
|
||||||
match event {
|
match event {
|
||||||
@ -97,12 +165,33 @@ impl ReqProps {
|
|||||||
if let Some(v) = val.clone() {
|
if let Some(v) = val.clone() {
|
||||||
should_get = &name.local_name == v;
|
should_get = &name.local_name == v;
|
||||||
} else {
|
} else {
|
||||||
break;
|
// end of balises to get then start over for
|
||||||
|
// next object if want multiple
|
||||||
|
if multiple {
|
||||||
|
values.push(content.clone());
|
||||||
|
iter = self.xml_balises.iter();
|
||||||
|
val = iter.next();
|
||||||
|
content = ObjProps::new();
|
||||||
|
if let Some(v) = val.clone() {
|
||||||
|
should_get = &name.local_name == v;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(XmlEvent::Characters(text)) => {
|
Ok(XmlEvent::Characters(text)) => {
|
||||||
if !text.trim().is_empty() && should_get {
|
if !text.trim().is_empty() && should_get {
|
||||||
values.push(text);
|
match val.unwrap().as_str() {
|
||||||
|
"href" => {
|
||||||
|
content.href = Some(text.clone());
|
||||||
|
content.relative_s = Some(get_relative_s(text, &(self.api_props.clone().unwrap())));
|
||||||
|
},
|
||||||
|
"getlastmodified" => {
|
||||||
|
content.lastmodified = Some(parse_timestamp(&text).unwrap());
|
||||||
|
},
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
val = iter.next()
|
val = iter.next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use crate::services::api::{ApiBuilder, ApiError};
|
|
||||||
use std::path::PathBuf;
|
|
||||||
use std::io::{Read};
|
use std::io::{Read};
|
||||||
|
use std::path::PathBuf;
|
||||||
use reqwest::{Method, Response, Error};
|
use reqwest::{Method, Response, Error};
|
||||||
|
use crate::services::api::{ApiBuilder, ApiError};
|
||||||
|
|
||||||
pub struct UploadFile {
|
pub struct UploadFile {
|
||||||
api_builder: ApiBuilder,
|
api_builder: ApiBuilder,
|
||||||
@ -34,10 +34,15 @@ impl UploadFile {
|
|||||||
self.api_builder.send().await
|
self.api_builder.send().await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_with_err(&mut self) -> Result<String, ApiError> {
|
pub fn send_with_err(&mut self) -> Result<String, ApiError> {
|
||||||
let res = self.send().await.map_err(ApiError::RequestError)?;
|
let res = tokio::runtime::Runtime::new().unwrap().block_on(async {
|
||||||
|
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 = tokio::runtime::Runtime::new().unwrap().block_on(async {
|
||||||
|
res.text().await
|
||||||
|
}).map_err(ApiError::EmptyError)?;
|
||||||
Ok(body)
|
Ok(body)
|
||||||
} else {
|
} else {
|
||||||
Err(ApiError::IncorrectRequest(res))
|
Err(ApiError::IncorrectRequest(res))
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::fs::{File, OpenOptions};
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use crate::utils::{read, path};
|
use std::fs::{File, OpenOptions};
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
use crate::utils::{read, path};
|
||||||
|
|
||||||
pub fn _read_only(mut path: PathBuf) -> File {
|
pub fn _read_only(mut path: PathBuf) -> File {
|
||||||
path.push("HEAD");
|
path.push("HEAD");
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use std::fs::OpenOptions;
|
use std::io;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
|
use std::fs::OpenOptions;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use crate::utils::{read, path};
|
use crate::utils::{read, path};
|
||||||
use std::io;
|
|
||||||
|
|
||||||
pub fn _read_only(mut path: PathBuf) -> File {
|
pub fn _read_only(mut path: PathBuf) -> File {
|
||||||
path.push("index");
|
path.push("index");
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
|
use std::fs::File;
|
||||||
|
use std::io::{self, Write};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use crate::utils::{read, path};
|
use std::fs::{OpenOptions, self};
|
||||||
use crate::store::head;
|
|
||||||
use crypto::sha1::Sha1;
|
use crypto::sha1::Sha1;
|
||||||
use crypto::digest::Digest;
|
use crypto::digest::Digest;
|
||||||
use std::fs::{OpenOptions, self};
|
use crate::utils::{read, path};
|
||||||
use std::io::{self, Write};
|
use crate::store::head;
|
||||||
use std::fs::File;
|
|
||||||
|
|
||||||
/// Returns (line, hash, name)
|
/// Returns (line, hash, name)
|
||||||
///
|
///
|
||||||
@ -40,7 +40,7 @@ pub fn parse_line(line: String) -> (String, String, String) {
|
|||||||
(String::from(ftype), String::from(hash), String::from(name))
|
(String::from(ftype), String::from(hash), String::from(name))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_tree(path: &Path) -> io::Result<()> {
|
pub fn add_tree(path: &Path, date: &str) -> io::Result<()> {
|
||||||
let (line, hash, name) = parse_path(path.clone(), false);
|
let (line, hash, name) = parse_path(path.clone(), false);
|
||||||
|
|
||||||
// add tree reference to parent
|
// add tree reference to parent
|
||||||
@ -51,7 +51,10 @@ pub fn add_tree(path: &Path) -> io::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// create tree object
|
// create tree object
|
||||||
create_object(hash, &name)?;
|
let mut content = name;
|
||||||
|
content.push_str(" ");
|
||||||
|
content.push_str(date);
|
||||||
|
create_object(hash, &content)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -93,8 +96,6 @@ pub fn add_blob(path: &Path, date: &str) -> io::Result<()> {
|
|||||||
|
|
||||||
let mut content = name.clone().to_owned();
|
let mut content = name.clone().to_owned();
|
||||||
content.push_str(" ");
|
content.push_str(" ");
|
||||||
content.push_str("tmp_hash");
|
|
||||||
content.push_str(" ");
|
|
||||||
content.push_str(date);
|
content.push_str(date);
|
||||||
|
|
||||||
// create blob object
|
// create blob object
|
||||||
@ -132,7 +133,6 @@ pub fn read_tree(tree: String) -> Option<(String, io::Lines<io::BufReader<File>>
|
|||||||
let (dir, res) = hash_obj(&tree);
|
let (dir, res) = hash_obj(&tree);
|
||||||
obj_p.push(dir);
|
obj_p.push(dir);
|
||||||
obj_p.push(res);
|
obj_p.push(res);
|
||||||
|
|
||||||
|
|
||||||
match read::read_lines(obj_p) {
|
match read::read_lines(obj_p) {
|
||||||
Ok(mut reader) => {
|
Ok(mut reader) => {
|
||||||
@ -147,7 +147,6 @@ pub fn read_tree(tree: String) -> Option<(String, io::Lines<io::BufReader<File>>
|
|||||||
None
|
None
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rm_node(path: &Path, node: &str) -> io::Result<()> {
|
fn rm_node(path: &Path, node: &str) -> io::Result<()> {
|
||||||
|
@ -2,3 +2,4 @@ pub mod path;
|
|||||||
pub mod read;
|
pub mod read;
|
||||||
pub mod nextsyncignore;
|
pub mod nextsyncignore;
|
||||||
pub mod api;
|
pub mod api;
|
||||||
|
pub mod time;
|
@ -1,23 +1,25 @@
|
|||||||
use std::path::{PathBuf, Path};
|
#[derive(Debug)]
|
||||||
use std::env;
|
pub struct ApiProps {
|
||||||
|
pub host: String, // nextcloud.example.com
|
||||||
pub fn get_local_path(p: String, local_p: PathBuf, username: &str, dist_p: &str) -> PathBuf {
|
pub username: String,
|
||||||
let mut final_p = Path::new(p.as_str());
|
pub root: String, // /dir/cloned
|
||||||
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 {
|
impl Clone for ApiProps {
|
||||||
dbg!(p.clone());
|
fn clone(&self) -> Self {
|
||||||
let username = env::var("USERNAME").unwrap();
|
ApiProps {
|
||||||
let root = env::var("ROOT").unwrap();
|
host: self.host.to_string(),
|
||||||
let mut final_p = p;
|
username: self.username.to_string(),
|
||||||
final_p = final_p.strip_prefix("/remote.php/dav/files/").unwrap();
|
root: self.root.to_string(),
|
||||||
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()
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::utils::path;
|
|
||||||
use regex::Regex;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufReader, BufRead};
|
use std::io::{BufReader, BufRead};
|
||||||
|
use regex::Regex;
|
||||||
|
use crate::utils::path;
|
||||||
|
|
||||||
pub 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() {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
|
use std::fs::canonicalize;
|
||||||
use std::path::{PathBuf, Path};
|
use std::path::{PathBuf, Path};
|
||||||
use crate::global::global::DIR_PATH;
|
use crate::global::global::DIR_PATH;
|
||||||
use std::fs::canonicalize;
|
|
||||||
|
|
||||||
pub fn current() -> Option<PathBuf> {
|
pub fn current() -> Option<PathBuf> {
|
||||||
let d = DIR_PATH.lock().unwrap();
|
let d = DIR_PATH.lock().unwrap();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::io::{self, BufRead, BufReader, Write};
|
|
||||||
use std::fs::{self, File, OpenOptions};
|
use std::fs::{self, File, OpenOptions};
|
||||||
|
use std::io::{self, BufRead, BufReader, Write};
|
||||||
|
|
||||||
pub fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
|
pub fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
|
||||||
where P: AsRef<Path>, {
|
where P: AsRef<Path>, {
|
||||||
|
6
src/utils/time.rs
Normal file
6
src/utils/time.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
use chrono::{DateTime, TimeZone, Utc, ParseError};
|
||||||
|
|
||||||
|
pub fn parse_timestamp(timestamp: &str) -> Result<DateTime<Utc>, ParseError> {
|
||||||
|
let format = "%a, %d %b %Y %H:%M:%S %Z";
|
||||||
|
Utc.datetime_from_str(timestamp, format)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user