From 188c04c62e55af2e103f9713cecce7d4f6ba74bb Mon Sep 17 00:00:00 2001 From: grimhilt Date: Wed, 4 Sep 2024 22:59:02 +0200 Subject: [PATCH] feat(indexer): started indexer --- src/commands/add.rs | 37 +++++++------ src/store.rs | 3 +- src/store/indexer.rs | 117 ++++++++++++++++++++++++++++++++++++++++++ src/store/nsobject.rs | 18 +++++-- src/store/object.rs | 23 ++++++++- 5 files changed, 177 insertions(+), 21 deletions(-) create mode 100644 src/store/indexer.rs diff --git a/src/commands/add.rs b/src/commands/add.rs index f8e5080..2d89f33 100644 --- a/src/commands/add.rs +++ b/src/commands/add.rs @@ -1,8 +1,12 @@ use crate::config::config::Config; -use crate::store::{ignorer::Ignorer, nsobject::NsObject}; +use crate::store::{ + ignorer::Ignorer, + indexer::Indexer, + nsobject::{self, NsObject}, +}; use std::fs; // use glob::glob; -use std::path::{Path, PathBuf}; +use std::path::PathBuf; pub struct AddArgs { /// List of files/dirs to add @@ -18,8 +22,16 @@ pub fn exec(args: AddArgs, config: Config) { let mut ignorer = Ignorer::new(config.get_root_unsafe()); ignorer.active_nsignore(!args.force); + // Init indexer + let mut indexer = Indexer::new(config.get_root_unsafe()); + dbg!(indexer.save()); + dbg!(indexer.load()); + return; + + nsobject::init(config.get_root_unsafe()); + if args.all { - return add_dir(config.get_root_unsafe(), &mut ignorer); + return add_dir(config.get_root_unsafe(), &mut ignorer, &mut indexer); } for obj_to_add in args.files.iter() { @@ -28,12 +40,12 @@ pub fn exec(args: AddArgs, config: Config) { if path_to_add.exists() { if path_to_add.is_dir() { - add_dir(&path_to_add, &mut ignorer); + add_dir(&path_to_add, &mut ignorer, &mut indexer); } else { - add_to_index(&path_to_add); + indexer.index_file(path_to_add); } } else if NsObject::from_local_path(&path_to_add).exists() { - add_to_index(&path_to_add); + indexer.index_file(path_to_add); } else { // try globbing // todo!() @@ -58,8 +70,7 @@ pub fn exec(args: AddArgs, config: Config) { /// /// # Parameters /// * `dir`: the directory to add from -/// * `force`: true if we should apply the nextsyncignore's rules -fn add_dir(dir: &PathBuf, ignorer: &mut Ignorer) { +fn add_dir(dir: &PathBuf, ignorer: &mut Ignorer, indexer: &mut Indexer) { let entries = match fs::read_dir(dir) { Ok(entries) => entries, Err(err) => { @@ -84,14 +95,10 @@ fn add_dir(dir: &PathBuf, ignorer: &mut Ignorer) { } if entry.path().is_dir() { - add_dir(&entry.path(), ignorer); - add_to_index(&entry.path()); + indexer.index_dir(entry.path().clone()); + add_dir(&entry.path(), ignorer, indexer); } else { - add_to_index(&entry.path()); + indexer.index_file(entry.path()); } } } - -fn add_to_index(path: &PathBuf) { - println!("{}", path.display()); -} diff --git a/src/store.rs b/src/store.rs index 2a9986d..a525f3b 100644 --- a/src/store.rs +++ b/src/store.rs @@ -1,4 +1,5 @@ pub mod ignorer; +pub mod indexer; pub mod nsignore; -pub mod object; pub mod nsobject; +pub mod object; diff --git a/src/store/indexer.rs b/src/store/indexer.rs new file mode 100644 index 0000000..7cdc32a --- /dev/null +++ b/src/store/indexer.rs @@ -0,0 +1,117 @@ +use crate::store::object::ObjType; +use std::fs::File; +use std::io::{self, Read, Seek, SeekFrom, Write}; +use std::path::PathBuf; + +fn get_level(previous_level: u16, path: &PathBuf) -> (u16, IndexLevel) { + let mut level = 0; + let mut path = path.clone(); + while path.pop() { + level += 1; + } + + let index_level = if previous_level < level { + IndexLevel::Down + } else { + IndexLevel::Up + }; + + (level, index_level) +} + +enum IndexLevel { + Up, + Down, +} + +struct IndexedObj { + obj_type: ObjType, + level: IndexLevel, + path: PathBuf, +} + +pub struct Indexer { + index_file: PathBuf, + previous_level: u16, + indexed_objs: Vec, +} + +impl Indexer { + pub fn new(repo_root: &PathBuf) -> Self { + let mut index_file = repo_root.clone(); + index_file.push(".nextsync"); + index_file.push("index"); + + Indexer { + index_file, + previous_level: 0, + indexed_objs: Vec::new(), + } + } + + pub fn load(&self) -> io::Result<()> { + let mut file = File::open(&self.index_file)?; + let mut str = String::new(); + + // Skip reserved bytes + let mut byte = [0; 1]; + file.read_exact(&mut byte)?; + file.seek(SeekFrom::Start(1))?; + + // Read usize value + let mut usize_bytes = [0; std::mem::size_of::()]; + file.read_exact(&mut usize_bytes)?; + dbg!(ObjType::try_from(byte[0])); + let usize_value = usize::from_le_bytes(usize_bytes); + + // Read PathBuf as string + let mut buffer = Vec::new(); + file.read_to_end(&mut buffer)?; + let path_str = String::from_utf8(buffer).unwrap(); + let path = PathBuf::from(path_str); + + println!("usize value: {}", usize_value); + println!("Path: {:?}", path); + Ok(()) + } + + fn index_obj(&mut self, path: PathBuf, obj_type: ObjType) { + let (level, index_level) = get_level(self.previous_level, &path); + self.previous_level = level; + + self.indexed_objs.push(IndexedObj { + obj_type, + level: index_level, + path: path.clone(), + }); + } + + pub fn index_file(&mut self, path: PathBuf) { + self.index_obj(path, ObjType::Blob); + } + + pub fn index_dir(&mut self, path: PathBuf) { + self.index_obj(path, ObjType::Tree); + } + + pub fn save(&self) -> io::Result<()> { + let mut file = File::create(&self.index_file)?; + + // Write reserved bytes + let variant = ObjType::Blob; + let byte: u8 = variant.into(); + file.write_all(&[byte])?; + + // Write usize value + let usize_value: usize = 12; + let usize_bytes = usize_value.to_le_bytes(); + file.write_all(&usize_bytes)?; + + // Write PathBuf as string + let path = PathBuf::from("/jodi/"); + let path_str = path.to_str().unwrap(); + file.write_all(path_str.as_bytes())?; + + Ok(()) + } +} diff --git a/src/store/nsobject.rs b/src/store/nsobject.rs index 3d69bde..a226145 100644 --- a/src/store/nsobject.rs +++ b/src/store/nsobject.rs @@ -4,6 +4,12 @@ use crypto::sha1::Sha1; use std::path::PathBuf; use std::sync::OnceLock; +pub static REPO_ROOT: OnceLock = OnceLock::new(); + +pub fn init(repo_root: &PathBuf) { + REPO_ROOT.set(repo_root.clone()); +} + type NsObjectChilds = Vec>; struct NsObjectPath { @@ -14,7 +20,12 @@ impl From<&str> for NsObjectPath { fn from(hash: &str) -> Self { let (dir, res) = hash.split_at(2); - let mut ns_obj_path = PathBuf::new(); + 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); @@ -107,15 +118,14 @@ impl NsObject { /// first line consists of all size fixed datas (obj_type, size, modified) /// next lines are the size variable datas /// - /// * if it is a Tree obj after an empty line there will be the definition + /// * if it is a Tree obj after an empty line there will be the definition /// of its subobjs (one line by subobj) * /// obj_type + hash pub fn save(&self) -> Result<(), ()> { - if !self.get_obj_path().exists { + if !self.get_obj_path().exists() { // delete current obj // delete reference on parent } else { - } Ok(()) } diff --git a/src/store/object.rs b/src/store/object.rs index f202ea6..28c9ddb 100644 --- a/src/store/object.rs +++ b/src/store/object.rs @@ -12,13 +12,34 @@ pub struct ObjMetadata { modified: Option, } -#[derive(PartialEq, Clone)] +#[derive(PartialEq, Clone, Debug)] +#[repr(u8)] pub enum ObjType { Obj, Blob, Tree, } +impl From for u8 { + fn from(variant: ObjType) -> Self { + variant as u8 + } +} + + +impl TryFrom for ObjType { + type Error = String; + + fn try_from(byte: u8) -> Result { + match byte { + 0 => Ok(ObjType::Obj), + 1 => Ok(ObjType::Blob), + 2 => Ok(ObjType::Tree), + _ => Err(format!("Invalid byte value: {}", byte)), + } + } +} + #[derive(PartialEq, Clone)] pub enum ObjStatus { Undefined,