##// END OF EJS Templates
rust: remove `FooError` structs with only `kind: FooErrorKind` enum field...
Simon Sapin -
r47163:3e2d539d default
parent child Browse files
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 CatRevErrorKind {
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) => CatRevErrorKind::IoError(err),
43 RevlogError::IoError(err) => CatRevError::IoError(err),
57 44 RevlogError::UnsuportedVersion(version) => {
58 CatRevErrorKind::UnsuportedRevlogVersion(version)
45 CatRevError::UnsuportedRevlogVersion(version)
59 46 }
60 RevlogError::InvalidRevision => CatRevErrorKind::InvalidRevision,
61 RevlogError::AmbiguousPrefix => CatRevErrorKind::AmbiguousPrefix,
62 RevlogError::Corrupted => CatRevErrorKind::CorruptedRevlog,
47 RevlogError::InvalidRevision => CatRevError::InvalidRevision,
48 RevlogError::AmbiguousPrefix => CatRevError::AmbiguousPrefix,
49 RevlogError::Corrupted => CatRevError::CorruptedRevlog,
63 50 RevlogError::UnknowDataFormat(format) => {
64 CatRevErrorKind::UnknowRevlogDataFormat(format)
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(|_| CatRevErrorKind::CorruptedRevlog)?;
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(|_| CatRevErrorKind::CorruptedRevlog)?;
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 DebugDataErrorKind {
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 let kind = DebugDataErrorKind::IoError(err);
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) => DebugDataErrorKind::IoError(err),
44 RevlogError::IoError(err) => DebugDataError::IoError(err),
59 45 RevlogError::UnsuportedVersion(version) => {
60 DebugDataErrorKind::UnsuportedRevlogVersion(version)
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 DebugDataErrorKind::UnknowRevlogDataFormat(format)
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 use std::path::{Path, PathBuf};
3 2
4 /// Kind of error encoutered by FindRoot
3 /// Error type for `find_root`
5 4 #[derive(Debug)]
6 pub enum FindRootErrorKind {
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().map_err(|e| FindRootError {
35 kind: FindRootErrorKind::GetCurrentDirError(e),
36 })?;
18 let current_dir = std::env::current_dir()
19 .map_err(|e| FindRootError::GetCurrentDirError(e))?;
37 20 Ok(find_root_from_path(&current_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 ListDirstateTrackedFilesErrorKind {
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 let kind = ListDirstateTrackedFilesErrorKind::IoError(err);
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(ListDirstateTrackedFilesErrorKind::ParseError)?;
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 /// Kind of error encountered by `ListRevTrackedFiles`
64 /// Error type `list_rev_tracked_files`
81 65 #[derive(Debug)]
82 pub enum ListRevTrackedFilesErrorKind {
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 ListRevTrackedFilesErrorKind::IoError(err)
85 ListRevTrackedFilesError::IoError(err)
115 86 }
116 87 RevlogError::UnsuportedVersion(version) => {
117 ListRevTrackedFilesErrorKind::UnsuportedRevlogVersion(version)
88 ListRevTrackedFilesError::UnsuportedRevlogVersion(version)
118 89 }
119 90 RevlogError::InvalidRevision => {
120 ListRevTrackedFilesErrorKind::InvalidRevision
91 ListRevTrackedFilesError::InvalidRevision
121 92 }
122 93 RevlogError::AmbiguousPrefix => {
123 ListRevTrackedFilesErrorKind::AmbiguousPrefix
94 ListRevTrackedFilesError::AmbiguousPrefix
124 95 }
125 96 RevlogError::Corrupted => {
126 ListRevTrackedFilesErrorKind::CorruptedRevlog
97 ListRevTrackedFilesError::CorruptedRevlog
127 98 }
128 99 RevlogError::UnknowDataFormat(format) => {
129 ListRevTrackedFilesErrorKind::UnknowRevlogDataFormat(format)
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(ListRevTrackedFilesErrorKind::CorruptedRevlog))?;
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, CatRevErrorKind};
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::{CommandError, CommandErrorKind};
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, CatRevErrorKind};
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(CommandErrorKind::CurrentDirNotFound(e)))?;
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(CommandErrorKind::Abort(None)))?;
44 .or(Err(CommandError::Abort(None)))?;
45 45 let hg_file = HgPathBuf::try_from(stripped.to_path_buf())
46 .or(Err(CommandErrorKind::Abort(None)))?;
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(CommandErrorKind::Unimplemented.into()),
56 None => Err(CommandError::Unimplemented.into()),
57 57 }
58 58 }
59 59 }
60 60
61 /// Convert `CatRevErrorKind` to `CommandError`
61 /// Convert `CatRevError` to `CommandError`
62 62 fn map_rev_error(rev: &str, err: CatRevError) -> CommandError {
63 CommandError {
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: invalid revision identifier {}\n",
71 rev
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::{CommandError, CommandErrorKind};
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.kind {
44 DebugDataErrorKind::IoError(err) => CommandError {
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 DebugDataErrorKind::CorruptedRevlog => CommandError {
77 kind: CommandErrorKind::Abort(Some(
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::{CommandError, CommandErrorKind};
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(CommandErrorKind::CurrentDirNotFound(e)))?;
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 `ListRevTrackedFilesErrorKind` to `CommandError`
66 /// Convert `ListRevTrackedFilesError` to `CommandError`
72 67 fn map_rev_error(rev: &str, err: ListRevTrackedFilesError) -> CommandError {
73 CommandError {
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 .into(),
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 .into(),
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 CommandError {
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::{FindRootError, FindRootErrorKind};
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 CommandErrorKind {
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 CommandErrorKind {
29 impl CommandError {
30 30 pub fn get_exit_code(&self) -> exitcode::ExitCode {
31 31 match self {
32 CommandErrorKind::RootNotFound(_) => exitcode::ABORT,
33 CommandErrorKind::CurrentDirNotFound(_) => exitcode::ABORT,
34 CommandErrorKind::RequirementsError(
32 CommandError::RootNotFound(_) => exitcode::ABORT,
33 CommandError::CurrentDirNotFound(_) => exitcode::ABORT,
34 CommandError::RequirementsError(
35 35 RequirementsError::Unsupported { .. },
36 36 ) => exitcode::UNIMPLEMENTED_COMMAND,
37 CommandErrorKind::RequirementsError(_) => exitcode::ABORT,
38 CommandErrorKind::StdoutError => exitcode::ABORT,
39 CommandErrorKind::StderrError => exitcode::ABORT,
40 CommandErrorKind::Abort(_) => exitcode::ABORT,
41 CommandErrorKind::Unimplemented => exitcode::UNIMPLEMENTED_COMMAND,
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 kind if any
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 CommandErrorKind::RootNotFound(path) => {
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 CommandErrorKind::CurrentDirNotFound(e) => Some(format_bytes!(
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 CommandErrorKind::RequirementsError(
60 RequirementsError::Corrupted,
61 ) => Some(
62 "abort: .hg/requires is corrupted\n".as_bytes().to_owned(),
63 ),
64 CommandErrorKind::Abort(message) => message.to_owned(),
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.kind.get_exit_code())
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 CommandError {
97 kind: match error {
98 UiError::StdoutError(_) => CommandErrorKind::StdoutError,
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.kind {
108 FindRootErrorKind::RootNotFound(path) => CommandError {
109 kind: CommandErrorKind::RootNotFound(path),
110 },
111 FindRootErrorKind::GetCurrentDirError(e) => CommandError {
112 kind: CommandErrorKind::CurrentDirNotFound(e),
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