use std::{io::Read, path::PathBuf};use crate::DOT_GIT_DIR;///pub mod from_gitdir_file { /// The error returned by [`from_gitdir_file()`][crate::path::from_gitdir_file()]. #[derive(Debug, thiserror::Error)] #[allow(missing_docs)] pub enum Error { #[error(transparent)] Io(#[from] std::io::Error), #[error(transparent)] Parse(#[from] crate::parse::gitdir::Error), }}fn read_regular_file_content_with_size_limit(path: impl AsRef<std::path::Path>) -> std::io::Result<Vec<u8>> { let path = path.as_ref(); let mut file = std::fs::File::open(path)?; let max_file_size = 1024 * 64; // NOTE: git allows 1MB here let file_size = file.metadata()?.len(); if file_size > max_file_size { return Err(std::io::Error::new( std::io::ErrorKind::Other, format!( "Refusing to open files larger than {} bytes, '{}' was {} bytes large", max_file_size, path.display(), file_size ), )); } let mut buf = Vec::with_capacity(512); file.read_to_end(&mut buf)?; Ok(buf)}/// Reads a plain path from a file that contains it as its only content, with trailing newlines trimmed.pub fn from_plain_file(path: impl AsRef<std::path::Path>) -> Option<std::io::Result<PathBuf>> { use bstr::ByteSlice; let mut buf = match read_regular_file_content_with_size_limit(path) { Ok(buf) => buf, Err(err) if err.kind() == std::io::ErrorKind::NotFound => return None, Err(err) => return Some(Err(err)), }; let trimmed_len = buf.trim_end().len(); buf.truncate(trimmed_len); Some(Ok(git_path::from_bstring(buf)))}/// Reads typical `gitdir: ` files from disk as used by worktrees and submodules.pub fn from_gitdir_file(path: impl AsRef<std::path::Path>) -> Result<PathBuf, from_gitdir_file::Error> { let path = path.as_ref(); let buf = read_regular_file_content_with_size_limit(path)?; let mut gitdir = crate::parse::gitdir(&buf)?; if let Some(parent) = path.parent() { gitdir = parent.join(gitdir); } Ok(gitdir)}/// Conditionally pop a trailing `.git` dir if present.pub fn without_dot_git_dir(mut path: PathBuf) -> PathBuf { if path.file_name().and_then(|n| n.to_str()) == Some(DOT_GIT_DIR) { path.pop(); } path}
use std::{io::Read, path::PathBuf};
use crate::DOT_GIT_DIR;
///
pub mod from_gitdir_file {
/// The error returned by [`from_gitdir_file()`][crate::path::from_gitdir_file()].
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
#[error(transparent)]
Io(#[from] std::io::Error),
#[error(transparent)]
Parse(#[from] crate::parse::gitdir::Error),
}
}
fn read_regular_file_content_with_size_limit(path: impl AsRef<std::path::Path>) -> std::io::Result<Vec<u8>> {
let path = path.as_ref();
let mut file = std::fs::File::open(path)?;
let max_file_size = 1024 * 64; // NOTE: git allows 1MB here
let file_size = file.metadata()?.len();
if file_size > max_file_size {
return Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!(
"Refusing to open files larger than {} bytes, '{}' was {} bytes large",
max_file_size,
path.display(),
file_size
),
));
}
let mut buf = Vec::with_capacity(512);
file.read_to_end(&mut buf)?;
Ok(buf)
}
/// Reads a plain path from a file that contains it as its only content, with trailing newlines trimmed.
pub fn from_plain_file(path: impl AsRef<std::path::Path>) -> Option<std::io::Result<PathBuf>> {
use bstr::ByteSlice;
let mut buf = match read_regular_file_content_with_size_limit(path) {
Ok(buf) => buf,
Err(err) if err.kind() == std::io::ErrorKind::NotFound => return None,
Err(err) => return Some(Err(err)),
};
let trimmed_len = buf.trim_end().len();
buf.truncate(trimmed_len);
Some(Ok(git_path::from_bstring(buf)))
}
/// Reads typical `gitdir: ` files from disk as used by worktrees and submodules.
pub fn from_gitdir_file(path: impl AsRef<std::path::Path>) -> Result<PathBuf, from_gitdir_file::Error> {
let path = path.as_ref();
let buf = read_regular_file_content_with_size_limit(path)?;
let mut gitdir = crate::parse::gitdir(&buf)?;
if let Some(parent) = path.parent() {
gitdir = parent.join(gitdir);
}
Ok(gitdir)
}
/// Conditionally pop a trailing `.git` dir if present.
pub fn without_dot_git_dir(mut path: PathBuf) -> PathBuf {
if path.file_name().and_then(|n| n.to_str()) == Some(DOT_GIT_DIR) {
path.pop();
}
path
}