rhg: Abort based on config on share-safe mismatch
authorSimon Sapin <simon.sapin@octobus.net>
Thu, 04 Feb 2021 14:29:47 +0100
changeset 46485 f031fe1c6ede
parent 46484 a6e4e4650bac
child 46486 d7685105e504
rhg: Abort based on config on share-safe mismatch Differential Revision: https://phab.mercurial-scm.org/D9963
rust/hg-core/src/errors.rs
rust/hg-core/src/repo.rs
--- a/rust/hg-core/src/errors.rs	Thu Feb 04 13:17:55 2021 +0100
+++ b/rust/hg-core/src/errors.rs	Thu Feb 04 14:29:47 2021 +0100
@@ -8,7 +8,9 @@
         context: IoErrorContext,
     },
 
-    /// A file under `.hg/` normally only written by Mercurial
+    /// A file under `.hg/` normally only written by Mercurial is not in the
+    /// expected format. This indicates a bug in Mercurial, filesystem
+    /// corruption, or hardware failure.
     ///
     /// The given string is a short explanation for users, not intended to be
     /// machine-readable.
@@ -21,6 +23,12 @@
     /// The given string is a short explanation for users, not intended to be
     /// machine-readable.
     UnsupportedFeature(String),
+
+    /// Operation cannot proceed for some other reason.
+    ///
+    /// The given string is a short explanation for users, not intended to be
+    /// machine-readable.
+    Abort(String),
 }
 
 /// Details about where an I/O error happened
@@ -46,6 +54,9 @@
     pub fn unsupported(explanation: impl Into<String>) -> Self {
         HgError::UnsupportedFeature(explanation.into())
     }
+    pub fn abort(explanation: impl Into<String>) -> Self {
+        HgError::Abort(explanation.into())
+    }
 }
 
 // TODO: use `DisplayBytes` instead to show non-Unicode filenames losslessly?
@@ -61,6 +72,7 @@
             HgError::UnsupportedFeature(explanation) => {
                 write!(f, "unsupported feature: {}", explanation)
             }
+            HgError::Abort(explanation) => explanation.fmt(f),
         }
     }
 }
--- a/rust/hg-core/src/repo.rs	Thu Feb 04 13:17:55 2021 +0100
+++ b/rust/hg-core/src/repo.rs	Thu Feb 04 14:29:47 2021 +0100
@@ -32,12 +32,12 @@
 impl Repo {
     /// Search the current directory and its ancestores for a repository:
     /// a working directory that contains a `.hg` sub-directory.
-    pub fn find(_config: &Config) -> Result<Self, RepoFindError> {
+    pub fn find(config: &Config) -> Result<Self, RepoFindError> {
         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 Ok(Self::new_at_path(ancestor.to_owned())?);
+                return Ok(Self::new_at_path(ancestor.to_owned(), config)?);
             }
         }
         Err(RepoFindError::NotFoundInCurrentDirectoryOrAncestors {
@@ -46,7 +46,10 @@
     }
 
     /// To be called after checking that `.hg` is a sub-directory
-    fn new_at_path(working_directory: PathBuf) -> Result<Self, HgError> {
+    fn new_at_path(
+        working_directory: PathBuf,
+        config: &Config,
+    ) -> Result<Self, HgError> {
         let dot_hg = working_directory.join(".hg");
 
         let hg_vfs = Vfs { base: &dot_hg };
@@ -95,11 +98,23 @@
                 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"));
+                return Err(match config.get(b"safe-mismatch", b"source-not-safe") {
+                    Some(b"abort") | None => HgError::abort(
+                        "share source does not support share-safe requirement"
+                    ),
+                    _ => HgError::unsupported("share-safe downgrade")
+                });
             } else if source_is_share_safe && !share_safe {
-                return Err(HgError::unsupported("share-safe upgrade"));
+                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"),
+                    },
+                );
             }
         }