rhg: add support for share-safe
authorSimon Sapin <simon.sapin@octobus.net>
Mon, 01 Feb 2021 11:41:10 +0100
changeset 46463 95b276283b67
parent 46462 d03b0601e0eb
child 46465 0e2becd1fe0c
rhg: add support for share-safe Differential Revision: https://phab.mercurial-scm.org/D9942
rust/hg-core/src/repo.rs
rust/hg-core/src/requirements.rs
tests/test-rhg.t
--- a/rust/hg-core/src/repo.rs	Thu Jan 14 13:04:12 2021 +0100
+++ b/rust/hg-core/src/repo.rs	Mon Feb 01 11:41:10 2021 +0100
@@ -47,15 +47,34 @@
     /// To be called after checking that `.hg` is a sub-directory
     fn new_at_path(working_directory: PathBuf) -> Result<Self, HgError> {
         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 {
--- a/rust/hg-core/src/requirements.rs	Thu Jan 14 13:04:12 2021 +0100
+++ b/rust/hg-core/src/requirements.rs	Mon Feb 01 11:41:10 2021 +0100
@@ -22,6 +22,10 @@
         .collect()
 }
 
+pub(crate) fn load(hg_vfs: Vfs) -> Result<HashSet<String>, HgError> {
+    parse(&hg_vfs.read("requires")?)
+}
+
 pub(crate) fn load_if_exists(hg_vfs: Vfs) -> Result<HashSet<String>, 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";
--- a/tests/test-rhg.t	Thu Jan 14 13:04:12 2021 +0100
+++ b/tests/test-rhg.t	Mon Feb 01 11:41:10 2021 +0100
@@ -256,7 +256,7 @@
 
   $ cd repo5
   $ rhg files
-  [252]
+  a
   $ rhg cat -r 0 a
-  [252]
+  a