use crate::{ parser::{GitReceivePackArgs, GitUploadPackArgs}, ShackleError, }; use git2::{Repository, RepositoryInitOptions}; use std::{ path::{Path, PathBuf}, process::Command, }; use user_info::get_username; pub struct GitInitResult { pub path: PathBuf, } fn personal_git_dir() -> Result { let username = get_username().ok_or(ShackleError::UserReadError)?; Ok(Path::new("git").join(username)) } fn is_valid_personal_git_repo(path: &PathBuf) -> Result { let valid_dir = personal_git_dir()?; let relative_path = match path.strip_prefix(&valid_dir) { Ok(relative_path) => relative_path, Err(_) => { return Ok(false); } }; if relative_path.parent() != Some(Path::new("")) || relative_path.extension().map(|ext| ext == "git") != Some(true) { return Ok(false); } Ok(true) } pub fn init(repo_name: &str) -> Result { let path = personal_git_dir()?.join(repo_name).with_extension("git"); Repository::init_opts( &path, &RepositoryInitOptions::new() .bare(true) .mkdir(true) .no_reinit(true), )?; Ok(GitInitResult { path }) } pub fn upload_pack(upload_pack_args: &GitUploadPackArgs) -> Result<(), ShackleError> { if !is_valid_personal_git_repo(&upload_pack_args.directory)? { return Err(ShackleError::InvalidDirectory); } let mut command = Command::new("git-upload-pack"); if upload_pack_args.strict { command.arg("strict"); } if upload_pack_args.no_strict { command.arg("no-strict"); } if let Some(timeout) = upload_pack_args.timeout { command.args(["timeout", &timeout.to_string()]); } if upload_pack_args.stateless_rpc { command.arg("stateless-rpc"); } if upload_pack_args.advertise_refs { command.arg("advertise-refs"); } command.arg(&upload_pack_args.directory); command.spawn()?.wait()?; Ok(()) } pub fn receive_pack(receive_pack_args: &GitReceivePackArgs) -> Result<(), ShackleError> { if !is_valid_personal_git_repo(&receive_pack_args.directory)? { return Err(ShackleError::InvalidDirectory); } let mut command = Command::new("git-receive-pack"); if receive_pack_args.http_backend_info_refs { command.arg("--http-backend-info-refs"); } command.arg(&receive_pack_args.directory); command.spawn()?.wait()?; Ok(()) }