##// END OF EJS Templates
rhg: add support for narrow clones and sparse checkouts...
rhg: add support for narrow clones and sparse checkouts This adds a minimal support that can be implemented without parsing the narrowspec. We can parse the narrowspec and add support for more operations later. The reason we need so few code changes is as follows: Most operations need no special treatment of sparse because some of them only read dirstate (`rhg files` without `-r`), which bakes in the filtering, some of them only read store (`rhg files -r`, `rhg cat`), and some of them read no data at all (`rhg root`, `rhg debugrequirements`). `status` is the command that might care about sparse, so we just disable rhg on it. For narrow clones, `rhg files` clearly needs the narrowspec to work correctly, so we fall back. `rhg cat` seems to work consistently with `hg cat` if the file exists. If the file is hidden by narrow spec, the error message is different and confusing, so that's something that we should improve in follow-up patches. Differential Revision: https://phab.mercurial-scm.org/D11764

File last commit:

r49238:005ae1a3 default
r49238:005ae1a3 default
Show More
repo.rs
417 lines | 14.2 KiB | application/rls-services+xml | RustLexer
Simon Sapin
rust: Keep lazily-initialized Changelog and Manifest log on the Repo object...
r48773 use crate::changelog::Changelog;
Simon Sapin
rhg: Parse per-repository configuration...
r47215 use crate::config::{Config, ConfigError, ConfigParseError};
Simon Sapin
rust: Add Repo::dirstate_map and use it in `rhg status`...
r48768 use crate::dirstate::DirstateParents;
use crate::dirstate_tree::dirstate_map::DirstateMap;
use crate::dirstate_tree::owning::OwningDirstateMap;
Simon Sapin
rust: Move VFS code to its own module...
r48764 use crate::errors::HgError;
Simon Sapin
rust: Add Repo::dirstate_map and use it in `rhg status`...
r48768 use crate::errors::HgResultExt;
Simon Sapin
rhg: Reuse manifest when checking status of multiple ambiguous files...
r48778 use crate::exit_codes;
Simon Sapin
rust: Add Repo::manifest(revision)...
r48774 use crate::manifest::{Manifest, Manifestlog};
Simon Sapin
rust: Add a Filelog struct that wraps Revlog...
r48775 use crate::revlog::filelog::Filelog;
Simon Sapin
rust: Keep lazily-initialized Changelog and Manifest log on the Repo object...
r48773 use crate::revlog::revlog::RevlogError;
Simon Sapin
rhg: initial support for shared repositories...
r47190 use crate::utils::files::get_path_from_bytes;
Simon Sapin
rust: Add a Filelog struct that wraps Revlog...
r48775 use crate::utils::hg_path::HgPath;
Simon Sapin
rhg: Don’t make repository path absolute too early...
r47474 use crate::utils::SliceExt;
Simon Sapin
rust: Move VFS code to its own module...
r48764 use crate::vfs::{is_dir, is_file, Vfs};
Simon Sapin
rhg: Reuse manifest when checking status of multiple ambiguous files...
r48778 use crate::{requirements, NodePrefix};
Simon Sapin
rust: Add Repo::manifest(revision)...
r48774 use crate::{DirstateError, Revision};
Simon Sapin
rust: Add Repo::dirstate_map and use it in `rhg status`...
r48768 use std::cell::{Cell, Ref, RefCell, RefMut};
Simon Sapin
rhg: initial support for shared repositories...
r47190 use std::collections::HashSet;
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 use std::path::{Path, PathBuf};
/// A repository on disk
pub struct Repo {
working_directory: PathBuf,
dot_hg: PathBuf,
store: PathBuf,
Simon Sapin
rhg: initial support for shared repositories...
r47190 requirements: HashSet<String>,
Simon Sapin
rhg: Parse per-repository configuration...
r47215 config: Config,
Simon Sapin
rust: Add Repo::dirstate_map and use it in `rhg status`...
r48768 // None means not known/initialized yet
dirstate_parents: Cell<Option<DirstateParents>>,
Simon Sapin
rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct...
r48772 dirstate_map: LazyCell<OwningDirstateMap, DirstateError>,
Simon Sapin
rust: Return HgError instead of RevlogError in revlog constructors...
r48777 changelog: LazyCell<Changelog, HgError>,
manifestlog: LazyCell<Manifestlog, HgError>,
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 }
Simon Sapin
rust: Fold find_root and check_requirements into Repo::find...
r47175 #[derive(Debug, derive_more::From)]
Simon Sapin
rhg: Parse per-repository configuration...
r47215 pub enum RepoError {
NotFound {
Simon Sapin
rhg: Add support for -R and --repository command-line arguments...
r47253 at: PathBuf,
Simon Sapin
rust: Fold find_root and check_requirements into Repo::find...
r47175 },
#[from]
Simon Sapin
rhg: Parse per-repository configuration...
r47215 ConfigParseError(ConfigParseError),
#[from]
Simon Sapin
rust: Fold find_root and check_requirements into Repo::find...
r47175 Other(HgError),
}
Simon Sapin
rhg: Parse per-repository configuration...
r47215 impl From<ConfigError> for RepoError {
fn from(error: ConfigError) -> Self {
match error {
ConfigError::Parse(error) => error.into(),
ConfigError::Other(error) => error.into(),
}
}
}
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 impl Repo {
Pulkit Goyal
rhg: look for repository in ancestors also instead of cwd only...
r48197 /// tries to find nearest repository root in current working directory or
/// its ancestors
pub fn find_repo_root() -> Result<PathBuf, RepoError> {
let current_directory = crate::utils::current_dir()?;
// ancestors() is inclusive: it first yields `current_directory`
// as-is.
for ancestor in current_directory.ancestors() {
Simon Sapin
rhg: Propagate permission errors when finding a repository...
r48584 if is_dir(ancestor.join(".hg"))? {
Pulkit Goyal
rhg: look for repository in ancestors also instead of cwd only...
r48197 return Ok(ancestor.to_path_buf());
}
}
return Err(RepoError::NotFound {
at: current_directory,
});
}
Simon Sapin
rhg: add limited support for the `config` sub-command...
r47255 /// Find a repository, either at the given path (which must contain a `.hg`
/// sub-directory) or by searching the current directory and its
/// ancestors.
Simon Sapin
rhg: Add support for -R and --repository command-line arguments...
r47253 ///
Simon Sapin
rhg: add limited support for the `config` sub-command...
r47255 /// A method with two very different "modes" like this usually a code smell
/// to make two methods instead, but in this case an `Option` is what rhg
/// sub-commands get from Clap for the `-R` / `--repository` CLI argument.
/// Having two methods would just move that `if` to almost all callers.
Simon Sapin
rhg: Add support for -R and --repository command-line arguments...
r47253 pub fn find(
config: &Config,
Pulkit Goyal
rhg: read [paths] for `--repository` value...
r48196 explicit_path: Option<PathBuf>,
Simon Sapin
rhg: Add support for -R and --repository command-line arguments...
r47253 ) -> Result<Self, RepoError> {
if let Some(root) = explicit_path {
Simon Sapin
rhg: Propagate permission errors when finding a repository...
r48584 if is_dir(root.join(".hg"))? {
Simon Sapin
rhg: Don’t make repository path absolute too early...
r47474 Self::new_at_path(root.to_owned(), config)
Simon Sapin
rhg: Propagate permission errors when finding a repository...
r48584 } else if is_file(&root)? {
Simon Sapin
rhg: Fall back to Python for bundle repositories...
r47464 Err(HgError::unsupported("bundle repository").into())
Simon Sapin
rhg: Add support for -R and --repository command-line arguments...
r47253 } else {
Err(RepoError::NotFound {
at: root.to_owned(),
})
Simon Sapin
rust: Fold find_root and check_requirements into Repo::find...
r47175 }
Simon Sapin
rhg: Add support for -R and --repository command-line arguments...
r47253 } else {
Pulkit Goyal
rhg: look for repository in ancestors also instead of cwd only...
r48197 let root = Self::find_repo_root()?;
Self::new_at_path(root, config)
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 }
}
Simon Sapin
rhg: initial support for shared repositories...
r47190 /// To be called after checking that `.hg` is a sub-directory
Simon Sapin
rhg: Abort based on config on share-safe mismatch...
r47214 fn new_at_path(
working_directory: PathBuf,
config: &Config,
Simon Sapin
rhg: Parse per-repository configuration...
r47215 ) -> Result<Self, RepoError> {
Simon Sapin
rhg: initial support for shared repositories...
r47190 let dot_hg = working_directory.join(".hg");
Simon Sapin
rhg: add support for share-safe...
r47191
Simon Sapin
rhg: Parse per-repository configuration...
r47215 let mut repo_config_files = Vec::new();
repo_config_files.push(dot_hg.join("hgrc"));
repo_config_files.push(dot_hg.join("hgrc-not-shared"));
Simon Sapin
rhg: initial support for shared repositories...
r47190 let hg_vfs = Vfs { base: &dot_hg };
Simon Sapin
rhg: add support for share-safe...
r47191 let mut reqs = requirements::load_if_exists(hg_vfs)?;
Simon Sapin
rhg: initial support for shared repositories...
r47190 let relative =
reqs.contains(requirements::RELATIVE_SHARED_REQUIREMENT);
let shared =
reqs.contains(requirements::SHARED_REQUIREMENT) || relative;
Simon Sapin
rhg: add support for share-safe...
r47191
// From `mercurial/localrepo.py`:
//
// if .hg/requires contains the sharesafe requirement, it means
// there exists a `.hg/store/requires` too and we should read it
// NOTE: presence of SHARESAFE_REQUIREMENT imply that store requirement
// is present. We never write SHARESAFE_REQUIREMENT for a repo if store
// is not present, refer checkrequirementscompat() for that
//
// However, if SHARESAFE_REQUIREMENT is not present, it means that the
// repository was shared the old way. We check the share source
// .hg/requires for SHARESAFE_REQUIREMENT to detect whether the
// current repository needs to be reshared
let share_safe = reqs.contains(requirements::SHARESAFE_REQUIREMENT);
Simon Sapin
rhg: initial support for shared repositories...
r47190 let store_path;
if !shared {
store_path = dot_hg.join("store");
} else {
let bytes = hg_vfs.read("sharedpath")?;
Simon Sapin
rhg: Ignore trailing newlines in .hg/sharedpath...
r47427 let mut shared_path =
Simon Sapin
rust: Generalize the `trim_end_newlines` utility of byte strings...
r48761 get_path_from_bytes(bytes.trim_end_matches(|b| b == b'\n'))
.to_owned();
Simon Sapin
rhg: initial support for shared repositories...
r47190 if relative {
shared_path = dot_hg.join(shared_path)
}
Simon Sapin
rhg: Propagate permission errors when finding a repository...
r48584 if !is_dir(&shared_path)? {
Simon Sapin
rhg: initial support for shared repositories...
r47190 return Err(HgError::corrupted(format!(
".hg/sharedpath points to nonexistent directory {}",
shared_path.display()
Simon Sapin
rhg: Parse per-repository configuration...
r47215 ))
.into());
Simon Sapin
rhg: initial support for shared repositories...
r47190 }
store_path = shared_path.join("store");
Simon Sapin
rhg: add support for share-safe...
r47191
let source_is_share_safe =
requirements::load(Vfs { base: &shared_path })?
.contains(requirements::SHARESAFE_REQUIREMENT);
if share_safe && !source_is_share_safe {
Simon Sapin
rhg: Parse per-repository configuration...
r47215 return Err(match config
Simon Sapin
rhg: Align with Python on some more error messages...
r47469 .get(b"share", b"safe-mismatch.source-not-safe")
Simon Sapin
rhg: Parse per-repository configuration...
r47215 {
Simon Sapin
rhg: Abort based on config on share-safe mismatch...
r47214 Some(b"abort") | None => HgError::abort(
Simon Sapin
rhg: Align with Python on some more error messages...
r47469 "abort: share source does not support share-safe requirement\n\
(see `hg help config.format.use-share-safe` for more information)",
Pulkit Goyal
rhg: add exit code to HgError::Abort()...
r48199 exit_codes::ABORT,
Simon Sapin
rhg: Abort based on config on share-safe mismatch...
r47214 ),
Simon Sapin
rhg: Parse per-repository configuration...
r47215 _ => HgError::unsupported("share-safe downgrade"),
}
.into());
Simon Sapin
rhg: add support for share-safe...
r47191 } else if source_is_share_safe && !share_safe {
Simon Sapin
rhg: Abort based on config on share-safe mismatch...
r47214 return Err(
Simon Sapin
rhg: Align with Python on some more error messages...
r47469 match config.get(b"share", b"safe-mismatch.source-safe") {
Simon Sapin
rhg: Abort based on config on share-safe mismatch...
r47214 Some(b"abort") | None => HgError::abort(
Simon Sapin
rhg: Align with Python on some more error messages...
r47469 "abort: version mismatch: source uses share-safe \
functionality while the current share does not\n\
(see `hg help config.format.use-share-safe` for more information)",
Pulkit Goyal
rhg: add exit code to HgError::Abort()...
r48199 exit_codes::ABORT,
Simon Sapin
rhg: Abort based on config on share-safe mismatch...
r47214 ),
_ => HgError::unsupported("share-safe upgrade"),
Simon Sapin
rhg: Parse per-repository configuration...
r47215 }
.into(),
Simon Sapin
rhg: Abort based on config on share-safe mismatch...
r47214 );
Simon Sapin
rhg: add support for share-safe...
r47191 }
Simon Sapin
rhg: Parse per-repository configuration...
r47215
if share_safe {
repo_config_files.insert(0, shared_path.join("hgrc"))
}
Simon Sapin
rhg: initial support for shared repositories...
r47190 }
Simon Sapin
rhg: Bug fix: with share-safe, always read store requirements...
r47357 if share_safe {
reqs.extend(requirements::load(Vfs { base: &store_path })?);
}
Simon Sapin
rhg: initial support for shared repositories...
r47190
Simon Sapin
rhg: Add support for the HGRCSKIPREPO environment variable...
r47475 let repo_config = if std::env::var_os("HGRCSKIPREPO").is_none() {
config.combine_with_repo(&repo_config_files)?
} else {
config.clone()
};
Simon Sapin
rhg: Parse per-repository configuration...
r47215
Simon Sapin
rhg: initial support for shared repositories...
r47190 let repo = Self {
requirements: reqs,
working_directory,
store: store_path,
dot_hg,
Simon Sapin
rhg: Parse per-repository configuration...
r47215 config: repo_config,
Simon Sapin
rust: Add Repo::dirstate_map and use it in `rhg status`...
r48768 dirstate_parents: Cell::new(None),
Simon Sapin
rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct...
r48772 dirstate_map: LazyCell::new(Self::new_dirstate_map),
Simon Sapin
rust: Keep lazily-initialized Changelog and Manifest log on the Repo object...
r48773 changelog: LazyCell::new(Changelog::open),
manifestlog: LazyCell::new(Manifestlog::open),
Simon Sapin
rhg: initial support for shared repositories...
r47190 };
requirements::check(&repo)?;
Ok(repo)
}
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 pub fn working_directory_path(&self) -> &Path {
&self.working_directory
}
Simon Sapin
rhg: initial support for shared repositories...
r47190 pub fn requirements(&self) -> &HashSet<String> {
&self.requirements
}
Simon Sapin
rhg: Parse per-repository configuration...
r47215 pub fn config(&self) -> &Config {
&self.config
}
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 /// For accessing repository files (in `.hg`), except for the store
/// (`.hg/store`).
Simon Sapin
rust: Add a log file rotation utility...
r47341 pub fn hg_vfs(&self) -> Vfs<'_> {
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 Vfs { base: &self.dot_hg }
}
/// For accessing repository store files (in `.hg/store`)
Simon Sapin
rust: Add a log file rotation utility...
r47341 pub fn store_vfs(&self) -> Vfs<'_> {
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 Vfs { base: &self.store }
}
/// For accessing the working copy
Georges Racinet
rhg: Initial support for the 'status' command...
r47578 pub fn working_directory_vfs(&self) -> Vfs<'_> {
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 Vfs {
base: &self.working_directory,
}
}
Simon Sapin
rhg: Add support for the blackbox extension...
r47343
Simon Sapin
rhg: Add support for dirstate-v2...
r48165 pub fn has_dirstate_v2(&self) -> bool {
self.requirements
.contains(requirements::DIRSTATE_V2_REQUIREMENT)
}
Arseniy Alekseyev
rhg: add support for narrow clones and sparse checkouts...
r49238 pub fn has_sparse(&self) -> bool {
self.requirements.contains(requirements::SPARSE_REQUIREMENT)
}
pub fn has_narrow(&self) -> bool {
self.requirements.contains(requirements::NARROW_REQUIREMENT)
}
Simon Sapin
rust: Add Repo::dirstate_map and use it in `rhg status`...
r48768 fn dirstate_file_contents(&self) -> Result<Vec<u8>, HgError> {
Ok(self
.hg_vfs()
.read("dirstate")
.io_not_found_as_none()?
.unwrap_or(Vec::new()))
}
pub fn dirstate_parents(&self) -> Result<DirstateParents, HgError> {
if let Some(parents) = self.dirstate_parents.get() {
return Ok(parents);
Simon Sapin
rhg: Add support for dirstate-v2...
r48165 }
Simon Sapin
rust: Add Repo::dirstate_map and use it in `rhg status`...
r48768 let dirstate = self.dirstate_file_contents()?;
let parents = if dirstate.is_empty() {
DirstateParents::NULL
} else if self.has_dirstate_v2() {
Simon Sapin
dirstate-v2: Introduce a docket file...
r48474 crate::dirstate_tree::on_disk::read_docket(&dirstate)?.parents()
Simon Sapin
rhg: Add support for dirstate-v2...
r48165 } else {
crate::dirstate::parsers::parse_dirstate_parents(&dirstate)?
Simon Sapin
dirstate-v2: Introduce a docket file...
r48474 .clone()
Simon Sapin
rhg: Add support for dirstate-v2...
r48165 };
Simon Sapin
rust: Add Repo::dirstate_map and use it in `rhg status`...
r48768 self.dirstate_parents.set(Some(parents));
Simon Sapin
dirstate-v2: Introduce a docket file...
r48474 Ok(parents)
Simon Sapin
rhg: Add support for the blackbox extension...
r47343 }
Simon Sapin
rust: Add Repo::dirstate_map and use it in `rhg status`...
r48768
fn new_dirstate_map(&self) -> Result<OwningDirstateMap, DirstateError> {
let dirstate_file_contents = self.dirstate_file_contents()?;
if dirstate_file_contents.is_empty() {
self.dirstate_parents.set(Some(DirstateParents::NULL));
Ok(OwningDirstateMap::new_empty(Vec::new()))
} else if self.has_dirstate_v2() {
let docket = crate::dirstate_tree::on_disk::read_docket(
&dirstate_file_contents,
)?;
self.dirstate_parents.set(Some(docket.parents()));
let data_size = docket.data_size();
let metadata = docket.tree_metadata();
let mut map = if let Some(data_mmap) = self
.hg_vfs()
.mmap_open(docket.data_filename())
.io_not_found_as_none()?
{
Simon Sapin
rust: Update the memmap2 crate to version 0.4.0...
r48795 OwningDirstateMap::new_empty(data_mmap)
Simon Sapin
rust: Add Repo::dirstate_map and use it in `rhg status`...
r48768 } else {
OwningDirstateMap::new_empty(Vec::new())
};
Simon Sapin
dirstate: Remove the Rust abstraction DirstateMapMethods...
r48883 let (on_disk, placeholder) = map.get_pair_mut();
Simon Sapin
rust: Add Repo::dirstate_map and use it in `rhg status`...
r48768 *placeholder = DirstateMap::new_v2(on_disk, data_size, metadata)?;
Ok(map)
} else {
let mut map = OwningDirstateMap::new_empty(dirstate_file_contents);
Simon Sapin
dirstate: Remove the Rust abstraction DirstateMapMethods...
r48883 let (on_disk, placeholder) = map.get_pair_mut();
Simon Sapin
rust: Add Repo::dirstate_map and use it in `rhg status`...
r48768 let (inner, parents) = DirstateMap::new_v1(on_disk)?;
self.dirstate_parents
.set(Some(parents.unwrap_or(DirstateParents::NULL)));
*placeholder = inner;
Ok(map)
}
}
pub fn dirstate_map(
&self,
) -> Result<Ref<OwningDirstateMap>, DirstateError> {
Simon Sapin
rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct...
r48772 self.dirstate_map.get_or_init(self)
}
pub fn dirstate_map_mut(
&self,
) -> Result<RefMut<OwningDirstateMap>, DirstateError> {
self.dirstate_map.get_mut_or_init(self)
}
Simon Sapin
rust: Keep lazily-initialized Changelog and Manifest log on the Repo object...
r48773
Simon Sapin
rust: Return HgError instead of RevlogError in revlog constructors...
r48777 pub fn changelog(&self) -> Result<Ref<Changelog>, HgError> {
Simon Sapin
rust: Keep lazily-initialized Changelog and Manifest log on the Repo object...
r48773 self.changelog.get_or_init(self)
}
Simon Sapin
rust: Return HgError instead of RevlogError in revlog constructors...
r48777 pub fn changelog_mut(&self) -> Result<RefMut<Changelog>, HgError> {
Simon Sapin
rust: Keep lazily-initialized Changelog and Manifest log on the Repo object...
r48773 self.changelog.get_mut_or_init(self)
}
Simon Sapin
rust: Return HgError instead of RevlogError in revlog constructors...
r48777 pub fn manifestlog(&self) -> Result<Ref<Manifestlog>, HgError> {
Simon Sapin
rust: Keep lazily-initialized Changelog and Manifest log on the Repo object...
r48773 self.manifestlog.get_or_init(self)
}
Simon Sapin
rust: Return HgError instead of RevlogError in revlog constructors...
r48777 pub fn manifestlog_mut(&self) -> Result<RefMut<Manifestlog>, HgError> {
Simon Sapin
rust: Keep lazily-initialized Changelog and Manifest log on the Repo object...
r48773 self.manifestlog.get_mut_or_init(self)
}
Simon Sapin
rust: Add Repo::manifest(revision)...
r48774
Simon Sapin
rust: Rename get_node methods to data_for_node, get_rev to data_for_rev...
r48783 /// Returns the manifest of the *changeset* with the given node ID
Simon Sapin
rhg: Reuse manifest when checking status of multiple ambiguous files...
r48778 pub fn manifest_for_node(
&self,
node: impl Into<NodePrefix>,
) -> Result<Manifest, RevlogError> {
Simon Sapin
rust: Rename get_node methods to data_for_node, get_rev to data_for_rev...
r48783 self.manifestlog()?.data_for_node(
Simon Sapin
rhg: Reuse manifest when checking status of multiple ambiguous files...
r48778 self.changelog()?
Simon Sapin
rust: Rename get_node methods to data_for_node, get_rev to data_for_rev...
r48783 .data_for_node(node.into())?
Simon Sapin
rhg: Reuse manifest when checking status of multiple ambiguous files...
r48778 .manifest_node()?
.into(),
)
}
Simon Sapin
rust: Rename get_node methods to data_for_node, get_rev to data_for_rev...
r48783 /// Returns the manifest of the *changeset* with the given revision number
Simon Sapin
rhg: Reuse manifest when checking status of multiple ambiguous files...
r48778 pub fn manifest_for_rev(
Simon Sapin
rust: Add Repo::manifest(revision)...
r48774 &self,
revision: Revision,
) -> Result<Manifest, RevlogError> {
Simon Sapin
rust: Rename get_node methods to data_for_node, get_rev to data_for_rev...
r48783 self.manifestlog()?.data_for_node(
self.changelog()?
.data_for_rev(revision)?
.manifest_node()?
.into(),
Simon Sapin
rhg: Reuse manifest when checking status of multiple ambiguous files...
r48778 )
Simon Sapin
rust: Add Repo::manifest(revision)...
r48774 }
Simon Sapin
rust: Add a Filelog struct that wraps Revlog...
r48775
Simon Sapin
rust: Return HgError instead of RevlogError in revlog constructors...
r48777 pub fn filelog(&self, path: &HgPath) -> Result<Filelog, HgError> {
Simon Sapin
rust: Add a Filelog struct that wraps Revlog...
r48775 Filelog::open(self, path)
}
Simon Sapin
rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct...
r48772 }
/// Lazily-initialized component of `Repo` with interior mutability
///
/// This differs from `OnceCell` in that the value can still be "deinitialized"
/// later by setting its inner `Option` to `None`.
struct LazyCell<T, E> {
value: RefCell<Option<T>>,
// `Fn`s that don’t capture environment are zero-size, so this box does
// not allocate:
init: Box<dyn Fn(&Repo) -> Result<T, E>>,
}
impl<T, E> LazyCell<T, E> {
fn new(init: impl Fn(&Repo) -> Result<T, E> + 'static) -> Self {
Self {
value: RefCell::new(None),
init: Box::new(init),
}
}
fn get_or_init(&self, repo: &Repo) -> Result<Ref<T>, E> {
let mut borrowed = self.value.borrow();
Simon Sapin
rust: Add Repo::dirstate_map and use it in `rhg status`...
r48768 if borrowed.is_none() {
drop(borrowed);
// Only use `borrow_mut` if it is really needed to avoid panic in
// case there is another outstanding borrow but mutation is not
// needed.
Simon Sapin
rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct...
r48772 *self.value.borrow_mut() = Some((self.init)(repo)?);
borrowed = self.value.borrow()
Simon Sapin
rust: Add Repo::dirstate_map and use it in `rhg status`...
r48768 }
Ok(Ref::map(borrowed, |option| option.as_ref().unwrap()))
}
Simon Sapin
rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct...
r48772 pub fn get_mut_or_init(&self, repo: &Repo) -> Result<RefMut<T>, E> {
let mut borrowed = self.value.borrow_mut();
Simon Sapin
rust: Add Repo::dirstate_map and use it in `rhg status`...
r48768 if borrowed.is_none() {
Simon Sapin
rust: Move lazy initialization of `Repo::dirstate_map` into a generic struct...
r48772 *borrowed = Some((self.init)(repo)?);
Simon Sapin
rust: Add Repo::dirstate_map and use it in `rhg status`...
r48768 }
Ok(RefMut::map(borrowed, |option| option.as_mut().unwrap()))
}
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 }