diff --git a/rust/hg-core/src/errors.rs b/rust/hg-core/src/errors.rs --- a/rust/hg-core/src/errors.rs +++ b/rust/hg-core/src/errors.rs @@ -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) -> Self { HgError::UnsupportedFeature(explanation.into()) } + pub fn abort(explanation: impl Into) -> 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), } } } 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 @@ -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 { + pub fn find(config: &Config) -> Result { 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 { + fn new_at_path( + working_directory: PathBuf, + config: &Config, + ) -> Result { 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"), + }, + ); } }