Index parsing and gitignore files

This commit is contained in:
Antonin Ruan
2026-03-11 17:49:08 +01:00
parent f600a89f5b
commit 3027a99b5f
13 changed files with 1072 additions and 268 deletions
+45
View File
@@ -0,0 +1,45 @@
use anyhow::Result;
use clap::Parser;
use std::path::Path;
use crate::{
git_fs::{gitignore::expands_and_filter_path, index::Index, normalize_path_in_worktree},
subcommands::hash_object::HashObjectSubcommand,
};
use super::Subcommand;
#[derive(Parser, Debug)]
pub struct AddSubcommand {
pub paths: Vec<String>,
}
impl Subcommand for AddSubcommand {
fn run(&self) -> Result<String> {
if self.paths.is_empty() {
return Ok(String::from("Nothing specified, nothing added"));
}
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 {
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,
}
.run_raw()?;
index.add_file(name, hash)?;
}
}
index.save()?;
Ok(String::from(""))
}
}
+19 -13
View File
@@ -1,32 +1,38 @@
use anyhow::{Result, bail};
use clap::Parser;
use hex::encode;
use crate::{
git_fs::object::{Blob, GitObject},
subcommands::Subcommand
subcommands::Subcommand,
};
use super::CmdResult;
#[derive(Parser, Debug)]
pub struct HashObjectSubcommand {
#[arg(short)]
#[arg(short, default_value_t = false)]
/// Save object in database
pub write: bool,
pub path: String,
}
impl Subcommand for HashObjectSubcommand {
fn run (&self) -> CmdResult {
let object = match Blob::create(self.path.clone()) {
Ok(o) => o,
_ => return Err("".to_owned())
impl HashObjectSubcommand {
pub fn run_raw(&self) -> Result<[u8; 20]> {
let object = Blob::create(self.path.clone())?;
let hash = object.hash(self.write)?;
let hash_final: [u8; 20] = match hash.first_chunk() {
Some(h) => *h,
None => bail!("Hash length not valid"),
};
match object.hash(self.write) {
Ok(hash) => Ok(encode(hash)),
_ => return Err("".to_owned())
}
Ok(hash_final)
}
}
impl Subcommand for HashObjectSubcommand {
fn run(&self) -> Result<String> {
let hash = self.run_raw()?;
Ok(encode(hash))
}
}
+22 -28
View File
@@ -1,14 +1,11 @@
use anyhow::Result;
use anyhow::bail;
use clap::Parser;
use std::{
fs,
path::Path
};
use std::{fs, path::Path};
use crate::GIT_DIR;
use crate::git_fs::head::Head;
use crate::subcommands::Subcommand;
use crate::GIT_DIR;
use super::CmdResult;
#[derive(Parser, Debug)]
pub struct InitSubcommand {
@@ -16,45 +13,42 @@ pub struct InitSubcommand {
}
impl Subcommand for InitSubcommand {
fn run(&self) -> CmdResult {
fn run(&self) -> Result<String> {
let path = match &self.directory {
None => Path::new("."),
Some(path) => Path::new(path),
}.join(GIT_DIR);
}
.join(GIT_DIR);
let new_repo = path.exists();
match fs::create_dir_all(&path) {
Err(_) => return Err("Error while creating dir".to_owned()),
Ok(()) => (),
if fs::create_dir_all(&path).is_err() {
bail!("Error while creating dir")
};
let folders = [
"objects/info",
"objects/pack",
"refs/heads",
"refs/tags",
];
let folders = ["objects/info", "objects/pack", "refs/heads", "refs/tags"];
for folder in folders {
match fs::create_dir_all(&path.join(folder)) {
Err(_) => return Err("".to_owned()),
Ok(()) => (),
};
fs::create_dir_all(path.join(folder))?;
}
let head = Head { ref_to: String::from("refs/heads/master") };
match head.save() {
Err(_) => return Err("".to_owned()),
Ok(()) => (),
let head = Head {
ref_to: String::from("refs/heads/master"),
};
head.save()?;
let canonical_path = path.canonicalize();
if new_repo {
Ok(format!("Reinitialized exisiting Git repo in {}", canonical_path.unwrap().display()))
Ok(format!(
"Reinitialized exisiting Git repo in {}",
canonical_path?.display()
))
} else {
Ok(format!("Initialized empty Git repo in {}", canonical_path.unwrap().display()))
Ok(format!(
"Initialized empty Git repo in {}",
canonical_path?.display()
))
}
}
}
+13 -7
View File
@@ -1,17 +1,21 @@
use crate::subcommands::{
init::InitSubcommand,
test::TestSubcommand,
hash_object::HashObjectSubcommand,
add::AddSubcommand, hash_object::HashObjectSubcommand, init::InitSubcommand,
remove::RemoveSubcommand, test::TestSubcommand,
};
use anyhow::Result;
mod add;
mod hash_object;
mod init;
mod remove;
mod test;
pub type CmdResult = Result<String, String>;
#[derive(clap::Parser, Debug)]
pub enum SubcommandType {
/// Add file(s) to index
Add(AddSubcommand),
/// Remove file from the working and the index
Remove(RemoveSubcommand),
/// Init a Git repository
Init(InitSubcommand),
HashObject(HashObjectSubcommand),
@@ -19,12 +23,14 @@ pub enum SubcommandType {
}
pub trait Subcommand {
fn run(&self) -> CmdResult;
fn run(&self) -> Result<String>;
}
impl Subcommand for SubcommandType {
fn run(&self) -> CmdResult {
fn run(&self) -> Result<String> {
match self {
Self::Add(cmd) => cmd.run(),
Self::Remove(cmd) => cmd.run(),
Self::Init(cmd) => cmd.run(),
Self::HashObject(cmd) => cmd.run(),
Self::Test(cmd) => cmd.run(),