Mercurial > hg
diff rust/hg-core/src/repo.rs @ 46167:8a4914397d02
rust: introduce Repo and Vfs types for filesystem abstraction
This is similar to the corresponding Python classes.
Repo represents a repository and knows the path to the `.hg` directory,
the `store` directory, and the working directory.
Separating these will enable supporting the share extension.
A Vfs is created from a Repo for one of these three directories.
It has filesystem access APIs that take a relative std::path::Path
as a parameter.
Differential Revision: https://phab.mercurial-scm.org/D9596
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Mon, 14 Dec 2020 16:33:15 +0100 |
parents | |
children | 02d3bb972121 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/hg-core/src/repo.rs Mon Dec 14 16:33:15 2020 +0100 @@ -0,0 +1,92 @@ +use crate::operations::{find_root, FindRootError}; +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, +} + +/// Filesystem access abstraction for the contents of a given "base" diretory +#[derive(Clone, Copy)] +pub(crate) struct Vfs<'a> { + base: &'a Path, +} + +impl Repo { + /// Returns `None` if the given path doesn’t look like a repository + /// (doesn’t contain a `.hg` sub-directory). + pub fn for_path(root: impl Into<PathBuf>) -> Self { + let working_directory = root.into(); + let dot_hg = working_directory.join(".hg"); + Self { + store: dot_hg.join("store"), + dot_hg, + working_directory, + } + } + + pub fn find() -> Result<Self, FindRootError> { + find_root().map(Self::for_path) + } + + pub fn check_requirements( + &self, + ) -> Result<(), requirements::RequirementsError> { + requirements::check(self) + } + + 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 read( + &self, + relative_path: impl AsRef<Path>, + ) -> std::io::Result<Vec<u8>> { + std::fs::read(self.base.join(relative_path)) + } + + pub(crate) fn open( + &self, + relative_path: impl AsRef<Path>, + ) -> std::io::Result<std::fs::File> { + std::fs::File::open(self.base.join(relative_path)) + } + + pub(crate) fn mmap_open( + &self, + relative_path: impl AsRef<Path>, + ) -> std::io::Result<Mmap> { + let file = self.open(relative_path)?; + // TODO: what are the safety requirements here? + let mmap = unsafe { MmapOptions::new().map(&file) }?; + Ok(mmap) + } +}