feat: adding ls-index
This commit is contained in:
parent
f047bb5181
commit
bed1464bb9
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -207,6 +207,12 @@ version = "0.2.169"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "mg"
|
||||
version = "0.1.0"
|
||||
@ -215,6 +221,7 @@ dependencies = [
|
||||
"clap",
|
||||
"flate2",
|
||||
"hex",
|
||||
"nom",
|
||||
"sha1",
|
||||
"thiserror",
|
||||
]
|
||||
@ -228,6 +235,15 @@ dependencies = [
|
||||
"adler2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "8.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df9761775871bdef83bee530e60050f7e54b1105350d6884eb0fb4f46c2f9405"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.2"
|
||||
|
@ -8,5 +8,6 @@ anyhow = "1.0.95"
|
||||
clap = { version = "4.5.27", features = ["derive", "string"] }
|
||||
flate2 = "1.0.35"
|
||||
hex = "0.4.3"
|
||||
nom = "8.0.0"
|
||||
sha1 = "0.10.6"
|
||||
thiserror = "2.0.11"
|
||||
|
150
src/index.rs
Normal file
150
src/index.rs
Normal file
@ -0,0 +1,150 @@
|
||||
use std::path::Path;
|
||||
|
||||
use nom::{
|
||||
bytes::complete::take,
|
||||
number::complete::{be_u16, be_u32},
|
||||
IResult, Parser,
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, Error, Result};
|
||||
|
||||
use crate::repository::Repository;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
struct IndexHeader {
|
||||
signature: [u8; 4], // "DIRC"
|
||||
version: u32, // 2, 3, or 4
|
||||
entries_count: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
struct IndexEntry {
|
||||
ctime_s: u32,
|
||||
ctime_n: u32,
|
||||
mtime_s: u32,
|
||||
mtime_n: u32,
|
||||
dev: u32,
|
||||
ino: u32,
|
||||
mode: u32,
|
||||
uid: u32,
|
||||
gid: u32,
|
||||
size: u32,
|
||||
sha1: [u8; 20],
|
||||
flags: u16,
|
||||
file_path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[allow(dead_code)]
|
||||
struct Index {
|
||||
header: IndexHeader,
|
||||
entries: Vec<IndexEntry>,
|
||||
}
|
||||
|
||||
fn parse_index(input: &[u8]) -> IResult<&[u8], Index> {
|
||||
let (mut input, header) = parse_header(input)?;
|
||||
|
||||
let mut entries = Vec::with_capacity(header.entries_count as usize);
|
||||
|
||||
for _ in 0..header.entries_count {
|
||||
let (remaining, entry) = parse_entry(input)?;
|
||||
entries.push(entry);
|
||||
input = remaining;
|
||||
}
|
||||
|
||||
Ok((input, Index { header, entries }))
|
||||
}
|
||||
|
||||
fn parse_header(input: &[u8]) -> IResult<&[u8], IndexHeader> {
|
||||
let (input, (signature, version, entries_count)) =
|
||||
(take(4usize), be_u32, be_u32).parse(input)?;
|
||||
|
||||
let mut sig = [0u8; 4];
|
||||
sig.copy_from_slice(signature);
|
||||
|
||||
Ok((
|
||||
input,
|
||||
IndexHeader {
|
||||
signature: sig,
|
||||
version,
|
||||
entries_count,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_entry(input: &[u8]) -> IResult<&[u8], IndexEntry> {
|
||||
let start_input_len = input.len();
|
||||
let (
|
||||
input,
|
||||
(ctime_s, ctime_n, mtime_s, mtime_n, dev, ino, mode, uid, gid, size, sha1_bytes, flags),
|
||||
) = (
|
||||
be_u32,
|
||||
be_u32,
|
||||
be_u32,
|
||||
be_u32,
|
||||
be_u32,
|
||||
be_u32,
|
||||
be_u32,
|
||||
be_u32,
|
||||
be_u32,
|
||||
be_u32,
|
||||
take(20usize),
|
||||
be_u16,
|
||||
)
|
||||
.parse(input)?;
|
||||
let current_input_len = input.len();
|
||||
|
||||
let path_len = flags & 0xFFF;
|
||||
let (input, path_bytes) = take(path_len as usize)(input)?;
|
||||
let file_path = String::from_utf8_lossy(path_bytes).into_owned();
|
||||
|
||||
// between 1 and 8 NUL bytes to pad the entry.
|
||||
let padding_len = 8 - ((start_input_len - current_input_len) + path_len as usize) % 8;
|
||||
let (input, _) = take(padding_len)(input)?;
|
||||
|
||||
let mut sha1 = [0u8; 20];
|
||||
sha1.copy_from_slice(sha1_bytes);
|
||||
|
||||
Ok((
|
||||
input,
|
||||
IndexEntry {
|
||||
ctime_s,
|
||||
ctime_n,
|
||||
mtime_s,
|
||||
mtime_n,
|
||||
dev,
|
||||
ino,
|
||||
mode,
|
||||
uid,
|
||||
gid,
|
||||
size,
|
||||
sha1,
|
||||
flags,
|
||||
file_path,
|
||||
},
|
||||
))
|
||||
}
|
||||
|
||||
impl Index {
|
||||
pub fn read_from_file(path: &Path) -> Result<Self, Error> {
|
||||
let content = std::fs::read(path)?;
|
||||
let (_remaining, index) =
|
||||
parse_index(&content).map_err(|e| anyhow!("Failed to parse index: {}", e))?;
|
||||
Ok(index)
|
||||
}
|
||||
}
|
||||
|
||||
impl Repository {
|
||||
pub fn read_index(&self) -> Result<()> {
|
||||
let index_path = self.path.join(".git").join("index");
|
||||
let index = Index::read_from_file(&index_path)?;
|
||||
|
||||
for entry in index.entries {
|
||||
println!("{} {}", hex::encode(entry.sha1), entry.file_path);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ use clap::Subcommand;
|
||||
|
||||
mod commit;
|
||||
mod error;
|
||||
mod index;
|
||||
mod kind;
|
||||
mod log;
|
||||
mod object;
|
||||
@ -59,6 +60,8 @@ enum Command {
|
||||
},
|
||||
/// Show the commit log
|
||||
Log,
|
||||
/// List the index entries
|
||||
LsIndex,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
@ -99,6 +102,10 @@ fn main() -> Result<(), Error> {
|
||||
Ok(_) => (),
|
||||
Err(e) => eprintln!("Failed to show log: {}", e),
|
||||
},
|
||||
Command::LsIndex => match repo.read_index() {
|
||||
Ok(_) => (),
|
||||
Err(e) => eprintln!("Failed to list index: {}", e),
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
Loading…
x
Reference in New Issue
Block a user