#![allow(missing_docs)]mod access { use crate::{Kind, Repository}; impl Repository { pub fn kind(&self) -> Kind { match self.work_tree { Some(_) => Kind::WorkTree, None => Kind::Bare, } } pub fn git_dir(&self) -> &std::path::Path { &self.refs.base } pub fn objects_dir(&self) -> &std::path::Path { &self.odb.dbs[0].loose.path } }} pub mod from_path { use std::convert::TryFrom; use crate::Path; impl TryFrom<crate::Path> for crate::Repository { type Error = crate::open::Error; fn try_from(value: Path) -> Result<Self, Self::Error> { let (git_dir, worktree_dir) = value.into_repository_and_work_tree_directories(); crate::Repository::open_from_paths(git_dir, worktree_dir) } }} pub mod open { use std::{borrow::Cow, path::PathBuf}; use git_config::values::{Boolean, Integer}; use crate::Repository; #[derive(Debug, thiserror::Error)] pub enum Error { #[error(transparent)] Config(#[from] git_config::parser::ParserOrIoError<'static>), #[error(transparent)] NotARepository(#[from] crate::path::is_git::Error), #[error(transparent)] ObjectStoreInitialization(#[from] git_odb::linked::init::Error), #[error("Cannot handle objects formatted as {:?}", .name)] UnsupportedObjectFormat { name: bstr::BString }, } impl Repository { pub fn open(path: impl Into<std::path::PathBuf>) -> Result<Self, Error> { let path = path.into(); let (path, kind) = match crate::path::is_git(&path) { Ok(kind) => (path, kind), Err(_) => { let git_dir = path.join(".git"); crate::path::is_git(&git_dir).map(|kind| (git_dir, kind))? } }; let (git_dir, worktree_dir) = crate::Path::from_dot_git_dir(path, kind).into_repository_and_work_tree_directories(); Repository::open_from_paths(git_dir, worktree_dir) } pub(in crate::repository) fn open_from_paths( git_dir: PathBuf, mut worktree_dir: Option<PathBuf>, ) -> Result<Self, Error> { let config = git_config::file::GitConfig::open(git_dir.join("config"))?; if worktree_dir.is_none() { let is_bare = config .value::<Boolean<'_>>("core", None, "bare") .map_or(false, |b| matches!(b, Boolean::True(_))); if !is_bare { worktree_dir = Some(git_dir.parent().expect("parent is always available").to_owned()); } } let hash_kind = if config .value::<Integer>("core", None, "repositoryFormatVersion") .map_or(0, |v| v.value) == 1 { if let Ok(format) = config.value::<Cow<'_, [u8]>>("extensions", None, "objectFormat") { match format.as_ref() { b"sha1" => git_hash::Kind::Sha1, _ => { return Err(Error::UnsupportedObjectFormat { name: format.to_vec().into(), }) } } } else { git_hash::Kind::Sha1 } } else { git_hash::Kind::Sha1 }; Ok(crate::Repository { odb: git_odb::linked::Store::at(git_dir.join("objects"))?, refs: git_ref::file::Store::at( git_dir, if worktree_dir.is_none() { git_ref::file::WriteReflog::Disable } else { git_ref::file::WriteReflog::Normal }, ), work_tree: worktree_dir, hash_kind, }) } }} pub mod init { use std::{convert::TryInto, path::Path}; use crate::Repository; #[derive(Debug, thiserror::Error)] pub enum Error { #[error(transparent)] Init(#[from] crate::path::create::Error), #[error(transparent)] Open(#[from] crate::open::Error), } impl Repository { /// Create a repository with work-tree within `directory`, creating intermediate directories as needed. /// /// Fails without action if there is already a `.git` repository inside of `directory`, but /// won't mind if the `directory` otherwise is non-empty. pub fn init(directory: impl AsRef<Path>, kind: crate::Kind) -> Result<Self, Error> { let path = crate::path::create::into(directory.as_ref(), kind)?; Ok(path.try_into()?) } }} mod location { use crate::Repository; impl Repository { /// The path to the `.git` directory itself, or equivalent if this is a bare repository. pub fn path(&self) -> &std::path::Path { &self.refs.base } /// Return the path to the working directory if this is not a bare repository. pub fn workdir(&self) -> Option<&std::path::Path> { self.work_tree.as_deref() } }} pub mod discover { use std::{convert::TryInto, path::Path}; use crate::{path::discover, Repository}; #[derive(Debug, thiserror::Error)] pub enum Error { #[error(transparent)] Discover(#[from] discover::existing::Error), #[error(transparent)] Open(#[from] crate::open::Error), } impl Repository { pub fn discover(directory: impl AsRef<Path>) -> Result<Self, Error> { let path = discover::existing(directory)?; Ok(path.try_into()?) } }} mod impls { use crate::Repository; impl std::fmt::Debug for Repository { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, "Repository(git = '{}', working_tree: {:?}", self.git_dir().display(), self.work_tree ) } } impl PartialEq<Repository> for Repository { fn eq(&self, other: &Repository) -> bool { self.git_dir() == other.git_dir() && self.work_tree == other.work_tree } }}
#![allow(missing_docs)]
mod access {
use crate::{Kind, Repository};
impl Repository {
pub fn kind(&self) -> Kind {
match self.work_tree {
Some(_) => Kind::WorkTree,
None => Kind::Bare,
}
}
pub fn git_dir(&self) -> &std::path::Path {
&self.refs.base
}
pub fn objects_dir(&self) -> &std::path::Path {
&self.odb.dbs[0].loose.path
}
}
}
pub mod from_path {
use std::convert::TryFrom;
use crate::Path;
impl TryFrom<crate::Path> for crate::Repository {
type Error = crate::open::Error;
fn try_from(value: Path) -> Result<Self, Self::Error> {
let (git_dir, worktree_dir) = value.into_repository_and_work_tree_directories();
crate::Repository::open_from_paths(git_dir, worktree_dir)
}
}
}
pub mod open {
use std::{borrow::Cow, path::PathBuf};
use git_config::values::{Boolean, Integer};
use crate::Repository;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error(transparent)]
Config(#[from] git_config::parser::ParserOrIoError<'static>),
#[error(transparent)]
NotARepository(#[from] crate::path::is_git::Error),
#[error(transparent)]
ObjectStoreInitialization(#[from] git_odb::linked::init::Error),
#[error("Cannot handle objects formatted as {:?}", .name)]
UnsupportedObjectFormat { name: bstr::BString },
}
impl Repository {
pub fn open(path: impl Into<std::path::PathBuf>) -> Result<Self, Error> {
let path = path.into();
let (path, kind) = match crate::path::is_git(&path) {
Ok(kind) => (path, kind),
Err(_) => {
let git_dir = path.join(".git");
crate::path::is_git(&git_dir).map(|kind| (git_dir, kind))?
}
};
let (git_dir, worktree_dir) =
crate::Path::from_dot_git_dir(path, kind).into_repository_and_work_tree_directories();
Repository::open_from_paths(git_dir, worktree_dir)
}
pub(in crate::repository) fn open_from_paths(
git_dir: PathBuf,
mut worktree_dir: Option<PathBuf>,
) -> Result<Self, Error> {
let config = git_config::file::GitConfig::open(git_dir.join("config"))?;
if worktree_dir.is_none() {
let is_bare = config
.value::<Boolean<'_>>("core", None, "bare")
.map_or(false, |b| matches!(b, Boolean::True(_)));
if !is_bare {
worktree_dir = Some(git_dir.parent().expect("parent is always available").to_owned());
}
}
let hash_kind = if config
.value::<Integer>("core", None, "repositoryFormatVersion")
.map_or(0, |v| v.value)
== 1
{
if let Ok(format) = config.value::<Cow<'_, [u8]>>("extensions", None, "objectFormat") {
match format.as_ref() {
b"sha1" => git_hash::Kind::Sha1,
_ => {
return Err(Error::UnsupportedObjectFormat {
name: format.to_vec().into(),
})
}
}
} else {
git_hash::Kind::Sha1
}
} else {
git_hash::Kind::Sha1
};
Ok(crate::Repository {
odb: git_odb::linked::Store::at(git_dir.join("objects"))?,
refs: git_ref::file::Store::at(
git_dir,
if worktree_dir.is_none() {
git_ref::file::WriteReflog::Disable
} else {
git_ref::file::WriteReflog::Normal
},
),
work_tree: worktree_dir,
hash_kind,
})
}
}
}
pub mod init {
use std::{convert::TryInto, path::Path};
use crate::Repository;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error(transparent)]
Init(#[from] crate::path::create::Error),
#[error(transparent)]
Open(#[from] crate::open::Error),
}
impl Repository {
/// Create a repository with work-tree within `directory`, creating intermediate directories as needed.
///
/// Fails without action if there is already a `.git` repository inside of `directory`, but
/// won't mind if the `directory` otherwise is non-empty.
pub fn init(directory: impl AsRef<Path>, kind: crate::Kind) -> Result<Self, Error> {
let path = crate::path::create::into(directory.as_ref(), kind)?;
Ok(path.try_into()?)
}
}
}
mod location {
use crate::Repository;
impl Repository {
/// The path to the `.git` directory itself, or equivalent if this is a bare repository.
pub fn path(&self) -> &std::path::Path {
&self.refs.base
}
/// Return the path to the working directory if this is not a bare repository.
pub fn workdir(&self) -> Option<&std::path::Path> {
self.work_tree.as_deref()
}
}
}
pub mod discover {
use std::{convert::TryInto, path::Path};
use crate::{path::discover, Repository};
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error(transparent)]
Discover(#[from] discover::existing::Error),
#[error(transparent)]
Open(#[from] crate::open::Error),
}
impl Repository {
pub fn discover(directory: impl AsRef<Path>) -> Result<Self, Error> {
let path = discover::existing(directory)?;
Ok(path.try_into()?)
}
}
}
mod impls {
use crate::Repository;
impl std::fmt::Debug for Repository {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Repository(git = '{}', working_tree: {:?}",
self.git_dir().display(),
self.work_tree
)
}
}
impl PartialEq<Repository> for Repository {
fn eq(&self, other: &Repository) -> bool {
self.git_dir() == other.git_dir() && self.work_tree == other.work_tree
}
}
}