feat: remove file from index
This commit is contained in:
@@ -184,7 +184,6 @@ fn parse_rule(raw: String, rel_to: &Path) -> Option<GitIgnoreRule> {
|
||||
}
|
||||
|
||||
fn load_rules(rel_to: &Path) -> Result<Vec<GitIgnoreRule>> {
|
||||
println!("Loading rule for {}", rel_to.display());
|
||||
let path = rel_to.join(".gitignore");
|
||||
let n_rel_to = normalize_path_in_worktree(rel_to)?;
|
||||
|
||||
|
||||
+54
-14
@@ -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<u8>) -> Result<Self> {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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<String> {
|
||||
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(),
|
||||
|
||||
@@ -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<String>,
|
||||
}
|
||||
|
||||
impl Subcommand for RmSubcommand {
|
||||
fn run(&self) -> Result<String> {
|
||||
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(""))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user