165 lines
5.0 KiB
Rust
165 lines
5.0 KiB
Rust
use std::io::Write;
|
|
use std::path::{Path, PathBuf};
|
|
use clap::Values;
|
|
use glob::glob;
|
|
use crate::store::{self, object::Object};
|
|
use crate::utils::{self, path};
|
|
use crate::store::object::object::{Obj, ObjMethods};
|
|
use crate::utils::nextsyncignore::{self, ignore_file};
|
|
use crate::utils::path::{normalize_relative, repo_root, path_buf_to_string};
|
|
|
|
pub struct AddArgs<'a> {
|
|
pub files: Option<Values<'a>>,
|
|
pub force: bool,
|
|
pub all: bool,
|
|
}
|
|
|
|
// todo match deleted files
|
|
pub fn add(args: AddArgs) {
|
|
|
|
let mut pattern: String;
|
|
let file_vec: Vec<&str> = match args.all {
|
|
true => {
|
|
pattern = path_buf_to_string(repo_root());
|
|
pattern.push_str("/*");
|
|
vec![&pattern]
|
|
},
|
|
false => args.files.unwrap().collect(),
|
|
};
|
|
|
|
let mut added_files: Vec<String> = vec![];
|
|
let mut ignored_f = vec![];
|
|
let rules = nextsyncignore::get_rules();
|
|
|
|
for file in file_vec {
|
|
dbg!(&file);
|
|
let f = match normalize_relative(file) {
|
|
Ok(f) => f,
|
|
Err(err) => {
|
|
eprintln!("err: {} {}", file, err);
|
|
continue;
|
|
}
|
|
};
|
|
|
|
let path = repo_root().join(Path::new(&f));
|
|
match path.exists() {
|
|
true => {
|
|
add_entry(path, args.force, &mut added_files, rules.clone(), &mut ignored_f);
|
|
},
|
|
false => {
|
|
if Object::new(path.to_str().unwrap()).exists() {
|
|
// object is deleted so not present but can still be added for deletion
|
|
added_files.push(String::from(f));
|
|
} else {
|
|
// try globbing if nothing has been found
|
|
for entry in try_globbing(path) {
|
|
add_entry(entry, args.force, &mut added_files, rules.clone(), &mut ignored_f);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
print_ignored_files(ignored_f);
|
|
write_added_files(added_files);
|
|
}
|
|
|
|
fn add_entry(entry: PathBuf, force: bool, added_files: &mut Vec<String>, rules: Vec<String>, ignored_f: &mut Vec<String>) {
|
|
// ignore nextsync config files
|
|
if path::is_nextsync_config(entry.clone()) {
|
|
return;
|
|
}
|
|
|
|
// check if the file must be ignored
|
|
if !force && ignore_file(&path_buf_to_string(entry.clone()), rules, ignored_f) {
|
|
return;
|
|
}
|
|
|
|
// add the parent if there is one and it is not already created
|
|
add_parent(entry.clone(), added_files);
|
|
|
|
added_files.push(path_buf_to_string(entry.strip_prefix(repo_root()).unwrap().to_path_buf()));
|
|
if entry.is_dir() {
|
|
add_folder_content(entry.to_path_buf(), added_files);
|
|
}
|
|
|
|
}
|
|
|
|
fn add_parent(entry: PathBuf, added_files: &mut Vec<String>) {
|
|
let test_parent = entry.strip_prefix(repo_root()).unwrap().parent();
|
|
if test_parent.is_none() || test_parent.unwrap() == PathBuf::new() {
|
|
return;
|
|
}
|
|
|
|
let parent = entry.parent().unwrap();
|
|
|
|
if !Obj::from_path(parent).exists_on_remote() {
|
|
add_parent(parent.to_path_buf(), added_files);
|
|
added_files.push(path_buf_to_string(parent.strip_prefix(repo_root()).unwrap().to_path_buf()));
|
|
}
|
|
}
|
|
|
|
fn print_ignored_files(ignored_files: Vec<String>) {
|
|
if ignored_files.len() > 0 {
|
|
// todo multiple nextsyncignore
|
|
println!("The following paths are ignored by your .nextsyncignore file:");
|
|
for file in ignored_files {
|
|
println!("{}", file);
|
|
}
|
|
}
|
|
}
|
|
|
|
fn write_added_files(added_files: Vec<String>) {
|
|
let mut index_file = store::index::open();
|
|
for file in added_files {
|
|
if store::index::alread_added(file.clone()) {
|
|
continue;
|
|
}
|
|
match writeln!(index_file, "{}", file) {
|
|
Ok(()) => (),
|
|
Err(err) => eprintln!("{}", err),
|
|
}
|
|
}
|
|
drop(index_file);
|
|
}
|
|
|
|
fn try_globbing(path: PathBuf) -> Vec<PathBuf> {
|
|
let mut paths: Vec<PathBuf> = vec![];
|
|
if let Ok(entries) = glob(path.to_str().unwrap()) {
|
|
for entry in entries {
|
|
match entry {
|
|
Ok(ppath) => paths.push(ppath),
|
|
Err(e) => {
|
|
eprintln!("err: {} incorrect pattern ({})", path.display(), e);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
eprintln!("err: {} is not something you can add.", path.to_str().unwrap());
|
|
}
|
|
return paths;
|
|
}
|
|
|
|
fn add_folder_content(path: PathBuf, added_files: &mut Vec<String>) {
|
|
// todo check for changes
|
|
let mut folders: Vec<PathBuf> = vec![];
|
|
folders.push(path);
|
|
|
|
while let Some(folder) = folders.pop() {
|
|
if let Ok(entries) = utils::read::read_folder(folder.clone()) {
|
|
for entry in entries {
|
|
let path_entry = PathBuf::from(entry);
|
|
if !path::is_nextsync_config(path_entry.clone())
|
|
{
|
|
if path_entry.is_dir() {
|
|
folders.push(path_entry.clone());
|
|
}
|
|
added_files.push(path_buf_to_string(path_entry.strip_prefix(repo_root()).unwrap().to_path_buf()));
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|