##// END OF EJS Templates
rust: replace RequirementsError with HgError...
Simon Sapin -
r47171:02d3bb97 default
parent child Browse files
Show More
@@ -1,3 +1,4 b''
1 use crate::errors::HgError;
1 use crate::operations::{find_root, FindRootError};
2 use crate::operations::{find_root, FindRootError};
2 use crate::requirements;
3 use crate::requirements;
3 use memmap::{Mmap, MmapOptions};
4 use memmap::{Mmap, MmapOptions};
@@ -33,9 +34,7 b' impl Repo {'
33 find_root().map(Self::for_path)
34 find_root().map(Self::for_path)
34 }
35 }
35
36
36 pub fn check_requirements(
37 pub fn check_requirements(&self) -> Result<(), HgError> {
37 &self,
38 ) -> Result<(), requirements::RequirementsError> {
39 requirements::check(self)
38 requirements::check(self)
40 }
39 }
41
40
@@ -1,19 +1,7 b''
1 use crate::errors::{HgError, HgResultExt, IoResultExt};
1 use crate::repo::Repo;
2 use crate::repo::Repo;
2 use std::io;
3
3
4 #[derive(Debug)]
4 fn parse(bytes: &[u8]) -> Result<Vec<String>, HgError> {
5 pub enum RequirementsError {
6 // TODO: include a path?
7 Io(io::Error),
8 /// The `requires` file is corrupted
9 Corrupted,
10 /// The repository requires a feature that we don't support
11 Unsupported {
12 feature: String,
13 },
14 }
15
16 fn parse(bytes: &[u8]) -> Result<Vec<String>, ()> {
17 // The Python code reading this file uses `str.splitlines`
5 // The Python code reading this file uses `str.splitlines`
18 // which looks for a number of line separators (even including a couple of
6 // which looks for a number of line separators (even including a couple of
19 // non-ASCII ones), but Python code writing it always uses `\n`.
7 // non-ASCII ones), but Python code writing it always uses `\n`.
@@ -27,16 +15,21 b' fn parse(bytes: &[u8]) -> Result<Vec<Str'
27 if line[0].is_ascii_alphanumeric() && line.is_ascii() {
15 if line[0].is_ascii_alphanumeric() && line.is_ascii() {
28 Ok(String::from_utf8(line.into()).unwrap())
16 Ok(String::from_utf8(line.into()).unwrap())
29 } else {
17 } else {
30 Err(())
18 Err(HgError::corrupted("parse error in 'requires' file"))
31 }
19 }
32 })
20 })
33 .collect()
21 .collect()
34 }
22 }
35
23
36 pub fn load(repo: &Repo) -> Result<Vec<String>, RequirementsError> {
24 pub fn load(repo: &Repo) -> Result<Vec<String>, HgError> {
37 match repo.hg_vfs().read("requires") {
25 if let Some(bytes) = repo
38 Ok(bytes) => parse(&bytes).map_err(|()| RequirementsError::Corrupted),
26 .hg_vfs()
39
27 .read("requires")
28 .for_file("requires".as_ref())
29 .io_not_found_as_none()?
30 {
31 parse(&bytes)
32 } else {
40 // Treat a missing file the same as an empty file.
33 // Treat a missing file the same as an empty file.
41 // From `mercurial/localrepo.py`:
34 // From `mercurial/localrepo.py`:
42 // > requires file contains a newline-delimited list of
35 // > requires file contains a newline-delimited list of
@@ -44,18 +37,19 b' pub fn load(repo: &Repo) -> Result<Vec<S'
44 // > the repository. This file was introduced in Mercurial 0.9.2,
37 // > the repository. This file was introduced in Mercurial 0.9.2,
45 // > which means very old repositories may not have one. We assume
38 // > which means very old repositories may not have one. We assume
46 // > a missing file translates to no requirements.
39 // > a missing file translates to no requirements.
47 Err(error) if error.kind() == std::io::ErrorKind::NotFound => {
40 Ok(Vec::new())
48 Ok(Vec::new())
49 }
50
51 Err(error) => Err(RequirementsError::Io(error))?,
52 }
41 }
53 }
42 }
54
43
55 pub fn check(repo: &Repo) -> Result<(), RequirementsError> {
44 pub fn check(repo: &Repo) -> Result<(), HgError> {
56 for feature in load(repo)? {
45 for feature in load(repo)? {
57 if !SUPPORTED.contains(&&*feature) {
46 if !SUPPORTED.contains(&&*feature) {
58 return Err(RequirementsError::Unsupported { feature });
47 // TODO: collect and all unknown features and include them in the
48 // error message?
49 return Err(HgError::UnsupportedFeature(format!(
50 "repository requires feature unknown to this Mercurial: {}",
51 feature
52 )));
59 }
53 }
60 }
54 }
61 Ok(())
55 Ok(())
@@ -4,7 +4,6 b' use crate::ui::UiError;'
4 use format_bytes::format_bytes;
4 use format_bytes::format_bytes;
5 use hg::errors::HgError;
5 use hg::errors::HgError;
6 use hg::operations::FindRootError;
6 use hg::operations::FindRootError;
7 use hg::requirements::RequirementsError;
8 use hg::revlog::revlog::RevlogError;
7 use hg::revlog::revlog::RevlogError;
9 use hg::utils::files::get_bytes_from_path;
8 use hg::utils::files::get_bytes_from_path;
10 use std::convert::From;
9 use std::convert::From;
@@ -17,9 +16,6 b' pub enum CommandError {'
17 RootNotFound(PathBuf),
16 RootNotFound(PathBuf),
18 /// The current directory cannot be found
17 /// The current directory cannot be found
19 CurrentDirNotFound(std::io::Error),
18 CurrentDirNotFound(std::io::Error),
20 /// `.hg/requires`
21 #[from]
22 RequirementsError(RequirementsError),
23 /// The standard output stream cannot be written to
19 /// The standard output stream cannot be written to
24 StdoutError,
20 StdoutError,
25 /// The standard error stream cannot be written to
21 /// The standard error stream cannot be written to
@@ -38,10 +34,6 b' impl CommandError {'
38 match self {
34 match self {
39 CommandError::RootNotFound(_) => exitcode::ABORT,
35 CommandError::RootNotFound(_) => exitcode::ABORT,
40 CommandError::CurrentDirNotFound(_) => exitcode::ABORT,
36 CommandError::CurrentDirNotFound(_) => exitcode::ABORT,
41 CommandError::RequirementsError(
42 RequirementsError::Unsupported { .. },
43 ) => exitcode::UNIMPLEMENTED_COMMAND,
44 CommandError::RequirementsError(_) => exitcode::ABORT,
45 CommandError::StdoutError => exitcode::ABORT,
37 CommandError::StdoutError => exitcode::ABORT,
46 CommandError::StderrError => exitcode::ABORT,
38 CommandError::StderrError => exitcode::ABORT,
47 CommandError::Abort(_) => exitcode::ABORT,
39 CommandError::Abort(_) => exitcode::ABORT,
@@ -67,15 +59,9 b' impl CommandError {'
67 b"abort: error getting current working directory: {}\n",
59 b"abort: error getting current working directory: {}\n",
68 e.to_string().as_bytes(),
60 e.to_string().as_bytes(),
69 )),
61 )),
70 CommandError::RequirementsError(RequirementsError::Corrupted) => {
71 Some(
72 "abort: .hg/requires is corrupted\n".as_bytes().to_owned(),
73 )
74 }
75 CommandError::Abort(message) => message.to_owned(),
62 CommandError::Abort(message) => message.to_owned(),
76
63
77 CommandError::RequirementsError(_)
64 CommandError::StdoutError
78 | CommandError::StdoutError
79 | CommandError::StderrError
65 | CommandError::StderrError
80 | CommandError::Unimplemented
66 | CommandError::Unimplemented
81 | CommandError::Other(HgError::UnsupportedFeature(_)) => None,
67 | CommandError::Other(HgError::UnsupportedFeature(_)) => None,
@@ -163,7 +163,7 b' Requirements'
163
163
164 $ echo -e '\xFF' >> .hg/requires
164 $ echo -e '\xFF' >> .hg/requires
165 $ rhg debugrequirements
165 $ rhg debugrequirements
166 abort: .hg/requires is corrupted
166 corrupted repository: parse error in 'requires' file
167 [255]
167 [255]
168
168
169 Persistent nodemap
169 Persistent nodemap
General Comments 0
You need to be logged in to leave comments. Login now