##// END OF EJS Templates
tagcache: distinguish between invalid and missing entries...
tagcache: distinguish between invalid and missing entries The TortoiseHg repo has typically not had a newly applied tag accessible by name for recent releases, for unknown reasons. Deleting and rebuilding the tag cache doesn't fix it, though deleting the cache and running `hg log -r $new_tag` does. Eventually the situation does sort itself out for new clones from the server. In an effort to figure out what the issue is, Pierre-Yves David suggested listing these entries in the debug output more specifically. This isn't complete yet- the second test change that says "missing" is more like "invalid", since it was truncated. The problem there is the code that reads the raw array truncates any partial records and then fills it with 0xFF, which signifies that it is missing. As a side note, that means the check for the length when validating an existing entry never fails. Differential Revision: https://phab.mercurial-scm.org/D9811

File last commit:

r47233:fb0ad038 default
r47245:5aac1a1a default
Show More
repo.rs
216 lines | 7.0 KiB | application/rls-services+xml | RustLexer
Simon Sapin
rhg: Parse per-repository configuration...
r47215 use crate::config::{Config, ConfigError, ConfigParseError};
Simon Sapin
rust: use HgError in RevlogError and Vfs...
r47172 use crate::errors::{HgError, IoResultExt};
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 use crate::requirements;
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
rust: Fold find_root and check_requirements into Repo::find...
r47175 current_directory: PathBuf,
},
#[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)]
pub(crate) struct Vfs<'a> {
base: &'a Path,
}
impl Repo {
Simon Sapin
rust: Fold find_root and check_requirements into Repo::find...
r47175 /// Search the current directory and its ancestores for a repository:
/// a working directory that contains a `.hg` sub-directory.
Simon Sapin
rhg: Parse per-repository configuration...
r47215 pub fn find(config: &Config) -> Result<Self, RepoError> {
Simon Sapin
rust: Fold find_root and check_requirements into Repo::find...
r47175 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: initial support for shared repositories...
r47190 if ancestor.join(".hg").is_dir() {
Simon Sapin
rhg: Abort based on config on share-safe mismatch...
r47214 return Ok(Self::new_at_path(ancestor.to_owned(), config)?);
Simon Sapin
rust: Fold find_root and check_requirements into Repo::find...
r47175 }
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 }
Simon Sapin
rhg: Parse per-repository configuration...
r47215 Err(RepoError::NotFound { 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");
Simon Sapin
rhg: add support for share-safe...
r47191 if share_safe {
reqs.extend(requirements::load(Vfs { base: &store_path })?);
}
Simon Sapin
rhg: initial support for shared repositories...
r47190 } 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: 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`).
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<'_> {
Simon Sapin
rust: Fold find_root and check_requirements into Repo::find...
r47175 pub(crate) fn join(&self, relative_path: impl AsRef<Path>) -> PathBuf {
self.base.join(relative_path)
}
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 pub(crate) fn read(
&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: use HgError in RevlogError and Vfs...
r47172 std::fs::read(&path).for_file(&path)
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 }
pub(crate) fn mmap_open(
&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);
let file = std::fs::File::open(&path).for_file(&path)?;
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 // TODO: what are the safety requirements here?
Simon Sapin
rust: use HgError in RevlogError and Vfs...
r47172 let mmap = unsafe { MmapOptions::new().map(&file) }.for_file(&path)?;
Simon Sapin
rust: introduce Repo and Vfs types for filesystem abstraction...
r46782 Ok(mmap)
}
}