Compare commits

...

6 Commits

Author SHA1 Message Date
grimhilt
b08e6d3898 set depth to 0 when looking for single result in req_props 2023-06-30 00:21:14 +02:00
grimhilt
723ceb2655 push deleted dir 2023-06-29 23:52:48 +02:00
grimhilt
2a0fe6d1d1 minor changes 2023-06-29 23:52:40 +02:00
grimhilt
45f8d486d8 remove objects 2023-06-29 23:52:19 +02:00
grimhilt
f812ad411e improve staging to take files in new folders 2023-06-29 23:51:13 +02:00
grimhilt
601f176198 improve getting staged in status 2023-06-29 22:55:19 +02:00
9 changed files with 211 additions and 66 deletions

View File

@ -17,3 +17,6 @@ regex = "1.8.3"
lazy_static = "1.4.0"
glob = "0.3.1"
chrono = "0.4.26"
[profile.release]
debug = true

View File

@ -5,11 +5,10 @@ use crate::commands::push::push_factory::{PushFactory, PushState};
pub mod push_factory;
pub mod new;
pub mod new_dir;
pub mod rm_dir;
pub mod deleted;
pub fn push() {
dbg!(status::get_all_staged());
let remote = match config::get("remote") {
Some(r) => r,
None => {
@ -22,7 +21,7 @@ pub fn push() {
let staged_objs = status::get_all_staged();
// path that certify that all its children can be push whithout hesistation
// (e.g if remote dir has no changes since last sync all children
// (e.g. if remote dir has no changes since last sync all children
// can be pushed without verification)
let mut whitelist: Option<PathBuf> = None;

View File

@ -5,6 +5,7 @@ use crate::store::object;
use crate::services::req_props::{ObjProps, ReqProps};
use crate::commands::push::new::New;
use crate::commands::push::new_dir::NewDir;
use crate::commands::push::rm_dir::RmDir;
use crate::commands::push::deleted::Deleted;
#[derive(Debug)]
@ -103,7 +104,7 @@ impl PushFactory {
State::New => Box::new(NewDir { obj }),
State::Renamed => todo!(),
State::Modified => todo!(),
State::Deleted => todo!(),
State::Deleted => Box::new(RmDir { obj }),
State::Default => todo!(),
}
}

View File

@ -0,0 +1,55 @@
use std::path::PathBuf;
use crate::services::api::ApiError;
use crate::services::delete_path::DeletePath;
use crate::store::index;
use crate::store::object::tree;
use crate::commands::status::LocalObj;
use crate::commands::push::push_factory::{PushState, PushChange, PushFlowState};
pub struct RmDir {
pub obj: LocalObj
}
impl PushChange for RmDir {
fn can_push(&self, whitelist: &mut Option<PathBuf>) -> PushState {
match self.flow(&self.obj, whitelist.clone()) {
PushFlowState::Whitelisted => PushState::Done,
PushFlowState::NotOnRemote => {
*whitelist = Some(self.obj.path.clone());
PushState::Done
},
PushFlowState::RemoteIsNewer => PushState::Conflict,
PushFlowState::LocalIsNewer => {
*whitelist = Some(self.obj.path.clone());
PushState::Valid
},
PushFlowState::Error => 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 dir {}: {}", obj.name, err.status());
std::process::exit(1);
},
Err(ApiError::RequestError(_)) => {
eprintln!("fatal: request error deleting dir {}", obj.name);
std::process::exit(1);
}
_ => (),
}
// update tree
tree::rm(&obj.path.clone());
// remove index
index::rm_line(obj.path.to_str().unwrap());
}
fn conflict(&self) {}
}

View File

@ -29,15 +29,21 @@ pub enum State {
// todo: relative path, filename, get modified
// todo: not catch added empty folder
pub fn status() {
let (mut new_objs, mut del_objs) = get_diff();
let mut renamed_objs = get_renamed(&mut new_objs, &mut del_objs);
let (mut new_objs_hashes, mut del_objs_hashes) = get_diff();
// get copy, modified
let mut objs = new_objs;
objs.append(&mut del_objs);
objs.append(&mut renamed_objs);
let staged_objs = get_staged(&mut objs);
let mut staged_objs = get_staged(&mut new_objs_hashes, &mut del_objs_hashes);
let mut objs: Vec<LocalObj> = del_objs_hashes.iter().map(|x| {
x.1.clone()
}).collect();
for (_, elt) in new_objs_hashes {
objs.push(elt.clone());
}
dbg!(objs.clone());
dbg!(staged_objs.clone());
print_status(staged_objs, objs);
dbg!(get_all_staged());
}
#[derive(Debug, Clone)]
@ -49,53 +55,63 @@ pub struct LocalObj {
}
pub fn get_all_staged() -> Vec<LocalObj> {
let (mut new_objs_hashes, mut del_objs_hashes) = get_diff();
// get copy, modified
let mut staged_objs = get_staged(&mut new_objs_hashes, &mut del_objs_hashes);
staged_objs.clone()
// todo opti getting staged and then finding differences ?
// todo opti return folder
let (mut new_objs, mut del_objs) = get_diff();
let mut renamed_objs = get_renamed(&mut new_objs, &mut del_objs);
// todo get copy, modified
let mut objs = new_objs;
objs.append(&mut del_objs);
objs.append(&mut renamed_objs);
let staged_objs = get_staged(&mut objs);
staged_objs
}
fn get_renamed(_new_obj: &mut Vec<LocalObj>, _del_obj: &mut Vec<LocalObj>) -> Vec<LocalObj> {
// get hash of all new obj, compare to hash of all del
let renamed_objs = vec![];
renamed_objs
}
fn get_staged(objs: &mut Vec<LocalObj>) -> Vec<LocalObj> {
let mut indexes = HashSet::new();
let mut staged_objs: Vec<LocalObj> = vec![];
fn get_staged(new_objs_h: &mut HashMap<String, LocalObj>, del_objs_h: &mut HashMap<String, LocalObj>) -> Vec<LocalObj> {
let mut lines: Vec<String> = vec![];
if let Ok(entries) = index::read_line() {
for entry in entries {
indexes.insert(entry.unwrap());
lines.push(entry.unwrap());
}
}
dbg!(objs.clone());
let mut tree_to_analyse: Vec<LocalObj> = vec![];
objs.retain(|obj| {
if indexes.contains(obj.clone().path.to_str().unwrap()) {
if obj.clone().otype == String::from("tree") {
tree_to_analyse.push(obj.clone());
}
staged_objs.push(obj.clone());
false
let mut hasher = Sha1::new();
let mut staged_objs: Vec<LocalObj> = vec![];
let ref_p = path::repo_root();
for obj in lines {
// hash the object
hasher.input_str(&obj);
let hash = hasher.result_str();
hasher.reset();
// find it on the list of hashes
if new_objs_h.contains_key(&hash) {
staged_objs.push(new_objs_h.get(&hash).unwrap().clone());
new_objs_h.remove(&hash);
} else if del_objs_h.contains_key(&hash) {
staged_objs.push(del_objs_h.get(&hash).unwrap().clone());
del_objs_h.remove(&hash);
}else {
true
let mut t_path = ref_p.clone();
t_path.push(PathBuf::from(obj.clone()));
staged_objs.push(LocalObj {
otype: get_otype(t_path.clone()),
name: obj.to_string(),
path: t_path.clone(),
state: {
if t_path.exists() {
State::New
} else {
State::Deleted
}
},
});
}
}
staged_objs
}
fn get_diff() -> (Vec<LocalObj>, Vec<LocalObj>) {
fn get_diff() -> (HashMap<String, LocalObj>, HashMap<String, LocalObj>) {
let mut hashes = HashMap::new();
let mut objs: Vec<String> = vec![];
@ -138,29 +154,31 @@ fn get_diff() -> (Vec<LocalObj>, Vec<LocalObj>) {
}
let del_objs: Vec<LocalObj> = hashes.iter().map(|x| {
LocalObj {
otype: x.1.otype.clone(),
name: x.1.name.clone(),
path: x.1.path.clone(),
state: State::Deleted
for (_, elt) in &mut hashes {
elt.state = State::Deleted;
}
}).collect();
let new_objs: Vec<LocalObj> = objs.iter().map(|x| {
let p = PathBuf::from(x.to_string());
let mut new_objs_hashes = HashMap::new();
let mut hasher = Sha1::new();
for obj in objs {
// hash the object
hasher.input_str(&obj);
let hash = hasher.result_str();
hasher.reset();
let p = PathBuf::from(obj.to_string());
// todo name
LocalObj {
otype: get_type(p.clone()),
name: x.to_string(),
new_objs_hashes.insert(String::from(hash), LocalObj {
otype: get_otype(p.clone()),
name: obj.to_string(),
path: p,
state: State::New
}
}).collect();
(new_objs, del_objs)
});
}
fn get_type(p: PathBuf) -> String {
(new_objs_hashes, hashes)
}
fn get_otype(p: PathBuf) -> String {
if p.is_dir() {
String::from("tree")
} else {

View File

@ -3,6 +3,7 @@ use dotenv::dotenv;
use reqwest::Client;
use reqwest::RequestBuilder;
use reqwest::{Response, Error, Method};
use reqwest::header::{HeaderValue, CONTENT_TYPE, HeaderMap, IntoHeaderName};
use crate::utils::api::ApiProps;
use crate::commands::config;
use crate::commands::clone::get_url_props;
@ -18,6 +19,7 @@ pub enum ApiError {
pub struct ApiBuilder {
client: Client,
request: Option<RequestBuilder>,
headers: Option<HeaderMap>
}
impl ApiBuilder {
@ -25,6 +27,7 @@ impl ApiBuilder {
ApiBuilder {
client: Client::new(),
request: None,
headers: None,
}
}
@ -40,7 +43,6 @@ impl ApiBuilder {
let mut url = String::from(host);
url.push_str("/remote.php/dav/files/");
url.push_str(username.unwrap());
url.push_str("/");
url.push_str(&root);
url.push_str("/");
url.push_str(path);
@ -85,11 +87,18 @@ impl ApiBuilder {
},
Some(req) => {
self.request = Some(req.body(xml_payload));
self.set_header(CONTENT_TYPE, HeaderValue::from_static("application/xml"));
}
}
self
}
pub fn set_header<K: IntoHeaderName>(&mut self, key: K, val: HeaderValue) -> &mut ApiBuilder {
let map = self.headers.get_or_insert(HeaderMap::new());
map.insert(key, val);
self
}
pub fn set_body(&mut self, body: Vec<u8>) -> &mut ApiBuilder {
match self.request.take() {
None => {
@ -111,7 +120,13 @@ impl ApiBuilder {
eprintln!("fatal: incorrect request");
std::process::exit(1);
},
Some(req) => req.send().await.map_err(Error::from),
Some(req) => {
if let Some(headers) = &self.headers {
req.headers(headers.clone()).send().await.map_err(Error::from)
} else {
req.send().await.map_err(Error::from)
}
},
}
}
}

View File

@ -2,6 +2,7 @@ use std::io::Cursor;
use chrono::{Utc, DateTime};
use reqwest::{Method, Response, Error};
use xml::reader::{EventReader, XmlEvent};
use reqwest::header::HeaderValue;
use crate::utils::time::parse_timestamp;
use crate::utils::api::{get_relative_s, ApiProps};
use crate::services::api::{ApiBuilder, ApiError};
@ -102,6 +103,11 @@ impl ReqProps {
self
}
pub fn set_depth(&mut self, depth: &str) -> &mut ReqProps {
self.api_builder.set_header("Depth", HeaderValue::from_str(depth).unwrap());
self
}
fn validate_xml(&mut self) -> &mut ReqProps {
let mut xml = String::from(r#"<?xml version="1.0" encoding="UTF-8"?><d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns" xmlns:nc="http://nextcloud.org/ns"><d:prop>"#);
xml.push_str(&self.xml_payload.clone());
@ -138,6 +144,8 @@ impl ReqProps {
}
pub fn send_req_single(&mut self) -> Result<ObjProps, ApiError> {
// set depth to 0 as we only need one element
self.set_depth("0");
match self.send_with_err() {
Ok(body) => {
let objs = self.parse(body, false);
@ -167,8 +175,8 @@ impl ReqProps {
} else {
// end of balises to get then start over for
// next object if want multiple
if multiple {
values.push(content.clone());
if multiple {
iter = self.xml_balises.iter();
val = iter.next();
content = ObjProps::new();

View File

@ -45,6 +45,15 @@ fn _object_path(obj: &str) -> PathBuf {
root
}
fn rm(hash: &str) -> io::Result<()> {
let mut root = path::objects();
let (dir, rest) = hash.split_at(2);
root.push(dir);
root.push(rest);
fs::remove_file(root)?;
Ok(())
}
fn rm_node(path: &Path, node: &str) -> io::Result<()> {
let mut root = path::objects();
let (dir, rest) = hash_obj(path.clone().to_str().unwrap());

View File

@ -3,7 +3,7 @@ use std::io::{self};
use std::path::Path;
use crate::utils::{read, path};
use crate::store::head;
use crate::store::object::{parse_path, hash_obj, add_node, create_obj};
use crate::store::object::{self, parse_path, hash_obj, add_node, create_obj};
pub fn add(path: &Path, date: &str) -> io::Result<()> {
let (line, hash, name) = parse_path(path.clone(), false);
@ -24,6 +24,43 @@ pub fn add(path: &Path, date: &str) -> io::Result<()> {
Ok(())
}
pub fn rm(path: &Path) -> io::Result<()> {
let (_, lines) = read(path.to_path_buf().to_str().unwrap().to_string()).unwrap();
for line in lines {
let (ftype, hash, _) = parse_line(line.unwrap());
if ftype == String::from("blob") {
object::rm(&hash);
} else {
rm_hash(hash);
}
}
Ok(())
}
fn rm_hash(hash: String) {
let mut obj_p = path::objects();
let (dir, res) = hash.split_at(2);
obj_p.push(dir);
obj_p.push(res);
match read::read_lines(obj_p) {
Ok(mut reader) => {
reader.next();
for line in reader {
let (ftype, hash, _) = parse_line(line.unwrap());
if ftype == String::from("blob") {
object::rm(&hash);
} else {
rm_hash(hash);
}
}
},
Err(err) => {
eprintln!("error reading tree: {}", err);
},
}
}
pub fn read(tree: String) -> Option<(String, io::Lines<io::BufReader<File>>)> {
let mut obj_p = path::objects();