feat(reset): introduce reset and fix ROOT_PATH

This commit is contained in:
grimhilt 2024-09-08 17:59:22 +02:00
parent bc6a23b76b
commit baeef1a33a
15 changed files with 178 additions and 52 deletions

View File

@ -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;

View File

@ -1,10 +1,12 @@
use crate::config::config::Config; use crate::config::config::Config;
use crate::store::{ use crate::store::{
structs::to_obj_path,
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;
@ -19,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);
@ -27,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);
} }
@ -38,6 +40,11 @@ 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);
@ -54,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
View 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();
}

View File

@ -1,9 +1,10 @@
use crate::config::config::Config; use crate::config::config::Config;
use crate::store::{ use crate::store::{
structs::to_obj_path,
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};
@ -109,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()
@ -236,13 +239,13 @@ fn compare_dir(
} }
}; };
if entry.path().ends_with(".nextsync") {
continue;
}
let local_obj = Obj::from_local_path(&entry.path().into()); 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) {

View File

@ -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

View File

@ -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 => {}
}; };

View File

@ -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
} }
} }

View File

@ -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()

View File

@ -5,21 +5,6 @@ use crate::store::{
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) {
let _ = REPO_ROOT.set(repo_root.clone());
}
pub fn get_repo_root() -> PathBuf {
match REPO_ROOT.get() {
Some(path) => path.clone(),
None => {
panic!("fatal: 'REPO_ROOT' not set, you must initialize nsobject before using it!")
}
}
}
type NsObjectChilds = Vec<Box<NsObject>>; type NsObjectChilds = Vec<Box<NsObject>>;
pub struct NsObject { pub struct NsObject {

View File

@ -1,22 +1,60 @@
use crate::store::nsobject::get_repo_root; use crate::utils::{path, tests};
use std::path::PathBuf;
use crypto::digest::Digest; use crypto::digest::Digest;
use crypto::sha1::Sha1; use crypto::sha1::Sha1;
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use crate::utils::path; 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)] #[derive(Debug, PartialEq, Clone)]
pub struct ObjPath { pub struct ObjPath {
path: PathBuf path: PathBuf,
} }
impl Deref for ObjPath { impl Deref for ObjPath {
type Target = PathBuf; type Target = PathBuf;
fn deref(&self) -> &PathBuf { &self.path } fn deref(&self) -> &PathBuf {
&self.path
}
} }
impl DerefMut for ObjPath { impl DerefMut for ObjPath {
fn deref_mut(&mut self) -> &mut PathBuf { &mut self.path } fn deref_mut(&mut self) -> &mut PathBuf {
&mut self.path
}
} }
pub fn to_obj_path(path: &PathBuf) -> ObjPath { pub fn to_obj_path(path: &PathBuf) -> ObjPath {
@ -25,28 +63,36 @@ pub fn to_obj_path(path: &PathBuf) -> ObjPath {
impl Into<ObjPath> for &PathBuf { impl Into<ObjPath> for &PathBuf {
fn into(self) -> ObjPath { fn into(self) -> ObjPath {
ObjPath { path: path::to_repo_relative(self, &get_repo_root())} ObjPath {
path: path::to_repo_relative(self),
}
} }
} }
impl Into<ObjPath> for PathBuf { impl Into<ObjPath> for PathBuf {
fn into(self) -> ObjPath { fn into(self) -> ObjPath {
ObjPath { path: path::to_repo_relative(&self, &get_repo_root())} ObjPath {
path: path::to_repo_relative(&self),
}
} }
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct NsObjPath { pub struct NsObjPath {
path: PathBuf path: PathBuf,
} }
impl Deref for NsObjPath { impl Deref for NsObjPath {
type Target = PathBuf; type Target = PathBuf;
fn deref(&self) -> &PathBuf { &self.path } fn deref(&self) -> &PathBuf {
&self.path
}
} }
impl DerefMut for NsObjPath { impl DerefMut for NsObjPath {
fn deref_mut(&mut self) -> &mut PathBuf { &mut self.path } fn deref_mut(&mut self) -> &mut PathBuf {
&mut self.path
}
} }
impl From<&str> for NsObjPath { impl From<&str> for NsObjPath {

View File

@ -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
View 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(),
);
}

View File

@ -1 +1,2 @@
pub mod path; pub mod path;
pub mod tests;

View File

@ -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
View 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()
}