##// END OF EJS Templates
rhg: Add basic test with a shared repository...
rhg: Add basic test with a shared repository Differential Revision: https://phab.mercurial-scm.org/D9940

File last commit:

r47175:1dcd9c99 default
r47189:f3f4d1b7 default
Show More
repo.rs
100 lines | 2.8 KiB | application/rls-services+xml | RustLexer
use crate::errors::{HgError, IoResultExt};
use crate::requirements;
use memmap::{Mmap, MmapOptions};
use std::path::{Path, PathBuf};
/// A repository on disk
pub struct Repo {
working_directory: PathBuf,
dot_hg: PathBuf,
store: PathBuf,
}
#[derive(Debug, derive_more::From)]
pub enum RepoFindError {
NotFoundInCurrentDirectoryOrAncestors {
current_directory: PathBuf,
},
#[from]
Other(HgError),
}
/// Filesystem access abstraction for the contents of a given "base" diretory
#[derive(Clone, Copy)]
pub(crate) struct Vfs<'a> {
base: &'a Path,
}
impl Repo {
/// Search the current directory and its ancestores for a repository:
/// a working directory that contains a `.hg` sub-directory.
pub fn find() -> Result<Self, RepoFindError> {
let current_directory = crate::utils::current_dir()?;
// ancestors() is inclusive: it first yields `current_directory` as-is.
for ancestor in current_directory.ancestors() {
let dot_hg = ancestor.join(".hg");
if dot_hg.is_dir() {
let repo = Self {
store: dot_hg.join("store"),
dot_hg,
working_directory: ancestor.to_owned(),
};
requirements::check(&repo)?;
return Ok(repo);
}
}
Err(RepoFindError::NotFoundInCurrentDirectoryOrAncestors {
current_directory,
})
}
pub fn working_directory_path(&self) -> &Path {
&self.working_directory
}
/// For accessing repository files (in `.hg`), except for the store
/// (`.hg/store`).
pub(crate) fn hg_vfs(&self) -> Vfs<'_> {
Vfs { base: &self.dot_hg }
}
/// For accessing repository store files (in `.hg/store`)
pub(crate) fn store_vfs(&self) -> Vfs<'_> {
Vfs { base: &self.store }
}
/// For accessing the working copy
// The undescore prefix silences the "never used" warning. Remove before
// using.
pub(crate) fn _working_directory_vfs(&self) -> Vfs<'_> {
Vfs {
base: &self.working_directory,
}
}
}
impl Vfs<'_> {
pub(crate) fn join(&self, relative_path: impl AsRef<Path>) -> PathBuf {
self.base.join(relative_path)
}
pub(crate) fn read(
&self,
relative_path: impl AsRef<Path>,
) -> Result<Vec<u8>, HgError> {
let path = self.join(relative_path);
std::fs::read(&path).for_file(&path)
}
pub(crate) fn mmap_open(
&self,
relative_path: impl AsRef<Path>,
) -> Result<Mmap, HgError> {
let path = self.base.join(relative_path);
let file = std::fs::File::open(&path).for_file(&path)?;
// TODO: what are the safety requirements here?
let mmap = unsafe { MmapOptions::new().map(&file) }.for_file(&path)?;
Ok(mmap)
}
}