##// END OF EJS Templates
commit: reorder if-else conditional to give mergestate info priority...
commit: reorder if-else conditional to give mergestate info priority Looking at the code now, I was unable to find a good reason as why we only rely on mergestate extras info after checking whether a filelog parent is ancestor of other or not. I mean if we have stored in mergestate that `other` was chosed, we should blindly pick that one. This cleanup will also help introduce more cases when both `fparent1` and `fparent2` are non-null but using info from mergestate, we can fastpath. Differential Revision: https://phab.mercurial-scm.org/D10116

File last commit:

r47357:f64b6953 default
r47403:39be29fa default
Show More
repo.rs
263 lines | 8.5 KiB | application/rls-services+xml | RustLexer
Simon Sapin
rhg: Parse per-repository configuration...
r47215 use crate::config::{Config, ConfigError, ConfigParseError};
Simon Sapin
rust: Add a log file rotation utility...
r47341 use crate::errors::{HgError, IoErrorContext, IoResultExt};
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 use crate::requirements;
Simon Sapin
rhg: Add support for -R and --repository command-line arguments...
r47253 use crate::utils::current_dir;
Simon Sapin
rhg: initial support for shared repositories...
r47190 use crate::utils::files::get_path_from_bytes;
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 use memmap::{Mmap, MmapOptions};
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: 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 /// Filesystem access abstraction for the contents of a given "base" diretory
#[derive(Clone, Copy)]
Simon Sapin
rust: Add a log file rotation utility...
r47341 pub struct Vfs<'a> {
pub(crate) base: &'a Path,
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 }
impl Repo {
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,
explicit_path: Option<&Path>,
) -> Result<Self, RepoError> {
if let Some(root) = explicit_path {
// Having an absolute path isn’t necessary here but can help code
// elsewhere
let root = current_dir()?.join(root);
if root.join(".hg").is_dir() {
Self::new_at_path(root, config)
} 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 {
let current_directory = crate::utils::current_dir()?;
// ancestors() is inclusive: it first yields `current_directory`
// as-is.
for ancestor in current_directory.ancestors() {
if ancestor.join(".hg").is_dir() {
return Self::new_at_path(ancestor.to_owned(), config);
}
}
Err(RepoError::NotFound {
at: current_directory,
})
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")?;
let mut shared_path = get_path_from_bytes(&bytes).to_owned();
if relative {
shared_path = dot_hg.join(shared_path)
}
if !shared_path.is_dir() {
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
.get(b"safe-mismatch", b"source-not-safe")
{
Simon Sapin
rhg: Abort based on config on share-safe mismatch...
r47214 Some(b"abort") | None => HgError::abort(
Simon Sapin
rhg: Parse per-repository configuration...
r47215 "share source does not support share-safe requirement",
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(
match config.get(b"safe-mismatch", b"source-safe") {
Some(b"abort") | None => HgError::abort(
"version mismatch: source uses share-safe \
functionality while the current share does not",
),
_ => 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: Parse per-repository configuration...
r47215 let repo_config = config.combine_with_repo(&repo_config_files)?;
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
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
// The undescore prefix silences the "never used" warning. Remove before
// using.
Simon Sapin
rust: Add a log file rotation utility...
r47341 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
pub fn dirstate_parents(
&self,
) -> Result<crate::dirstate::DirstateParents, HgError> {
let dirstate = self.hg_vfs().mmap_open("dirstate")?;
let parents =
crate::dirstate::parsers::parse_dirstate_parents(&dirstate)?;
Ok(parents.clone())
}
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 }
impl Vfs<'_> {
Simon Sapin
rust: Add a log file rotation utility...
r47341 pub fn join(&self, relative_path: impl AsRef<Path>) -> PathBuf {
Simon Sapin
rust: Fold find_root and check_requirements into Repo::find...
r47175 self.base.join(relative_path)
}
Simon Sapin
rust: Add a log file rotation utility...
r47341 pub fn read(
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 &self,
relative_path: impl AsRef<Path>,
Simon Sapin
rust: use HgError in RevlogError and Vfs...
r47172 ) -> Result<Vec<u8>, HgError> {
Simon Sapin
rust: Fold find_root and check_requirements into Repo::find...
r47175 let path = self.join(relative_path);
Simon Sapin
rust: Add a log file rotation utility...
r47341 std::fs::read(&path).when_reading_file(&path)
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 }
Simon Sapin
rust: Add a log file rotation utility...
r47341 pub fn mmap_open(
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 &self,
relative_path: impl AsRef<Path>,
Simon Sapin
rust: use HgError in RevlogError and Vfs...
r47172 ) -> Result<Mmap, HgError> {
let path = self.base.join(relative_path);
Simon Sapin
rust: Add a log file rotation utility...
r47341 let file = std::fs::File::open(&path).when_reading_file(&path)?;
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 // TODO: what are the safety requirements here?
Simon Sapin
rust: Add a log file rotation utility...
r47341 let mmap = unsafe { MmapOptions::new().map(&file) }
.when_reading_file(&path)?;
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 Ok(mmap)
}
Simon Sapin
rust: Add a log file rotation utility...
r47341
pub fn rename(
&self,
relative_from: impl AsRef<Path>,
relative_to: impl AsRef<Path>,
) -> Result<(), HgError> {
let from = self.join(relative_from);
let to = self.join(relative_to);
std::fs::rename(&from, &to)
.with_context(|| IoErrorContext::RenamingFile { from, to })
}
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 }