feat: adding write-index
This commit is contained in:
parent
bed1464bb9
commit
8c6994986c
29
Cargo.lock
generated
29
Cargo.lock
generated
@ -224,6 +224,7 @@ dependencies = [
|
||||
"nom",
|
||||
"sha1",
|
||||
"thiserror",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -268,6 +269,15 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha1"
|
||||
version = "0.10.6"
|
||||
@ -340,6 +350,25 @@ version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
|
||||
dependencies = [
|
||||
"same-file",
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
|
@ -11,3 +11,4 @@ hex = "0.4.3"
|
||||
nom = "8.0.0"
|
||||
sha1 = "0.10.6"
|
||||
thiserror = "2.0.11"
|
||||
walkdir = "2.5.0"
|
||||
|
@ -88,6 +88,8 @@ impl Repository {
|
||||
// update current branch's commit id
|
||||
self.set_current_commit(&hash)?;
|
||||
|
||||
self.write_index()?;
|
||||
|
||||
Ok(hash)
|
||||
}
|
||||
|
||||
|
108
src/index.rs
108
src/index.rs
@ -1,4 +1,4 @@
|
||||
use std::path::Path;
|
||||
use std::{os::linux::fs::MetadataExt, path::Path};
|
||||
|
||||
use nom::{
|
||||
bytes::complete::take,
|
||||
@ -7,6 +7,8 @@ use nom::{
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, Error, Result};
|
||||
use sha1::{Digest, Sha1};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use crate::repository::Repository;
|
||||
|
||||
@ -147,4 +149,108 @@ impl Repository {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_index(&self) -> Result<()> {
|
||||
let index_path = self.path.join(".git").join("index");
|
||||
|
||||
// list all files in the repository
|
||||
let files = list_all_files(&self.path, &self.ignore)?;
|
||||
|
||||
let index = Index {
|
||||
header: IndexHeader {
|
||||
signature: *b"DIRC",
|
||||
version: 2,
|
||||
entries_count: files.len() as u32,
|
||||
},
|
||||
entries: Vec::new(),
|
||||
};
|
||||
|
||||
let mut content = Vec::new();
|
||||
content.extend_from_slice(&index.header.signature);
|
||||
content.extend_from_slice(&index.header.version.to_be_bytes());
|
||||
content.extend_from_slice(&index.header.entries_count.to_be_bytes());
|
||||
|
||||
for file in files {
|
||||
let metadata = std::fs::metadata(self.path.join(file.clone()))?;
|
||||
|
||||
let entry = IndexEntry {
|
||||
ctime_s: metadata.st_ctime() as u32,
|
||||
ctime_n: metadata.st_ctime_nsec() as u32,
|
||||
mtime_s: metadata.st_mtime() as u32,
|
||||
mtime_n: metadata.st_mtime_nsec() as u32,
|
||||
dev: metadata.st_dev() as u32,
|
||||
ino: metadata.st_ino() as u32,
|
||||
mode: metadata.st_mode(),
|
||||
uid: metadata.st_uid(),
|
||||
gid: metadata.st_gid(),
|
||||
size: metadata.st_size() as u32,
|
||||
sha1: hash_file(&self.path.join(file.clone()))?,
|
||||
flags: 0,
|
||||
file_path: file,
|
||||
};
|
||||
|
||||
let mut entry_content = Vec::new();
|
||||
entry_content.extend_from_slice(&entry.ctime_s.to_be_bytes());
|
||||
entry_content.extend_from_slice(&entry.ctime_n.to_be_bytes());
|
||||
entry_content.extend_from_slice(&entry.mtime_s.to_be_bytes());
|
||||
entry_content.extend_from_slice(&entry.mtime_n.to_be_bytes());
|
||||
entry_content.extend_from_slice(&entry.dev.to_be_bytes());
|
||||
entry_content.extend_from_slice(&entry.ino.to_be_bytes());
|
||||
entry_content.extend_from_slice(&entry.mode.to_be_bytes());
|
||||
entry_content.extend_from_slice(&entry.uid.to_be_bytes());
|
||||
entry_content.extend_from_slice(&entry.gid.to_be_bytes());
|
||||
entry_content.extend_from_slice(&entry.size.to_be_bytes());
|
||||
entry_content.extend_from_slice(&entry.sha1);
|
||||
//entry_content.extend_from_slice(&entry.flags.to_be_bytes());
|
||||
|
||||
let path_bytes = entry.file_path.as_bytes();
|
||||
entry_content.extend_from_slice(&(path_bytes.len() as u16).to_be_bytes());
|
||||
entry_content.extend_from_slice(path_bytes);
|
||||
|
||||
// between 1 and 8 NUL bytes to pad the entry.
|
||||
let padding_len = 8 - entry_content.len() % 8;
|
||||
entry_content.extend(vec![0u8; padding_len]);
|
||||
|
||||
content.extend(entry_content);
|
||||
}
|
||||
|
||||
std::fs::write(index_path, content)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn list_all_files(path: &Path, ignore_list: &[String]) -> Result<Vec<String>> {
|
||||
let mut files = Vec::new();
|
||||
|
||||
for entry in WalkDir::new(path).into_iter().filter_map(|e| e.ok()) {
|
||||
if entry.file_type().is_file() {
|
||||
if ignore_list.iter().any(|i| entry.path().ends_with(i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let s = entry.path().to_path_buf().to_str().unwrap().to_string();
|
||||
let s = s.strip_prefix(path.to_str().unwrap()).unwrap().to_string();
|
||||
|
||||
if ignore_list.iter().any(|i| s.starts_with(i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
files.push(s.strip_prefix("/").unwrap().to_string());
|
||||
}
|
||||
}
|
||||
|
||||
files.sort();
|
||||
|
||||
Ok(files)
|
||||
}
|
||||
|
||||
fn hash_file(path: &Path) -> Result<[u8; 20]> {
|
||||
let content = std::fs::read(path)?;
|
||||
|
||||
let mut hasher = Sha1::new();
|
||||
hasher.update(format!("blob {}\0", content.len()).as_bytes());
|
||||
hasher.update(content);
|
||||
|
||||
Ok(hasher.finalize().into())
|
||||
}
|
||||
|
@ -62,6 +62,8 @@ enum Command {
|
||||
Log,
|
||||
/// List the index entries
|
||||
LsIndex,
|
||||
/// Write the index file
|
||||
WriteIndex,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), Error> {
|
||||
@ -106,6 +108,10 @@ fn main() -> Result<(), Error> {
|
||||
Ok(_) => (),
|
||||
Err(e) => eprintln!("Failed to list index: {}", e),
|
||||
},
|
||||
Command::WriteIndex => match repo.write_index() {
|
||||
Ok(_) => (),
|
||||
Err(e) => eprintln!("Failed to write index: {}", e),
|
||||
},
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -38,6 +38,7 @@ impl Repository {
|
||||
|
||||
let ignore_content = read_to_string(ignore_path)?;
|
||||
self.ignore = ignore_content.lines().map(String::from).collect();
|
||||
self.ignore.push("/.git/".to_string());
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user