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>, |
|
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<(), |
|
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:: |
|
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