Show More
@@ -1,125 +1,111 b'' | |||
|
1 | 1 | // list_tracked_files.rs |
|
2 | 2 | // |
|
3 | 3 | // Copyright 2020 Antoine Cezar <antoine.cezar@octobus.net> |
|
4 | 4 | // |
|
5 | 5 | // This software may be used and distributed according to the terms of the |
|
6 | 6 | // GNU General Public License version 2 or any later version. |
|
7 | 7 | |
|
8 | 8 | use std::convert::From; |
|
9 | 9 | use std::path::PathBuf; |
|
10 | 10 | |
|
11 | 11 | use crate::repo::Repo; |
|
12 | 12 | use crate::revlog::changelog::Changelog; |
|
13 | 13 | use crate::revlog::manifest::Manifest; |
|
14 | 14 | use crate::revlog::path_encode::path_encode; |
|
15 | 15 | use crate::revlog::revlog::Revlog; |
|
16 | 16 | use crate::revlog::revlog::RevlogError; |
|
17 | 17 | use crate::revlog::Node; |
|
18 | 18 | use crate::utils::files::get_path_from_bytes; |
|
19 | 19 | use crate::utils::hg_path::{HgPath, HgPathBuf}; |
|
20 | 20 | |
|
21 | 21 | const METADATA_DELIMITER: [u8; 2] = [b'\x01', b'\n']; |
|
22 | 22 | |
|
23 | /// Kind of error encountered by `CatRev` | |
|
23 | /// Error type for `cat` | |
|
24 | 24 | #[derive(Debug)] |
|
25 |
pub enum CatRevError |
|
|
25 | pub enum CatRevError { | |
|
26 | 26 | /// Error when reading a `revlog` file. |
|
27 | 27 | IoError(std::io::Error), |
|
28 | 28 | /// The revision has not been found. |
|
29 | 29 | InvalidRevision, |
|
30 | 30 | /// Found more than one revision whose ID match the requested prefix |
|
31 | 31 | AmbiguousPrefix, |
|
32 | 32 | /// A `revlog` file is corrupted. |
|
33 | 33 | CorruptedRevlog, |
|
34 | 34 | /// The `revlog` format version is not supported. |
|
35 | 35 | UnsuportedRevlogVersion(u16), |
|
36 | 36 | /// The `revlog` data format is not supported. |
|
37 | 37 | UnknowRevlogDataFormat(u8), |
|
38 | 38 | } |
|
39 | 39 | |
|
40 | /// A `CatRev` error | |
|
41 | #[derive(Debug)] | |
|
42 | pub struct CatRevError { | |
|
43 | /// Kind of error encountered by `CatRev` | |
|
44 | pub kind: CatRevErrorKind, | |
|
45 | } | |
|
46 | ||
|
47 | impl From<CatRevErrorKind> for CatRevError { | |
|
48 | fn from(kind: CatRevErrorKind) -> Self { | |
|
49 | CatRevError { kind } | |
|
50 | } | |
|
51 | } | |
|
52 | ||
|
53 | 40 | impl From<RevlogError> for CatRevError { |
|
54 | 41 | fn from(err: RevlogError) -> Self { |
|
55 | 42 | match err { |
|
56 |
RevlogError::IoError(err) => CatRevError |
|
|
43 | RevlogError::IoError(err) => CatRevError::IoError(err), | |
|
57 | 44 | RevlogError::UnsuportedVersion(version) => { |
|
58 |
CatRevError |
|
|
45 | CatRevError::UnsuportedRevlogVersion(version) | |
|
59 | 46 | } |
|
60 |
RevlogError::InvalidRevision => CatRevError |
|
|
61 |
RevlogError::AmbiguousPrefix => CatRevError |
|
|
62 |
RevlogError::Corrupted => CatRevError |
|
|
47 | RevlogError::InvalidRevision => CatRevError::InvalidRevision, | |
|
48 | RevlogError::AmbiguousPrefix => CatRevError::AmbiguousPrefix, | |
|
49 | RevlogError::Corrupted => CatRevError::CorruptedRevlog, | |
|
63 | 50 | RevlogError::UnknowDataFormat(format) => { |
|
64 |
CatRevError |
|
|
51 | CatRevError::UnknowRevlogDataFormat(format) | |
|
65 | 52 | } |
|
66 | 53 | } |
|
67 | .into() | |
|
68 | 54 | } |
|
69 | 55 | } |
|
70 | 56 | |
|
71 | 57 | /// List files under Mercurial control at a given revision. |
|
72 | 58 | /// |
|
73 | 59 | /// * `root`: Repository root |
|
74 | 60 | /// * `rev`: The revision to cat the files from. |
|
75 | 61 | /// * `files`: The files to output. |
|
76 | 62 | pub fn cat( |
|
77 | 63 | repo: &Repo, |
|
78 | 64 | revset: &str, |
|
79 | 65 | files: &[HgPathBuf], |
|
80 | 66 | ) -> Result<Vec<u8>, CatRevError> { |
|
81 | 67 | let rev = crate::revset::resolve_single(revset, repo)?; |
|
82 | 68 | let changelog = Changelog::open(repo)?; |
|
83 | 69 | let manifest = Manifest::open(repo)?; |
|
84 | 70 | let changelog_entry = changelog.get_rev(rev)?; |
|
85 | 71 | let manifest_node = Node::from_hex(&changelog_entry.manifest_node()?) |
|
86 |
.map_err(|_| CatRevError |
|
|
72 | .map_err(|_| CatRevError::CorruptedRevlog)?; | |
|
87 | 73 | let manifest_entry = manifest.get_node(manifest_node.into())?; |
|
88 | 74 | let mut bytes = vec![]; |
|
89 | 75 | |
|
90 | 76 | for (manifest_file, node_bytes) in manifest_entry.files_with_nodes() { |
|
91 | 77 | for cat_file in files.iter() { |
|
92 | 78 | if cat_file.as_bytes() == manifest_file.as_bytes() { |
|
93 | 79 | let index_path = store_path(manifest_file, b".i"); |
|
94 | 80 | let data_path = store_path(manifest_file, b".d"); |
|
95 | 81 | |
|
96 | 82 | let file_log = |
|
97 | 83 | Revlog::open(repo, &index_path, Some(&data_path))?; |
|
98 | 84 | let file_node = Node::from_hex(node_bytes) |
|
99 |
.map_err(|_| CatRevError |
|
|
85 | .map_err(|_| CatRevError::CorruptedRevlog)?; | |
|
100 | 86 | let file_rev = file_log.get_node_rev(file_node.into())?; |
|
101 | 87 | let data = file_log.get_rev_data(file_rev)?; |
|
102 | 88 | if data.starts_with(&METADATA_DELIMITER) { |
|
103 | 89 | let end_delimiter_position = data |
|
104 | 90 | [METADATA_DELIMITER.len()..] |
|
105 | 91 | .windows(METADATA_DELIMITER.len()) |
|
106 | 92 | .position(|bytes| bytes == METADATA_DELIMITER); |
|
107 | 93 | if let Some(position) = end_delimiter_position { |
|
108 | 94 | let offset = METADATA_DELIMITER.len() * 2; |
|
109 | 95 | bytes.extend(data[position + offset..].iter()); |
|
110 | 96 | } |
|
111 | 97 | } else { |
|
112 | 98 | bytes.extend(data); |
|
113 | 99 | } |
|
114 | 100 | } |
|
115 | 101 | } |
|
116 | 102 | } |
|
117 | 103 | |
|
118 | 104 | Ok(bytes) |
|
119 | 105 | } |
|
120 | 106 | |
|
121 | 107 | fn store_path(hg_path: &HgPath, suffix: &[u8]) -> PathBuf { |
|
122 | 108 | let encoded_bytes = |
|
123 | 109 | path_encode(&[b"data/", hg_path.as_bytes(), suffix].concat()); |
|
124 | 110 | get_path_from_bytes(&encoded_bytes).into() |
|
125 | 111 | } |
@@ -1,92 +1,73 b'' | |||
|
1 | 1 | // debugdata.rs |
|
2 | 2 | // |
|
3 | 3 | // Copyright 2020 Antoine Cezar <antoine.cezar@octobus.net> |
|
4 | 4 | // |
|
5 | 5 | // This software may be used and distributed according to the terms of the |
|
6 | 6 | // GNU General Public License version 2 or any later version. |
|
7 | 7 | |
|
8 | 8 | use crate::repo::Repo; |
|
9 | 9 | use crate::revlog::revlog::{Revlog, RevlogError}; |
|
10 | 10 | |
|
11 | 11 | /// Kind of data to debug |
|
12 | 12 | #[derive(Debug, Copy, Clone)] |
|
13 | 13 | pub enum DebugDataKind { |
|
14 | 14 | Changelog, |
|
15 | 15 | Manifest, |
|
16 | 16 | } |
|
17 | 17 | |
|
18 | /// Kind of error encountered by DebugData | |
|
18 | /// Error type for `debug_data` | |
|
19 | 19 | #[derive(Debug)] |
|
20 |
pub enum DebugDataError |
|
|
20 | pub enum DebugDataError { | |
|
21 | 21 | /// Error when reading a `revlog` file. |
|
22 | 22 | IoError(std::io::Error), |
|
23 | 23 | /// The revision has not been found. |
|
24 | 24 | InvalidRevision, |
|
25 | 25 | /// Found more than one revision whose ID match the requested prefix |
|
26 | 26 | AmbiguousPrefix, |
|
27 | 27 | /// A `revlog` file is corrupted. |
|
28 | 28 | CorruptedRevlog, |
|
29 | 29 | /// The `revlog` format version is not supported. |
|
30 | 30 | UnsuportedRevlogVersion(u16), |
|
31 | 31 | /// The `revlog` data format is not supported. |
|
32 | 32 | UnknowRevlogDataFormat(u8), |
|
33 | 33 | } |
|
34 | 34 | |
|
35 | /// A DebugData error | |
|
36 | #[derive(Debug)] | |
|
37 | pub struct DebugDataError { | |
|
38 | /// Kind of error encountered by DebugData | |
|
39 | pub kind: DebugDataErrorKind, | |
|
40 | } | |
|
41 | ||
|
42 | impl From<DebugDataErrorKind> for DebugDataError { | |
|
43 | fn from(kind: DebugDataErrorKind) -> Self { | |
|
44 | DebugDataError { kind } | |
|
45 | } | |
|
46 | } | |
|
47 | ||
|
48 | 35 | impl From<std::io::Error> for DebugDataError { |
|
49 | 36 | fn from(err: std::io::Error) -> Self { |
|
50 |
|
|
|
51 | DebugDataError { kind } | |
|
37 | DebugDataError::IoError(err) | |
|
52 | 38 | } |
|
53 | 39 | } |
|
54 | 40 | |
|
55 | 41 | impl From<RevlogError> for DebugDataError { |
|
56 | 42 | fn from(err: RevlogError) -> Self { |
|
57 | 43 | match err { |
|
58 |
RevlogError::IoError(err) => DebugDataError |
|
|
44 | RevlogError::IoError(err) => DebugDataError::IoError(err), | |
|
59 | 45 | RevlogError::UnsuportedVersion(version) => { |
|
60 |
DebugDataError |
|
|
61 | } | |
|
62 | RevlogError::InvalidRevision => { | |
|
63 | DebugDataErrorKind::InvalidRevision | |
|
46 | DebugDataError::UnsuportedRevlogVersion(version) | |
|
64 | 47 | } |
|
65 | RevlogError::AmbiguousPrefix => { | |
|
66 | DebugDataErrorKind::AmbiguousPrefix | |
|
67 | } | |
|
68 | RevlogError::Corrupted => DebugDataErrorKind::CorruptedRevlog, | |
|
48 | RevlogError::InvalidRevision => DebugDataError::InvalidRevision, | |
|
49 | RevlogError::AmbiguousPrefix => DebugDataError::AmbiguousPrefix, | |
|
50 | RevlogError::Corrupted => DebugDataError::CorruptedRevlog, | |
|
69 | 51 | RevlogError::UnknowDataFormat(format) => { |
|
70 |
DebugDataError |
|
|
52 | DebugDataError::UnknowRevlogDataFormat(format) | |
|
71 | 53 | } |
|
72 | 54 | } |
|
73 | .into() | |
|
74 | 55 | } |
|
75 | 56 | } |
|
76 | 57 | |
|
77 | 58 | /// Dump the contents data of a revision. |
|
78 | 59 | pub fn debug_data( |
|
79 | 60 | repo: &Repo, |
|
80 | 61 | revset: &str, |
|
81 | 62 | kind: DebugDataKind, |
|
82 | 63 | ) -> Result<Vec<u8>, DebugDataError> { |
|
83 | 64 | let index_file = match kind { |
|
84 | 65 | DebugDataKind::Changelog => "00changelog.i", |
|
85 | 66 | DebugDataKind::Manifest => "00manifest.i", |
|
86 | 67 | }; |
|
87 | 68 | let revlog = Revlog::open(repo, index_file, None)?; |
|
88 | 69 | let rev = |
|
89 | 70 | crate::revset::resolve_rev_number_or_hex_prefix(revset, &revlog)?; |
|
90 | 71 | let data = revlog.get_rev_data(rev)?; |
|
91 | 72 | Ok(data) |
|
92 | 73 | } |
@@ -1,100 +1,79 b'' | |||
|
1 | use std::fmt; | |
|
2 | 1 |
|
|
3 | 2 | |
|
4 | /// Kind of error encoutered by FindRoot | |
|
3 | /// Error type for `find_root` | |
|
5 | 4 | #[derive(Debug)] |
|
6 |
pub enum FindRootError |
|
|
5 | pub enum FindRootError { | |
|
7 | 6 | /// Root of the repository has not been found |
|
8 | 7 | /// Contains the current directory used by FindRoot |
|
9 | 8 | RootNotFound(PathBuf), |
|
10 | 9 | /// The current directory does not exists or permissions are insufficient |
|
11 | 10 | /// to get access to it |
|
12 | 11 | GetCurrentDirError(std::io::Error), |
|
13 | 12 | } |
|
14 | 13 | |
|
15 | /// A FindRoot error | |
|
16 | #[derive(Debug)] | |
|
17 | pub struct FindRootError { | |
|
18 | /// Kind of error encoutered by FindRoot | |
|
19 | pub kind: FindRootErrorKind, | |
|
20 | } | |
|
21 | ||
|
22 | impl std::error::Error for FindRootError {} | |
|
23 | ||
|
24 | impl fmt::Display for FindRootError { | |
|
25 | fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
|
26 | unimplemented!() | |
|
27 | } | |
|
28 | } | |
|
29 | ||
|
30 | 14 | /// Find the root of the repository |
|
31 | 15 | /// by searching for a .hg directory in the processβ current directory and its |
|
32 | 16 | /// ancestors |
|
33 | 17 | pub fn find_root() -> Result<PathBuf, FindRootError> { |
|
34 |
let current_dir = std::env::current_dir() |
|
|
35 |
|
|
|
36 | })?; | |
|
18 | let current_dir = std::env::current_dir() | |
|
19 | .map_err(|e| FindRootError::GetCurrentDirError(e))?; | |
|
37 | 20 | Ok(find_root_from_path(¤t_dir)?.into()) |
|
38 | 21 | } |
|
39 | 22 | |
|
40 | 23 | /// Find the root of the repository |
|
41 | 24 | /// by searching for a .hg directory in the given directory and its ancestors |
|
42 | 25 | pub fn find_root_from_path(start: &Path) -> Result<&Path, FindRootError> { |
|
43 | 26 | if start.join(".hg").exists() { |
|
44 | 27 | return Ok(start); |
|
45 | 28 | } |
|
46 | 29 | for ancestor in start.ancestors() { |
|
47 | 30 | if ancestor.join(".hg").exists() { |
|
48 | 31 | return Ok(ancestor); |
|
49 | 32 | } |
|
50 | 33 | } |
|
51 | Err(FindRootError { | |
|
52 | kind: FindRootErrorKind::RootNotFound(start.into()), | |
|
53 | }) | |
|
34 | Err(FindRootError::RootNotFound(start.into())) | |
|
54 | 35 | } |
|
55 | 36 | |
|
56 | 37 | #[cfg(test)] |
|
57 | 38 | mod tests { |
|
58 | 39 | use super::*; |
|
59 | 40 | use std::fs; |
|
60 | 41 | use tempfile; |
|
61 | 42 | |
|
62 | 43 | #[test] |
|
63 | 44 | fn dot_hg_not_found() { |
|
64 | 45 | let tmp_dir = tempfile::tempdir().unwrap(); |
|
65 | 46 | let path = tmp_dir.path(); |
|
66 | 47 | |
|
67 | 48 | let err = find_root_from_path(&path).unwrap_err(); |
|
68 | 49 | |
|
69 | 50 | // TODO do something better |
|
70 | 51 | assert!(match err { |
|
71 | FindRootError { kind } => match kind { | |
|
72 | FindRootErrorKind::RootNotFound(p) => p == path.to_path_buf(), | |
|
73 | _ => false, | |
|
74 | }, | |
|
52 | FindRootError::RootNotFound(p) => p == path.to_path_buf(), | |
|
53 | _ => false, | |
|
75 | 54 | }) |
|
76 | 55 | } |
|
77 | 56 | |
|
78 | 57 | #[test] |
|
79 | 58 | fn dot_hg_in_current_path() { |
|
80 | 59 | let tmp_dir = tempfile::tempdir().unwrap(); |
|
81 | 60 | let root = tmp_dir.path(); |
|
82 | 61 | fs::create_dir_all(root.join(".hg")).unwrap(); |
|
83 | 62 | |
|
84 | 63 | let result = find_root_from_path(&root).unwrap(); |
|
85 | 64 | |
|
86 | 65 | assert_eq!(result, root) |
|
87 | 66 | } |
|
88 | 67 | |
|
89 | 68 | #[test] |
|
90 | 69 | fn dot_hg_in_parent() { |
|
91 | 70 | let tmp_dir = tempfile::tempdir().unwrap(); |
|
92 | 71 | let root = tmp_dir.path(); |
|
93 | 72 | fs::create_dir_all(root.join(".hg")).unwrap(); |
|
94 | 73 | |
|
95 | 74 | let directory = root.join("some/nested/directory"); |
|
96 | 75 | let result = find_root_from_path(&directory).unwrap(); |
|
97 | 76 | |
|
98 | 77 | assert_eq!(result, root) |
|
99 | 78 | } |
|
100 | 79 | } /* tests */ |
@@ -1,157 +1,127 b'' | |||
|
1 | 1 | // list_tracked_files.rs |
|
2 | 2 | // |
|
3 | 3 | // Copyright 2020 Antoine Cezar <antoine.cezar@octobus.net> |
|
4 | 4 | // |
|
5 | 5 | // This software may be used and distributed according to the terms of the |
|
6 | 6 | // GNU General Public License version 2 or any later version. |
|
7 | 7 | |
|
8 | 8 | use crate::dirstate::parsers::parse_dirstate; |
|
9 | 9 | use crate::repo::Repo; |
|
10 | 10 | use crate::revlog::changelog::Changelog; |
|
11 | 11 | use crate::revlog::manifest::{Manifest, ManifestEntry}; |
|
12 | 12 | use crate::revlog::node::Node; |
|
13 | 13 | use crate::revlog::revlog::RevlogError; |
|
14 | 14 | use crate::utils::hg_path::HgPath; |
|
15 | 15 | use crate::{DirstateParseError, EntryState}; |
|
16 | 16 | use rayon::prelude::*; |
|
17 | 17 | use std::convert::From; |
|
18 | 18 | |
|
19 | /// Kind of error encountered by `ListDirstateTrackedFiles` | |
|
19 | /// Error type for `Dirstate` methods | |
|
20 | 20 | #[derive(Debug)] |
|
21 |
pub enum ListDirstateTrackedFilesError |
|
|
21 | pub enum ListDirstateTrackedFilesError { | |
|
22 | 22 | /// Error when reading the `dirstate` file |
|
23 | 23 | IoError(std::io::Error), |
|
24 | 24 | /// Error when parsing the `dirstate` file |
|
25 | 25 | ParseError(DirstateParseError), |
|
26 | 26 | } |
|
27 | 27 | |
|
28 | /// A `ListDirstateTrackedFiles` error | |
|
29 | #[derive(Debug)] | |
|
30 | pub struct ListDirstateTrackedFilesError { | |
|
31 | /// Kind of error encountered by `ListDirstateTrackedFiles` | |
|
32 | pub kind: ListDirstateTrackedFilesErrorKind, | |
|
33 | } | |
|
34 | ||
|
35 | impl From<ListDirstateTrackedFilesErrorKind> | |
|
36 | for ListDirstateTrackedFilesError | |
|
37 | { | |
|
38 | fn from(kind: ListDirstateTrackedFilesErrorKind) -> Self { | |
|
39 | ListDirstateTrackedFilesError { kind } | |
|
40 | } | |
|
41 | } | |
|
42 | ||
|
43 | 28 | impl From<std::io::Error> for ListDirstateTrackedFilesError { |
|
44 | 29 | fn from(err: std::io::Error) -> Self { |
|
45 |
|
|
|
46 | ListDirstateTrackedFilesError { kind } | |
|
30 | ListDirstateTrackedFilesError::IoError(err) | |
|
47 | 31 | } |
|
48 | 32 | } |
|
49 | 33 | |
|
50 | 34 | /// List files under Mercurial control in the working directory |
|
51 | 35 | /// by reading the dirstate |
|
52 | 36 | pub struct Dirstate { |
|
53 | 37 | /// The `dirstate` content. |
|
54 | 38 | content: Vec<u8>, |
|
55 | 39 | } |
|
56 | 40 | |
|
57 | 41 | impl Dirstate { |
|
58 | 42 | pub fn new(repo: &Repo) -> Result<Self, ListDirstateTrackedFilesError> { |
|
59 | 43 | let content = repo.hg_vfs().read("dirstate")?; |
|
60 | 44 | Ok(Self { content }) |
|
61 | 45 | } |
|
62 | 46 | |
|
63 | 47 | pub fn tracked_files( |
|
64 | 48 | &self, |
|
65 | 49 | ) -> Result<Vec<&HgPath>, ListDirstateTrackedFilesError> { |
|
66 | 50 | let (_, entries, _) = parse_dirstate(&self.content) |
|
67 |
.map_err(ListDirstateTrackedFilesError |
|
|
51 | .map_err(ListDirstateTrackedFilesError::ParseError)?; | |
|
68 | 52 | let mut files: Vec<&HgPath> = entries |
|
69 | 53 | .into_iter() |
|
70 | 54 | .filter_map(|(path, entry)| match entry.state { |
|
71 | 55 | EntryState::Removed => None, |
|
72 | 56 | _ => Some(path), |
|
73 | 57 | }) |
|
74 | 58 | .collect(); |
|
75 | 59 | files.par_sort_unstable(); |
|
76 | 60 | Ok(files) |
|
77 | 61 | } |
|
78 | 62 | } |
|
79 | 63 | |
|
80 |
/// |
|
|
64 | /// Error type `list_rev_tracked_files` | |
|
81 | 65 | #[derive(Debug)] |
|
82 |
pub enum ListRevTrackedFilesError |
|
|
66 | pub enum ListRevTrackedFilesError { | |
|
83 | 67 | /// Error when reading a `revlog` file. |
|
84 | 68 | IoError(std::io::Error), |
|
85 | 69 | /// The revision has not been found. |
|
86 | 70 | InvalidRevision, |
|
87 | 71 | /// Found more than one revision whose ID match the requested prefix |
|
88 | 72 | AmbiguousPrefix, |
|
89 | 73 | /// A `revlog` file is corrupted. |
|
90 | 74 | CorruptedRevlog, |
|
91 | 75 | /// The `revlog` format version is not supported. |
|
92 | 76 | UnsuportedRevlogVersion(u16), |
|
93 | 77 | /// The `revlog` data format is not supported. |
|
94 | 78 | UnknowRevlogDataFormat(u8), |
|
95 | 79 | } |
|
96 | 80 | |
|
97 | /// A `ListRevTrackedFiles` error | |
|
98 | #[derive(Debug)] | |
|
99 | pub struct ListRevTrackedFilesError { | |
|
100 | /// Kind of error encountered by `ListRevTrackedFiles` | |
|
101 | pub kind: ListRevTrackedFilesErrorKind, | |
|
102 | } | |
|
103 | ||
|
104 | impl From<ListRevTrackedFilesErrorKind> for ListRevTrackedFilesError { | |
|
105 | fn from(kind: ListRevTrackedFilesErrorKind) -> Self { | |
|
106 | ListRevTrackedFilesError { kind } | |
|
107 | } | |
|
108 | } | |
|
109 | ||
|
110 | 81 | impl From<RevlogError> for ListRevTrackedFilesError { |
|
111 | 82 | fn from(err: RevlogError) -> Self { |
|
112 | 83 | match err { |
|
113 | 84 | RevlogError::IoError(err) => { |
|
114 |
ListRevTrackedFilesError |
|
|
85 | ListRevTrackedFilesError::IoError(err) | |
|
115 | 86 | } |
|
116 | 87 | RevlogError::UnsuportedVersion(version) => { |
|
117 |
ListRevTrackedFilesError |
|
|
88 | ListRevTrackedFilesError::UnsuportedRevlogVersion(version) | |
|
118 | 89 | } |
|
119 | 90 | RevlogError::InvalidRevision => { |
|
120 |
ListRevTrackedFilesError |
|
|
91 | ListRevTrackedFilesError::InvalidRevision | |
|
121 | 92 | } |
|
122 | 93 | RevlogError::AmbiguousPrefix => { |
|
123 |
ListRevTrackedFilesError |
|
|
94 | ListRevTrackedFilesError::AmbiguousPrefix | |
|
124 | 95 | } |
|
125 | 96 | RevlogError::Corrupted => { |
|
126 |
ListRevTrackedFilesError |
|
|
97 | ListRevTrackedFilesError::CorruptedRevlog | |
|
127 | 98 | } |
|
128 | 99 | RevlogError::UnknowDataFormat(format) => { |
|
129 |
ListRevTrackedFilesError |
|
|
100 | ListRevTrackedFilesError::UnknowRevlogDataFormat(format) | |
|
130 | 101 | } |
|
131 | 102 | } |
|
132 | .into() | |
|
133 | 103 | } |
|
134 | 104 | } |
|
135 | 105 | |
|
136 | 106 | /// List files under Mercurial control at a given revision. |
|
137 | 107 | pub fn list_rev_tracked_files( |
|
138 | 108 | repo: &Repo, |
|
139 | 109 | revset: &str, |
|
140 | 110 | ) -> Result<FilesForRev, ListRevTrackedFilesError> { |
|
141 | 111 | let rev = crate::revset::resolve_single(revset, repo)?; |
|
142 | 112 | let changelog = Changelog::open(repo)?; |
|
143 | 113 | let manifest = Manifest::open(repo)?; |
|
144 | 114 | let changelog_entry = changelog.get_rev(rev)?; |
|
145 | 115 | let manifest_node = Node::from_hex(&changelog_entry.manifest_node()?) |
|
146 |
.or(Err(ListRevTrackedFilesError |
|
|
116 | .or(Err(ListRevTrackedFilesError::CorruptedRevlog))?; | |
|
147 | 117 | let manifest_entry = manifest.get_node(manifest_node.into())?; |
|
148 | 118 | Ok(FilesForRev(manifest_entry)) |
|
149 | 119 | } |
|
150 | 120 | |
|
151 | 121 | pub struct FilesForRev(ManifestEntry); |
|
152 | 122 | |
|
153 | 123 | impl FilesForRev { |
|
154 | 124 | pub fn iter(&self) -> impl Iterator<Item = &HgPath> { |
|
155 | 125 | self.0.files() |
|
156 | 126 | } |
|
157 | 127 | } |
@@ -1,23 +1,16 b'' | |||
|
1 | 1 | //! A distinction is made between operations and commands. |
|
2 | 2 | //! An operation is what can be done whereas a command is what is exposed by |
|
3 | 3 | //! the cli. A single command can use several operations to achieve its goal. |
|
4 | 4 | |
|
5 | 5 | mod cat; |
|
6 | 6 | mod debugdata; |
|
7 | 7 | mod dirstate_status; |
|
8 | 8 | mod find_root; |
|
9 | 9 | mod list_tracked_files; |
|
10 |
pub use cat::{cat, CatRevError |
|
|
11 | pub use debugdata::{ | |
|
12 | debug_data, DebugDataError, DebugDataErrorKind, DebugDataKind, | |
|
13 | }; | |
|
14 | pub use find_root::{ | |
|
15 | find_root, find_root_from_path, FindRootError, FindRootErrorKind, | |
|
16 | }; | |
|
10 | pub use cat::{cat, CatRevError}; | |
|
11 | pub use debugdata::{debug_data, DebugDataError, DebugDataKind}; | |
|
12 | pub use find_root::{find_root, find_root_from_path, FindRootError}; | |
|
17 | 13 | pub use list_tracked_files::{ |
|
18 | 14 | list_rev_tracked_files, FilesForRev, ListRevTrackedFilesError, |
|
19 | ListRevTrackedFilesErrorKind, | |
|
20 | 15 | }; |
|
21 | pub use list_tracked_files::{ | |
|
22 | Dirstate, ListDirstateTrackedFilesError, ListDirstateTrackedFilesErrorKind, | |
|
23 | }; | |
|
16 | pub use list_tracked_files::{Dirstate, ListDirstateTrackedFilesError}; |
@@ -1,105 +1,103 b'' | |||
|
1 | 1 | use crate::commands::Command; |
|
2 |
use crate::error:: |
|
|
2 | use crate::error::CommandError; | |
|
3 | 3 | use crate::ui::utf8_to_local; |
|
4 | 4 | use crate::ui::Ui; |
|
5 |
use hg::operations::{cat, CatRevError |
|
|
5 | use hg::operations::{cat, CatRevError}; | |
|
6 | 6 | use hg::repo::Repo; |
|
7 | 7 | use hg::utils::hg_path::HgPathBuf; |
|
8 | 8 | use micro_timer::timed; |
|
9 | 9 | use std::convert::TryFrom; |
|
10 | 10 | |
|
11 | 11 | pub const HELP_TEXT: &str = " |
|
12 | 12 | Output the current or given revision of files |
|
13 | 13 | "; |
|
14 | 14 | |
|
15 | 15 | pub struct CatCommand<'a> { |
|
16 | 16 | rev: Option<&'a str>, |
|
17 | 17 | files: Vec<&'a str>, |
|
18 | 18 | } |
|
19 | 19 | |
|
20 | 20 | impl<'a> CatCommand<'a> { |
|
21 | 21 | pub fn new(rev: Option<&'a str>, files: Vec<&'a str>) -> Self { |
|
22 | 22 | Self { rev, files } |
|
23 | 23 | } |
|
24 | 24 | |
|
25 | 25 | fn display(&self, ui: &Ui, data: &[u8]) -> Result<(), CommandError> { |
|
26 | 26 | ui.write_stdout(data)?; |
|
27 | 27 | Ok(()) |
|
28 | 28 | } |
|
29 | 29 | } |
|
30 | 30 | |
|
31 | 31 | impl<'a> Command for CatCommand<'a> { |
|
32 | 32 | #[timed] |
|
33 | 33 | fn run(&self, ui: &Ui) -> Result<(), CommandError> { |
|
34 | 34 | let repo = Repo::find()?; |
|
35 | 35 | repo.check_requirements()?; |
|
36 | 36 | let cwd = std::env::current_dir() |
|
37 |
.or_else(|e| Err(CommandError |
|
|
37 | .or_else(|e| Err(CommandError::CurrentDirNotFound(e)))?; | |
|
38 | 38 | |
|
39 | 39 | let mut files = vec![]; |
|
40 | 40 | for file in self.files.iter() { |
|
41 | 41 | let normalized = cwd.join(&file); |
|
42 | 42 | let stripped = normalized |
|
43 | 43 | .strip_prefix(&repo.working_directory_path()) |
|
44 |
.or(Err(CommandError |
|
|
44 | .or(Err(CommandError::Abort(None)))?; | |
|
45 | 45 | let hg_file = HgPathBuf::try_from(stripped.to_path_buf()) |
|
46 |
.or(Err(CommandError |
|
|
46 | .or(Err(CommandError::Abort(None)))?; | |
|
47 | 47 | files.push(hg_file); |
|
48 | 48 | } |
|
49 | 49 | |
|
50 | 50 | match self.rev { |
|
51 | 51 | Some(rev) => { |
|
52 | 52 | let data = cat(&repo, rev, &files) |
|
53 | 53 | .map_err(|e| map_rev_error(rev, e))?; |
|
54 | 54 | self.display(ui, &data) |
|
55 | 55 | } |
|
56 |
None => Err(CommandError |
|
|
56 | None => Err(CommandError::Unimplemented.into()), | |
|
57 | 57 | } |
|
58 | 58 | } |
|
59 | 59 | } |
|
60 | 60 | |
|
61 |
/// Convert `CatRevError |
|
|
61 | /// Convert `CatRevError` to `CommandError` | |
|
62 | 62 | fn map_rev_error(rev: &str, err: CatRevError) -> CommandError { |
|
63 |
|
|
|
64 | kind: match err.kind { | |
|
65 | CatRevErrorKind::IoError(err) => CommandErrorKind::Abort(Some( | |
|
66 | utf8_to_local(&format!("abort: {}\n", err)).into(), | |
|
67 | )), | |
|
68 | CatRevErrorKind::InvalidRevision => CommandErrorKind::Abort(Some( | |
|
63 | match err { | |
|
64 | CatRevError::IoError(err) => CommandError::Abort(Some( | |
|
65 | utf8_to_local(&format!("abort: {}\n", err)).into(), | |
|
66 | )), | |
|
67 | CatRevError::InvalidRevision => CommandError::Abort(Some( | |
|
68 | utf8_to_local(&format!( | |
|
69 | "abort: invalid revision identifier {}\n", | |
|
70 | rev | |
|
71 | )) | |
|
72 | .into(), | |
|
73 | )), | |
|
74 | CatRevError::AmbiguousPrefix => CommandError::Abort(Some( | |
|
75 | utf8_to_local(&format!( | |
|
76 | "abort: ambiguous revision identifier {}\n", | |
|
77 | rev | |
|
78 | )) | |
|
79 | .into(), | |
|
80 | )), | |
|
81 | CatRevError::UnsuportedRevlogVersion(version) => { | |
|
82 | CommandError::Abort(Some( | |
|
69 | 83 | utf8_to_local(&format!( |
|
70 |
"abort: |
|
|
71 |
|
|
|
72 | )) | |
|
73 | .into(), | |
|
74 | )), | |
|
75 | CatRevErrorKind::AmbiguousPrefix => CommandErrorKind::Abort(Some( | |
|
76 | utf8_to_local(&format!( | |
|
77 | "abort: ambiguous revision identifier {}\n", | |
|
78 | rev | |
|
84 | "abort: unsupported revlog version {}\n", | |
|
85 | version | |
|
79 | 86 | )) |
|
80 | 87 | .into(), |
|
81 |
)) |
|
|
82 | CatRevErrorKind::UnsuportedRevlogVersion(version) => { | |
|
83 | CommandErrorKind::Abort(Some( | |
|
84 | utf8_to_local(&format!( | |
|
85 | "abort: unsupported revlog version {}\n", | |
|
86 | version | |
|
87 | )) | |
|
88 | .into(), | |
|
88 | )) | |
|
89 | } | |
|
90 | CatRevError::CorruptedRevlog => { | |
|
91 | CommandError::Abort(Some("abort: corrupted revlog\n".into())) | |
|
92 | } | |
|
93 | CatRevError::UnknowRevlogDataFormat(format) => { | |
|
94 | CommandError::Abort(Some( | |
|
95 | utf8_to_local(&format!( | |
|
96 | "abort: unknow revlog dataformat {:?}\n", | |
|
97 | format | |
|
89 | 98 | )) |
|
90 |
|
|
|
91 | CatRevErrorKind::CorruptedRevlog => CommandErrorKind::Abort(Some( | |
|
92 | "abort: corrupted revlog\n".into(), | |
|
93 | )), | |
|
94 | CatRevErrorKind::UnknowRevlogDataFormat(format) => { | |
|
95 | CommandErrorKind::Abort(Some( | |
|
96 | utf8_to_local(&format!( | |
|
97 | "abort: unknow revlog dataformat {:?}\n", | |
|
98 | format | |
|
99 | )) | |
|
100 | .into(), | |
|
101 | )) | |
|
102 | } | |
|
103 | }, | |
|
99 | .into(), | |
|
100 | )) | |
|
101 | } | |
|
104 | 102 | } |
|
105 | 103 | } |
@@ -1,91 +1,81 b'' | |||
|
1 | 1 | use crate::commands::Command; |
|
2 |
use crate::error:: |
|
|
2 | use crate::error::CommandError; | |
|
3 | 3 | use crate::ui::utf8_to_local; |
|
4 | 4 | use crate::ui::Ui; |
|
5 | use hg::operations::{ | |
|
6 | debug_data, DebugDataError, DebugDataErrorKind, DebugDataKind, | |
|
7 | }; | |
|
5 | use hg::operations::{debug_data, DebugDataError, DebugDataKind}; | |
|
8 | 6 | use hg::repo::Repo; |
|
9 | 7 | use micro_timer::timed; |
|
10 | 8 | |
|
11 | 9 | pub const HELP_TEXT: &str = " |
|
12 | 10 | Dump the contents of a data file revision |
|
13 | 11 | "; |
|
14 | 12 | |
|
15 | 13 | pub struct DebugDataCommand<'a> { |
|
16 | 14 | rev: &'a str, |
|
17 | 15 | kind: DebugDataKind, |
|
18 | 16 | } |
|
19 | 17 | |
|
20 | 18 | impl<'a> DebugDataCommand<'a> { |
|
21 | 19 | pub fn new(rev: &'a str, kind: DebugDataKind) -> Self { |
|
22 | 20 | DebugDataCommand { rev, kind } |
|
23 | 21 | } |
|
24 | 22 | } |
|
25 | 23 | |
|
26 | 24 | impl<'a> Command for DebugDataCommand<'a> { |
|
27 | 25 | #[timed] |
|
28 | 26 | fn run(&self, ui: &Ui) -> Result<(), CommandError> { |
|
29 | 27 | let repo = Repo::find()?; |
|
30 | 28 | let data = debug_data(&repo, self.rev, self.kind) |
|
31 | 29 | .map_err(|e| to_command_error(self.rev, e))?; |
|
32 | 30 | |
|
33 | 31 | let mut stdout = ui.stdout_buffer(); |
|
34 | 32 | stdout.write_all(&data)?; |
|
35 | 33 | stdout.flush()?; |
|
36 | 34 | |
|
37 | 35 | Ok(()) |
|
38 | 36 | } |
|
39 | 37 | } |
|
40 | 38 | |
|
41 | 39 | /// Convert operation errors to command errors |
|
42 | 40 | fn to_command_error(rev: &str, err: DebugDataError) -> CommandError { |
|
43 |
match err |
|
|
44 |
DebugDataError |
|
|
45 | kind: CommandErrorKind::Abort(Some( | |
|
46 | utf8_to_local(&format!("abort: {}\n", err)).into(), | |
|
47 | )), | |
|
48 | }, | |
|
49 | DebugDataErrorKind::InvalidRevision => CommandError { | |
|
50 | kind: CommandErrorKind::Abort(Some( | |
|
51 | utf8_to_local(&format!( | |
|
52 | "abort: invalid revision identifier{}\n", | |
|
53 | rev | |
|
54 | )) | |
|
55 | .into(), | |
|
56 | )), | |
|
57 | }, | |
|
58 | DebugDataErrorKind::AmbiguousPrefix => CommandError { | |
|
59 | kind: CommandErrorKind::Abort(Some( | |
|
60 | utf8_to_local(&format!( | |
|
61 | "abort: ambiguous revision identifier{}\n", | |
|
62 | rev | |
|
63 | )) | |
|
64 | .into(), | |
|
65 | )), | |
|
66 | }, | |
|
67 | DebugDataErrorKind::UnsuportedRevlogVersion(version) => CommandError { | |
|
68 | kind: CommandErrorKind::Abort(Some( | |
|
41 | match err { | |
|
42 | DebugDataError::IoError(err) => CommandError::Abort(Some( | |
|
43 | utf8_to_local(&format!("abort: {}\n", err)).into(), | |
|
44 | )), | |
|
45 | DebugDataError::InvalidRevision => CommandError::Abort(Some( | |
|
46 | utf8_to_local(&format!( | |
|
47 | "abort: invalid revision identifier{}\n", | |
|
48 | rev | |
|
49 | )) | |
|
50 | .into(), | |
|
51 | )), | |
|
52 | DebugDataError::AmbiguousPrefix => CommandError::Abort(Some( | |
|
53 | utf8_to_local(&format!( | |
|
54 | "abort: ambiguous revision identifier{}\n", | |
|
55 | rev | |
|
56 | )) | |
|
57 | .into(), | |
|
58 | )), | |
|
59 | DebugDataError::UnsuportedRevlogVersion(version) => { | |
|
60 | CommandError::Abort(Some( | |
|
69 | 61 | utf8_to_local(&format!( |
|
70 | 62 | "abort: unsupported revlog version {}\n", |
|
71 | 63 | version |
|
72 | 64 | )) |
|
73 | 65 | .into(), |
|
74 |
)) |
|
|
75 |
} |
|
|
76 |
DebugDataError |
|
|
77 |
|
|
|
78 | "abort: corrupted revlog\n".into(), | |
|
79 | )), | |
|
80 | }, | |
|
81 | DebugDataErrorKind::UnknowRevlogDataFormat(format) => CommandError { | |
|
82 | kind: CommandErrorKind::Abort(Some( | |
|
66 | )) | |
|
67 | } | |
|
68 | DebugDataError::CorruptedRevlog => { | |
|
69 | CommandError::Abort(Some("abort: corrupted revlog\n".into())) | |
|
70 | } | |
|
71 | DebugDataError::UnknowRevlogDataFormat(format) => { | |
|
72 | CommandError::Abort(Some( | |
|
83 | 73 | utf8_to_local(&format!( |
|
84 | 74 | "abort: unknow revlog dataformat {:?}\n", |
|
85 | 75 | format |
|
86 | 76 | )) |
|
87 | 77 | .into(), |
|
88 |
)) |
|
|
89 |
} |
|
|
78 | )) | |
|
79 | } | |
|
90 | 80 | } |
|
91 | 81 | } |
@@ -1,142 +1,127 b'' | |||
|
1 | 1 | use crate::commands::Command; |
|
2 |
use crate::error:: |
|
|
2 | use crate::error::CommandError; | |
|
3 | 3 | use crate::ui::utf8_to_local; |
|
4 | 4 | use crate::ui::Ui; |
|
5 | use hg::operations::{ | |
|
6 | list_rev_tracked_files, ListRevTrackedFilesError, | |
|
7 | ListRevTrackedFilesErrorKind, | |
|
8 | }; | |
|
9 | use hg::operations::{ | |
|
10 | Dirstate, ListDirstateTrackedFilesError, ListDirstateTrackedFilesErrorKind, | |
|
11 | }; | |
|
5 | use hg::operations::{list_rev_tracked_files, ListRevTrackedFilesError}; | |
|
6 | use hg::operations::{Dirstate, ListDirstateTrackedFilesError}; | |
|
12 | 7 | use hg::repo::Repo; |
|
13 | 8 | use hg::utils::files::{get_bytes_from_path, relativize_path}; |
|
14 | 9 | use hg::utils::hg_path::{HgPath, HgPathBuf}; |
|
15 | 10 | |
|
16 | 11 | pub const HELP_TEXT: &str = " |
|
17 | 12 | List tracked files. |
|
18 | 13 | |
|
19 | 14 | Returns 0 on success. |
|
20 | 15 | "; |
|
21 | 16 | |
|
22 | 17 | pub struct FilesCommand<'a> { |
|
23 | 18 | rev: Option<&'a str>, |
|
24 | 19 | } |
|
25 | 20 | |
|
26 | 21 | impl<'a> FilesCommand<'a> { |
|
27 | 22 | pub fn new(rev: Option<&'a str>) -> Self { |
|
28 | 23 | FilesCommand { rev } |
|
29 | 24 | } |
|
30 | 25 | |
|
31 | 26 | fn display_files( |
|
32 | 27 | &self, |
|
33 | 28 | ui: &Ui, |
|
34 | 29 | repo: &Repo, |
|
35 | 30 | files: impl IntoIterator<Item = &'a HgPath>, |
|
36 | 31 | ) -> Result<(), CommandError> { |
|
37 | 32 | let cwd = std::env::current_dir() |
|
38 |
.or_else(|e| Err(CommandError |
|
|
33 | .or_else(|e| Err(CommandError::CurrentDirNotFound(e)))?; | |
|
39 | 34 | let rooted_cwd = cwd |
|
40 | 35 | .strip_prefix(repo.working_directory_path()) |
|
41 | 36 | .expect("cwd was already checked within the repository"); |
|
42 | 37 | let rooted_cwd = HgPathBuf::from(get_bytes_from_path(rooted_cwd)); |
|
43 | 38 | |
|
44 | 39 | let mut stdout = ui.stdout_buffer(); |
|
45 | 40 | |
|
46 | 41 | for file in files { |
|
47 | 42 | stdout.write_all(relativize_path(file, &rooted_cwd).as_ref())?; |
|
48 | 43 | stdout.write_all(b"\n")?; |
|
49 | 44 | } |
|
50 | 45 | stdout.flush()?; |
|
51 | 46 | Ok(()) |
|
52 | 47 | } |
|
53 | 48 | } |
|
54 | 49 | |
|
55 | 50 | impl<'a> Command for FilesCommand<'a> { |
|
56 | 51 | fn run(&self, ui: &Ui) -> Result<(), CommandError> { |
|
57 | 52 | let repo = Repo::find()?; |
|
58 | 53 | repo.check_requirements()?; |
|
59 | 54 | if let Some(rev) = self.rev { |
|
60 | 55 | let files = list_rev_tracked_files(&repo, rev) |
|
61 | 56 | .map_err(|e| map_rev_error(rev, e))?; |
|
62 | 57 | self.display_files(ui, &repo, files.iter()) |
|
63 | 58 | } else { |
|
64 | 59 | let distate = Dirstate::new(&repo).map_err(map_dirstate_error)?; |
|
65 | 60 | let files = distate.tracked_files().map_err(map_dirstate_error)?; |
|
66 | 61 | self.display_files(ui, &repo, files) |
|
67 | 62 | } |
|
68 | 63 | } |
|
69 | 64 | } |
|
70 | 65 | |
|
71 |
/// Convert `ListRevTrackedFilesError |
|
|
66 | /// Convert `ListRevTrackedFilesError` to `CommandError` | |
|
72 | 67 | fn map_rev_error(rev: &str, err: ListRevTrackedFilesError) -> CommandError { |
|
73 |
|
|
|
74 | kind: match err.kind { | |
|
75 | ListRevTrackedFilesErrorKind::IoError(err) => { | |
|
76 | CommandErrorKind::Abort(Some( | |
|
77 | utf8_to_local(&format!("abort: {}\n", err)).into(), | |
|
68 | match err { | |
|
69 | ListRevTrackedFilesError::IoError(err) => CommandError::Abort(Some( | |
|
70 | utf8_to_local(&format!("abort: {}\n", err)).into(), | |
|
71 | )), | |
|
72 | ListRevTrackedFilesError::InvalidRevision => { | |
|
73 | CommandError::Abort(Some( | |
|
74 | utf8_to_local(&format!( | |
|
75 | "abort: invalid revision identifier {}\n", | |
|
76 | rev | |
|
78 | 77 | )) |
|
79 |
|
|
|
80 | ListRevTrackedFilesErrorKind::InvalidRevision => { | |
|
81 | CommandErrorKind::Abort(Some( | |
|
82 | utf8_to_local(&format!( | |
|
83 | "abort: invalid revision identifier {}\n", | |
|
84 | rev | |
|
85 | )) | |
|
86 |
|
|
|
87 | )) | |
|
88 | } | |
|
89 | ListRevTrackedFilesErrorKind::AmbiguousPrefix => { | |
|
90 | CommandErrorKind::Abort(Some( | |
|
91 | utf8_to_local(&format!( | |
|
92 | "abort: ambiguous revision identifier {}\n", | |
|
93 | rev | |
|
94 | )) | |
|
95 | .into(), | |
|
78 | .into(), | |
|
79 | )) | |
|
80 | } | |
|
81 | ListRevTrackedFilesError::AmbiguousPrefix => { | |
|
82 | CommandError::Abort(Some( | |
|
83 | utf8_to_local(&format!( | |
|
84 | "abort: ambiguous revision identifier {}\n", | |
|
85 | rev | |
|
96 | 86 | )) |
|
97 |
|
|
|
98 | ListRevTrackedFilesErrorKind::UnsuportedRevlogVersion(version) => { | |
|
99 | CommandErrorKind::Abort(Some( | |
|
100 | utf8_to_local(&format!( | |
|
101 | "abort: unsupported revlog version {}\n", | |
|
102 | version | |
|
103 | )) | |
|
104 |
|
|
|
87 | .into(), | |
|
88 | )) | |
|
89 | } | |
|
90 | ListRevTrackedFilesError::UnsuportedRevlogVersion(version) => { | |
|
91 | CommandError::Abort(Some( | |
|
92 | utf8_to_local(&format!( | |
|
93 | "abort: unsupported revlog version {}\n", | |
|
94 | version | |
|
105 | 95 | )) |
|
106 |
|
|
|
107 | ListRevTrackedFilesErrorKind::CorruptedRevlog => { | |
|
108 | CommandErrorKind::Abort(Some( | |
|
109 | "abort: corrupted revlog\n".into(), | |
|
96 | .into(), | |
|
97 | )) | |
|
98 | } | |
|
99 | ListRevTrackedFilesError::CorruptedRevlog => { | |
|
100 | CommandError::Abort(Some("abort: corrupted revlog\n".into())) | |
|
101 | } | |
|
102 | ListRevTrackedFilesError::UnknowRevlogDataFormat(format) => { | |
|
103 | CommandError::Abort(Some( | |
|
104 | utf8_to_local(&format!( | |
|
105 | "abort: unknow revlog dataformat {:?}\n", | |
|
106 | format | |
|
110 | 107 | )) |
|
111 |
|
|
|
112 | ListRevTrackedFilesErrorKind::UnknowRevlogDataFormat(format) => { | |
|
113 | CommandErrorKind::Abort(Some( | |
|
114 | utf8_to_local(&format!( | |
|
115 | "abort: unknow revlog dataformat {:?}\n", | |
|
116 | format | |
|
117 | )) | |
|
118 | .into(), | |
|
119 | )) | |
|
120 | } | |
|
121 | }, | |
|
108 | .into(), | |
|
109 | )) | |
|
110 | } | |
|
122 | 111 | } |
|
123 | 112 | } |
|
124 | 113 | |
|
125 | 114 | /// Convert `ListDirstateTrackedFilesError` to `CommandError` |
|
126 | 115 | fn map_dirstate_error(err: ListDirstateTrackedFilesError) -> CommandError { |
|
127 |
|
|
|
128 | kind: match err.kind { | |
|
129 | ListDirstateTrackedFilesErrorKind::IoError(err) => { | |
|
130 | CommandErrorKind::Abort(Some( | |
|
131 | utf8_to_local(&format!("abort: {}\n", err)).into(), | |
|
132 | )) | |
|
133 | } | |
|
134 | ListDirstateTrackedFilesErrorKind::ParseError(_) => { | |
|
135 | CommandErrorKind::Abort(Some( | |
|
136 | // TODO find a better error message | |
|
137 | b"abort: parse error\n".to_vec(), | |
|
138 | )) | |
|
139 | } | |
|
140 | }, | |
|
116 | match err { | |
|
117 | ListDirstateTrackedFilesError::IoError(err) => CommandError::Abort( | |
|
118 | Some(utf8_to_local(&format!("abort: {}\n", err)).into()), | |
|
119 | ), | |
|
120 | ListDirstateTrackedFilesError::ParseError(_) => { | |
|
121 | CommandError::Abort(Some( | |
|
122 | // TODO find a better error message | |
|
123 | b"abort: parse error\n".to_vec(), | |
|
124 | )) | |
|
125 | } | |
|
141 | 126 | } |
|
142 | 127 | } |
@@ -1,124 +1,101 b'' | |||
|
1 | 1 | use crate::exitcode; |
|
2 | 2 | use crate::ui::UiError; |
|
3 | 3 | use format_bytes::format_bytes; |
|
4 |
use hg::operations:: |
|
|
4 | use hg::operations::FindRootError; | |
|
5 | 5 | use hg::requirements::RequirementsError; |
|
6 | 6 | use hg::utils::files::get_bytes_from_path; |
|
7 | 7 | use std::convert::From; |
|
8 | 8 | use std::path::PathBuf; |
|
9 | 9 | |
|
10 | 10 | /// The kind of command error |
|
11 | 11 | #[derive(Debug)] |
|
12 |
pub enum CommandError |
|
|
12 | pub enum CommandError { | |
|
13 | 13 | /// The root of the repository cannot be found |
|
14 | 14 | RootNotFound(PathBuf), |
|
15 | 15 | /// The current directory cannot be found |
|
16 | 16 | CurrentDirNotFound(std::io::Error), |
|
17 | 17 | /// `.hg/requires` |
|
18 | 18 | RequirementsError(RequirementsError), |
|
19 | 19 | /// The standard output stream cannot be written to |
|
20 | 20 | StdoutError, |
|
21 | 21 | /// The standard error stream cannot be written to |
|
22 | 22 | StderrError, |
|
23 | 23 | /// The command aborted |
|
24 | 24 | Abort(Option<Vec<u8>>), |
|
25 | 25 | /// A mercurial capability as not been implemented. |
|
26 | 26 | Unimplemented, |
|
27 | 27 | } |
|
28 | 28 | |
|
29 |
impl CommandError |
|
|
29 | impl CommandError { | |
|
30 | 30 | pub fn get_exit_code(&self) -> exitcode::ExitCode { |
|
31 | 31 | match self { |
|
32 |
CommandError |
|
|
33 |
CommandError |
|
|
34 |
CommandError |
|
|
32 | CommandError::RootNotFound(_) => exitcode::ABORT, | |
|
33 | CommandError::CurrentDirNotFound(_) => exitcode::ABORT, | |
|
34 | CommandError::RequirementsError( | |
|
35 | 35 | RequirementsError::Unsupported { .. }, |
|
36 | 36 | ) => exitcode::UNIMPLEMENTED_COMMAND, |
|
37 |
CommandError |
|
|
38 |
CommandError |
|
|
39 |
CommandError |
|
|
40 |
CommandError |
|
|
41 |
CommandError |
|
|
37 | CommandError::RequirementsError(_) => exitcode::ABORT, | |
|
38 | CommandError::StdoutError => exitcode::ABORT, | |
|
39 | CommandError::StderrError => exitcode::ABORT, | |
|
40 | CommandError::Abort(_) => exitcode::ABORT, | |
|
41 | CommandError::Unimplemented => exitcode::UNIMPLEMENTED_COMMAND, | |
|
42 | 42 | } |
|
43 | 43 | } |
|
44 | 44 | |
|
45 |
/// Return the message corresponding to the error |
|
|
45 | /// Return the message corresponding to the error if any | |
|
46 | 46 | pub fn get_error_message_bytes(&self) -> Option<Vec<u8>> { |
|
47 | 47 | match self { |
|
48 |
CommandError |
|
|
48 | CommandError::RootNotFound(path) => { | |
|
49 | 49 | let bytes = get_bytes_from_path(path); |
|
50 | 50 | Some(format_bytes!( |
|
51 | 51 | b"abort: no repository found in '{}' (.hg not found)!\n", |
|
52 | 52 | bytes.as_slice() |
|
53 | 53 | )) |
|
54 | 54 | } |
|
55 |
CommandError |
|
|
55 | CommandError::CurrentDirNotFound(e) => Some(format_bytes!( | |
|
56 | 56 | b"abort: error getting current working directory: {}\n", |
|
57 | 57 | e.to_string().as_bytes(), |
|
58 | 58 | )), |
|
59 |
CommandError |
|
|
60 | RequirementsError::Corrupted, | |
|
61 | ) => Some( | |
|
62 | "abort: .hg/requires is corrupted\n".as_bytes().to_owned(), | |
|
63 |
|
|
|
64 |
CommandError |
|
|
59 | CommandError::RequirementsError(RequirementsError::Corrupted) => { | |
|
60 | Some( | |
|
61 | "abort: .hg/requires is corrupted\n".as_bytes().to_owned(), | |
|
62 | ) | |
|
63 | } | |
|
64 | CommandError::Abort(message) => message.to_owned(), | |
|
65 | 65 | _ => None, |
|
66 | 66 | } |
|
67 | 67 | } |
|
68 | } | |
|
69 | 68 | |
|
70 | /// The error type for the Command trait | |
|
71 | #[derive(Debug)] | |
|
72 | pub struct CommandError { | |
|
73 | pub kind: CommandErrorKind, | |
|
74 | } | |
|
75 | ||
|
76 | impl CommandError { | |
|
77 | 69 | /// Exist the process with the corresponding exit code. |
|
78 | 70 | pub fn exit(&self) { |
|
79 |
std::process::exit(self. |
|
|
80 | } | |
|
81 | ||
|
82 | /// Return the message corresponding to the command error if any | |
|
83 | pub fn get_error_message_bytes(&self) -> Option<Vec<u8>> { | |
|
84 | self.kind.get_error_message_bytes() | |
|
85 | } | |
|
86 | } | |
|
87 | ||
|
88 | impl From<CommandErrorKind> for CommandError { | |
|
89 | fn from(kind: CommandErrorKind) -> Self { | |
|
90 | CommandError { kind } | |
|
71 | std::process::exit(self.get_exit_code()) | |
|
91 | 72 | } |
|
92 | 73 | } |
|
93 | 74 | |
|
94 | 75 | impl From<UiError> for CommandError { |
|
95 | 76 | fn from(error: UiError) -> Self { |
|
96 |
|
|
|
97 | kind: match error { | |
|
98 |
|
|
|
99 | UiError::StderrError(_) => CommandErrorKind::StderrError, | |
|
100 | }, | |
|
77 | match error { | |
|
78 | UiError::StdoutError(_) => CommandError::StdoutError, | |
|
79 | UiError::StderrError(_) => CommandError::StderrError, | |
|
101 | 80 | } |
|
102 | 81 | } |
|
103 | 82 | } |
|
104 | 83 | |
|
105 | 84 | impl From<FindRootError> for CommandError { |
|
106 | 85 | fn from(err: FindRootError) -> Self { |
|
107 |
match err |
|
|
108 |
FindRootError |
|
|
109 |
|
|
|
110 |
} |
|
|
111 |
FindRootError |
|
|
112 |
|
|
|
113 |
} |
|
|
86 | match err { | |
|
87 | FindRootError::RootNotFound(path) => { | |
|
88 | CommandError::RootNotFound(path) | |
|
89 | } | |
|
90 | FindRootError::GetCurrentDirError(e) => { | |
|
91 | CommandError::CurrentDirNotFound(e) | |
|
92 | } | |
|
114 | 93 | } |
|
115 | 94 | } |
|
116 | 95 | } |
|
117 | 96 | |
|
118 | 97 | impl From<RequirementsError> for CommandError { |
|
119 | 98 | fn from(err: RequirementsError) -> Self { |
|
120 |
CommandError |
|
|
121 | kind: CommandErrorKind::RequirementsError(err), | |
|
122 | } | |
|
99 | CommandError::RequirementsError(err) | |
|
123 | 100 | } |
|
124 | 101 | } |
General Comments 0
You need to be logged in to leave comments.
Login now