changeset 46510:02d3bb972121

rust: replace RequirementsError with HgError Differential Revision: https://phab.mercurial-scm.org/D9896
author Simon Sapin <simon.sapin@octobus.net>
date Wed, 27 Jan 2021 14:59:09 +0100
parents 741e36f472a5
children 43d63979a75e
files rust/hg-core/src/repo.rs rust/hg-core/src/requirements.rs rust/rhg/src/error.rs tests/test-rhg.t
diffstat 4 files changed, 24 insertions(+), 45 deletions(-) [+]
line wrap: on
line diff
--- a/rust/hg-core/src/repo.rs	Wed Jan 27 15:04:51 2021 +0100
+++ b/rust/hg-core/src/repo.rs	Wed Jan 27 14:59:09 2021 +0100
@@ -1,3 +1,4 @@
+use crate::errors::HgError;
 use crate::operations::{find_root, FindRootError};
 use crate::requirements;
 use memmap::{Mmap, MmapOptions};
@@ -33,9 +34,7 @@
         find_root().map(Self::for_path)
     }
 
-    pub fn check_requirements(
-        &self,
-    ) -> Result<(), requirements::RequirementsError> {
+    pub fn check_requirements(&self) -> Result<(), HgError> {
         requirements::check(self)
     }
 
--- a/rust/hg-core/src/requirements.rs	Wed Jan 27 15:04:51 2021 +0100
+++ b/rust/hg-core/src/requirements.rs	Wed Jan 27 14:59:09 2021 +0100
@@ -1,19 +1,7 @@
+use crate::errors::{HgError, HgResultExt, IoResultExt};
 use crate::repo::Repo;
-use std::io;
 
-#[derive(Debug)]
-pub enum RequirementsError {
-    // TODO: include a path?
-    Io(io::Error),
-    /// The `requires` file is corrupted
-    Corrupted,
-    /// The repository requires a feature that we don't support
-    Unsupported {
-        feature: String,
-    },
-}
-
-fn parse(bytes: &[u8]) -> Result<Vec<String>, ()> {
+fn parse(bytes: &[u8]) -> Result<Vec<String>, HgError> {
     // The Python code reading this file uses `str.splitlines`
     // which looks for a number of line separators (even including a couple of
     // non-ASCII ones), but Python code writing it always uses `\n`.
@@ -27,16 +15,21 @@
             if line[0].is_ascii_alphanumeric() && line.is_ascii() {
                 Ok(String::from_utf8(line.into()).unwrap())
             } else {
-                Err(())
+                Err(HgError::corrupted("parse error in 'requires' file"))
             }
         })
         .collect()
 }
 
-pub fn load(repo: &Repo) -> Result<Vec<String>, RequirementsError> {
-    match repo.hg_vfs().read("requires") {
-        Ok(bytes) => parse(&bytes).map_err(|()| RequirementsError::Corrupted),
-
+pub fn load(repo: &Repo) -> Result<Vec<String>, HgError> {
+    if let Some(bytes) = repo
+        .hg_vfs()
+        .read("requires")
+        .for_file("requires".as_ref())
+        .io_not_found_as_none()?
+    {
+        parse(&bytes)
+    } else {
         // Treat a missing file the same as an empty file.
         // From `mercurial/localrepo.py`:
         // > requires file contains a newline-delimited list of
@@ -44,18 +37,19 @@
         // > the repository. This file was introduced in Mercurial 0.9.2,
         // > which means very old repositories may not have one. We assume
         // > a missing file translates to no requirements.
-        Err(error) if error.kind() == std::io::ErrorKind::NotFound => {
-            Ok(Vec::new())
-        }
-
-        Err(error) => Err(RequirementsError::Io(error))?,
+        Ok(Vec::new())
     }
 }
 
-pub fn check(repo: &Repo) -> Result<(), RequirementsError> {
+pub fn check(repo: &Repo) -> Result<(), HgError> {
     for feature in load(repo)? {
         if !SUPPORTED.contains(&&*feature) {
-            return Err(RequirementsError::Unsupported { feature });
+            // TODO: collect and all unknown features and include them in the
+            // error message?
+            return Err(HgError::UnsupportedFeature(format!(
+                "repository requires feature unknown to this Mercurial: {}",
+                feature
+            )));
         }
     }
     Ok(())
--- a/rust/rhg/src/error.rs	Wed Jan 27 15:04:51 2021 +0100
+++ b/rust/rhg/src/error.rs	Wed Jan 27 14:59:09 2021 +0100
@@ -4,7 +4,6 @@
 use format_bytes::format_bytes;
 use hg::errors::HgError;
 use hg::operations::FindRootError;
-use hg::requirements::RequirementsError;
 use hg::revlog::revlog::RevlogError;
 use hg::utils::files::get_bytes_from_path;
 use std::convert::From;
@@ -17,9 +16,6 @@
     RootNotFound(PathBuf),
     /// The current directory cannot be found
     CurrentDirNotFound(std::io::Error),
-    /// `.hg/requires`
-    #[from]
-    RequirementsError(RequirementsError),
     /// The standard output stream cannot be written to
     StdoutError,
     /// The standard error stream cannot be written to
@@ -38,10 +34,6 @@
         match self {
             CommandError::RootNotFound(_) => exitcode::ABORT,
             CommandError::CurrentDirNotFound(_) => exitcode::ABORT,
-            CommandError::RequirementsError(
-                RequirementsError::Unsupported { .. },
-            ) => exitcode::UNIMPLEMENTED_COMMAND,
-            CommandError::RequirementsError(_) => exitcode::ABORT,
             CommandError::StdoutError => exitcode::ABORT,
             CommandError::StderrError => exitcode::ABORT,
             CommandError::Abort(_) => exitcode::ABORT,
@@ -67,15 +59,9 @@
                 b"abort: error getting current working directory: {}\n",
                 e.to_string().as_bytes(),
             )),
-            CommandError::RequirementsError(RequirementsError::Corrupted) => {
-                Some(
-                    "abort: .hg/requires is corrupted\n".as_bytes().to_owned(),
-                )
-            }
             CommandError::Abort(message) => message.to_owned(),
 
-            CommandError::RequirementsError(_)
-            | CommandError::StdoutError
+            CommandError::StdoutError
             | CommandError::StderrError
             | CommandError::Unimplemented
             | CommandError::Other(HgError::UnsupportedFeature(_)) => None,
--- a/tests/test-rhg.t	Wed Jan 27 15:04:51 2021 +0100
+++ b/tests/test-rhg.t	Wed Jan 27 14:59:09 2021 +0100
@@ -163,7 +163,7 @@
 
   $ echo -e '\xFF' >> .hg/requires
   $ rhg debugrequirements
-  abort: .hg/requires is corrupted
+  corrupted repository: parse error in 'requires' file
   [255]
 
 Persistent nodemap