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>> {
|
fn load_rules(rel_to: &Path) -> Result<Vec<GitIgnoreRule>> {
|
||||||
println!("Loading rule for {}", rel_to.display());
|
|
||||||
let path = rel_to.join(".gitignore");
|
let path = rel_to.join(".gitignore");
|
||||||
let n_rel_to = normalize_path_in_worktree(rel_to)?;
|
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 cname = CStr::from_bytes_until_nul(&bytes[62..])?;
|
||||||
let name = String::from(cname.to_str()?);
|
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((
|
Ok((
|
||||||
IndexEntry {
|
IndexEntry {
|
||||||
@@ -159,16 +159,6 @@ impl Index {
|
|||||||
Ok(())
|
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<()> {
|
pub fn add_file(&mut self, name: String, hash: [u8; 20]) -> Result<()> {
|
||||||
let metadata = fs::metadata(&name)?;
|
let metadata = fs::metadata(&name)?;
|
||||||
if metadata.is_dir() {
|
if metadata.is_dir() {
|
||||||
@@ -212,6 +202,16 @@ impl Index {
|
|||||||
Ok(())
|
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> {
|
fn from_bytes(bytes: Vec<u8>) -> Result<Self> {
|
||||||
match &bytes[0..4] {
|
match &bytes[0..4] {
|
||||||
b"DIRC" => (),
|
b"DIRC" => (),
|
||||||
@@ -328,7 +328,7 @@ mod tests {
|
|||||||
hash: [0x19u8; 20],
|
hash: [0x19u8; 20],
|
||||||
name: String::from("src/git_fs/head.rs"),
|
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, 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, 0x81, 0xa4,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x19,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x19,
|
||||||
@@ -345,7 +345,7 @@ mod tests {
|
|||||||
hash: [0x19u8; 20],
|
hash: [0x19u8; 20],
|
||||||
name: String::from("src/git_fs/head.r"),
|
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, 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, 0xE0, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x19,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x19,
|
||||||
@@ -361,7 +361,7 @@ mod tests {
|
|||||||
hash: [0x19u8; 20],
|
hash: [0x19u8; 20],
|
||||||
name: String::from("src/git_fs/head.rst"),
|
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, 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, 0xA0, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x19,
|
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!(entry1, expected1);
|
||||||
assert_eq!(entry2, expected2);
|
assert_eq!(entry2, expected2);
|
||||||
assert_eq!(entry3, expected3);
|
assert_eq!(entry3, expected3);
|
||||||
|
|
||||||
|
assert_eq!(len1, 88);
|
||||||
|
assert_eq!(len2, 80);
|
||||||
|
assert_eq!(len3, 88);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -418,4 +422,40 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(index, expected);
|
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()) {
|
for path in self.paths.iter().map(|p| Path::new(p).to_path_buf()) {
|
||||||
let expanded = expands_and_filter_path(path)?;
|
let expanded = expands_and_filter_path(path)?;
|
||||||
for p in expanded {
|
for p in expanded {
|
||||||
println!("Adding {}", p.display());
|
|
||||||
let path_str = String::from(p.to_str().unwrap());
|
let path_str = String::from(p.to_str().unwrap());
|
||||||
let name = String::from(normalize_path_in_worktree(&p)?.to_str().unwrap());
|
let name = String::from(normalize_path_in_worktree(&p)?.to_str().unwrap());
|
||||||
println!("adding {}", name);
|
|
||||||
let hash = HashObjectSubcommand {
|
let hash = HashObjectSubcommand {
|
||||||
write: true,
|
write: true,
|
||||||
path: path_str,
|
path: path_str,
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
use crate::subcommands::{
|
use crate::subcommands::{
|
||||||
add::AddSubcommand, hash_object::HashObjectSubcommand, init::InitSubcommand,
|
add::AddSubcommand, hash_object::HashObjectSubcommand, init::InitSubcommand, rm::RmSubcommand,
|
||||||
remove::RemoveSubcommand, test::TestSubcommand,
|
test::TestSubcommand,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
mod add;
|
mod add;
|
||||||
mod hash_object;
|
mod hash_object;
|
||||||
mod init;
|
mod init;
|
||||||
mod remove;
|
mod rm;
|
||||||
mod test;
|
mod test;
|
||||||
|
|
||||||
#[derive(clap::Parser, Debug)]
|
#[derive(clap::Parser, Debug)]
|
||||||
pub enum SubcommandType {
|
pub enum SubcommandType {
|
||||||
/// Add file(s) to index
|
/// Add file(s) to index
|
||||||
Add(AddSubcommand),
|
Add(AddSubcommand),
|
||||||
/// Remove file from the working and the index
|
/// Remove file(s) from the index
|
||||||
Remove(RemoveSubcommand),
|
Rm(RmSubcommand),
|
||||||
/// Init a Git repository
|
/// Init a Git repository
|
||||||
Init(InitSubcommand),
|
Init(InitSubcommand),
|
||||||
HashObject(HashObjectSubcommand),
|
HashObject(HashObjectSubcommand),
|
||||||
@@ -30,7 +30,7 @@ impl Subcommand for SubcommandType {
|
|||||||
fn run(&self) -> Result<String> {
|
fn run(&self) -> Result<String> {
|
||||||
match self {
|
match self {
|
||||||
Self::Add(cmd) => cmd.run(),
|
Self::Add(cmd) => cmd.run(),
|
||||||
Self::Remove(cmd) => cmd.run(),
|
Self::Rm(cmd) => cmd.run(),
|
||||||
Self::Init(cmd) => cmd.run(),
|
Self::Init(cmd) => cmd.run(),
|
||||||
Self::HashObject(cmd) => cmd.run(),
|
Self::HashObject(cmd) => cmd.run(),
|
||||||
Self::Test(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