diff --git a/rust/hg-core/src/repo.rs b/rust/hg-core/src/repo.rs --- a/rust/hg-core/src/repo.rs +++ b/rust/hg-core/src/repo.rs @@ -47,15 +47,34 @@ /// To be called after checking that `.hg` is a sub-directory fn new_at_path(working_directory: PathBuf) -> Result { let dot_hg = working_directory.join(".hg"); + let hg_vfs = Vfs { base: &dot_hg }; - let reqs = requirements::load_if_exists(hg_vfs)?; + let mut reqs = requirements::load_if_exists(hg_vfs)?; let relative = reqs.contains(requirements::RELATIVE_SHARED_REQUIREMENT); let shared = reqs.contains(requirements::SHARED_REQUIREMENT) || relative; + + // 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); + let store_path; if !shared { store_path = dot_hg.join("store"); + if share_safe { + reqs.extend(requirements::load(Vfs { base: &store_path })?); + } } else { let bytes = hg_vfs.read("sharedpath")?; let mut shared_path = get_path_from_bytes(&bytes).to_owned(); @@ -70,6 +89,17 @@ } store_path = shared_path.join("store"); + + let source_is_share_safe = + requirements::load(Vfs { base: &shared_path })? + .contains(requirements::SHARESAFE_REQUIREMENT); + + // TODO: support for `share.safe-mismatch.*` config + if share_safe && !source_is_share_safe { + return Err(HgError::unsupported("share-safe downgrade")); + } else if source_is_share_safe && !share_safe { + return Err(HgError::unsupported("share-safe upgrade")); + } } let repo = Self { diff --git a/rust/hg-core/src/requirements.rs b/rust/hg-core/src/requirements.rs --- a/rust/hg-core/src/requirements.rs +++ b/rust/hg-core/src/requirements.rs @@ -22,6 +22,10 @@ .collect() } +pub(crate) fn load(hg_vfs: Vfs) -> Result, HgError> { + parse(&hg_vfs.read("requires")?) +} + pub(crate) fn load_if_exists(hg_vfs: Vfs) -> Result, HgError> { if let Some(bytes) = hg_vfs.read("requires").io_not_found_as_none()? { parse(&bytes) @@ -58,6 +62,7 @@ "generaldelta", "revlogv1", SHARED_REQUIREMENT, + SHARESAFE_REQUIREMENT, SPARSEREVLOG_REQUIREMENT, RELATIVE_SHARED_REQUIREMENT, "store", @@ -130,4 +135,4 @@ /// store and working copy requirements i.e. both `.hg/requires` and /// `.hg/store/requires` are present. #[allow(unused)] -pub(crate) const SHARESAFE_REQUIREMENT: &str = "exp-sharesafe"; +pub(crate) const SHARESAFE_REQUIREMENT: &str = "share-safe"; diff --git a/tests/test-rhg.t b/tests/test-rhg.t --- a/tests/test-rhg.t +++ b/tests/test-rhg.t @@ -256,7 +256,7 @@ $ cd repo5 $ rhg files - [252] + a $ rhg cat -r 0 a - [252] + a