Skip to content

Commit

Permalink
Merge pull request #22 from mehm8128/refactor/iroiro
Browse files Browse the repository at this point in the history
色々リファクタ
  • Loading branch information
mehm8128 authored Apr 17, 2024
2 parents d9fd6bb + 7193b43 commit 15fa677
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 175 deletions.
23 changes: 23 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ byteorder = "1.5.0"
bpaf = "0.9.8"
anyhow = "1.0.79"
chrono = "0.4.31"
itertools = "0.12.1"
indoc = "2.0.5"

[lints.clippy]
pedantic = "deny"
185 changes: 78 additions & 107 deletions src/command/add.rs
Original file line number Diff line number Diff line change
@@ -1,66 +1,47 @@
use core::panic;
use std::collections;
use std::ffi::OsStr;
use std::fs::{self, File};
use std::io::{self, Read, Write};
use std::os::linux::fs::MetadataExt;
use std::os::unix::ffi::OsStrExt;
use std::path::{Path, PathBuf};

use byteorder::{BigEndian, ByteOrder};
use hex;

use crate::util;

struct IndexHeader {
signature: [u8; 4],
version: [u8; 4],
entries: [u8; 4],
}

struct IndexEntry {
ctime: [u8; 4],
ctime_nsec: [u8; 4],
mtime: [u8; 4],
mtime_nsec: [u8; 4],
dev: [u8; 4],
ino: [u8; 4],
mode: [u8; 4],
uid: [u8; 4],
gid: [u8; 4],
file_size: [u8; 4],
oid: String, // 20byte
flags: [u8; 2],
path: String,
}

fn travel_dir(
file_name: &str,
file_path_list: &mut Vec<String>,
file_name: impl AsRef<Path>,
file_path_list: &mut Vec<PathBuf>,
hash_list: &mut Vec<String>,
) -> io::Result<()> {
if fs::metadata(file_name)?.is_dir() {
// 再帰的にaddする
for entry in fs::read_dir(file_name)? {
let path = entry?.path();
if path.starts_with("./.git") {
continue;
}
let file_name = path.to_str().unwrap().to_string();
if path.is_dir() {
travel_dir(&file_name, file_path_list, hash_list)?;
continue;
}
let hash = generate_blob_object(&file_name)?;
file_path_list.push(file_name);
hash_list.push(hash);
if !fs::metadata(&file_name)?.is_dir() {
let hash = generate_blob_object(&file_name)?;
file_path_list.push(file_name.as_ref().to_path_buf());
hash_list.push(hash);
return Ok(());
}

// 再帰的にaddする
for entry in fs::read_dir(file_name)? {
let path = entry?.path();
if path.starts_with("./.git") {
continue;
}
} else {
let hash = generate_blob_object(file_name)?;
file_path_list.push(file_name.to_string());

if path.is_dir() {
travel_dir(&path, file_path_list, hash_list)?;
continue;
}
let hash = generate_blob_object(&path)?;
file_path_list.push(path);
hash_list.push(hash);
}
Ok(())
}

pub fn add(file_names: &[String]) -> anyhow::Result<()> {
pub fn add(file_names: &[PathBuf]) -> anyhow::Result<()> {
let mut hash_list = Vec::new();
let mut file_path_list = Vec::new();
for file_name in file_names {
Expand All @@ -69,7 +50,7 @@ pub fn add(file_names: &[String]) -> anyhow::Result<()> {
update_index(&file_path_list, &hash_list)
}

fn generate_blob_object(file_name: &str) -> Result<String, io::Error> {
fn generate_blob_object(file_name: impl AsRef<Path>) -> Result<String, io::Error> {
let contents = fs::read_to_string(file_name)?;
let file_length = contents.len();

Expand All @@ -95,7 +76,7 @@ fn generate_blob_object(file_name: &str) -> Result<String, io::Error> {
#[derive(Clone)]
struct IndexEntrySummary {
index_entry: Vec<u8>,
path: String,
path: PathBuf,
}

// 既存のentriesと新しく追加されるentriesをmergeする
Expand Down Expand Up @@ -130,9 +111,9 @@ fn merge_entries(
result
}

fn decode_index_file() -> anyhow::Result<Option<Vec<IndexEntrySummary>>> {
fn decode_index_file() -> Option<Vec<IndexEntrySummary>> {
let Ok(mut file) = File::open(".git/index") else {
return Ok(None);
return None;
};
let mut content = Vec::new();
let mut index_entry_summaries = Vec::<IndexEntrySummary>::new();
Expand All @@ -142,89 +123,83 @@ fn decode_index_file() -> anyhow::Result<Option<Vec<IndexEntrySummary>>> {
let entry_count = BigEndian::read_u32(&content[8..12]);
let mut entries = &content[12..];
for _ in 0..entry_count {
let (next_byte, index_entry_summary) = decode_index_entry(entries)?;
let (next_byte, index_entry_summary) = decode_index_entry(entries);
index_entry_summaries.push(index_entry_summary);
entries = &entries[next_byte..];
}

Ok(Some(index_entry_summaries))
Some(index_entry_summaries)
}

fn decode_index_entry(entry: &[u8]) -> Result<(usize, IndexEntrySummary), std::str::Utf8Error> {
fn decode_index_entry(entry: &[u8]) -> (usize, IndexEntrySummary) {
let flags = BigEndian::read_u16(&entry[60..62]);
let file_path_end_byte = (62 + flags) as usize;
let path = std::str::from_utf8(&entry[62..file_path_end_byte])?;
let path: &Path = OsStr::from_bytes(&entry[62..file_path_end_byte]).as_ref();

let padding = 4 - (file_path_end_byte % 4);
let next_byte = file_path_end_byte + padding;
let index_entry_summary = IndexEntrySummary {
index_entry: entry[..next_byte].to_vec(),
path: path.to_string(),
path: path.to_path_buf(),
};

Ok((next_byte, index_entry_summary))
(next_byte, index_entry_summary)
}

fn update_index(file_names: &[String], hash_list: &[String]) -> anyhow::Result<()> {
fn update_index(file_names: &[PathBuf], hash_list: &[String]) -> anyhow::Result<()> {
// 既にindex fileが存在したらそれを読み込み、entriesをdecode
// headerは新しく作る(entryの数が違うため)

// 更新されるファイルのentries
let exists = decode_index_file()?;
let exists = decode_index_file();

// 新しく追加されるファイルのentries
let mut new_entries = Vec::<IndexEntrySummary>::new();

for (index, file_name) in file_names.iter().enumerate() {
let mut content: Vec<u8> = Vec::new();
let metadata = fs::metadata(file_name)?;

let new_file_name = match file_name.strip_prefix("./") {
Some(file_name) => file_name,
None => file_name,
};
// スライスで長さが保証できているのでunwrapのまま
let index_entry = IndexEntry {
ctime: metadata.st_ctime().to_be_bytes()[4..8].try_into().unwrap(),
ctime_nsec: metadata.st_ctime_nsec().to_be_bytes()[4..8]
.try_into()
.unwrap(),
mtime: metadata.st_mtime().to_be_bytes()[4..8].try_into().unwrap(),
mtime_nsec: metadata.st_mtime_nsec().to_be_bytes()[4..8]
.try_into()
.unwrap(),
dev: metadata.st_dev().to_be_bytes()[4..8].try_into().unwrap(),
ino: metadata.st_ino().to_be_bytes()[4..8].try_into().unwrap(),
mode: metadata.st_mode().to_be_bytes(),
uid: metadata.st_uid().to_be_bytes(),
gid: metadata.st_gid().to_be_bytes(),
file_size: metadata.st_size().to_be_bytes()[4..8].try_into().unwrap(),
oid: hash_list[index].clone(),
// TODO: 正しく計算
flags: new_file_name.len().to_be_bytes()[6..8].try_into().unwrap(),
path: new_file_name.to_string(),
};
let new_file_name = &file_name.strip_prefix("./").unwrap_or(file_name);
let change_time = &metadata.st_ctime().to_be_bytes()[4..8];
let change_time_nsec = &metadata.st_ctime_nsec().to_be_bytes()[4..8];
let modification_time = &metadata.st_mtime().to_be_bytes()[4..8];
let modification_time_nsec = &metadata.st_mtime_nsec().to_be_bytes()[4..8];
let dev = &metadata.st_dev().to_be_bytes()[4..8];
let ino = &metadata.st_ino().to_be_bytes()[4..8];
let mode = &metadata.st_mode().to_be_bytes();
let user_id = &metadata.st_uid().to_be_bytes();
let group_id = &metadata.st_gid().to_be_bytes();
let file_size = &metadata.st_size().to_be_bytes()[4..8];
let oid = &hash_list[index];
let decoded_oid = hex::decode(oid)?;
let decoded_oid_slice = decoded_oid.as_slice();
// TODO: 正しく計算
let flags = &new_file_name.as_os_str().len().to_be_bytes()[6..8];
let path = new_file_name.to_path_buf();

let mut content: Vec<u8> = [
change_time,
change_time_nsec,
modification_time,
modification_time_nsec,
dev,
ino,
mode,
user_id,
group_id,
file_size,
decoded_oid_slice,
flags,
path.as_os_str().as_bytes(),
]
.concat();

content.extend(index_entry.ctime.to_vec());
content.extend(index_entry.ctime_nsec.to_vec());
content.extend(index_entry.mtime.to_vec());
content.extend(index_entry.mtime_nsec.to_vec());
content.extend(index_entry.dev.to_vec());
content.extend(index_entry.ino.to_vec());
content.extend(index_entry.mode.to_vec());
content.extend(index_entry.uid.to_vec());
content.extend(index_entry.gid.to_vec());
content.extend(index_entry.file_size.to_vec());
let decoded_oid = hex::decode(&index_entry.oid)?;
content.extend(decoded_oid);
content.extend(index_entry.flags.to_vec());
content.extend(index_entry.path.as_bytes().to_vec());
let padding = 4 - (content.len() % 4);
content.resize(content.len() + padding, 0);

let index_entry_summary = IndexEntrySummary {
index_entry: content.clone(),
path: index_entry.path.to_string(),
index_entry: content,
path,
};
new_entries.push(index_entry_summary);
}
Expand All @@ -234,16 +209,12 @@ fn update_index(file_names: &[String], hash_list: &[String]) -> anyhow::Result<(
None => new_entries,
};

let mut contents: Vec<u8> = Vec::new();
// header
let index_header = IndexHeader {
signature: "DIRC".as_bytes().try_into().unwrap(),
version: 2u32.to_be_bytes(),
entries: merged_entries.len().to_be_bytes()[4..8].try_into().unwrap(),
};
contents.extend(index_header.signature.to_vec());
contents.extend(index_header.version.to_vec());
contents.extend(index_header.entries.to_vec());
let signature = b"DIRC";
let version = &2u32.to_be_bytes();
let entrie_count = &merged_entries.len().to_be_bytes()[4..8];

let mut contents: Vec<u8> = [signature, version, entrie_count].concat();

// entries
for entry in merged_entries {
Expand Down
Loading

0 comments on commit 15fa677

Please sign in to comment.