Compare commits
No commits in common. "4842a20024918abb9cc83b84a77469a5830c84c5" and "b16058b4d3a03f449f06bfeff2c9110615b15597" have entirely different histories.
4842a20024
...
b16058b4d3
72
Cargo.lock
generated
72
Cargo.lock
generated
@ -11,21 +11,6 @@ dependencies = [
|
||||
"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]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
@ -88,21 +73,6 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "clap"
|
||||
version = "2.34.0"
|
||||
@ -406,29 +376,6 @@ dependencies = [
|
||||
"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]]
|
||||
name = "idna"
|
||||
version = "0.3.0"
|
||||
@ -579,7 +526,6 @@ dependencies = [
|
||||
name = "nextsync"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"colored",
|
||||
"dotenv",
|
||||
@ -592,15 +538,6 @@ dependencies = [
|
||||
"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]]
|
||||
name = "num_cpus"
|
||||
version = "1.15.0"
|
||||
@ -1322,15 +1259,6 @@ version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
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]]
|
||||
name = "windows-sys"
|
||||
version = "0.42.0"
|
||||
|
@ -16,4 +16,3 @@ xml-rs = "0.8.0"
|
||||
regex = "1.8.3"
|
||||
lazy_static = "1.4.0"
|
||||
glob = "0.3.1"
|
||||
chrono = "0.4.26"
|
||||
|
@ -1,21 +0,0 @@
|
||||
# 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 crate::store;
|
||||
use crate::utils::{self};
|
||||
use crate::utils::nextsyncignore::{self, ignore_file};
|
||||
use crate::store;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::io::Write;
|
||||
|
||||
pub struct AddArgs<'a> {
|
||||
pub files: Values<'a>,
|
||||
|
@ -2,19 +2,19 @@ use std::fs::DirBuilder;
|
||||
use std::path::{Path, PathBuf};
|
||||
use clap::Values;
|
||||
use regex::Regex;
|
||||
use crate::utils::api::ApiProps;
|
||||
use crate::global::global::{DIR_PATH, set_dir_path};
|
||||
use crate::services::api::ApiError;
|
||||
use crate::services::req_props::{ReqProps, ObjProps};
|
||||
use crate::services::list_folders::ListFolders;
|
||||
use crate::services::download_files::DownloadFiles;
|
||||
use crate::store::object::{self, add_blob, add_tree};
|
||||
use crate::commands::init;
|
||||
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};
|
||||
|
||||
pub fn clone(remote: Values<'_>) {
|
||||
let d = DIR_PATH.lock().unwrap().clone();
|
||||
|
||||
let url = remote.clone().next().unwrap();
|
||||
let (host, tmp_user, dist_path_str) = get_url_props(url);
|
||||
let (domain, tmp_user, dist_path_str) = get_url_props(url);
|
||||
let username = match tmp_user {
|
||||
Some(u) => u,
|
||||
None => {
|
||||
@ -22,11 +22,6 @@ pub fn clone(remote: Values<'_>) {
|
||||
todo!();
|
||||
}
|
||||
};
|
||||
let api_props = ApiProps {
|
||||
host: host.clone(),
|
||||
username: username.to_string(),
|
||||
root: dist_path_str.to_string(),
|
||||
};
|
||||
|
||||
let ref_path = match d.clone() {
|
||||
Some(dir) => Path::new(&dir).to_owned(),
|
||||
@ -39,40 +34,43 @@ pub fn clone(remote: Values<'_>) {
|
||||
},
|
||||
};
|
||||
|
||||
let mut folders: Vec<ObjProps> = vec![ObjProps::new()];
|
||||
let mut files: Vec<ObjProps> = vec![];
|
||||
let mut folders = vec![String::from(dist_path_str)];
|
||||
let mut url_request;
|
||||
let mut files: Vec<String> = vec![];
|
||||
let mut first_iter = true;
|
||||
while folders.len() > 0 {
|
||||
let folder = folders.pop().unwrap();
|
||||
|
||||
let relative_s = match folder.relative_s {
|
||||
Some(relative_s) => relative_s,
|
||||
None => String::from(""),
|
||||
};
|
||||
url_request = String::from(domain.clone());
|
||||
if first_iter {
|
||||
url_request.push_str("/remote.php/dav/files/");
|
||||
url_request.push_str(username);
|
||||
}
|
||||
url_request.push_str(folder.as_str());
|
||||
|
||||
// request folder content
|
||||
let res = ReqProps::new()
|
||||
.set_request(relative_s.as_str(), &api_props)
|
||||
.gethref()
|
||||
.getlastmodified()
|
||||
.send_req_multiple();
|
||||
|
||||
let mut 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![]
|
||||
let mut objs = vec![];
|
||||
tokio::runtime::Runtime::new().unwrap().block_on(async {
|
||||
let res = ListFolders::new(url_request.as_str())
|
||||
.gethref()
|
||||
.send_with_res()
|
||||
.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!()
|
||||
}
|
||||
Err(ApiError::RequestError(err)) => {
|
||||
eprintln!("fatal: {}", err);
|
||||
std::process::exit(1);
|
||||
},
|
||||
Err(ApiError::Unexpected(_)) => todo!()
|
||||
};
|
||||
});
|
||||
|
||||
// create folder
|
||||
if first_iter {
|
||||
@ -81,20 +79,19 @@ pub fn clone(remote: Values<'_>) {
|
||||
// destination path 'path' already exists and is not an empty directory.
|
||||
//std::process::exit(1);
|
||||
} else {
|
||||
init::init();
|
||||
commands::init::init();
|
||||
}
|
||||
} else {
|
||||
// create folder
|
||||
let p = ref_path.clone().join(Path::new(&relative_s));
|
||||
if let Err(err) = DirBuilder::new().recursive(true).create(p.clone()) {
|
||||
eprintln!("err: cannot create directory {} ({})", p.display(), err);
|
||||
let local_folder = get_local_path(folder, ref_path.clone(), username, dist_path_str);
|
||||
if let Err(err) = DirBuilder::new().recursive(true).create(local_folder.clone()) {
|
||||
eprintln!("error: cannot create directory {}: {}", local_folder.display(), err);
|
||||
}
|
||||
|
||||
// add tree
|
||||
let path_folder = p.strip_prefix(ref_path.clone()).unwrap();
|
||||
let lastmodified = folder.lastmodified.unwrap().timestamp_millis();
|
||||
if let Err(err) = add_tree(&path_folder, &lastmodified.to_string()) {
|
||||
eprintln!("err: saving ref of {} ({})", path_folder.display(), err);
|
||||
let path_folder = local_folder.strip_prefix(ref_path.clone()).unwrap();
|
||||
if object::add_tree(&path_folder).is_err() {
|
||||
eprintln!("error: cannot store object {}", path_folder.display());
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,45 +100,48 @@ pub fn clone(remote: Values<'_>) {
|
||||
iter.next(); // jump first element which is the folder cloned
|
||||
for object in iter {
|
||||
if object.href.clone().unwrap().chars().last().unwrap() == '/' {
|
||||
folders.push(object.clone());
|
||||
folders.push(object.href.clone().unwrap().to_string());
|
||||
} else {
|
||||
files.push(object.clone());
|
||||
files.push(object.href.clone().unwrap().to_string());
|
||||
}
|
||||
}
|
||||
first_iter = false;
|
||||
}
|
||||
|
||||
download_files(ref_path.clone(), files, &api_props);
|
||||
download_files(ref_path.clone(), files);
|
||||
}
|
||||
|
||||
fn download_files(ref_p: PathBuf, files: Vec<ObjProps>, api_props: &ApiProps) {
|
||||
for obj in files {
|
||||
let relative_s = &obj.clone().relative_s.unwrap();
|
||||
let res = DownloadFiles::new()
|
||||
.set_url(&relative_s, api_props)
|
||||
.save(ref_p.clone());
|
||||
fn download_files(local_p: PathBuf, files: Vec<String>) {
|
||||
for remote_file in files {
|
||||
tokio::runtime::Runtime::new().unwrap().block_on(async {
|
||||
let res = DownloadFiles::new()
|
||||
.set_url_with_remote(remote_file.as_str())
|
||||
.save(local_p.clone()).await;
|
||||
|
||||
match res {
|
||||
Ok(()) => {
|
||||
let relative_p = Path::new(&relative_s);
|
||||
let lastmodified = obj.clone().lastmodified.unwrap().timestamp_millis();
|
||||
if let Err(err) = add_blob(relative_p, &lastmodified.to_string()) {
|
||||
eprintln!("err: saving ref of {} ({})", relative_s.clone(), err);
|
||||
match res {
|
||||
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)) => {
|
||||
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::io::{self, Write};
|
||||
use crate::utils::{path, read};
|
||||
|
||||
pub fn set(var: &str, val: &str) -> io::Result<()> {
|
||||
let mut root = match path::nextsync() {
|
||||
@ -40,6 +40,7 @@ pub fn get(var: &str) -> Option<String> {
|
||||
if let Ok(lines) = read::read_lines(root) {
|
||||
for line in lines {
|
||||
if let Ok(l) = line {
|
||||
dbg!(l.clone());
|
||||
if l.starts_with(var.clone()) {
|
||||
let (_, val) = l.split_once(" ").unwrap();
|
||||
return Some(val.to_owned());
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::env;
|
||||
use std::fs::{DirBuilder, File};
|
||||
use std::path::PathBuf;
|
||||
use std::env;
|
||||
use crate::global::global::DIR_PATH;
|
||||
|
||||
pub fn init() {
|
||||
|
@ -1,16 +1,11 @@
|
||||
use crate::commands::{status, config};
|
||||
use crate::services::req_props::ReqProps;
|
||||
use crate::services::api::ApiError;
|
||||
use crate::services::upload_file::UploadFile;
|
||||
use crate::services::delete_path::DeletePath;
|
||||
use crate::services::req_props::{ReqProps, ObjProps};
|
||||
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;
|
||||
use crate::store::object::{add_blob, rm_blob};
|
||||
use crate::store::index;
|
||||
|
||||
pub fn push() {
|
||||
dbg!(status::get_all_staged());
|
||||
@ -41,3 +36,205 @@ pub fn push() {
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
@ -1,70 +0,0 @@
|
||||
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());
|
||||
}
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
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());
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
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::path::PathBuf;
|
||||
use std::io::{self, Lines, BufReader};
|
||||
use std::collections::{HashSet, HashMap};
|
||||
use crypto::digest::Digest;
|
||||
use crypto::sha1::Sha1;
|
||||
use std::collections::{HashSet, HashMap};
|
||||
use colored::Colorize;
|
||||
use std::path::PathBuf;
|
||||
use std::io::{self, Lines, BufReader};
|
||||
use crate::utils;
|
||||
use crate::store::{self, object};
|
||||
|
||||
@ -58,9 +58,10 @@ pub fn get_all_staged() -> Vec<Obj> {
|
||||
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
|
||||
let renamed_objs = vec![];
|
||||
|
||||
renamed_objs
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
use clap::{App, Arg, SubCommand};
|
||||
use crate::commands::add::AddArgs;
|
||||
|
||||
mod commands;
|
||||
mod utils;
|
||||
mod services;
|
||||
|
@ -1,4 +1,5 @@
|
||||
pub mod api;
|
||||
pub mod list_folders;
|
||||
pub mod download_files;
|
||||
pub mod req_props;
|
||||
pub mod upload_file;
|
||||
|
@ -1,9 +1,8 @@
|
||||
use std::env;
|
||||
use dotenv::dotenv;
|
||||
use reqwest::Client;
|
||||
use reqwest::RequestBuilder;
|
||||
use reqwest::{Response, Error, IntoUrl, Method};
|
||||
use crate::utils::api::ApiProps;
|
||||
use std::env;
|
||||
use dotenv::dotenv;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ApiError {
|
||||
@ -26,7 +25,7 @@ impl ApiBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_request<U: IntoUrl>(&mut self, method: Method, url: U) -> &mut ApiBuilder {
|
||||
pub fn set_request<U: IntoUrl>(mut self, method: Method, url: U) -> ApiBuilder {
|
||||
self.request = Some(self.client.request(method, url));
|
||||
self
|
||||
}
|
||||
@ -49,14 +48,13 @@ impl ApiBuilder {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_req(&mut self, meth: Method, p: &str, api_props: &ApiProps) -> &mut ApiBuilder {
|
||||
let mut url = String::from(&api_props.host);
|
||||
url.push_str("/remote.php/dav/files/");
|
||||
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(&api_props.username);
|
||||
url.push_str(&api_props.root);
|
||||
url.push_str("/");
|
||||
url.push_str(p);
|
||||
url.push_str(path);
|
||||
dbg!(url.clone());
|
||||
self.request = Some(self.client.request(meth, url));
|
||||
self
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use reqwest::{Method, IntoUrl, Response, Error};
|
||||
use crate::services::api::{ApiBuilder, ApiError};
|
||||
use reqwest::{Method, IntoUrl, Response, Error};
|
||||
|
||||
pub struct CreateFolder {
|
||||
api_builder: ApiBuilder,
|
||||
|
@ -1,5 +1,5 @@
|
||||
use reqwest::{Method, Response, Error};
|
||||
use crate::services::api::{ApiBuilder, ApiError};
|
||||
use reqwest::{Method, Response, Error};
|
||||
|
||||
pub struct DeletePath {
|
||||
api_builder: ApiBuilder,
|
||||
@ -21,15 +21,10 @@ impl DeletePath {
|
||||
self.api_builder.send().await
|
||||
}
|
||||
|
||||
pub fn send_with_err(&mut self) -> Result<String, ApiError> {
|
||||
let res = tokio::runtime::Runtime::new().unwrap().block_on(async {
|
||||
self.send().await
|
||||
}).map_err(ApiError::RequestError)?;
|
||||
|
||||
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 = tokio::runtime::Runtime::new().unwrap().block_on(async {
|
||||
res.text().await
|
||||
}).map_err(ApiError::EmptyError)?;
|
||||
let body = res.text().await.map_err(ApiError::EmptyError)?;
|
||||
Ok(body)
|
||||
} else {
|
||||
Err(ApiError::IncorrectRequest(res))
|
||||
|
@ -1,26 +1,26 @@
|
||||
use crate::services::api::{ApiBuilder, ApiError};
|
||||
use std::path::PathBuf;
|
||||
use reqwest::{Method, Response, Error};
|
||||
use crate::utils::api::get_local_path_t;
|
||||
use std::fs::OpenOptions;
|
||||
use std::io::{self, Write};
|
||||
use reqwest::{Method, Response, Error};
|
||||
use crate::utils::api::ApiProps;
|
||||
use crate::services::api::{ApiBuilder, ApiError};
|
||||
|
||||
pub struct DownloadFiles {
|
||||
api_builder: ApiBuilder,
|
||||
relative_ps: String,
|
||||
path: String,
|
||||
}
|
||||
|
||||
impl DownloadFiles {
|
||||
pub fn new() -> Self {
|
||||
DownloadFiles {
|
||||
api_builder: ApiBuilder::new(),
|
||||
relative_ps: String::from(""),
|
||||
path: String::from(""),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_url(&mut self, relative_ps: &str, api_props: &ApiProps) -> &mut DownloadFiles {
|
||||
self.relative_ps = relative_ps.to_string();
|
||||
self.api_builder.set_req(Method::from_bytes(b"PROPFIND").unwrap(), relative_ps, api_props);
|
||||
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
|
||||
}
|
||||
|
||||
@ -38,20 +38,18 @@ impl DownloadFiles {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn save(&mut self, ref_p: PathBuf) -> Result<(), ApiError> {
|
||||
tokio::runtime::Runtime::new().unwrap().block_on(async {
|
||||
let p = ref_p.join(PathBuf::from(self.relative_ps.clone()));
|
||||
let res = self.send().await.map_err(ApiError::RequestError)?;
|
||||
if res.status().is_success() {
|
||||
let body = res.bytes().await.map_err(ApiError::EmptyError)?;
|
||||
match DownloadFiles::write_file(p, &body.to_vec()) {
|
||||
Err(_) => Err(ApiError::Unexpected(String::from(""))),
|
||||
Ok(_) => Ok(()),
|
||||
}
|
||||
} else {
|
||||
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<()> {
|
||||
|
114
src/services/list_folders.rs
Normal file
114
src/services/list_folders.rs
Normal file
@ -0,0 +1,114 @@
|
||||
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,52 +1,20 @@
|
||||
use std::io::Cursor;
|
||||
use chrono::{Utc, DateTime};
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
use xml::reader::{EventReader, XmlEvent};
|
||||
use std::io::Cursor;
|
||||
use reqwest::{Method, Response, Error};
|
||||
|
||||
pub struct ReqProps {
|
||||
api_builder: ApiBuilder,
|
||||
xml_balises: Vec<String>,
|
||||
xml_list: Vec<String>,
|
||||
xml_payload: String,
|
||||
api_props: Option<ApiProps>
|
||||
}
|
||||
|
||||
impl ReqProps {
|
||||
pub fn new() -> Self {
|
||||
ReqProps {
|
||||
api_builder: ApiBuilder::new(),
|
||||
xml_balises: vec![],
|
||||
xml_list: vec![],
|
||||
xml_payload: String::new(),
|
||||
api_props: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,49 +23,38 @@ impl ReqProps {
|
||||
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 {
|
||||
self.xml_balises.push(String::from("getlastmodified"));
|
||||
self.xml_list.push(String::from("getlastmodified"));
|
||||
self.xml_payload.push_str(r#"<d:getlastmodified/>"#);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn getcontentlenght(&mut self) -> &mut ReqProps {
|
||||
self.xml_balises.push(String::from("getcontentlength"));
|
||||
self.xml_list.push(String::from("getcontentlength"));
|
||||
self.xml_payload.push_str(r#"<d:getcontentlength/>"#);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn _getcontenttype(&mut self) -> &mut ReqProps {
|
||||
self.xml_balises.push(String::from("getcontenttype"));
|
||||
self.xml_list.push(String::from("getcontenttype"));
|
||||
self.xml_payload.push_str(r#"<d:getcontenttype/>"#);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn _getpermissions(&mut self) -> &mut ReqProps {
|
||||
self.xml_balises.push(String::from("permissions"));
|
||||
self.xml_list.push(String::from("permissions"));
|
||||
self.xml_payload.push_str(r#"<oc:permissions/>"#);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn _getressourcetype(&mut self) -> &mut ReqProps {
|
||||
self.xml_balises.push(String::from("resourcetype"));
|
||||
self.xml_list.push(String::from("resourcetype"));
|
||||
self.xml_payload.push_str(r#"<d:resourcetype/>"#);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn _getetag(&mut self) -> &mut ReqProps {
|
||||
self.xml_balises.push(String::from("getetag"));
|
||||
self.xml_list.push(String::from("getetag"));
|
||||
self.xml_payload.push_str(r#"<d:getetag/>"#);
|
||||
self
|
||||
}
|
||||
@ -115,49 +72,24 @@ impl ReqProps {
|
||||
self.api_builder.send().await
|
||||
}
|
||||
|
||||
pub fn send_with_err(&mut self) -> Result<String, ApiError> {
|
||||
let res = tokio::runtime::Runtime::new().unwrap().block_on(async {
|
||||
self.send().await
|
||||
}).map_err(ApiError::RequestError)?;
|
||||
|
||||
pub async fn send_with_err(&mut self) -> Result<Vec<String>, ApiError> {
|
||||
let res = self.send().await.map_err(ApiError::RequestError)?;
|
||||
if res.status().is_success() {
|
||||
let body = tokio::runtime::Runtime::new().unwrap().block_on(async {
|
||||
res.text().await
|
||||
}).map_err(ApiError::EmptyError)?;
|
||||
Ok(body)
|
||||
let body = res.text().await.map_err(ApiError::EmptyError)?;
|
||||
Ok(self.parse(body))
|
||||
} else {
|
||||
Err(ApiError::IncorrectRequest(res))
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
pub fn parse(&self, xml: String) -> Vec<String> {
|
||||
let cursor = Cursor::new(xml);
|
||||
let parser = EventReader::new(cursor);
|
||||
|
||||
let mut should_get = false;
|
||||
let mut values: Vec<ObjProps> = vec![];
|
||||
|
||||
let mut iter = self.xml_balises.iter();
|
||||
let mut values: Vec<String> = vec![];
|
||||
let mut iter = self.xml_list.iter();
|
||||
let mut val = iter.next();
|
||||
let mut content = ObjProps::new();
|
||||
|
||||
for event in parser {
|
||||
match event {
|
||||
@ -165,33 +97,12 @@ impl ReqProps {
|
||||
if let Some(v) = val.clone() {
|
||||
should_get = &name.local_name == v;
|
||||
} else {
|
||||
// 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;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(XmlEvent::Characters(text)) => {
|
||||
if !text.trim().is_empty() && should_get {
|
||||
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());
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
values.push(text);
|
||||
val = iter.next()
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use std::fs::File;
|
||||
use std::io::{Read};
|
||||
use std::path::PathBuf;
|
||||
use reqwest::{Method, Response, Error};
|
||||
use crate::services::api::{ApiBuilder, ApiError};
|
||||
use std::path::PathBuf;
|
||||
use std::io::{Read};
|
||||
use reqwest::{Method, Response, Error};
|
||||
|
||||
pub struct UploadFile {
|
||||
api_builder: ApiBuilder,
|
||||
@ -34,15 +34,10 @@ impl UploadFile {
|
||||
self.api_builder.send().await
|
||||
}
|
||||
|
||||
pub fn send_with_err(&mut self) -> Result<String, ApiError> {
|
||||
let res = tokio::runtime::Runtime::new().unwrap().block_on(async {
|
||||
self.send().await
|
||||
}).map_err(ApiError::RequestError)?;
|
||||
|
||||
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 = tokio::runtime::Runtime::new().unwrap().block_on(async {
|
||||
res.text().await
|
||||
}).map_err(ApiError::EmptyError)?;
|
||||
let body = res.text().await.map_err(ApiError::EmptyError)?;
|
||||
Ok(body)
|
||||
} else {
|
||||
Err(ApiError::IncorrectRequest(res))
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::path::PathBuf;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{self, Write};
|
||||
use std::path::PathBuf;
|
||||
use crate::utils::{read, path};
|
||||
use std::io::{self, Write};
|
||||
|
||||
pub fn _read_only(mut path: PathBuf) -> File {
|
||||
path.push("HEAD");
|
||||
|
@ -1,8 +1,8 @@
|
||||
use std::io;
|
||||
use std::fs::File;
|
||||
use std::fs::OpenOptions;
|
||||
use std::fs::File;
|
||||
use std::path::PathBuf;
|
||||
use crate::utils::{read, path};
|
||||
use std::io;
|
||||
|
||||
pub fn _read_only(mut path: PathBuf) -> File {
|
||||
path.push("index");
|
||||
|
@ -1,11 +1,11 @@
|
||||
use std::fs::File;
|
||||
use std::io::{self, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::fs::{OpenOptions, self};
|
||||
use crypto::sha1::Sha1;
|
||||
use crypto::digest::Digest;
|
||||
use crate::utils::{read, path};
|
||||
use crate::store::head;
|
||||
use crypto::sha1::Sha1;
|
||||
use crypto::digest::Digest;
|
||||
use std::fs::{OpenOptions, self};
|
||||
use std::io::{self, Write};
|
||||
use std::fs::File;
|
||||
|
||||
/// 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))
|
||||
}
|
||||
|
||||
pub fn add_tree(path: &Path, date: &str) -> io::Result<()> {
|
||||
pub fn add_tree(path: &Path) -> io::Result<()> {
|
||||
let (line, hash, name) = parse_path(path.clone(), false);
|
||||
|
||||
// add tree reference to parent
|
||||
@ -51,10 +51,7 @@ pub fn add_tree(path: &Path, date: &str) -> io::Result<()> {
|
||||
}
|
||||
|
||||
// create tree object
|
||||
let mut content = name;
|
||||
content.push_str(" ");
|
||||
content.push_str(date);
|
||||
create_object(hash, &content)?;
|
||||
create_object(hash, &name)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -96,6 +93,8 @@ pub fn add_blob(path: &Path, date: &str) -> io::Result<()> {
|
||||
|
||||
let mut content = name.clone().to_owned();
|
||||
content.push_str(" ");
|
||||
content.push_str("tmp_hash");
|
||||
content.push_str(" ");
|
||||
content.push_str(date);
|
||||
|
||||
// create blob object
|
||||
@ -133,6 +132,7 @@ pub fn read_tree(tree: String) -> Option<(String, io::Lines<io::BufReader<File>>
|
||||
let (dir, res) = hash_obj(&tree);
|
||||
obj_p.push(dir);
|
||||
obj_p.push(res);
|
||||
|
||||
|
||||
match read::read_lines(obj_p) {
|
||||
Ok(mut reader) => {
|
||||
@ -147,6 +147,7 @@ pub fn read_tree(tree: String) -> Option<(String, io::Lines<io::BufReader<File>>
|
||||
None
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fn rm_node(path: &Path, node: &str) -> io::Result<()> {
|
||||
|
@ -2,4 +2,3 @@ pub mod path;
|
||||
pub mod read;
|
||||
pub mod nextsyncignore;
|
||||
pub mod api;
|
||||
pub mod time;
|
@ -1,25 +1,23 @@
|
||||
#[derive(Debug)]
|
||||
pub struct ApiProps {
|
||||
pub host: String, // nextcloud.example.com
|
||||
pub username: String,
|
||||
pub root: String, // /dir/cloned
|
||||
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())
|
||||
}
|
||||
|
||||
impl Clone for ApiProps {
|
||||
fn clone(&self) -> Self {
|
||||
ApiProps {
|
||||
host: self.host.to_string(),
|
||||
username: self.username.to_string(),
|
||||
root: self.root.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_relative_s(p: String, api_props: &ApiProps) -> String {
|
||||
let mut final_p = p.clone();
|
||||
final_p = final_p.strip_prefix("/remote.php/dav/files/").unwrap().to_string();
|
||||
final_p = final_p.strip_prefix(&api_props.username).unwrap().to_string();
|
||||
final_p = final_p.strip_prefix(&api_props.root).unwrap().to_string();
|
||||
final_p = final_p.strip_prefix("/").unwrap().to_string();
|
||||
final_p
|
||||
pub fn get_local_path_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()
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::utils::path;
|
||||
use regex::Regex;
|
||||
use std::fs::File;
|
||||
use std::io::{BufReader, BufRead};
|
||||
use regex::Regex;
|
||||
use crate::utils::path;
|
||||
|
||||
pub fn read_lines() -> Result<Vec<String>, ()> {
|
||||
if let Some(path) = path::nextsyncignore() {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use std::env;
|
||||
use std::fs::canonicalize;
|
||||
use std::path::{PathBuf, Path};
|
||||
use crate::global::global::DIR_PATH;
|
||||
use std::fs::canonicalize;
|
||||
|
||||
pub fn current() -> Option<PathBuf> {
|
||||
let d = DIR_PATH.lock().unwrap();
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::fs::{self, File, OpenOptions};
|
||||
use std::io::{self, BufRead, BufReader, Write};
|
||||
use std::fs::{self, File, OpenOptions};
|
||||
|
||||
pub fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
|
||||
where P: AsRef<Path>, {
|
||||
|
@ -1,6 +0,0 @@
|
||||
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