Compare commits

..

6 Commits

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

2
README.md Normal file
View File

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

View File

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

View File

@ -1,16 +1,13 @@
use std::fs::OpenOptions;
use std::fs::DirBuilder;
use std::io::prelude::*;
use std::io::{self, Cursor};
use std::path::{Path, PathBuf};
use clap::Values;
use regex::Regex;
use xml::reader::{EventReader, XmlEvent};
use crate::services::api::ApiError;
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};
pub fn clone(remote: Values<'_>) {
@ -23,11 +20,10 @@ pub fn clone(remote: Values<'_>) {
None => {
eprintln!("No username found");
todo!();
""
}
};
let local_path = match d.clone() {
let ref_path = match d.clone() {
Some(dir) => Path::new(&dir).to_owned(),
None => {
let iter = Path::new(dist_path_str).iter();
@ -52,16 +48,33 @@ pub fn clone(remote: Values<'_>) {
url_request.push_str(folder.as_str());
// request folder content
let mut body = Default::default();
let mut objs = vec![];
tokio::runtime::Runtime::new().unwrap().block_on(async {
body = ListFolders::new(url_request.as_str())
let res = ListFolders::new(url_request.as_str())
.gethref()
.send_with_res()
.await;
objs = match res {
Ok(o) => o,
Err(ApiError::IncorrectRequest(err)) => {
eprintln!("fatal: {}", err.status());
std::process::exit(1);
},
Err(ApiError::EmptyError(_)) => {
eprintln!("Failed to get body");
vec![]
}
Err(ApiError::RequestError(err)) => {
eprintln!("fatal: {}", err);
std::process::exit(1);
},
Err(ApiError::Unexpected(_)) => todo!()
}
});
// create folder
if first_iter {
if DirBuilder::new().create(local_path.clone()).is_err() {
if DirBuilder::new().create(ref_path.clone()).is_err() {
eprintln!("fatal: directory already exist");
// destination path 'path' already exists and is not an empty directory.
//std::process::exit(1);
@ -70,70 +83,54 @@ pub fn clone(remote: Values<'_>) {
}
} else {
// create folder
let local_folder = get_local_path(folder, local_path.clone(), username, dist_path_str);
let local_folder = get_local_path(folder, ref_path.clone(), username, dist_path_str);
if let Err(err) = DirBuilder::new().recursive(true).create(local_folder.clone()) {
eprintln!("error: cannot create directory {}: {}", local_folder.display(), err);
}
// add tree
let path_folder = local_folder.strip_prefix(local_path.clone()).unwrap();
let path_folder = local_folder.strip_prefix(ref_path.clone()).unwrap();
if object::add_tree(&path_folder).is_err() {
eprintln!("error: cannot store object {}", path_folder.display());
}
}
// find folders and files in response
let objects = get_objects_xml(body);
let mut iter = objects.iter();
iter.next(); // jump first element which the folder fetched
let mut iter = objs.iter();
iter.next(); // jump first element which is the folder cloned
for object in iter {
if object.chars().last().unwrap() == '/' {
folders.push(object.to_string());
if object.href.clone().unwrap().chars().last().unwrap() == '/' {
folders.push(object.href.clone().unwrap().to_string());
} else {
files.push(object.to_string());
files.push(object.href.clone().unwrap().to_string());
}
}
first_iter = false;
}
download_files(&domain, local_path.clone(), username, dist_path_str, files);
download_files(ref_path.clone(), files);
}
fn get_local_path(p: String, local_p: PathBuf, username: &str, dist_p: &str) -> PathBuf {
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())
}
fn write_file(path: PathBuf, content: &Vec<u8>, local_p: PathBuf) -> io::Result<()> {
let mut f = OpenOptions::new()
.write(true)
.create(true)
.open(path.clone())?;
f.write_all(&content)?;
let relative_p = Path::new(&path).strip_prefix(local_p).unwrap();
object::add_blob(relative_p, "tmpdate")?;
Ok(())
}
fn download_files(domain: &str, local_p: PathBuf, username: &str, dist_p: &str, files: Vec<String>) {
for file in files {
let mut url_request = String::from(domain.clone());
url_request.push_str(file.as_str());
fn download_files(local_p: PathBuf, files: Vec<String>) {
for remote_file in files {
tokio::runtime::Runtime::new().unwrap().block_on(async {
match DownloadFiles::new(url_request.as_str()).send_with_err().await {
Ok(b) => {
let p_to_save = get_local_path(file.clone(), local_p.clone(), username, dist_p);
let res = DownloadFiles::new()
.set_url_with_remote(remote_file.as_str())
.save(local_p.clone()).await;
if let Err(_) = write_file(p_to_save, &b, local_p.clone()) {
eprintln!("error writing {}", file);
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);
@ -148,37 +145,6 @@ fn download_files(domain: &str, local_p: PathBuf, username: &str, dist_p: &str,
}
}
fn get_objects_xml(xml: String) -> Vec<String> {
let cursor = Cursor::new(xml);
let parser = EventReader::new(cursor);
let mut should_get = false;
let mut objects: Vec<String> = vec![];
for event in parser {
match event {
Ok(XmlEvent::StartElement { name, .. }) => {
should_get = name.local_name == "href";
}
Ok(XmlEvent::Characters(text)) => {
if !text.trim().is_empty() && should_get {
objects.push(text);
}
}
Ok(XmlEvent::EndElement { .. }) => {
should_get = false;
}
Err(e) => {
eprintln!("Error: {}", e);
break;
}
_ => {}
}
}
objects
}
// todo allow http
fn get_url_props(url: &str) -> (String, Option<&str>, &str) {
let mut username = None;
let mut domain = "";
@ -193,7 +159,7 @@ fn get_url_props(url: &str) -> (String, Option<&str>, &str) {
}
None => (),
}
} else if url.find("?").is_some() {
} else if url.find("?").is_some() { // from browser url
let re = Regex::new(r"((https?://)?.+?)/.+dir=(.+?)&").unwrap();
match re.captures_iter(url).last() {
Some(cap) => {
@ -218,9 +184,13 @@ fn get_url_props(url: &str) -> (String, Option<&str>, &str) {
}
let re = Regex::new(r"^http://").unwrap();
if !re.is_match(domain) {
let re = Regex::new(r"(^https?://)?").unwrap();
let secure_domain = re.replace(domain, "https://").to_string();
(secure_domain, username, path)
return (secure_domain, username, path);
}
(domain.to_string(), username, path)
}
#[cfg(test)]
@ -231,21 +201,22 @@ mod tests {
fn test_get_url_props() {
let p = "/foo/bar";
let u = Some("user");
let d = String::from("https://nextcloud.com");
let ld = String::from("https://nextcloud.example.com");
assert_eq!(get_url_props("user@nextcloud.com/remote.php/dav/files/user/foo/bar"), (d.clone(), u, p));
assert_eq!(get_url_props("user@nextcloud.com/foo/bar"), (d.clone(), u, p));
assert_eq!(get_url_props("user@nextcloud.example.com/remote.php/dav/files/user/foo/bar"), (ld.clone(), u, p));
assert_eq!(get_url_props("user@nextcloud.example.com/foo/bar"), (ld.clone(), u, p));
assert_eq!(get_url_props("https://nextcloud.example.com/apps/files/?dir=/foo/bar&fileid=166666"), (ld.clone(), None, p));
assert_eq!(get_url_props("https://nextcloud.com/apps/files/?dir=/foo/bar&fileid=166666"), (d.clone(), None, p));
let d = String::from("http://nextcloud.com");
let sd = String::from("https://nextcloud.com");
let sld = String::from("https://nextcloud.example.com");
let ld = String::from("http://nextcloud.example.com");
assert_eq!(get_url_props("user@nextcloud.com/remote.php/dav/files/user/foo/bar"), (sd.clone(), u, p));
assert_eq!(get_url_props("user@nextcloud.com/foo/bar"), (sd.clone(), u, p));
assert_eq!(get_url_props("user@nextcloud.example.com/remote.php/dav/files/user/foo/bar"), (sld.clone(), u, p));
assert_eq!(get_url_props("user@nextcloud.example.com/foo/bar"), (sld.clone(), u, p));
assert_eq!(get_url_props("https://nextcloud.example.com/apps/files/?dir=/foo/bar&fileid=166666"), (sld.clone(), None, p));
assert_eq!(get_url_props("https://nextcloud.com/apps/files/?dir=/foo/bar&fileid=166666"), (sd.clone(), None, p));
assert_eq!(get_url_props("http://nextcloud.example.com/remote.php/dav/files/user/foo/bar"), (ld.clone(), u, p));
assert_eq!(get_url_props("https://nextcloud.example.com/remote.php/dav/files/user/foo/bar"), (ld.clone(), u, p));
assert_eq!(get_url_props("https://nextcloud.example.com/remote.php/dav/files/user/foo/bar"), (sld.clone(), u, p));
assert_eq!(get_url_props("http://nextcloud.example.com/remote.php/dav/files/user/foo/bar"), (ld.clone(), u, p));
assert_eq!(get_url_props("nextcloud.example.com/remote.php/dav/files/user/foo/bar"), (ld.clone(), u, p));
assert_eq!(get_url_props("https://nextcloud.example.com/foo/bar"), (ld.clone(), None, p));
assert_eq!(get_url_props("nextcloud.example.com/remote.php/dav/files/user/foo/bar"), (sld.clone(), u, p));
assert_eq!(get_url_props("https://nextcloud.example.com/foo/bar"), (sld.clone(), None, p));
assert_eq!(get_url_props("http://nextcloud.example.com/foo/bar"), (ld.clone(), None, p));
assert_eq!(get_url_props("nextcloud.example.com/foo/bar"), (ld.clone(), None, p));
assert_eq!(get_url_props("nextcloud.example.com/foo/bar"), (sld.clone(), None, p));
}
}

View File

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

View File

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

View File

@ -9,6 +9,7 @@ pub enum ApiError {
IncorrectRequest(reqwest::Response),
EmptyError(reqwest::Error),
RequestError(reqwest::Error),
Unexpected(String),
}
pub struct ApiBuilder {
@ -47,6 +48,17 @@ impl ApiBuilder {
self
}
pub fn build_request_remote(&mut self, meth: Method, path: &str) -> &mut ApiBuilder {
dotenv().ok();
let host = env::var("HOST").unwrap();
let mut url = String::from(host);
url.push_str("/");
url.push_str(path);
dbg!(url.clone());
self.request = Some(self.client.request(meth, url));
self
}
fn set_auth(&mut self) -> &mut ApiBuilder {
// todo if not exist
dotenv().ok();

View File

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

View File

@ -1,8 +1,31 @@
use crate::services::api::{ApiBuilder, ApiError};
use 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 {
@ -10,14 +33,20 @@ impl ListFolders {
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> {
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)?;
@ -27,21 +56,59 @@ impl ListFolders {
}
}
pub async fn send_with_res(self) -> String {
pub async fn send_with_res(&mut self) -> Result<Vec<FolderContent>, ApiError> {
match self.send_with_err().await {
Ok(body) => body,
Err(ApiError::IncorrectRequest(err)) => {
eprintln!("fatal: {}", err.status());
std::process::exit(1);
},
Err(ApiError::EmptyError(_)) => {
eprintln!("Failed to get body");
String::from("")
}
Err(ApiError::RequestError(err)) => {
eprintln!("fatal: {}", err);
std::process::exit(1);
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
}
}

View File

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

View File

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

View File

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

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

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

View File

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