##// END OF EJS Templates
rust: Remove DirstateParseError and ListDirstateTrackedFilesError...
Simon Sapin -
r47169:776b9717 default
parent child Browse files
Show More
@@ -5,7 +5,8 b''
5 // This software may be used and distributed according to the terms of the
5 // This software may be used and distributed according to the terms of the
6 // GNU General Public License version 2 or any later version.
6 // GNU General Public License version 2 or any later version.
7
7
8 use crate::{utils::hg_path::HgPathBuf, DirstateParseError, FastHashMap};
8 use crate::errors::HgError;
9 use crate::{utils::hg_path::HgPathBuf, FastHashMap};
9 use std::collections::hash_map;
10 use std::collections::hash_map;
10 use std::convert::TryFrom;
11 use std::convert::TryFrom;
11
12
@@ -60,7 +61,7 b' pub enum EntryState {'
60 }
61 }
61
62
62 impl TryFrom<u8> for EntryState {
63 impl TryFrom<u8> for EntryState {
63 type Error = DirstateParseError;
64 type Error = HgError;
64
65
65 fn try_from(value: u8) -> Result<Self, Self::Error> {
66 fn try_from(value: u8) -> Result<Self, Self::Error> {
66 match value {
67 match value {
@@ -69,8 +70,8 b' impl TryFrom<u8> for EntryState {'
69 b'r' => Ok(EntryState::Removed),
70 b'r' => Ok(EntryState::Removed),
70 b'm' => Ok(EntryState::Merged),
71 b'm' => Ok(EntryState::Merged),
71 b'?' => Ok(EntryState::Unknown),
72 b'?' => Ok(EntryState::Unknown),
72 _ => Err(DirstateParseError::CorruptedEntry(format!(
73 _ => Err(HgError::CorruptedRepository(format!(
73 "Incorrect entry state {}",
74 "Incorrect dirstate entry state {}",
74 value
75 value
75 ))),
76 ))),
76 }
77 }
@@ -5,6 +5,7 b''
5 // This software may be used and distributed according to the terms of the
5 // This software may be used and distributed according to the terms of the
6 // GNU General Public License version 2 or any later version.
6 // GNU General Public License version 2 or any later version.
7
7
8 use crate::errors::HgError;
8 use crate::revlog::node::NULL_NODE_ID;
9 use crate::revlog::node::NULL_NODE_ID;
9 use crate::{
10 use crate::{
10 dirstate::{parsers::PARENT_SIZE, EntryState, SIZE_FROM_OTHER_PARENT},
11 dirstate::{parsers::PARENT_SIZE, EntryState, SIZE_FROM_OTHER_PARENT},
@@ -14,7 +15,7 b' use crate::{'
14 hg_path::{HgPath, HgPathBuf},
15 hg_path::{HgPath, HgPathBuf},
15 },
16 },
16 CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateMapError,
17 CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateMapError,
17 DirstateParents, DirstateParseError, FastHashMap, StateMap,
18 DirstateParents, FastHashMap, StateMap,
18 };
19 };
19 use micro_timer::timed;
20 use micro_timer::timed;
20 use std::collections::HashSet;
21 use std::collections::HashSet;
@@ -370,7 +371,9 b' impl DirstateMap {'
370 p2: NULL_NODE_ID,
371 p2: NULL_NODE_ID,
371 };
372 };
372 } else {
373 } else {
373 return Err(DirstateError::Parse(DirstateParseError::Damaged));
374 return Err(
375 HgError::corrupted("Dirstate appears to be damaged").into()
376 );
374 }
377 }
375
378
376 self.parents = Some(parents);
379 self.parents = Some(parents);
@@ -7,7 +7,7 b' use crate::errors::HgError;'
7 use crate::utils::hg_path::HgPath;
7 use crate::utils::hg_path::HgPath;
8 use crate::{
8 use crate::{
9 dirstate::{CopyMap, EntryState, StateMap},
9 dirstate::{CopyMap, EntryState, StateMap},
10 DirstateEntry, DirstateParents, DirstateParseError,
10 DirstateEntry, DirstateParents,
11 };
11 };
12 use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
12 use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
13 use micro_timer::timed;
13 use micro_timer::timed;
@@ -27,11 +27,9 b" type ParseResult<'a> = ("
27 );
27 );
28
28
29 #[timed]
29 #[timed]
30 pub fn parse_dirstate(
30 pub fn parse_dirstate(contents: &[u8]) -> Result<ParseResult, HgError> {
31 contents: &[u8],
32 ) -> Result<ParseResult, DirstateParseError> {
33 if contents.len() < PARENT_SIZE * 2 {
31 if contents.len() < PARENT_SIZE * 2 {
34 return Err(DirstateParseError::TooLittleData);
32 return Err(HgError::corrupted("Too little data for dirstate."));
35 }
33 }
36 let mut copies = vec![];
34 let mut copies = vec![];
37 let mut entries = vec![];
35 let mut entries = vec![];
@@ -44,19 +42,21 b' pub fn parse_dirstate('
44
42
45 while curr_pos < contents.len() {
43 while curr_pos < contents.len() {
46 if curr_pos + MIN_ENTRY_SIZE > contents.len() {
44 if curr_pos + MIN_ENTRY_SIZE > contents.len() {
47 return Err(DirstateParseError::Overflow);
45 return Err(HgError::corrupted("Overflow in dirstate."));
48 }
46 }
49 let entry_bytes = &contents[curr_pos..];
47 let entry_bytes = &contents[curr_pos..];
50
48
51 let mut cursor = Cursor::new(entry_bytes);
49 let mut cursor = Cursor::new(entry_bytes);
52 let state = EntryState::try_from(cursor.read_u8()?)?;
50 // Unwraping errors from `byteorder` as we’ve already checked
53 let mode = cursor.read_i32::<BigEndian>()?;
51 // `MIN_ENTRY_SIZE` so the input should never be too short.
54 let size = cursor.read_i32::<BigEndian>()?;
52 let state = EntryState::try_from(cursor.read_u8().unwrap())?;
55 let mtime = cursor.read_i32::<BigEndian>()?;
53 let mode = cursor.read_i32::<BigEndian>().unwrap();
56 let path_len = cursor.read_i32::<BigEndian>()? as usize;
54 let size = cursor.read_i32::<BigEndian>().unwrap();
55 let mtime = cursor.read_i32::<BigEndian>().unwrap();
56 let path_len = cursor.read_i32::<BigEndian>().unwrap() as usize;
57
57
58 if path_len > contents.len() - curr_pos {
58 if path_len > contents.len() - curr_pos {
59 return Err(DirstateParseError::Overflow);
59 return Err(HgError::corrupted("Overflow in dirstate."));
60 }
60 }
61
61
62 // Slice instead of allocating a Vec needed for `read_exact`
62 // Slice instead of allocating a Vec needed for `read_exact`
@@ -51,33 +51,6 b' pub type LineNumber = usize;'
51 /// write access to your repository, you have other issues.
51 /// write access to your repository, you have other issues.
52 pub type FastHashMap<K, V> = HashMap<K, V, RandomXxHashBuilder64>;
52 pub type FastHashMap<K, V> = HashMap<K, V, RandomXxHashBuilder64>;
53
53
54 #[derive(Clone, Debug, PartialEq)]
55 pub enum DirstateParseError {
56 TooLittleData,
57 Overflow,
58 // TODO refactor to use bytes instead of String
59 CorruptedEntry(String),
60 Damaged,
61 }
62
63 impl From<std::io::Error> for DirstateParseError {
64 fn from(e: std::io::Error) -> Self {
65 DirstateParseError::CorruptedEntry(e.to_string())
66 }
67 }
68
69 impl ToString for DirstateParseError {
70 fn to_string(&self) -> String {
71 use crate::DirstateParseError::*;
72 match self {
73 TooLittleData => "Too little data for dirstate.".to_string(),
74 Overflow => "Overflow in dirstate.".to_string(),
75 CorruptedEntry(e) => format!("Corrupted entry: {:?}.", e),
76 Damaged => "Dirstate appears to be damaged.".to_string(),
77 }
78 }
79 }
80
81 #[derive(Debug, PartialEq)]
54 #[derive(Debug, PartialEq)]
82 pub enum DirstateMapError {
55 pub enum DirstateMapError {
83 PathNotFound(HgPathBuf),
56 PathNotFound(HgPathBuf),
@@ -99,9 +72,7 b' impl ToString for DirstateMapError {'
99
72
100 #[derive(Debug, derive_more::From)]
73 #[derive(Debug, derive_more::From)]
101 pub enum DirstateError {
74 pub enum DirstateError {
102 Parse(DirstateParseError),
103 Map(DirstateMapError),
75 Map(DirstateMapError),
104 IO(std::io::Error),
105 Common(errors::HgError),
76 Common(errors::HgError),
106 }
77 }
107
78
@@ -6,24 +6,16 b''
6 // GNU General Public License version 2 or any later version.
6 // GNU General Public License version 2 or any later version.
7
7
8 use crate::dirstate::parsers::parse_dirstate;
8 use crate::dirstate::parsers::parse_dirstate;
9 use crate::errors::{HgError, IoResultExt};
9 use crate::repo::Repo;
10 use crate::repo::Repo;
10 use crate::revlog::changelog::Changelog;
11 use crate::revlog::changelog::Changelog;
11 use crate::revlog::manifest::{Manifest, ManifestEntry};
12 use crate::revlog::manifest::{Manifest, ManifestEntry};
12 use crate::revlog::node::Node;
13 use crate::revlog::node::Node;
13 use crate::revlog::revlog::RevlogError;
14 use crate::revlog::revlog::RevlogError;
14 use crate::utils::hg_path::HgPath;
15 use crate::utils::hg_path::HgPath;
15 use crate::{DirstateParseError, EntryState};
16 use crate::EntryState;
16 use rayon::prelude::*;
17 use rayon::prelude::*;
17
18
18 /// Error type for `Dirstate` methods
19 #[derive(Debug, derive_more::From)]
20 pub enum ListDirstateTrackedFilesError {
21 /// Error when reading the `dirstate` file
22 IoError(std::io::Error),
23 /// Error when parsing the `dirstate` file
24 ParseError(DirstateParseError),
25 }
26
27 /// List files under Mercurial control in the working directory
19 /// List files under Mercurial control in the working directory
28 /// by reading the dirstate
20 /// by reading the dirstate
29 pub struct Dirstate {
21 pub struct Dirstate {
@@ -32,16 +24,18 b' pub struct Dirstate {'
32 }
24 }
33
25
34 impl Dirstate {
26 impl Dirstate {
35 pub fn new(repo: &Repo) -> Result<Self, ListDirstateTrackedFilesError> {
27 pub fn new(repo: &Repo) -> Result<Self, HgError> {
36 let content = repo.hg_vfs().read("dirstate")?;
28 let content = repo
29 .hg_vfs()
30 .read("dirstate")
31 // TODO: this will be more accurate when we use `HgError` in
32 // `Vfs::read`.
33 .for_file("dirstate".as_ref())?;
37 Ok(Self { content })
34 Ok(Self { content })
38 }
35 }
39
36
40 pub fn tracked_files(
37 pub fn tracked_files(&self) -> Result<Vec<&HgPath>, HgError> {
41 &self,
38 let (_, entries, _) = parse_dirstate(&self.content)?;
42 ) -> Result<Vec<&HgPath>, ListDirstateTrackedFilesError> {
43 let (_, entries, _) = parse_dirstate(&self.content)
44 .map_err(ListDirstateTrackedFilesError::ParseError)?;
45 let mut files: Vec<&HgPath> = entries
39 let mut files: Vec<&HgPath> = entries
46 .into_iter()
40 .into_iter()
47 .filter_map(|(path, entry)| match entry.state {
41 .filter_map(|(path, entry)| match entry.state {
@@ -10,5 +10,5 b' mod list_tracked_files;'
10 pub use cat::cat;
10 pub use cat::cat;
11 pub use debugdata::{debug_data, DebugDataKind};
11 pub use debugdata::{debug_data, DebugDataKind};
12 pub use find_root::{find_root, find_root_from_path, FindRootError};
12 pub use find_root::{find_root, find_root_from_path, FindRootError};
13 pub use list_tracked_files::Dirstate;
13 pub use list_tracked_files::{list_rev_tracked_files, FilesForRev};
14 pub use list_tracked_files::{list_rev_tracked_files, FilesForRev};
14 pub use list_tracked_files::{Dirstate, ListDirstateTrackedFilesError};
@@ -24,10 +24,7 b' use cpython::{'
24 exc, PyBytes, PyDict, PyErr, PyList, PyModule, PyObject, PyResult,
24 exc, PyBytes, PyDict, PyErr, PyList, PyModule, PyObject, PyResult,
25 PySequence, Python,
25 PySequence, Python,
26 };
26 };
27 use hg::{
27 use hg::{utils::hg_path::HgPathBuf, DirstateEntry, EntryState, StateMap};
28 utils::hg_path::HgPathBuf, DirstateEntry, DirstateParseError, EntryState,
29 StateMap,
30 };
31 use libc::{c_char, c_int};
28 use libc::{c_char, c_int};
32 use std::convert::TryFrom;
29 use std::convert::TryFrom;
33
30
@@ -79,11 +76,10 b' pub fn extract_dirstate(py: Python, dmap'
79 .map(|(filename, stats)| {
76 .map(|(filename, stats)| {
80 let stats = stats.extract::<PySequence>(py)?;
77 let stats = stats.extract::<PySequence>(py)?;
81 let state = stats.get_item(py, 0)?.extract::<PyBytes>(py)?;
78 let state = stats.get_item(py, 0)?.extract::<PyBytes>(py)?;
82 let state = EntryState::try_from(state.data(py)[0]).map_err(
79 let state =
83 |e: DirstateParseError| {
80 EntryState::try_from(state.data(py)[0]).map_err(|e| {
84 PyErr::new::<exc::ValueError, _>(py, e.to_string())
81 PyErr::new::<exc::ValueError, _>(py, e.to_string())
85 },
82 })?;
86 )?;
87 let mode = stats.get_item(py, 1)?.extract(py)?;
83 let mode = stats.get_item(py, 1)?.extract(py)?;
88 let size = stats.get_item(py, 2)?.extract(py)?;
84 let size = stats.get_item(py, 2)?.extract(py)?;
89 let mtime = stats.get_item(py, 3)?.extract(py)?;
85 let mtime = stats.get_item(py, 3)?.extract(py)?;
@@ -18,9 +18,9 b' use cpython::{'
18
18
19 use crate::dirstate::extract_dirstate;
19 use crate::dirstate::extract_dirstate;
20 use hg::{
20 use hg::{
21 errors::HgError,
21 utils::hg_path::{HgPath, HgPathBuf},
22 utils::hg_path::{HgPath, HgPathBuf},
22 DirsMultiset, DirsMultisetIter, DirstateMapError, DirstateParseError,
23 DirsMultiset, DirsMultisetIter, DirstateMapError, EntryState,
23 EntryState,
24 };
24 };
25
25
26 py_class!(pub class Dirs |py| {
26 py_class!(pub class Dirs |py| {
@@ -38,7 +38,7 b' py_class!(pub class Dirs |py| {'
38 skip_state = Some(
38 skip_state = Some(
39 skip.extract::<PyBytes>(py)?.data(py)[0]
39 skip.extract::<PyBytes>(py)?.data(py)[0]
40 .try_into()
40 .try_into()
41 .map_err(|e: DirstateParseError| {
41 .map_err(|e: HgError| {
42 PyErr::new::<exc::ValueError, _>(py, e.to_string())
42 PyErr::new::<exc::ValueError, _>(py, e.to_string())
43 })?,
43 })?,
44 );
44 );
@@ -46,7 +46,7 b' py_class!(pub class Dirs |py| {'
46 let inner = if let Ok(map) = map.cast_as::<PyDict>(py) {
46 let inner = if let Ok(map) = map.cast_as::<PyDict>(py) {
47 let dirstate = extract_dirstate(py, &map)?;
47 let dirstate = extract_dirstate(py, &map)?;
48 DirsMultiset::from_dirstate(&dirstate, skip_state)
48 DirsMultiset::from_dirstate(&dirstate, skip_state)
49 .map_err(|e| {
49 .map_err(|e: DirstateMapError| {
50 PyErr::new::<exc::ValueError, _>(py, e.to_string())
50 PyErr::new::<exc::ValueError, _>(py, e.to_string())
51 })?
51 })?
52 } else {
52 } else {
@@ -26,10 +26,10 b' use crate::{'
26 dirstate::{dirs_multiset::Dirs, make_dirstate_tuple},
26 dirstate::{dirs_multiset::Dirs, make_dirstate_tuple},
27 };
27 };
28 use hg::{
28 use hg::{
29 errors::HgError,
29 utils::hg_path::{HgPath, HgPathBuf},
30 utils::hg_path::{HgPath, HgPathBuf},
30 DirsMultiset, DirstateEntry, DirstateMap as RustDirstateMap,
31 DirsMultiset, DirstateEntry, DirstateMap as RustDirstateMap,
31 DirstateMapError, DirstateParents, DirstateParseError, EntryState,
32 DirstateMapError, DirstateParents, EntryState, StateMapIter, PARENT_SIZE,
32 StateMapIter, PARENT_SIZE,
33 };
33 };
34
34
35 // TODO
35 // TODO
@@ -84,13 +84,13 b' py_class!(pub class DirstateMap |py| {'
84 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
84 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
85 oldstate.extract::<PyBytes>(py)?.data(py)[0]
85 oldstate.extract::<PyBytes>(py)?.data(py)[0]
86 .try_into()
86 .try_into()
87 .map_err(|e: DirstateParseError| {
87 .map_err(|e: HgError| {
88 PyErr::new::<exc::ValueError, _>(py, e.to_string())
88 PyErr::new::<exc::ValueError, _>(py, e.to_string())
89 })?,
89 })?,
90 DirstateEntry {
90 DirstateEntry {
91 state: state.extract::<PyBytes>(py)?.data(py)[0]
91 state: state.extract::<PyBytes>(py)?.data(py)[0]
92 .try_into()
92 .try_into()
93 .map_err(|e: DirstateParseError| {
93 .map_err(|e: HgError| {
94 PyErr::new::<exc::ValueError, _>(py, e.to_string())
94 PyErr::new::<exc::ValueError, _>(py, e.to_string())
95 })?,
95 })?,
96 mode: mode.extract(py)?,
96 mode: mode.extract(py)?,
@@ -113,7 +113,7 b' py_class!(pub class DirstateMap |py| {'
113 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
113 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
114 oldstate.extract::<PyBytes>(py)?.data(py)[0]
114 oldstate.extract::<PyBytes>(py)?.data(py)[0]
115 .try_into()
115 .try_into()
116 .map_err(|e: DirstateParseError| {
116 .map_err(|e: HgError| {
117 PyErr::new::<exc::ValueError, _>(py, e.to_string())
117 PyErr::new::<exc::ValueError, _>(py, e.to_string())
118 })?,
118 })?,
119 size.extract(py)?,
119 size.extract(py)?,
@@ -137,7 +137,7 b' py_class!(pub class DirstateMap |py| {'
137 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
137 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
138 oldstate.extract::<PyBytes>(py)?.data(py)[0]
138 oldstate.extract::<PyBytes>(py)?.data(py)[0]
139 .try_into()
139 .try_into()
140 .map_err(|e: DirstateParseError| {
140 .map_err(|e: HgError| {
141 PyErr::new::<exc::ValueError, _>(py, e.to_string())
141 PyErr::new::<exc::ValueError, _>(py, e.to_string())
142 })?,
142 })?,
143 )
143 )
@@ -15,7 +15,7 b' use cpython::{'
15 };
15 };
16 use hg::{
16 use hg::{
17 pack_dirstate, parse_dirstate, utils::hg_path::HgPathBuf, DirstateEntry,
17 pack_dirstate, parse_dirstate, utils::hg_path::HgPathBuf, DirstateEntry,
18 DirstateParents, DirstateParseError, FastHashMap, PARENT_SIZE,
18 DirstateParents, FastHashMap, PARENT_SIZE,
19 };
19 };
20 use std::convert::TryInto;
20 use std::convert::TryInto;
21
21
@@ -58,21 +58,7 b' fn parse_dirstate_wrapper('
58 .to_py_object(py),
58 .to_py_object(py),
59 )
59 )
60 }
60 }
61 Err(e) => Err(PyErr::new::<exc::ValueError, _>(
61 Err(e) => Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())),
62 py,
63 match e {
64 DirstateParseError::TooLittleData => {
65 "too little data for parents".to_string()
66 }
67 DirstateParseError::Overflow => {
68 "overflow in dirstate".to_string()
69 }
70 DirstateParseError::CorruptedEntry(e) => e,
71 DirstateParseError::Damaged => {
72 "dirstate appears to be damaged".to_string()
73 }
74 },
75 )),
76 }
62 }
77 }
63 }
78
64
@@ -2,7 +2,8 b' use crate::exitcode;'
2 use crate::ui::utf8_to_local;
2 use crate::ui::utf8_to_local;
3 use crate::ui::UiError;
3 use crate::ui::UiError;
4 use format_bytes::format_bytes;
4 use format_bytes::format_bytes;
5 use hg::operations::{FindRootError, ListDirstateTrackedFilesError};
5 use hg::errors::HgError;
6 use hg::operations::FindRootError;
6 use hg::requirements::RequirementsError;
7 use hg::requirements::RequirementsError;
7 use hg::revlog::revlog::RevlogError;
8 use hg::revlog::revlog::RevlogError;
8 use hg::utils::files::get_bytes_from_path;
9 use hg::utils::files::get_bytes_from_path;
@@ -27,6 +28,9 b' pub enum CommandError {'
27 Abort(Option<Vec<u8>>),
28 Abort(Option<Vec<u8>>),
28 /// A mercurial capability as not been implemented.
29 /// A mercurial capability as not been implemented.
29 Unimplemented,
30 Unimplemented,
31 /// Common cases
32 #[from]
33 Other(HgError),
30 }
34 }
31
35
32 impl CommandError {
36 impl CommandError {
@@ -42,6 +46,10 b' impl CommandError {'
42 CommandError::StderrError => exitcode::ABORT,
46 CommandError::StderrError => exitcode::ABORT,
43 CommandError::Abort(_) => exitcode::ABORT,
47 CommandError::Abort(_) => exitcode::ABORT,
44 CommandError::Unimplemented => exitcode::UNIMPLEMENTED_COMMAND,
48 CommandError::Unimplemented => exitcode::UNIMPLEMENTED_COMMAND,
49 CommandError::Other(HgError::UnsupportedFeature(_)) => {
50 exitcode::UNIMPLEMENTED_COMMAND
51 }
52 CommandError::Other(_) => exitcode::ABORT,
45 }
53 }
46 }
54 }
47
55
@@ -141,21 +149,3 b' impl From<(RevlogError, &str)> for Comma'
141 }
149 }
142 }
150 }
143 }
151 }
144
145 impl From<ListDirstateTrackedFilesError> for CommandError {
146 fn from(err: ListDirstateTrackedFilesError) -> Self {
147 match err {
148 ListDirstateTrackedFilesError::IoError(err) => {
149 CommandError::Abort(Some(
150 utf8_to_local(&format!("abort: {}\n", err)).into(),
151 ))
152 }
153 ListDirstateTrackedFilesError::ParseError(_) => {
154 CommandError::Abort(Some(
155 // TODO find a better error message
156 b"abort: parse error\n".to_vec(),
157 ))
158 }
159 }
160 }
161 }
General Comments 0
You need to be logged in to leave comments. Login now