Compare commits
3 Commits
1df9c3fba5
...
e66dc8d408
Author | SHA1 | Date | |
---|---|---|---|
|
e66dc8d408 | ||
|
baeef1a33a | ||
|
bc6a23b76b |
@ -1,3 +1,4 @@
|
|||||||
pub mod add;
|
pub mod add;
|
||||||
pub mod init;
|
pub mod init;
|
||||||
pub mod status;
|
pub mod status;
|
||||||
|
pub mod reset;
|
||||||
|
@ -3,7 +3,10 @@ use crate::store::{
|
|||||||
ignorer::Ignorer,
|
ignorer::Ignorer,
|
||||||
indexer::Indexer,
|
indexer::Indexer,
|
||||||
nsobject::{self, NsObject},
|
nsobject::{self, NsObject},
|
||||||
|
structs::{self, to_obj_path},
|
||||||
};
|
};
|
||||||
|
use crate::utils::path::to_repo_relative;
|
||||||
|
use colored::Colorize;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
// use glob::glob;
|
// use glob::glob;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@ -18,6 +21,8 @@ pub struct AddArgs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn exec(args: AddArgs, config: Config) {
|
pub fn exec(args: AddArgs, config: Config) {
|
||||||
|
structs::init(config.get_root());
|
||||||
|
|
||||||
// Init ignorer
|
// Init ignorer
|
||||||
let mut ignorer = Ignorer::new(config.get_root_unsafe());
|
let mut ignorer = Ignorer::new(config.get_root_unsafe());
|
||||||
ignorer.active_nsignore(!args.force);
|
ignorer.active_nsignore(!args.force);
|
||||||
@ -26,8 +31,6 @@ pub fn exec(args: AddArgs, config: Config) {
|
|||||||
let mut indexer = Indexer::new(config.get_root_unsafe());
|
let mut indexer = Indexer::new(config.get_root_unsafe());
|
||||||
let _ = indexer.load();
|
let _ = indexer.load();
|
||||||
|
|
||||||
nsobject::init(config.get_root_unsafe());
|
|
||||||
|
|
||||||
if args.all {
|
if args.all {
|
||||||
return add_dir(config.get_root_unsafe(), &mut ignorer, &mut indexer);
|
return add_dir(config.get_root_unsafe(), &mut ignorer, &mut indexer);
|
||||||
}
|
}
|
||||||
@ -37,13 +40,18 @@ pub fn exec(args: AddArgs, config: Config) {
|
|||||||
path_to_add.push(PathBuf::from(obj_to_add));
|
path_to_add.push(PathBuf::from(obj_to_add));
|
||||||
|
|
||||||
if path_to_add.exists() {
|
if path_to_add.exists() {
|
||||||
|
// ignore object if it is ns config file or nsignored
|
||||||
|
if ignorer.should_ignore(&path_to_add) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if path_to_add.is_dir() {
|
if path_to_add.is_dir() {
|
||||||
indexer.index_dir(path_to_add.clone());
|
indexer.index_dir(path_to_add.clone());
|
||||||
add_dir(&path_to_add, &mut ignorer, &mut indexer);
|
add_dir(&path_to_add, &mut ignorer, &mut indexer);
|
||||||
} else {
|
} else {
|
||||||
indexer.index_file(path_to_add);
|
indexer.index_file(path_to_add);
|
||||||
}
|
}
|
||||||
} else if NsObject::from_local_path(&path_to_add).exists() {
|
} else if NsObject::from_local_path(&to_obj_path(&path_to_add)).exists() {
|
||||||
indexer.index_file(path_to_add);
|
indexer.index_file(path_to_add);
|
||||||
} else {
|
} else {
|
||||||
// try globbing
|
// try globbing
|
||||||
@ -53,17 +61,31 @@ pub fn exec(args: AddArgs, config: Config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// print all path ignored
|
||||||
|
if ignorer.ignored_paths.len() > 0 {
|
||||||
|
println!("The following paths are ignored by one of your .nsignore files:");
|
||||||
|
for ignored_path in ignorer.ignored_paths {
|
||||||
|
println!("{}", to_repo_relative(&ignored_path).display());
|
||||||
|
}
|
||||||
|
println!(
|
||||||
|
"{}",
|
||||||
|
"hint: Use -f if you really want to add them.".bright_red()
|
||||||
|
);
|
||||||
|
// hint: Turn this message off by running
|
||||||
|
// hint: "git config advice.addIgnoredFile false"
|
||||||
|
}
|
||||||
|
|
||||||
dbg!(indexer.save());
|
dbg!(indexer.save());
|
||||||
/*
|
/*
|
||||||
for all files
|
for all files
|
||||||
if globbing
|
if globbing
|
||||||
take all match glob nextsyncignore
|
take all match glob nextsyncignore
|
||||||
else
|
else
|
||||||
if dir
|
if dir
|
||||||
add dir
|
add dir
|
||||||
add all childs with nextsyncignore
|
add all childs with nextsyncignore
|
||||||
else
|
else
|
||||||
add files
|
add files
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
11
src/commands/reset.rs
Normal file
11
src/commands/reset.rs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
use crate::config::config::Config;
|
||||||
|
use crate::store::indexer::Indexer;
|
||||||
|
|
||||||
|
pub struct ResetArgs {
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn exec(args: ResetArgs, config: Config) {
|
||||||
|
// Init ignorer
|
||||||
|
let indexer = Indexer::new(config.get_root_unsafe());
|
||||||
|
let _ = indexer.save();
|
||||||
|
}
|
@ -3,6 +3,8 @@ use crate::store::{
|
|||||||
indexer::Indexer,
|
indexer::Indexer,
|
||||||
nsobject::NsObject,
|
nsobject::NsObject,
|
||||||
object::{Obj, ObjStatus, ObjType},
|
object::{Obj, ObjStatus, ObjType},
|
||||||
|
structs,
|
||||||
|
structs::to_obj_path,
|
||||||
};
|
};
|
||||||
use crate::utils::path;
|
use crate::utils::path;
|
||||||
use colored::{ColoredString, Colorize};
|
use colored::{ColoredString, Colorize};
|
||||||
@ -108,6 +110,8 @@ pub fn exec(args: StatusArgs, config: Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_obj_changes(args: &StatusArgs, config: &Config) -> ObjStaged {
|
pub fn get_obj_changes(args: &StatusArgs, config: &Config) -> ObjStaged {
|
||||||
|
structs::init(config.get_root());
|
||||||
|
|
||||||
// use root of repo if no custom path has been set by the command
|
// use root of repo if no custom path has been set by the command
|
||||||
let root = if config.is_custom_execution_path {
|
let root = if config.is_custom_execution_path {
|
||||||
config.execution_path.clone()
|
config.execution_path.clone()
|
||||||
@ -235,14 +239,13 @@ fn compare_dir(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let repo_relative_entry = path::to_repo_relative(&entry.path(), root_path);
|
if entry.path().ends_with(".nextsync") {
|
||||||
let local_obj = Obj::from_local_path(&repo_relative_entry);
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let local_obj = Obj::from_local_path(&entry.path().into());
|
||||||
|
|
||||||
if entry.path().is_dir() {
|
if entry.path().is_dir() {
|
||||||
if entry.path().ends_with(".nextsync") {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if local_obj.is_new() {
|
if local_obj.is_new() {
|
||||||
// TODO: opti move files in new directory
|
// TODO: opti move files in new directory
|
||||||
if indexer.is_staged_parent(&local_obj) {
|
if indexer.is_staged_parent(&local_obj) {
|
||||||
@ -280,7 +283,7 @@ fn compare_dir(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Read ns objects to find deleted
|
// Read ns objects to find deleted
|
||||||
let entries = NsObject::from_local_path(&path);
|
let entries = NsObject::from_local_path(&to_obj_path(&path));
|
||||||
for entry in entries.iter() {
|
for entry in entries.iter() {
|
||||||
if entry.is_file() {
|
if entry.is_file() {
|
||||||
match local_files.get(entry.get_obj_path().to_str().unwrap()) {
|
match local_files.get(entry.get_obj_path().to_str().unwrap()) {
|
||||||
@ -324,8 +327,7 @@ fn add_childs(root_path: &PathBuf, path: &PathBuf, res: Arc<ObjStatuses>) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let repo_relative_entry = path::to_repo_relative(&entry.path(), root_path);
|
let local_obj = Obj::from_local_path(&entry.path().into());
|
||||||
let local_obj = Obj::from_local_path(&repo_relative_entry);
|
|
||||||
if entry.path().is_dir() {
|
if entry.path().is_dir() {
|
||||||
if entry.path().ends_with(".nextsync") {
|
if entry.path().ends_with(".nextsync") {
|
||||||
continue;
|
continue;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use std::env;
|
use std::env;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
use crate::store::structs;
|
||||||
|
|
||||||
///
|
///
|
||||||
/// # Parameters
|
/// # Parameters
|
||||||
|
@ -15,6 +15,7 @@ fn main() {
|
|||||||
subcommands::init::create(),
|
subcommands::init::create(),
|
||||||
subcommands::add::create(),
|
subcommands::add::create(),
|
||||||
subcommands::status::create(),
|
subcommands::status::create(),
|
||||||
|
subcommands::reset::create(),
|
||||||
]);
|
]);
|
||||||
// .setting(clap::AppSettings::SubcommandRequiredElseHelp);
|
// .setting(clap::AppSettings::SubcommandRequiredElseHelp);
|
||||||
|
|
||||||
@ -24,6 +25,7 @@ fn main() {
|
|||||||
Some(("init", args)) => subcommands::init::handler(args),
|
Some(("init", args)) => subcommands::init::handler(args),
|
||||||
Some(("add", args)) => subcommands::add::handler(args),
|
Some(("add", args)) => subcommands::add::handler(args),
|
||||||
Some(("status", args)) => subcommands::status::handler(args),
|
Some(("status", args)) => subcommands::status::handler(args),
|
||||||
|
Some(("reset", args)) => subcommands::reset::handler(args),
|
||||||
Some((_, _)) => {}
|
Some((_, _)) => {}
|
||||||
None => {}
|
None => {}
|
||||||
};
|
};
|
||||||
|
@ -3,3 +3,4 @@ pub mod indexer;
|
|||||||
pub mod nsignore;
|
pub mod nsignore;
|
||||||
pub mod nsobject;
|
pub mod nsobject;
|
||||||
pub mod object;
|
pub mod object;
|
||||||
|
pub mod structs;
|
||||||
|
@ -9,6 +9,8 @@ pub struct Ignorer {
|
|||||||
use_nsignore: bool,
|
use_nsignore: bool,
|
||||||
/// Nsignore's rules
|
/// Nsignore's rules
|
||||||
rules: OnceLock<Vec<String>>,
|
rules: OnceLock<Vec<String>>,
|
||||||
|
/// Path that have been ignored by should_ignore function
|
||||||
|
pub ignored_paths: Vec<PathBuf>,
|
||||||
childs: Option<Vec<Box<Ignorer>>>,
|
childs: Option<Vec<Box<Ignorer>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,6 +20,7 @@ impl Ignorer {
|
|||||||
path: path.to_path_buf(),
|
path: path.to_path_buf(),
|
||||||
use_nsignore: true,
|
use_nsignore: true,
|
||||||
rules: OnceLock::new(),
|
rules: OnceLock::new(),
|
||||||
|
ignored_paths: Vec::new(),
|
||||||
childs: None,
|
childs: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -52,6 +55,11 @@ impl Ignorer {
|
|||||||
///
|
///
|
||||||
/// * `path`:
|
/// * `path`:
|
||||||
pub fn should_ignore(&mut self, path: &PathBuf) -> bool {
|
pub fn should_ignore(&mut self, path: &PathBuf) -> bool {
|
||||||
self.is_config_file(path) || (self.use_nsignore && self.is_ignored(path))
|
let should = self.is_config_file(path) || (self.use_nsignore && self.is_ignored(path));
|
||||||
|
|
||||||
|
if should {
|
||||||
|
self.ignored_paths.push(path.clone());
|
||||||
|
}
|
||||||
|
should
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,9 +27,9 @@ fn sort_paths_hierarchically(paths: &mut Vec<PathBuf>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct IndexedObj {
|
pub struct IndexedObj {
|
||||||
obj_type: ObjType,
|
obj_type: ObjType,
|
||||||
path: PathBuf,
|
pub path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Indexer {
|
pub struct Indexer {
|
||||||
@ -76,6 +76,14 @@ impl Indexer {
|
|||||||
dbg!(&self.indexed_objs);
|
dbg!(&self.indexed_objs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.indexed_objs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_indexed_objs(&self) -> &Vec<IndexedObj> {
|
||||||
|
&self.indexed_objs
|
||||||
|
}
|
||||||
|
|
||||||
fn is_indexed(&self, obj: &IndexedObj) -> bool {
|
fn is_indexed(&self, obj: &IndexedObj) -> bool {
|
||||||
self.indexed_objs
|
self.indexed_objs
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1,66 +1,28 @@
|
|||||||
use crate::store::object::{Obj, ObjMetadata, ObjType};
|
use crate::store::{
|
||||||
use crypto::digest::Digest;
|
object::{Obj, ObjMetadata, ObjType},
|
||||||
use crypto::sha1::Sha1;
|
structs::{NsObjPath, ObjPath},
|
||||||
|
};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
pub static REPO_ROOT: OnceLock<PathBuf> = OnceLock::new();
|
|
||||||
|
|
||||||
pub fn init(repo_root: &PathBuf) {
|
|
||||||
REPO_ROOT.set(repo_root.clone());
|
|
||||||
}
|
|
||||||
|
|
||||||
type NsObjectChilds = Vec<Box<NsObject>>;
|
type NsObjectChilds = Vec<Box<NsObject>>;
|
||||||
|
|
||||||
struct NsObjectPath {
|
|
||||||
path: PathBuf,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&str> for NsObjectPath {
|
|
||||||
fn from(hash: &str) -> Self {
|
|
||||||
let (dir, res) = hash.split_at(2);
|
|
||||||
|
|
||||||
let mut ns_obj_path = match REPO_ROOT.get() {
|
|
||||||
Some(path) => path.clone(),
|
|
||||||
None => {
|
|
||||||
panic!("fatal: 'REPO_ROOT' not set, you must initialize nsobject before using it!")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
ns_obj_path.push(dir);
|
|
||||||
ns_obj_path.push(res);
|
|
||||||
|
|
||||||
NsObjectPath { path: ns_obj_path }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&PathBuf> for NsObjectPath {
|
|
||||||
fn from(obj_path: &PathBuf) -> Self {
|
|
||||||
let mut hasher = Sha1::new();
|
|
||||||
hasher.input_str(
|
|
||||||
obj_path
|
|
||||||
.to_str()
|
|
||||||
.expect("Cannot contains non UTF-8 char in path"),
|
|
||||||
);
|
|
||||||
NsObjectPath::from(hasher.result_str().as_str())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct NsObject {
|
pub struct NsObject {
|
||||||
pub obj_type: ObjType,
|
pub obj_type: ObjType,
|
||||||
obj_path: OnceLock<PathBuf>,
|
/// path of the obj in the repo
|
||||||
nsobj_path: OnceLock<PathBuf>,
|
obj_path: OnceLock<ObjPath>,
|
||||||
|
/// path of the nsobj file in the store
|
||||||
|
nsobj_path: OnceLock<NsObjPath>,
|
||||||
childs: OnceLock<NsObjectChilds>,
|
childs: OnceLock<NsObjectChilds>,
|
||||||
index: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NsObject {
|
impl NsObject {
|
||||||
pub fn from_local_path(path: &PathBuf) -> Self {
|
pub fn from_local_path(path: &ObjPath) -> Self {
|
||||||
NsObject {
|
NsObject {
|
||||||
obj_type: ObjType::Obj,
|
obj_type: ObjType::Obj,
|
||||||
obj_path: OnceLock::from(path.to_path_buf()),
|
obj_path: OnceLock::from(path.clone()),
|
||||||
nsobj_path: OnceLock::new(),
|
nsobj_path: OnceLock::new(),
|
||||||
childs: OnceLock::new(),
|
childs: OnceLock::new(),
|
||||||
index: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,19 +30,18 @@ impl NsObject {
|
|||||||
NsObject {
|
NsObject {
|
||||||
obj_type: ObjType::Obj,
|
obj_type: ObjType::Obj,
|
||||||
obj_path: OnceLock::new(),
|
obj_path: OnceLock::new(),
|
||||||
nsobj_path: OnceLock::from(NsObjectPath::from(hash).path),
|
nsobj_path: OnceLock::from(NsObjPath::from(hash)),
|
||||||
childs: OnceLock::new(),
|
childs: OnceLock::new(),
|
||||||
index: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_obj_path(&self) -> &PathBuf {
|
pub fn get_obj_path(&self) -> &ObjPath {
|
||||||
self.obj_path.get_or_init(|| todo!())
|
self.obj_path.get_or_init(|| todo!())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_nsobj_path(&self) -> &PathBuf {
|
fn get_nsobj_path(&self) -> &NsObjPath {
|
||||||
self.nsobj_path
|
self.nsobj_path
|
||||||
.get_or_init(|| NsObjectPath::from(self.get_obj_path()).path)
|
.get_or_init(|| NsObjPath::from(self.get_obj_path()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the existence of the nsobj in the store
|
/// Return the existence of the nsobj in the store
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use crate::store::nsobject::NsObject;
|
use crate::store::{structs::ObjPath, nsobject::NsObject};
|
||||||
use crate::utils::path;
|
use crate::utils::path;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@ -55,16 +55,16 @@ pub struct Obj {
|
|||||||
obj_type: ObjType,
|
obj_type: ObjType,
|
||||||
status: OnceLock<ObjStatus>,
|
status: OnceLock<ObjStatus>,
|
||||||
/// path of the object from root
|
/// path of the object from root
|
||||||
obj_path: PathBuf,
|
obj_path: ObjPath,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Obj {
|
impl Obj {
|
||||||
pub fn from_local_path(path: &PathBuf) -> Self {
|
pub fn from_local_path(path: &ObjPath) -> Self {
|
||||||
// todo set state
|
// todo set state
|
||||||
Obj {
|
Obj {
|
||||||
obj_type: ObjType::Obj,
|
obj_type: ObjType::Obj,
|
||||||
status: OnceLock::new(),
|
status: OnceLock::new(),
|
||||||
obj_path: path.to_path_buf(),
|
obj_path: path.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ impl Obj {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_metadata(&self) -> Option<ObjMetadata> {
|
pub fn get_metadata(&self) -> Option<ObjMetadata> {
|
||||||
let metadata = match fs::metadata(&self.obj_path) {
|
let metadata = match fs::metadata(&*self.obj_path) {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
|
120
src/store/structs.rs
Normal file
120
src/store/structs.rs
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
use crate::utils::{path, tests};
|
||||||
|
use crypto::digest::Digest;
|
||||||
|
use crypto::sha1::Sha1;
|
||||||
|
use std::ops::{Deref, DerefMut};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::sync::{LazyLock, Mutex, OnceLock};
|
||||||
|
|
||||||
|
// for tests only as it is mutable
|
||||||
|
static REPO_ROOT_DEV: LazyLock<Mutex<Vec<PathBuf>>> =
|
||||||
|
LazyLock::new(|| Mutex::new(vec![PathBuf::new()]));
|
||||||
|
|
||||||
|
static REPO_ROOT: OnceLock<PathBuf> = OnceLock::new();
|
||||||
|
|
||||||
|
pub fn init(repo_root: &Option<PathBuf>) {
|
||||||
|
if tests::is_var_setup() {
|
||||||
|
REPO_ROOT_DEV.lock().unwrap()[0] = repo_root.clone().unwrap();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(repo_root) = repo_root {
|
||||||
|
if REPO_ROOT.get().is_none() {
|
||||||
|
let _ = REPO_ROOT.set(repo_root.clone());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
eprintln!("REPO_ROOT failed to initialize");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_repo_root() -> PathBuf {
|
||||||
|
if tests::is_var_setup() {
|
||||||
|
return REPO_ROOT_DEV.lock().unwrap()[0].clone();
|
||||||
|
}
|
||||||
|
|
||||||
|
match REPO_ROOT.get() {
|
||||||
|
Some(path) => path.clone(),
|
||||||
|
None => {
|
||||||
|
panic!("fatal: 'REPO_ROOT' not set, you must initialize nsobject before using it!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
pub struct ObjPath {
|
||||||
|
path: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for ObjPath {
|
||||||
|
type Target = PathBuf;
|
||||||
|
fn deref(&self) -> &PathBuf {
|
||||||
|
&self.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for ObjPath {
|
||||||
|
fn deref_mut(&mut self) -> &mut PathBuf {
|
||||||
|
&mut self.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_obj_path(path: &PathBuf) -> ObjPath {
|
||||||
|
ObjPath { path: path.clone() }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<ObjPath> for &PathBuf {
|
||||||
|
fn into(self) -> ObjPath {
|
||||||
|
ObjPath {
|
||||||
|
path: path::to_repo_relative(self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<ObjPath> for PathBuf {
|
||||||
|
fn into(self) -> ObjPath {
|
||||||
|
ObjPath {
|
||||||
|
path: path::to_repo_relative(&self),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
pub struct NsObjPath {
|
||||||
|
path: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for NsObjPath {
|
||||||
|
type Target = PathBuf;
|
||||||
|
fn deref(&self) -> &PathBuf {
|
||||||
|
&self.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for NsObjPath {
|
||||||
|
fn deref_mut(&mut self) -> &mut PathBuf {
|
||||||
|
&mut self.path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&str> for NsObjPath {
|
||||||
|
fn from(hash: &str) -> Self {
|
||||||
|
let (dir, res) = hash.split_at(2);
|
||||||
|
|
||||||
|
let mut ns_obj_path = get_repo_root();
|
||||||
|
ns_obj_path.push(dir);
|
||||||
|
ns_obj_path.push(res);
|
||||||
|
|
||||||
|
NsObjPath { path: ns_obj_path }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&ObjPath> for NsObjPath {
|
||||||
|
fn from(obj_path: &ObjPath) -> Self {
|
||||||
|
let mut hasher = Sha1::new();
|
||||||
|
hasher.input_str(
|
||||||
|
obj_path
|
||||||
|
.to_str()
|
||||||
|
.expect("Cannot contains non UTF-8 char in path"),
|
||||||
|
);
|
||||||
|
NsObjPath::from(hasher.result_str().as_str())
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
pub mod add;
|
pub mod add;
|
||||||
pub mod init;
|
pub mod init;
|
||||||
|
pub mod reset;
|
||||||
pub mod status;
|
pub mod status;
|
||||||
|
17
src/subcommands/reset.rs
Normal file
17
src/subcommands/reset.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
use clap::{Arg, ArgAction, ArgMatches, Command};
|
||||||
|
|
||||||
|
use crate::commands;
|
||||||
|
use crate::commands::reset::ResetArgs;
|
||||||
|
use crate::config::config::Config;
|
||||||
|
|
||||||
|
pub fn create() -> Command {
|
||||||
|
Command::new("reset")
|
||||||
|
.about("Clear the index")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handler(args: &ArgMatches) {
|
||||||
|
commands::reset::exec(
|
||||||
|
ResetArgs {},
|
||||||
|
Config::new(),
|
||||||
|
);
|
||||||
|
}
|
@ -1 +1,2 @@
|
|||||||
pub mod path;
|
pub mod path;
|
||||||
|
pub mod tests;
|
||||||
|
@ -1,7 +1,15 @@
|
|||||||
use std::path::{Path, PathBuf, Component};
|
use std::path::{Component, Path, PathBuf};
|
||||||
|
use crate::store::structs;
|
||||||
|
|
||||||
pub fn to_repo_relative(path: &PathBuf, root: &PathBuf) -> PathBuf {
|
pub fn to_repo_relative(path: &PathBuf) -> PathBuf {
|
||||||
path.strip_prefix(root).unwrap().to_path_buf()
|
let root = structs::get_repo_root();
|
||||||
|
path.strip_prefix(&root)
|
||||||
|
.expect(&format!(
|
||||||
|
"Expect '{}' to be in the repo '{}'",
|
||||||
|
path.display(),
|
||||||
|
root.display()
|
||||||
|
))
|
||||||
|
.to_path_buf()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_string(path: &PathBuf) -> String {
|
pub fn to_string(path: &PathBuf) -> String {
|
||||||
@ -18,9 +26,7 @@ pub fn to_string(path: &PathBuf) -> String {
|
|||||||
/// This function ensures a given path ending with '/' still
|
/// This function ensures a given path ending with '/' still
|
||||||
/// ends with '/' after normalization.
|
/// ends with '/' after normalization.
|
||||||
pub fn normalize_path<P: AsRef<Path>>(path: P) -> PathBuf {
|
pub fn normalize_path<P: AsRef<Path>>(path: P) -> PathBuf {
|
||||||
let ends_with_slash = path.as_ref()
|
let ends_with_slash = path.as_ref().to_str().map_or(false, |s| s.ends_with('/'));
|
||||||
.to_str()
|
|
||||||
.map_or(false, |s| s.ends_with('/'));
|
|
||||||
let mut normalized = PathBuf::new();
|
let mut normalized = PathBuf::new();
|
||||||
for component in path.as_ref().components() {
|
for component in path.as_ref().components() {
|
||||||
match &component {
|
match &component {
|
||||||
|
15
src/utils/tests.rs
Normal file
15
src/utils/tests.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
use std::env;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub fn is_running() -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
|
pub fn is_running() -> bool {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_var_setup() -> bool {
|
||||||
|
env::var("RUNNING_TESTS").is_ok()
|
||||||
|
}
|
49
tests/add_test.rs
Normal file
49
tests/add_test.rs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
mod common;
|
||||||
|
|
||||||
|
use common::client::ClientTest;
|
||||||
|
use nextsync::store::indexer::Indexer;
|
||||||
|
use nextsync::commands::status::{get_obj_changes, StatusArgs};
|
||||||
|
use nextsync::config::config::Config;
|
||||||
|
use std::io;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
const DEFAULT_STATUS_ARG: StatusArgs = StatusArgs { nostyle: false };
|
||||||
|
|
||||||
|
fn indexed_expected(indexer: &Indexer, expected: Vec<&str>) {
|
||||||
|
let objs = indexer.get_indexed_objs();
|
||||||
|
|
||||||
|
assert_eq!(objs.len(), expected.len());
|
||||||
|
|
||||||
|
for obj in expected {
|
||||||
|
assert!(objs
|
||||||
|
.iter()
|
||||||
|
.position(|e| { e.path == PathBuf::from(obj) })
|
||||||
|
.is_some());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_ignored_file() -> io::Result<()> {
|
||||||
|
let mut client = ClientTest::new("add__simple_file").init();
|
||||||
|
client.add_ignore_rule("foo");
|
||||||
|
client.add_file("foo", "foo")?;
|
||||||
|
|
||||||
|
let mut indexer = Indexer::new(client.get_config().get_root_unsafe());
|
||||||
|
|
||||||
|
client.exec_ok("add foo");
|
||||||
|
let _ = indexer.load();
|
||||||
|
indexed_expected(&indexer, vec![]);
|
||||||
|
|
||||||
|
client.exec_ok("add foo -f");
|
||||||
|
let _ = indexer.load();
|
||||||
|
indexed_expected(&indexer, vec!["foo"]);
|
||||||
|
|
||||||
|
client.ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
// add double globbing
|
||||||
|
// add all
|
||||||
|
// add folders
|
||||||
|
// add part of folders
|
||||||
|
// add all folder
|
||||||
|
// add automatic ignored if is tracked
|
@ -1,4 +1,5 @@
|
|||||||
use nextsync::config::config::Config;
|
use nextsync::config::config::Config;
|
||||||
|
use std::fs::OpenOptions;
|
||||||
use rand::{distributions::Alphanumeric, Rng};
|
use rand::{distributions::Alphanumeric, Rng};
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
@ -125,6 +126,18 @@ impl ClientTest {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_ignore_rule(&self, rule: &str) {
|
||||||
|
let mut nsignore_path = self.volume.clone();
|
||||||
|
nsignore_path.push_str("/.nsignore");
|
||||||
|
let mut file = OpenOptions::new()
|
||||||
|
.write(true)
|
||||||
|
.create(true)
|
||||||
|
.append(true)
|
||||||
|
.open(nsignore_path).unwrap();
|
||||||
|
|
||||||
|
let _ = writeln!(file, "{rule}").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
// pub fn has_file(&mut self, file: &str, content: &str) -> bool {
|
// pub fn has_file(&mut self, file: &str, content: &str) -> bool {
|
||||||
// let full_path = PathBuf::from(self.volume.clone()).join(file);
|
// let full_path = PathBuf::from(self.volume.clone()).join(file);
|
||||||
|
|
||||||
|
4
tests/reset_test.rs
Normal file
4
tests/reset_test.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// reset all
|
||||||
|
// reset file
|
||||||
|
// reset folder
|
||||||
|
// reset unknown
|
@ -8,7 +8,7 @@ use std::path::PathBuf;
|
|||||||
|
|
||||||
const DEFAULT_STATUS_ARG: StatusArgs = StatusArgs { nostyle: false };
|
const DEFAULT_STATUS_ARG: StatusArgs = StatusArgs { nostyle: false };
|
||||||
|
|
||||||
fn status_exepected(config: &Config, staged: Vec<&str>, not_staged: Vec<&str>) {
|
fn status_expected(config: &Config, staged: Vec<&str>, not_staged: Vec<&str>) {
|
||||||
let res = get_obj_changes(&DEFAULT_STATUS_ARG, config);
|
let res = get_obj_changes(&DEFAULT_STATUS_ARG, config);
|
||||||
|
|
||||||
assert_eq!(res.staged.len(), staged.len());
|
assert_eq!(res.staged.len(), staged.len());
|
||||||
@ -36,16 +36,15 @@ fn simple_file() -> io::Result<()> {
|
|||||||
let mut client = ClientTest::new("status__simple_file").init();
|
let mut client = ClientTest::new("status__simple_file").init();
|
||||||
|
|
||||||
client.add_file("foo", "foo")?;
|
client.add_file("foo", "foo")?;
|
||||||
status_exepected(&client.get_config(), vec![], vec!["foo"]);
|
status_expected(&client.get_config(), vec![], vec!["foo"]);
|
||||||
|
|
||||||
client.exec_ok("add foo");
|
client.exec_ok("add foo");
|
||||||
status_exepected(&client.get_config(), vec!["foo"], vec![]);
|
status_expected(&client.get_config(), vec!["foo"], vec![]);
|
||||||
|
|
||||||
client.ok()
|
client.ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[ignore]
|
|
||||||
fn all_folder() -> io::Result<()> {
|
fn all_folder() -> io::Result<()> {
|
||||||
let mut client = ClientTest::new("status__all_folder").init();
|
let mut client = ClientTest::new("status__all_folder").init();
|
||||||
|
|
||||||
@ -53,10 +52,10 @@ fn all_folder() -> io::Result<()> {
|
|||||||
client.add_file("dir/foo", "foo")?;
|
client.add_file("dir/foo", "foo")?;
|
||||||
client.add_file("dir/bar", "bar")?;
|
client.add_file("dir/bar", "bar")?;
|
||||||
client.add_file("foo", "foo")?;
|
client.add_file("foo", "foo")?;
|
||||||
status_exepected(&client.get_config(), vec![], vec!["foo", "dir"]);
|
status_expected(&client.get_config(), vec![], vec!["foo", "dir"]);
|
||||||
|
|
||||||
client.exec_ok("add dir");
|
client.exec_ok("add dir");
|
||||||
status_exepected(&client.get_config(), vec!["dir"], vec!["foo"]);
|
status_expected(&client.get_config(), vec!["dir/foo", "dir/bar"], vec!["foo"]);
|
||||||
|
|
||||||
client.ok()
|
client.ok()
|
||||||
}
|
}
|
||||||
@ -70,10 +69,10 @@ fn all_folder_current() -> io::Result<()> {
|
|||||||
client.add_file("dir/foo", "foo")?;
|
client.add_file("dir/foo", "foo")?;
|
||||||
client.add_file("dir/bar", "bar")?;
|
client.add_file("dir/bar", "bar")?;
|
||||||
client.add_file("foor", "foor")?;
|
client.add_file("foor", "foor")?;
|
||||||
status_exepected(&client.get_config(), vec![], vec!["foor", "dir"]);
|
status_expected(&client.get_config(), vec![], vec!["foor", "dir"]);
|
||||||
|
|
||||||
client.exec_ok("add dir");
|
client.exec_ok("add dir");
|
||||||
status_exepected(
|
status_expected(
|
||||||
&Config::from(Some(&String::from("./dir"))),
|
&Config::from(Some(&String::from("./dir"))),
|
||||||
vec!["foor", "bar"],
|
vec!["foor", "bar"],
|
||||||
vec!["../foo"],
|
vec!["../foo"],
|
||||||
@ -90,10 +89,10 @@ fn part_of_folder() -> io::Result<()> {
|
|||||||
client.add_file("dir/foo", "foo")?;
|
client.add_file("dir/foo", "foo")?;
|
||||||
client.add_file("dir/bar", "bar")?;
|
client.add_file("dir/bar", "bar")?;
|
||||||
client.add_file("foor", "foor")?;
|
client.add_file("foor", "foor")?;
|
||||||
status_exepected(&client.get_config(), vec![], vec!["foor", "dir"]);
|
status_expected(&client.get_config(), vec![], vec!["foor", "dir"]);
|
||||||
|
|
||||||
client.exec_ok("add dir/foo");
|
client.exec_ok("add dir/foo");
|
||||||
status_exepected(
|
status_expected(
|
||||||
&client.get_config(),
|
&client.get_config(),
|
||||||
vec!["dir/foo"],
|
vec!["dir/foo"],
|
||||||
vec!["foor", "dir/bar"],
|
vec!["foor", "dir/bar"],
|
||||||
@ -103,3 +102,6 @@ fn part_of_folder() -> io::Result<()> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ../folder/file add
|
// ../folder/file add
|
||||||
|
// force add ignored file
|
||||||
|
// status without ignored file
|
||||||
|
// all folder without ignored file
|
||||||
|
Loading…
Reference in New Issue
Block a user