diff --git a/src/git_fs/gitignore.rs b/src/git_fs/gitignore.rs index 3491d53..b32d877 100644 --- a/src/git_fs/gitignore.rs +++ b/src/git_fs/gitignore.rs @@ -184,7 +184,6 @@ fn parse_rule(raw: String, rel_to: &Path) -> Option { } fn load_rules(rel_to: &Path) -> Result> { - println!("Loading rule for {}", rel_to.display()); let path = rel_to.join(".gitignore"); let n_rel_to = normalize_path_in_worktree(rel_to)?; diff --git a/src/git_fs/index.rs b/src/git_fs/index.rs index 2b98784..e84414a 100644 --- a/src/git_fs/index.rs +++ b/src/git_fs/index.rs @@ -58,7 +58,7 @@ impl IndexEntry { let cname = CStr::from_bytes_until_nul(&bytes[62..])?; let name = String::from(cname.to_str()?); - let entry_size = usize::div_ceil(62 + cname.count_bytes(), 8) * 8; + let entry_size = usize::div_ceil(62 + cname.count_bytes() + 1, 8) * 8; Ok(( IndexEntry { @@ -159,16 +159,6 @@ impl Index { Ok(()) } - fn insert_entry(&mut self, entry: IndexEntry) { - match self - .entries - .binary_search_by_key(&entry.name, |e| e.name.clone()) - { - Ok(pos) => self.entries[pos] = entry, - Err(pos) => self.entries.insert(pos, entry), - } - } - pub fn add_file(&mut self, name: String, hash: [u8; 20]) -> Result<()> { let metadata = fs::metadata(&name)?; if metadata.is_dir() { @@ -212,6 +202,16 @@ impl Index { Ok(()) } + fn insert_entry(&mut self, entry: IndexEntry) { + match self + .entries + .binary_search_by_key(&entry.name, |e| e.name.clone()) + { + Ok(pos) => self.entries[pos] = entry, + Err(pos) => self.entries.insert(pos, entry), + } + } + fn from_bytes(bytes: Vec) -> Result { match &bytes[0..4] { b"DIRC" => (), @@ -328,7 +328,7 @@ mod tests { hash: [0x19u8; 20], name: String::from("src/git_fs/head.rs"), }; - let (entry1, _) = IndexEntry::from_bytes(&vec![ + let (entry1, len1) = IndexEntry::from_bytes(&vec![ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x19, @@ -345,7 +345,7 @@ mod tests { hash: [0x19u8; 20], name: String::from("src/git_fs/head.r"), }; - let (entry2, _) = IndexEntry::from_bytes(&vec![ + let (entry2, len2) = IndexEntry::from_bytes(&vec![ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x19, @@ -361,7 +361,7 @@ mod tests { hash: [0x19u8; 20], name: String::from("src/git_fs/head.rst"), }; - let (entry3, _) = IndexEntry::from_bytes(&vec![ + let (entry3, len3) = IndexEntry::from_bytes(&vec![ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x19, @@ -375,6 +375,10 @@ mod tests { assert_eq!(entry1, expected1); assert_eq!(entry2, expected2); assert_eq!(entry3, expected3); + + assert_eq!(len1, 88); + assert_eq!(len2, 80); + assert_eq!(len3, 88); } #[test] @@ -418,4 +422,40 @@ mod tests { assert_eq!(index, expected); } + + #[test] + fn index_remove_entry() { + let entry1 = IndexEntry { + object_type: ObjectType::Regular, + permissions: 0o644u16, + hash: [0x19u8; 20], + name: String::from("a"), + }; + let entry2 = IndexEntry { + object_type: ObjectType::Regular, + permissions: 0o644u16, + hash: [0x19u8; 20], + name: String::from("b"), + }; + let entry3 = IndexEntry { + object_type: ObjectType::SymLink, + permissions: 0, + hash: [0x19u8; 20], + name: String::from(".hello"), + }; + + let mut index = Index { + entries: vec![entry3.clone(), entry1, entry2.clone()], + ..Default::default() + }; + + index.remove_file(String::from("a")).unwrap(); + + let expected = Index { + entries: vec![entry3, entry2], + ..Default::default() + }; + + assert_eq!(index, expected); + } } diff --git a/src/subcommands/add.rs b/src/subcommands/add.rs index fa813fc..6410011 100644 --- a/src/subcommands/add.rs +++ b/src/subcommands/add.rs @@ -25,10 +25,8 @@ impl Subcommand for AddSubcommand { for path in self.paths.iter().map(|p| Path::new(p).to_path_buf()) { let expanded = expands_and_filter_path(path)?; for p in expanded { - println!("Adding {}", p.display()); let path_str = String::from(p.to_str().unwrap()); let name = String::from(normalize_path_in_worktree(&p)?.to_str().unwrap()); - println!("adding {}", name); let hash = HashObjectSubcommand { write: true, path: path_str, diff --git a/src/subcommands/mod.rs b/src/subcommands/mod.rs index 103dcc9..1971aa8 100644 --- a/src/subcommands/mod.rs +++ b/src/subcommands/mod.rs @@ -1,21 +1,21 @@ use crate::subcommands::{ - add::AddSubcommand, hash_object::HashObjectSubcommand, init::InitSubcommand, - remove::RemoveSubcommand, test::TestSubcommand, + add::AddSubcommand, hash_object::HashObjectSubcommand, init::InitSubcommand, rm::RmSubcommand, + test::TestSubcommand, }; use anyhow::Result; mod add; mod hash_object; mod init; -mod remove; +mod rm; mod test; #[derive(clap::Parser, Debug)] pub enum SubcommandType { /// Add file(s) to index Add(AddSubcommand), - /// Remove file from the working and the index - Remove(RemoveSubcommand), + /// Remove file(s) from the index + Rm(RmSubcommand), /// Init a Git repository Init(InitSubcommand), HashObject(HashObjectSubcommand), @@ -30,7 +30,7 @@ impl Subcommand for SubcommandType { fn run(&self) -> Result { match self { Self::Add(cmd) => cmd.run(), - Self::Remove(cmd) => cmd.run(), + Self::Rm(cmd) => cmd.run(), Self::Init(cmd) => cmd.run(), Self::HashObject(cmd) => cmd.run(), Self::Test(cmd) => cmd.run(), diff --git a/src/subcommands/rm.rs b/src/subcommands/rm.rs new file mode 100644 index 0000000..e7f91ef --- /dev/null +++ b/src/subcommands/rm.rs @@ -0,0 +1,37 @@ +use anyhow::Result; +use clap::Parser; +use std::path::Path; + +use crate::git_fs::{gitignore::expands_and_filter_path, index::Index}; + +use super::Subcommand; + +#[derive(Parser, Debug)] +pub struct RmSubcommand { + #[arg(short, long, default_value_t = false)] + /// Only remove object in index + pub cached: bool, + + pub paths: Vec, +} + +impl Subcommand for RmSubcommand { + fn run(&self) -> Result { + if self.paths.is_empty() { + return Ok(String::from("Nothing specified, nothing removed")); + } + + let mut index = Index::load()?; + + for path in self.paths.iter().map(|p| Path::new(p).to_path_buf()) { + let expanded = expands_and_filter_path(path)?; + for p in expanded { + index.remove_file(String::from(p.to_str().unwrap()))?; + } + } + + index.save()?; + + Ok(String::from("")) + } +}