Show More
@@ -1,176 +1,139 b'' | |||||
1 | // list_tracked_files.rs |
|
1 | // list_tracked_files.rs | |
2 | // |
|
2 | // | |
3 | // Copyright 2020 Antoine Cezar <antoine.cezar@octobus.net> |
|
3 | // Copyright 2020 Antoine Cezar <antoine.cezar@octobus.net> | |
4 | // |
|
4 | // | |
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 std::convert::From; |
|
8 | use std::convert::From; | |
9 | use std::path::{Path, PathBuf}; |
|
9 | use std::path::{Path, PathBuf}; | |
10 |
|
10 | |||
11 | use crate::revlog::changelog::Changelog; |
|
11 | use crate::revlog::changelog::Changelog; | |
12 |
use crate::revlog::manifest:: |
|
12 | use crate::revlog::manifest::Manifest; | |
13 | use crate::revlog::path_encode::path_encode; |
|
13 | use crate::revlog::path_encode::path_encode; | |
14 | use crate::revlog::revlog::Revlog; |
|
14 | use crate::revlog::revlog::Revlog; | |
15 | use crate::revlog::revlog::RevlogError; |
|
15 | use crate::revlog::revlog::RevlogError; | |
16 | use crate::revlog::Node; |
|
16 | use crate::revlog::Node; | |
17 | use crate::revlog::NodePrefix; |
|
17 | use crate::revlog::NodePrefix; | |
18 | use crate::revlog::Revision; |
|
18 | use crate::revlog::Revision; | |
19 | use crate::utils::files::get_path_from_bytes; |
|
19 | use crate::utils::files::get_path_from_bytes; | |
20 | use crate::utils::hg_path::{HgPath, HgPathBuf}; |
|
20 | use crate::utils::hg_path::{HgPath, HgPathBuf}; | |
21 |
|
21 | |||
22 | const METADATA_DELIMITER: [u8; 2] = [b'\x01', b'\n']; |
|
22 | const METADATA_DELIMITER: [u8; 2] = [b'\x01', b'\n']; | |
23 |
|
23 | |||
24 | /// Kind of error encountered by `CatRev` |
|
24 | /// Kind of error encountered by `CatRev` | |
25 | #[derive(Debug)] |
|
25 | #[derive(Debug)] | |
26 | pub enum CatRevErrorKind { |
|
26 | pub enum CatRevErrorKind { | |
27 | /// Error when reading a `revlog` file. |
|
27 | /// Error when reading a `revlog` file. | |
28 | IoError(std::io::Error), |
|
28 | IoError(std::io::Error), | |
29 | /// The revision has not been found. |
|
29 | /// The revision has not been found. | |
30 | InvalidRevision, |
|
30 | InvalidRevision, | |
31 | /// Found more than one revision whose ID match the requested prefix |
|
31 | /// Found more than one revision whose ID match the requested prefix | |
32 | AmbiguousPrefix, |
|
32 | AmbiguousPrefix, | |
33 | /// A `revlog` file is corrupted. |
|
33 | /// A `revlog` file is corrupted. | |
34 | CorruptedRevlog, |
|
34 | CorruptedRevlog, | |
35 | /// The `revlog` format version is not supported. |
|
35 | /// The `revlog` format version is not supported. | |
36 | UnsuportedRevlogVersion(u16), |
|
36 | UnsuportedRevlogVersion(u16), | |
37 | /// The `revlog` data format is not supported. |
|
37 | /// The `revlog` data format is not supported. | |
38 | UnknowRevlogDataFormat(u8), |
|
38 | UnknowRevlogDataFormat(u8), | |
39 | } |
|
39 | } | |
40 |
|
40 | |||
41 | /// A `CatRev` error |
|
41 | /// A `CatRev` error | |
42 | #[derive(Debug)] |
|
42 | #[derive(Debug)] | |
43 | pub struct CatRevError { |
|
43 | pub struct CatRevError { | |
44 | /// Kind of error encountered by `CatRev` |
|
44 | /// Kind of error encountered by `CatRev` | |
45 | pub kind: CatRevErrorKind, |
|
45 | pub kind: CatRevErrorKind, | |
46 | } |
|
46 | } | |
47 |
|
47 | |||
48 | impl From<CatRevErrorKind> for CatRevError { |
|
48 | impl From<CatRevErrorKind> for CatRevError { | |
49 | fn from(kind: CatRevErrorKind) -> Self { |
|
49 | fn from(kind: CatRevErrorKind) -> Self { | |
50 | CatRevError { kind } |
|
50 | CatRevError { kind } | |
51 | } |
|
51 | } | |
52 | } |
|
52 | } | |
53 |
|
53 | |||
54 | impl From<RevlogError> for CatRevError { |
|
54 | impl From<RevlogError> for CatRevError { | |
55 | fn from(err: RevlogError) -> Self { |
|
55 | fn from(err: RevlogError) -> Self { | |
56 | match err { |
|
56 | match err { | |
57 | RevlogError::IoError(err) => CatRevErrorKind::IoError(err), |
|
57 | RevlogError::IoError(err) => CatRevErrorKind::IoError(err), | |
58 | RevlogError::UnsuportedVersion(version) => { |
|
58 | RevlogError::UnsuportedVersion(version) => { | |
59 | CatRevErrorKind::UnsuportedRevlogVersion(version) |
|
59 | CatRevErrorKind::UnsuportedRevlogVersion(version) | |
60 | } |
|
60 | } | |
61 | RevlogError::InvalidRevision => CatRevErrorKind::InvalidRevision, |
|
61 | RevlogError::InvalidRevision => CatRevErrorKind::InvalidRevision, | |
62 | RevlogError::AmbiguousPrefix => CatRevErrorKind::AmbiguousPrefix, |
|
62 | RevlogError::AmbiguousPrefix => CatRevErrorKind::AmbiguousPrefix, | |
63 | RevlogError::Corrupted => CatRevErrorKind::CorruptedRevlog, |
|
63 | RevlogError::Corrupted => CatRevErrorKind::CorruptedRevlog, | |
64 | RevlogError::UnknowDataFormat(format) => { |
|
64 | RevlogError::UnknowDataFormat(format) => { | |
65 | CatRevErrorKind::UnknowRevlogDataFormat(format) |
|
65 | CatRevErrorKind::UnknowRevlogDataFormat(format) | |
66 | } |
|
66 | } | |
67 | } |
|
67 | } | |
68 | .into() |
|
68 | .into() | |
69 | } |
|
69 | } | |
70 | } |
|
70 | } | |
71 |
|
71 | |||
72 | /// List files under Mercurial control at a given revision. |
|
72 | /// List files under Mercurial control at a given revision. | |
73 | pub struct CatRev<'a> { |
|
|||
74 | root: &'a Path, |
|
|||
75 | /// The revision to cat the files from. |
|
|||
76 | rev: &'a str, |
|
|||
77 | /// The files to output. |
|
|||
78 | files: &'a [HgPathBuf], |
|
|||
79 | /// The changelog file |
|
|||
80 | changelog: Changelog, |
|
|||
81 | /// The manifest file |
|
|||
82 | manifest: Manifest, |
|
|||
83 | /// The manifest entry corresponding to the revision. |
|
|||
84 |
|
|
73 | /// | |
85 | /// Used to hold the owner of the returned references. |
|
74 | /// * `root`: Repository root | |
86 | manifest_entry: Option<ManifestEntry>, |
|
75 | /// * `rev`: The revision to cat the files from. | |
87 | } |
|
76 | /// * `files`: The files to output. | |
88 |
|
77 | pub fn cat( | ||
89 | impl<'a> CatRev<'a> { |
|
78 | root: &Path, | |
90 | pub fn new( |
|
79 | rev: &str, | |
91 | root: &'a Path, |
|
80 | files: &[HgPathBuf], | |
92 | rev: &'a str, |
|
81 | ) -> Result<Vec<u8>, CatRevError> { | |
93 | files: &'a [HgPathBuf], |
|
|||
94 | ) -> Result<Self, CatRevError> { |
|
|||
95 |
|
|
82 | let changelog = Changelog::open(&root)?; | |
96 |
|
|
83 | let manifest = Manifest::open(&root)?; | |
97 | let manifest_entry = None; |
|
|||
98 |
|
84 | |||
99 | Ok(Self { |
|
85 | let changelog_entry = match rev.parse::<Revision>() { | |
100 | root, |
|
86 | Ok(rev) => changelog.get_rev(rev)?, | |
101 | rev, |
|
|||
102 | files, |
|
|||
103 | changelog, |
|
|||
104 | manifest, |
|
|||
105 | manifest_entry, |
|
|||
106 | }) |
|
|||
107 | } |
|
|||
108 |
|
||||
109 | pub fn run(&mut self) -> Result<Vec<u8>, CatRevError> { |
|
|||
110 | let changelog_entry = match self.rev.parse::<Revision>() { |
|
|||
111 | Ok(rev) => self.changelog.get_rev(rev)?, |
|
|||
112 |
|
|
87 | _ => { | |
113 |
|
|
88 | let changelog_node = NodePrefix::from_hex(&rev) | |
114 |
|
|
89 | .map_err(|_| CatRevErrorKind::InvalidRevision)?; | |
115 |
|
|
90 | changelog.get_node(changelog_node.borrow())? | |
116 |
|
|
91 | } | |
117 |
|
|
92 | }; | |
118 |
|
|
93 | let manifest_node = Node::from_hex(&changelog_entry.manifest_node()?) | |
119 |
|
|
94 | .map_err(|_| CatRevErrorKind::CorruptedRevlog)?; | |
120 |
|
95 | |||
121 | self.manifest_entry = |
|
96 | let manifest_entry = manifest.get_node((&manifest_node).into())?; | |
122 | Some(self.manifest.get_node((&manifest_node).into())?); |
|
|||
123 | if let Some(ref manifest_entry) = self.manifest_entry { |
|
|||
124 |
|
|
97 | let mut bytes = vec![]; | |
125 |
|
98 | |||
126 |
|
|
99 | for (manifest_file, node_bytes) in manifest_entry.files_with_nodes() { | |
127 | manifest_entry.files_with_nodes() |
|
100 | for cat_file in files.iter() { | |
128 | { |
|
|||
129 | for cat_file in self.files.iter() { |
|
|||
130 |
|
|
101 | if cat_file.as_bytes() == manifest_file.as_bytes() { | |
131 | let index_path = |
|
102 | let index_path = store_path(root, manifest_file, b".i"); | |
132 |
|
|
103 | let data_path = store_path(root, manifest_file, b".d"); | |
133 | let data_path = |
|
|||
134 | store_path(self.root, manifest_file, b".d"); |
|
|||
135 |
|
104 | |||
136 | let file_log = |
|
105 | let file_log = Revlog::open(&index_path, Some(&data_path))?; | |
137 | Revlog::open(&index_path, Some(&data_path))?; |
|
|||
138 |
|
|
106 | let file_node = Node::from_hex(node_bytes) | |
139 |
|
|
107 | .map_err(|_| CatRevErrorKind::CorruptedRevlog)?; | |
140 | let file_rev = |
|
108 | let file_rev = file_log.get_node_rev((&file_node).into())?; | |
141 | file_log.get_node_rev((&file_node).into())?; |
|
|||
142 |
|
|
109 | let data = file_log.get_rev_data(file_rev)?; | |
143 |
|
|
110 | if data.starts_with(&METADATA_DELIMITER) { | |
144 |
|
|
111 | let end_delimiter_position = data | |
145 |
|
|
112 | [METADATA_DELIMITER.len()..] | |
146 |
|
|
113 | .windows(METADATA_DELIMITER.len()) | |
147 |
|
|
114 | .position(|bytes| bytes == METADATA_DELIMITER); | |
148 |
|
|
115 | if let Some(position) = end_delimiter_position { | |
149 |
|
|
116 | let offset = METADATA_DELIMITER.len() * 2; | |
150 |
|
|
117 | bytes.extend(data[position + offset..].iter()); | |
151 |
|
|
118 | } | |
152 |
|
|
119 | } else { | |
153 |
|
|
120 | bytes.extend(data); | |
154 |
|
|
121 | } | |
155 |
|
|
122 | } | |
156 |
|
|
123 | } | |
157 | } |
|
124 | } | |
158 |
|
125 | |||
159 |
|
|
126 | Ok(bytes) | |
160 | } else { |
|
|||
161 | unreachable!("manifest_entry should have been stored"); |
|
|||
162 | } |
|
|||
163 | } |
|
|||
164 | } |
|
127 | } | |
165 |
|
128 | |||
166 | fn store_path(root: &Path, hg_path: &HgPath, suffix: &[u8]) -> PathBuf { |
|
129 | fn store_path(root: &Path, hg_path: &HgPath, suffix: &[u8]) -> PathBuf { | |
167 | let encoded_bytes = |
|
130 | let encoded_bytes = | |
168 | path_encode(&[b"data/", hg_path.as_bytes(), suffix].concat()); |
|
131 | path_encode(&[b"data/", hg_path.as_bytes(), suffix].concat()); | |
169 | [ |
|
132 | [ | |
170 | root, |
|
133 | root, | |
171 | &Path::new(".hg/store/"), |
|
134 | &Path::new(".hg/store/"), | |
172 | get_path_from_bytes(&encoded_bytes), |
|
135 | get_path_from_bytes(&encoded_bytes), | |
173 | ] |
|
136 | ] | |
174 | .iter() |
|
137 | .iter() | |
175 | .collect() |
|
138 | .collect() | |
176 | } |
|
139 | } |
@@ -1,120 +1,103 b'' | |||||
1 | // debugdata.rs |
|
1 | // debugdata.rs | |
2 | // |
|
2 | // | |
3 | // Copyright 2020 Antoine Cezar <antoine.cezar@octobus.net> |
|
3 | // Copyright 2020 Antoine Cezar <antoine.cezar@octobus.net> | |
4 | // |
|
4 | // | |
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 super::find_root; |
|
8 | use std::path::Path; | |
|
9 | ||||
9 | use crate::revlog::revlog::{Revlog, RevlogError}; |
|
10 | use crate::revlog::revlog::{Revlog, RevlogError}; | |
10 | use crate::revlog::NodePrefix; |
|
11 | use crate::revlog::NodePrefix; | |
11 | use crate::revlog::Revision; |
|
12 | use crate::revlog::Revision; | |
12 |
|
13 | |||
13 | /// Kind of data to debug |
|
14 | /// Kind of data to debug | |
14 | #[derive(Debug, Copy, Clone)] |
|
15 | #[derive(Debug, Copy, Clone)] | |
15 | pub enum DebugDataKind { |
|
16 | pub enum DebugDataKind { | |
16 | Changelog, |
|
17 | Changelog, | |
17 | Manifest, |
|
18 | Manifest, | |
18 | } |
|
19 | } | |
19 |
|
20 | |||
20 | /// Kind of error encountered by DebugData |
|
21 | /// Kind of error encountered by DebugData | |
21 | #[derive(Debug)] |
|
22 | #[derive(Debug)] | |
22 | pub enum DebugDataErrorKind { |
|
23 | pub enum DebugDataErrorKind { | |
23 | FindRootError(find_root::FindRootError), |
|
|||
24 | /// Error when reading a `revlog` file. |
|
24 | /// Error when reading a `revlog` file. | |
25 | IoError(std::io::Error), |
|
25 | IoError(std::io::Error), | |
26 | /// The revision has not been found. |
|
26 | /// The revision has not been found. | |
27 | InvalidRevision, |
|
27 | InvalidRevision, | |
28 | /// Found more than one revision whose ID match the requested prefix |
|
28 | /// Found more than one revision whose ID match the requested prefix | |
29 | AmbiguousPrefix, |
|
29 | AmbiguousPrefix, | |
30 | /// A `revlog` file is corrupted. |
|
30 | /// A `revlog` file is corrupted. | |
31 | CorruptedRevlog, |
|
31 | CorruptedRevlog, | |
32 | /// The `revlog` format version is not supported. |
|
32 | /// The `revlog` format version is not supported. | |
33 | UnsuportedRevlogVersion(u16), |
|
33 | UnsuportedRevlogVersion(u16), | |
34 | /// The `revlog` data format is not supported. |
|
34 | /// The `revlog` data format is not supported. | |
35 | UnknowRevlogDataFormat(u8), |
|
35 | UnknowRevlogDataFormat(u8), | |
36 | } |
|
36 | } | |
37 |
|
37 | |||
38 | /// A DebugData error |
|
38 | /// A DebugData error | |
39 | #[derive(Debug)] |
|
39 | #[derive(Debug)] | |
40 | pub struct DebugDataError { |
|
40 | pub struct DebugDataError { | |
41 | /// Kind of error encountered by DebugData |
|
41 | /// Kind of error encountered by DebugData | |
42 | pub kind: DebugDataErrorKind, |
|
42 | pub kind: DebugDataErrorKind, | |
43 | } |
|
43 | } | |
44 |
|
44 | |||
45 | impl From<DebugDataErrorKind> for DebugDataError { |
|
45 | impl From<DebugDataErrorKind> for DebugDataError { | |
46 | fn from(kind: DebugDataErrorKind) -> Self { |
|
46 | fn from(kind: DebugDataErrorKind) -> Self { | |
47 | DebugDataError { kind } |
|
47 | DebugDataError { kind } | |
48 | } |
|
48 | } | |
49 | } |
|
49 | } | |
50 |
|
50 | |||
51 | impl From<find_root::FindRootError> for DebugDataError { |
|
|||
52 | fn from(err: find_root::FindRootError) -> Self { |
|
|||
53 | let kind = DebugDataErrorKind::FindRootError(err); |
|
|||
54 | DebugDataError { kind } |
|
|||
55 | } |
|
|||
56 | } |
|
|||
57 |
|
||||
58 | impl From<std::io::Error> for DebugDataError { |
|
51 | impl From<std::io::Error> for DebugDataError { | |
59 | fn from(err: std::io::Error) -> Self { |
|
52 | fn from(err: std::io::Error) -> Self { | |
60 | let kind = DebugDataErrorKind::IoError(err); |
|
53 | let kind = DebugDataErrorKind::IoError(err); | |
61 | DebugDataError { kind } |
|
54 | DebugDataError { kind } | |
62 | } |
|
55 | } | |
63 | } |
|
56 | } | |
64 |
|
57 | |||
65 | impl From<RevlogError> for DebugDataError { |
|
58 | impl From<RevlogError> for DebugDataError { | |
66 | fn from(err: RevlogError) -> Self { |
|
59 | fn from(err: RevlogError) -> Self { | |
67 | match err { |
|
60 | match err { | |
68 | RevlogError::IoError(err) => DebugDataErrorKind::IoError(err), |
|
61 | RevlogError::IoError(err) => DebugDataErrorKind::IoError(err), | |
69 | RevlogError::UnsuportedVersion(version) => { |
|
62 | RevlogError::UnsuportedVersion(version) => { | |
70 | DebugDataErrorKind::UnsuportedRevlogVersion(version) |
|
63 | DebugDataErrorKind::UnsuportedRevlogVersion(version) | |
71 | } |
|
64 | } | |
72 | RevlogError::InvalidRevision => { |
|
65 | RevlogError::InvalidRevision => { | |
73 | DebugDataErrorKind::InvalidRevision |
|
66 | DebugDataErrorKind::InvalidRevision | |
74 | } |
|
67 | } | |
75 | RevlogError::AmbiguousPrefix => { |
|
68 | RevlogError::AmbiguousPrefix => { | |
76 | DebugDataErrorKind::AmbiguousPrefix |
|
69 | DebugDataErrorKind::AmbiguousPrefix | |
77 | } |
|
70 | } | |
78 | RevlogError::Corrupted => DebugDataErrorKind::CorruptedRevlog, |
|
71 | RevlogError::Corrupted => DebugDataErrorKind::CorruptedRevlog, | |
79 | RevlogError::UnknowDataFormat(format) => { |
|
72 | RevlogError::UnknowDataFormat(format) => { | |
80 | DebugDataErrorKind::UnknowRevlogDataFormat(format) |
|
73 | DebugDataErrorKind::UnknowRevlogDataFormat(format) | |
81 | } |
|
74 | } | |
82 | } |
|
75 | } | |
83 | .into() |
|
76 | .into() | |
84 | } |
|
77 | } | |
85 | } |
|
78 | } | |
86 |
|
79 | |||
87 | /// Dump the contents data of a revision. |
|
80 | /// Dump the contents data of a revision. | |
88 | pub struct DebugData<'a> { |
|
81 | pub fn debug_data( | |
89 | /// Revision or hash of the revision. |
|
82 | root: &Path, | |
90 |
rev: & |
|
83 | rev: &str, | |
91 | /// Kind of data to debug. |
|
|||
92 | kind: DebugDataKind, |
|
84 | kind: DebugDataKind, | |
93 | } |
|
85 | ) -> Result<Vec<u8>, DebugDataError> { | |
94 |
|
86 | let index_file = match kind { | ||
95 | impl<'a> DebugData<'a> { |
|
|||
96 | pub fn new(rev: &'a str, kind: DebugDataKind) -> Self { |
|
|||
97 | DebugData { rev, kind } |
|
|||
98 | } |
|
|||
99 |
|
||||
100 | pub fn run(&mut self) -> Result<Vec<u8>, DebugDataError> { |
|
|||
101 | let root = find_root::FindRoot::new().run()?; |
|
|||
102 | let index_file = match self.kind { |
|
|||
103 |
|
|
87 | DebugDataKind::Changelog => root.join(".hg/store/00changelog.i"), | |
104 |
|
|
88 | DebugDataKind::Manifest => root.join(".hg/store/00manifest.i"), | |
105 |
|
|
89 | }; | |
106 |
|
|
90 | let revlog = Revlog::open(&index_file, None)?; | |
107 |
|
91 | |||
108 |
|
|
92 | let data = match rev.parse::<Revision>() { | |
109 |
|
|
93 | Ok(rev) => revlog.get_rev_data(rev)?, | |
110 |
|
|
94 | _ => { | |
111 |
|
|
95 | let node = NodePrefix::from_hex(&rev) | |
112 |
|
|
96 | .map_err(|_| DebugDataErrorKind::InvalidRevision)?; | |
113 |
|
|
97 | let rev = revlog.get_node_rev(node.borrow())?; | |
114 |
|
|
98 | revlog.get_rev_data(rev)? | |
115 |
|
|
99 | } | |
116 |
|
|
100 | }; | |
117 |
|
101 | |||
118 |
|
|
102 | Ok(data) | |
119 | } |
|
103 | } | |
120 | } |
|
@@ -1,119 +1,100 b'' | |||||
1 | use std::fmt; |
|
1 | use std::fmt; | |
2 | use std::path::{Path, PathBuf}; |
|
2 | use std::path::{Path, PathBuf}; | |
3 |
|
3 | |||
4 | /// Kind of error encoutered by FindRoot |
|
4 | /// Kind of error encoutered by FindRoot | |
5 | #[derive(Debug)] |
|
5 | #[derive(Debug)] | |
6 | pub enum FindRootErrorKind { |
|
6 | pub enum FindRootErrorKind { | |
7 | /// Root of the repository has not been found |
|
7 | /// Root of the repository has not been found | |
8 | /// Contains the current directory used by FindRoot |
|
8 | /// Contains the current directory used by FindRoot | |
9 | RootNotFound(PathBuf), |
|
9 | RootNotFound(PathBuf), | |
10 | /// The current directory does not exists or permissions are insufficient |
|
10 | /// The current directory does not exists or permissions are insufficient | |
11 | /// to get access to it |
|
11 | /// to get access to it | |
12 | GetCurrentDirError(std::io::Error), |
|
12 | GetCurrentDirError(std::io::Error), | |
13 | } |
|
13 | } | |
14 |
|
14 | |||
15 | /// A FindRoot error |
|
15 | /// A FindRoot error | |
16 | #[derive(Debug)] |
|
16 | #[derive(Debug)] | |
17 | pub struct FindRootError { |
|
17 | pub struct FindRootError { | |
18 | /// Kind of error encoutered by FindRoot |
|
18 | /// Kind of error encoutered by FindRoot | |
19 | pub kind: FindRootErrorKind, |
|
19 | pub kind: FindRootErrorKind, | |
20 | } |
|
20 | } | |
21 |
|
21 | |||
22 | impl std::error::Error for FindRootError {} |
|
22 | impl std::error::Error for FindRootError {} | |
23 |
|
23 | |||
24 | impl fmt::Display for FindRootError { |
|
24 | impl fmt::Display for FindRootError { | |
25 | fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { |
|
25 | fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
26 | unimplemented!() |
|
26 | unimplemented!() | |
27 | } |
|
27 | } | |
28 | } |
|
28 | } | |
29 |
|
29 | |||
30 | /// Find the root of the repository |
|
30 | /// Find the root of the repository | |
31 | /// by searching for a .hg directory in the current directory and its |
|
31 | /// by searching for a .hg directory in the process’ current directory and its | |
32 | /// ancestors |
|
32 | /// ancestors | |
33 | pub struct FindRoot<'a> { |
|
33 | pub fn find_root() -> Result<PathBuf, FindRootError> { | |
34 | current_dir: Option<&'a Path>, |
|
34 | let current_dir = std::env::current_dir().map_err(|e| FindRootError { | |
35 | } |
|
35 | kind: FindRootErrorKind::GetCurrentDirError(e), | |
36 |
|
36 | })?; | ||
37 | impl<'a> FindRoot<'a> { |
|
37 | Ok(find_root_from_path(¤t_dir)?.into()) | |
38 | pub fn new() -> Self { |
|
|||
39 | Self { current_dir: None } |
|
|||
40 | } |
|
|||
41 |
|
||||
42 | pub fn new_from_path(current_dir: &'a Path) -> Self { |
|
|||
43 | Self { |
|
|||
44 | current_dir: Some(current_dir), |
|
|||
45 | } |
|
|||
46 | } |
|
38 | } | |
47 |
|
39 | |||
48 | pub fn run(&self) -> Result<PathBuf, FindRootError> { |
|
40 | /// Find the root of the repository | |
49 | let current_dir = match self.current_dir { |
|
41 | /// by searching for a .hg directory in the given directory and its ancestors | |
50 | None => std::env::current_dir().or_else(|e| { |
|
42 | pub fn find_root_from_path(start: &Path) -> Result<&Path, FindRootError> { | |
51 | Err(FindRootError { |
|
43 | if start.join(".hg").exists() { | |
52 | kind: FindRootErrorKind::GetCurrentDirError(e), |
|
44 | return Ok(start); | |
53 | }) |
|
|||
54 | })?, |
|
|||
55 | Some(path) => path.into(), |
|
|||
56 | }; |
|
|||
57 |
|
||||
58 | if current_dir.join(".hg").exists() { |
|
|||
59 | return Ok(current_dir); |
|
|||
60 |
|
|
45 | } | |
61 |
|
|
46 | for ancestor in start.ancestors() { | |
62 | for parent in ancestors { |
|
47 | if ancestor.join(".hg").exists() { | |
63 | if parent.join(".hg").exists() { |
|
48 | return Ok(ancestor); | |
64 | return Ok(parent.into()); |
|
|||
65 |
|
|
49 | } | |
66 |
|
|
50 | } | |
67 |
|
|
51 | Err(FindRootError { | |
68 |
|
|
52 | kind: FindRootErrorKind::RootNotFound(start.into()), | |
69 |
|
|
53 | }) | |
70 | } |
|
54 | } | |
71 | } |
|
|||
72 |
|
55 | |||
73 | #[cfg(test)] |
|
56 | #[cfg(test)] | |
74 | mod tests { |
|
57 | mod tests { | |
75 | use super::*; |
|
58 | use super::*; | |
76 | use std::fs; |
|
59 | use std::fs; | |
77 | use tempfile; |
|
60 | use tempfile; | |
78 |
|
61 | |||
79 | #[test] |
|
62 | #[test] | |
80 | fn dot_hg_not_found() { |
|
63 | fn dot_hg_not_found() { | |
81 | let tmp_dir = tempfile::tempdir().unwrap(); |
|
64 | let tmp_dir = tempfile::tempdir().unwrap(); | |
82 | let path = tmp_dir.path(); |
|
65 | let path = tmp_dir.path(); | |
83 |
|
66 | |||
84 |
let err = |
|
67 | let err = find_root_from_path(&path).unwrap_err(); | |
85 |
|
68 | |||
86 | // TODO do something better |
|
69 | // TODO do something better | |
87 | assert!(match err { |
|
70 | assert!(match err { | |
88 | FindRootError { kind } => match kind { |
|
71 | FindRootError { kind } => match kind { | |
89 | FindRootErrorKind::RootNotFound(p) => p == path.to_path_buf(), |
|
72 | FindRootErrorKind::RootNotFound(p) => p == path.to_path_buf(), | |
90 | _ => false, |
|
73 | _ => false, | |
91 | }, |
|
74 | }, | |
92 | }) |
|
75 | }) | |
93 | } |
|
76 | } | |
94 |
|
77 | |||
95 | #[test] |
|
78 | #[test] | |
96 | fn dot_hg_in_current_path() { |
|
79 | fn dot_hg_in_current_path() { | |
97 | let tmp_dir = tempfile::tempdir().unwrap(); |
|
80 | let tmp_dir = tempfile::tempdir().unwrap(); | |
98 | let root = tmp_dir.path(); |
|
81 | let root = tmp_dir.path(); | |
99 | fs::create_dir_all(root.join(".hg")).unwrap(); |
|
82 | fs::create_dir_all(root.join(".hg")).unwrap(); | |
100 |
|
83 | |||
101 |
let result = |
|
84 | let result = find_root_from_path(&root).unwrap(); | |
102 |
|
85 | |||
103 | assert_eq!(result, root) |
|
86 | assert_eq!(result, root) | |
104 | } |
|
87 | } | |
105 |
|
88 | |||
106 | #[test] |
|
89 | #[test] | |
107 | fn dot_hg_in_parent() { |
|
90 | fn dot_hg_in_parent() { | |
108 | let tmp_dir = tempfile::tempdir().unwrap(); |
|
91 | let tmp_dir = tempfile::tempdir().unwrap(); | |
109 | let root = tmp_dir.path(); |
|
92 | let root = tmp_dir.path(); | |
110 | fs::create_dir_all(root.join(".hg")).unwrap(); |
|
93 | fs::create_dir_all(root.join(".hg")).unwrap(); | |
111 |
|
94 | |||
112 | let result = |
|
95 | let directory = root.join("some/nested/directory"); | |
113 | FindRoot::new_from_path(&root.join("some/nested/directory")) |
|
96 | let result = find_root_from_path(&directory).unwrap(); | |
114 | .run() |
|
|||
115 | .unwrap(); |
|
|||
116 |
|
97 | |||
117 | assert_eq!(result, root) |
|
98 | assert_eq!(result, root) | |
118 | } |
|
99 | } | |
119 | } /* tests */ |
|
100 | } /* tests */ |
@@ -1,194 +1,167 b'' | |||||
1 | // list_tracked_files.rs |
|
1 | // list_tracked_files.rs | |
2 | // |
|
2 | // | |
3 | // Copyright 2020 Antoine Cezar <antoine.cezar@octobus.net> |
|
3 | // Copyright 2020 Antoine Cezar <antoine.cezar@octobus.net> | |
4 | // |
|
4 | // | |
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::dirstate::parsers::parse_dirstate; |
|
8 | use crate::dirstate::parsers::parse_dirstate; | |
9 | use crate::revlog::changelog::Changelog; |
|
9 | use crate::revlog::changelog::Changelog; | |
10 | use crate::revlog::manifest::{Manifest, ManifestEntry}; |
|
10 | use crate::revlog::manifest::{Manifest, ManifestEntry}; | |
11 | use crate::revlog::node::{Node, NodePrefix}; |
|
11 | use crate::revlog::node::{Node, NodePrefix}; | |
12 | use crate::revlog::revlog::RevlogError; |
|
12 | use crate::revlog::revlog::RevlogError; | |
13 | use crate::revlog::Revision; |
|
13 | use crate::revlog::Revision; | |
14 | use crate::utils::hg_path::HgPath; |
|
14 | use crate::utils::hg_path::HgPath; | |
15 | use crate::{DirstateParseError, EntryState}; |
|
15 | use crate::{DirstateParseError, EntryState}; | |
16 | use rayon::prelude::*; |
|
16 | use rayon::prelude::*; | |
17 | use std::convert::From; |
|
17 | use std::convert::From; | |
18 | use std::fs; |
|
18 | use std::fs; | |
19 | use std::path::Path; |
|
19 | use std::path::Path; | |
20 |
|
20 | |||
21 | /// Kind of error encountered by `ListDirstateTrackedFiles` |
|
21 | /// Kind of error encountered by `ListDirstateTrackedFiles` | |
22 | #[derive(Debug)] |
|
22 | #[derive(Debug)] | |
23 | pub enum ListDirstateTrackedFilesErrorKind { |
|
23 | pub enum ListDirstateTrackedFilesErrorKind { | |
24 | /// Error when reading the `dirstate` file |
|
24 | /// Error when reading the `dirstate` file | |
25 | IoError(std::io::Error), |
|
25 | IoError(std::io::Error), | |
26 | /// Error when parsing the `dirstate` file |
|
26 | /// Error when parsing the `dirstate` file | |
27 | ParseError(DirstateParseError), |
|
27 | ParseError(DirstateParseError), | |
28 | } |
|
28 | } | |
29 |
|
29 | |||
30 | /// A `ListDirstateTrackedFiles` error |
|
30 | /// A `ListDirstateTrackedFiles` error | |
31 | #[derive(Debug)] |
|
31 | #[derive(Debug)] | |
32 | pub struct ListDirstateTrackedFilesError { |
|
32 | pub struct ListDirstateTrackedFilesError { | |
33 | /// Kind of error encountered by `ListDirstateTrackedFiles` |
|
33 | /// Kind of error encountered by `ListDirstateTrackedFiles` | |
34 | pub kind: ListDirstateTrackedFilesErrorKind, |
|
34 | pub kind: ListDirstateTrackedFilesErrorKind, | |
35 | } |
|
35 | } | |
36 |
|
36 | |||
37 | impl From<ListDirstateTrackedFilesErrorKind> |
|
37 | impl From<ListDirstateTrackedFilesErrorKind> | |
38 | for ListDirstateTrackedFilesError |
|
38 | for ListDirstateTrackedFilesError | |
39 | { |
|
39 | { | |
40 | fn from(kind: ListDirstateTrackedFilesErrorKind) -> Self { |
|
40 | fn from(kind: ListDirstateTrackedFilesErrorKind) -> Self { | |
41 | ListDirstateTrackedFilesError { kind } |
|
41 | ListDirstateTrackedFilesError { kind } | |
42 | } |
|
42 | } | |
43 | } |
|
43 | } | |
44 |
|
44 | |||
45 | impl From<std::io::Error> for ListDirstateTrackedFilesError { |
|
45 | impl From<std::io::Error> for ListDirstateTrackedFilesError { | |
46 | fn from(err: std::io::Error) -> Self { |
|
46 | fn from(err: std::io::Error) -> Self { | |
47 | let kind = ListDirstateTrackedFilesErrorKind::IoError(err); |
|
47 | let kind = ListDirstateTrackedFilesErrorKind::IoError(err); | |
48 | ListDirstateTrackedFilesError { kind } |
|
48 | ListDirstateTrackedFilesError { kind } | |
49 | } |
|
49 | } | |
50 | } |
|
50 | } | |
51 |
|
51 | |||
52 | /// List files under Mercurial control in the working directory |
|
52 | /// List files under Mercurial control in the working directory | |
53 | /// by reading the dirstate |
|
53 | /// by reading the dirstate | |
54 |
pub struct |
|
54 | pub struct Dirstate { | |
55 | /// The `dirstate` content. |
|
55 | /// The `dirstate` content. | |
56 | content: Vec<u8>, |
|
56 | content: Vec<u8>, | |
57 | } |
|
57 | } | |
58 |
|
58 | |||
59 |
impl |
|
59 | impl Dirstate { | |
60 | pub fn new(root: &Path) -> Result<Self, ListDirstateTrackedFilesError> { |
|
60 | pub fn new(root: &Path) -> Result<Self, ListDirstateTrackedFilesError> { | |
61 | let dirstate = root.join(".hg/dirstate"); |
|
61 | let dirstate = root.join(".hg/dirstate"); | |
62 | let content = fs::read(&dirstate)?; |
|
62 | let content = fs::read(&dirstate)?; | |
63 | Ok(Self { content }) |
|
63 | Ok(Self { content }) | |
64 | } |
|
64 | } | |
65 |
|
65 | |||
66 |
pub fn |
|
66 | pub fn tracked_files( | |
67 |
& |
|
67 | &self, | |
68 | ) -> Result<Vec<&HgPath>, ListDirstateTrackedFilesError> { |
|
68 | ) -> Result<Vec<&HgPath>, ListDirstateTrackedFilesError> { | |
69 | let (_, entries, _) = parse_dirstate(&self.content) |
|
69 | let (_, entries, _) = parse_dirstate(&self.content) | |
70 | .map_err(ListDirstateTrackedFilesErrorKind::ParseError)?; |
|
70 | .map_err(ListDirstateTrackedFilesErrorKind::ParseError)?; | |
71 | let mut files: Vec<&HgPath> = entries |
|
71 | let mut files: Vec<&HgPath> = entries | |
72 | .into_iter() |
|
72 | .into_iter() | |
73 | .filter_map(|(path, entry)| match entry.state { |
|
73 | .filter_map(|(path, entry)| match entry.state { | |
74 | EntryState::Removed => None, |
|
74 | EntryState::Removed => None, | |
75 | _ => Some(path), |
|
75 | _ => Some(path), | |
76 | }) |
|
76 | }) | |
77 | .collect(); |
|
77 | .collect(); | |
78 | files.par_sort_unstable(); |
|
78 | files.par_sort_unstable(); | |
79 | Ok(files) |
|
79 | Ok(files) | |
80 | } |
|
80 | } | |
81 | } |
|
81 | } | |
82 |
|
82 | |||
83 | /// Kind of error encountered by `ListRevTrackedFiles` |
|
83 | /// Kind of error encountered by `ListRevTrackedFiles` | |
84 | #[derive(Debug)] |
|
84 | #[derive(Debug)] | |
85 | pub enum ListRevTrackedFilesErrorKind { |
|
85 | pub enum ListRevTrackedFilesErrorKind { | |
86 | /// Error when reading a `revlog` file. |
|
86 | /// Error when reading a `revlog` file. | |
87 | IoError(std::io::Error), |
|
87 | IoError(std::io::Error), | |
88 | /// The revision has not been found. |
|
88 | /// The revision has not been found. | |
89 | InvalidRevision, |
|
89 | InvalidRevision, | |
90 | /// Found more than one revision whose ID match the requested prefix |
|
90 | /// Found more than one revision whose ID match the requested prefix | |
91 | AmbiguousPrefix, |
|
91 | AmbiguousPrefix, | |
92 | /// A `revlog` file is corrupted. |
|
92 | /// A `revlog` file is corrupted. | |
93 | CorruptedRevlog, |
|
93 | CorruptedRevlog, | |
94 | /// The `revlog` format version is not supported. |
|
94 | /// The `revlog` format version is not supported. | |
95 | UnsuportedRevlogVersion(u16), |
|
95 | UnsuportedRevlogVersion(u16), | |
96 | /// The `revlog` data format is not supported. |
|
96 | /// The `revlog` data format is not supported. | |
97 | UnknowRevlogDataFormat(u8), |
|
97 | UnknowRevlogDataFormat(u8), | |
98 | } |
|
98 | } | |
99 |
|
99 | |||
100 | /// A `ListRevTrackedFiles` error |
|
100 | /// A `ListRevTrackedFiles` error | |
101 | #[derive(Debug)] |
|
101 | #[derive(Debug)] | |
102 | pub struct ListRevTrackedFilesError { |
|
102 | pub struct ListRevTrackedFilesError { | |
103 | /// Kind of error encountered by `ListRevTrackedFiles` |
|
103 | /// Kind of error encountered by `ListRevTrackedFiles` | |
104 | pub kind: ListRevTrackedFilesErrorKind, |
|
104 | pub kind: ListRevTrackedFilesErrorKind, | |
105 | } |
|
105 | } | |
106 |
|
106 | |||
107 | impl From<ListRevTrackedFilesErrorKind> for ListRevTrackedFilesError { |
|
107 | impl From<ListRevTrackedFilesErrorKind> for ListRevTrackedFilesError { | |
108 | fn from(kind: ListRevTrackedFilesErrorKind) -> Self { |
|
108 | fn from(kind: ListRevTrackedFilesErrorKind) -> Self { | |
109 | ListRevTrackedFilesError { kind } |
|
109 | ListRevTrackedFilesError { kind } | |
110 | } |
|
110 | } | |
111 | } |
|
111 | } | |
112 |
|
112 | |||
113 | impl From<RevlogError> for ListRevTrackedFilesError { |
|
113 | impl From<RevlogError> for ListRevTrackedFilesError { | |
114 | fn from(err: RevlogError) -> Self { |
|
114 | fn from(err: RevlogError) -> Self { | |
115 | match err { |
|
115 | match err { | |
116 | RevlogError::IoError(err) => { |
|
116 | RevlogError::IoError(err) => { | |
117 | ListRevTrackedFilesErrorKind::IoError(err) |
|
117 | ListRevTrackedFilesErrorKind::IoError(err) | |
118 | } |
|
118 | } | |
119 | RevlogError::UnsuportedVersion(version) => { |
|
119 | RevlogError::UnsuportedVersion(version) => { | |
120 | ListRevTrackedFilesErrorKind::UnsuportedRevlogVersion(version) |
|
120 | ListRevTrackedFilesErrorKind::UnsuportedRevlogVersion(version) | |
121 | } |
|
121 | } | |
122 | RevlogError::InvalidRevision => { |
|
122 | RevlogError::InvalidRevision => { | |
123 | ListRevTrackedFilesErrorKind::InvalidRevision |
|
123 | ListRevTrackedFilesErrorKind::InvalidRevision | |
124 | } |
|
124 | } | |
125 | RevlogError::AmbiguousPrefix => { |
|
125 | RevlogError::AmbiguousPrefix => { | |
126 | ListRevTrackedFilesErrorKind::AmbiguousPrefix |
|
126 | ListRevTrackedFilesErrorKind::AmbiguousPrefix | |
127 | } |
|
127 | } | |
128 | RevlogError::Corrupted => { |
|
128 | RevlogError::Corrupted => { | |
129 | ListRevTrackedFilesErrorKind::CorruptedRevlog |
|
129 | ListRevTrackedFilesErrorKind::CorruptedRevlog | |
130 | } |
|
130 | } | |
131 | RevlogError::UnknowDataFormat(format) => { |
|
131 | RevlogError::UnknowDataFormat(format) => { | |
132 | ListRevTrackedFilesErrorKind::UnknowRevlogDataFormat(format) |
|
132 | ListRevTrackedFilesErrorKind::UnknowRevlogDataFormat(format) | |
133 | } |
|
133 | } | |
134 | } |
|
134 | } | |
135 | .into() |
|
135 | .into() | |
136 | } |
|
136 | } | |
137 | } |
|
137 | } | |
138 |
|
138 | |||
139 | /// List files under Mercurial control at a given revision. |
|
139 | /// List files under Mercurial control at a given revision. | |
140 |
pub |
|
140 | pub fn list_rev_tracked_files( | |
141 | /// The revision to list the files from. |
|
|||
142 | rev: &'a str, |
|
|||
143 | /// The changelog file |
|
|||
144 | changelog: Changelog, |
|
|||
145 | /// The manifest file |
|
|||
146 | manifest: Manifest, |
|
|||
147 | /// The manifest entry corresponding to the revision. |
|
|||
148 | /// |
|
|||
149 | /// Used to hold the owner of the returned references. |
|
|||
150 | manifest_entry: Option<ManifestEntry>, |
|
|||
151 | } |
|
|||
152 |
|
||||
153 | impl<'a> ListRevTrackedFiles<'a> { |
|
|||
154 | pub fn new( |
|
|||
155 |
|
|
141 | root: &Path, | |
156 |
|
|
142 | rev: &str, | |
157 |
|
|
143 | ) -> Result<FilesForRev, ListRevTrackedFilesError> { | |
158 |
|
|
144 | let changelog = Changelog::open(root)?; | |
159 |
|
|
145 | let manifest = Manifest::open(root)?; | |
160 |
|
146 | |||
161 | Ok(Self { |
|
147 | let changelog_entry = match rev.parse::<Revision>() { | |
162 | rev, |
|
148 | Ok(rev) => changelog.get_rev(rev)?, | |
163 | changelog, |
|
|||
164 | manifest, |
|
|||
165 | manifest_entry: None, |
|
|||
166 | }) |
|
|||
167 | } |
|
|||
168 |
|
||||
169 | pub fn run( |
|
|||
170 | &mut self, |
|
|||
171 | ) -> Result<impl Iterator<Item = &HgPath>, ListRevTrackedFilesError> { |
|
|||
172 | let changelog_entry = match self.rev.parse::<Revision>() { |
|
|||
173 | Ok(rev) => self.changelog.get_rev(rev)?, |
|
|||
174 |
|
|
149 | _ => { | |
175 |
|
|
150 | let changelog_node = NodePrefix::from_hex(&rev) | |
176 |
|
|
151 | .or(Err(ListRevTrackedFilesErrorKind::InvalidRevision))?; | |
177 |
|
|
152 | changelog.get_node(changelog_node.borrow())? | |
178 |
|
|
153 | } | |
179 |
|
|
154 | }; | |
180 |
|
|
155 | let manifest_node = Node::from_hex(&changelog_entry.manifest_node()?) | |
181 |
|
|
156 | .or(Err(ListRevTrackedFilesErrorKind::CorruptedRevlog))?; | |
182 |
|
157 | let manifest_entry = manifest.get_node((&manifest_node).into())?; | ||
183 |
|
|
158 | Ok(FilesForRev(manifest_entry)) | |
184 | Some(self.manifest.get_node((&manifest_node).into())?); |
|
159 | } | |
185 |
|
160 | |||
186 | if let Some(ref manifest_entry) = self.manifest_entry { |
|
161 | pub struct FilesForRev(ManifestEntry); | |
187 | Ok(manifest_entry.files()) |
|
162 | ||
188 | } else { |
|
163 | impl FilesForRev { | |
189 | panic!( |
|
164 | pub fn iter(&self) -> impl Iterator<Item = &HgPath> { | |
190 | "manifest entry should have been stored in self.manifest_node to ensure its lifetime since references are returned from it" |
|
165 | self.0.files() | |
191 | ) |
|
|||
192 |
|
|
166 | } | |
193 | } |
|
167 | } | |
194 | } |
|
@@ -1,28 +1,23 b'' | |||||
1 | //! A distinction is made between operations and commands. |
|
1 | //! A distinction is made between operations and commands. | |
2 | //! An operation is what can be done whereas a command is what is exposed by |
|
2 | //! An operation is what can be done whereas a command is what is exposed by | |
3 | //! the cli. A single command can use several operations to achieve its goal. |
|
3 | //! the cli. A single command can use several operations to achieve its goal. | |
4 |
|
4 | |||
5 | mod cat; |
|
5 | mod cat; | |
6 | mod debugdata; |
|
6 | mod debugdata; | |
7 | mod dirstate_status; |
|
7 | mod dirstate_status; | |
8 | mod find_root; |
|
8 | mod find_root; | |
9 | mod list_tracked_files; |
|
9 | mod list_tracked_files; | |
10 |
pub use cat::{ |
|
10 | pub use cat::{cat, CatRevError, CatRevErrorKind}; | |
11 | pub use debugdata::{ |
|
11 | pub use debugdata::{ | |
12 |
|
|
12 | debug_data, DebugDataError, DebugDataErrorKind, DebugDataKind, | |
13 | }; |
|
13 | }; | |
14 | pub use find_root::{FindRoot, FindRootError, FindRootErrorKind}; |
|
14 | pub use find_root::{ | |
15 | pub use list_tracked_files::{ |
|
15 | find_root, find_root_from_path, FindRootError, FindRootErrorKind, | |
16 | ListDirstateTrackedFiles, ListDirstateTrackedFilesError, |
|
|||
17 | ListDirstateTrackedFilesErrorKind, |
|
|||
18 | }; |
|
16 | }; | |
19 | pub use list_tracked_files::{ |
|
17 | pub use list_tracked_files::{ | |
20 |
|
|
18 | list_rev_tracked_files, FilesForRev, ListRevTrackedFilesError, | |
21 | ListRevTrackedFilesErrorKind, |
|
19 | ListRevTrackedFilesErrorKind, | |
22 | }; |
|
20 | }; | |
23 |
|
21 | pub use list_tracked_files::{ | ||
24 | // TODO add an `Operation` trait when GAT have landed (rust #44265): |
|
22 | Dirstate, ListDirstateTrackedFilesError, ListDirstateTrackedFilesErrorKind, | |
25 | // there is no way to currently define a trait which can both return |
|
23 | }; | |
26 | // references to `self` and to passed data, which is what we would need. |
|
|||
27 | // Generic Associated Types may fix this and allow us to have a unified |
|
|||
28 | // interface. |
|
@@ -1,108 +1,106 b'' | |||||
1 | use crate::commands::Command; |
|
1 | use crate::commands::Command; | |
2 | use crate::error::{CommandError, CommandErrorKind}; |
|
2 | use crate::error::{CommandError, CommandErrorKind}; | |
3 | use crate::ui::utf8_to_local; |
|
3 | use crate::ui::utf8_to_local; | |
4 | use crate::ui::Ui; |
|
4 | use crate::ui::Ui; | |
5 |
use hg::operations:: |
|
5 | use hg::operations::find_root; | |
6 |
use hg::operations::{ |
|
6 | use hg::operations::{cat, CatRevError, CatRevErrorKind}; | |
7 | use hg::requirements; |
|
7 | use hg::requirements; | |
8 | use hg::utils::hg_path::HgPathBuf; |
|
8 | use hg::utils::hg_path::HgPathBuf; | |
9 | use micro_timer::timed; |
|
9 | use micro_timer::timed; | |
10 | use std::convert::TryFrom; |
|
10 | use std::convert::TryFrom; | |
11 |
|
11 | |||
12 | pub const HELP_TEXT: &str = " |
|
12 | pub const HELP_TEXT: &str = " | |
13 | Output the current or given revision of files |
|
13 | Output the current or given revision of files | |
14 | "; |
|
14 | "; | |
15 |
|
15 | |||
16 | pub struct CatCommand<'a> { |
|
16 | pub struct CatCommand<'a> { | |
17 | rev: Option<&'a str>, |
|
17 | rev: Option<&'a str>, | |
18 | files: Vec<&'a str>, |
|
18 | files: Vec<&'a str>, | |
19 | } |
|
19 | } | |
20 |
|
20 | |||
21 | impl<'a> CatCommand<'a> { |
|
21 | impl<'a> CatCommand<'a> { | |
22 | pub fn new(rev: Option<&'a str>, files: Vec<&'a str>) -> Self { |
|
22 | pub fn new(rev: Option<&'a str>, files: Vec<&'a str>) -> Self { | |
23 | Self { rev, files } |
|
23 | Self { rev, files } | |
24 | } |
|
24 | } | |
25 |
|
25 | |||
26 | fn display(&self, ui: &Ui, data: &[u8]) -> Result<(), CommandError> { |
|
26 | fn display(&self, ui: &Ui, data: &[u8]) -> Result<(), CommandError> { | |
27 | ui.write_stdout(data)?; |
|
27 | ui.write_stdout(data)?; | |
28 | Ok(()) |
|
28 | Ok(()) | |
29 | } |
|
29 | } | |
30 | } |
|
30 | } | |
31 |
|
31 | |||
32 | impl<'a> Command for CatCommand<'a> { |
|
32 | impl<'a> Command for CatCommand<'a> { | |
33 | #[timed] |
|
33 | #[timed] | |
34 | fn run(&self, ui: &Ui) -> Result<(), CommandError> { |
|
34 | fn run(&self, ui: &Ui) -> Result<(), CommandError> { | |
35 |
let root = |
|
35 | let root = find_root()?; | |
36 | requirements::check(&root)?; |
|
36 | requirements::check(&root)?; | |
37 | let cwd = std::env::current_dir() |
|
37 | let cwd = std::env::current_dir() | |
38 | .or_else(|e| Err(CommandErrorKind::CurrentDirNotFound(e)))?; |
|
38 | .or_else(|e| Err(CommandErrorKind::CurrentDirNotFound(e)))?; | |
39 |
|
39 | |||
40 | let mut files = vec![]; |
|
40 | let mut files = vec![]; | |
41 | for file in self.files.iter() { |
|
41 | for file in self.files.iter() { | |
42 | let normalized = cwd.join(&file); |
|
42 | let normalized = cwd.join(&file); | |
43 | let stripped = normalized |
|
43 | let stripped = normalized | |
44 | .strip_prefix(&root) |
|
44 | .strip_prefix(&root) | |
45 | .or(Err(CommandErrorKind::Abort(None)))?; |
|
45 | .or(Err(CommandErrorKind::Abort(None)))?; | |
46 | let hg_file = HgPathBuf::try_from(stripped.to_path_buf()) |
|
46 | let hg_file = HgPathBuf::try_from(stripped.to_path_buf()) | |
47 | .or(Err(CommandErrorKind::Abort(None)))?; |
|
47 | .or(Err(CommandErrorKind::Abort(None)))?; | |
48 | files.push(hg_file); |
|
48 | files.push(hg_file); | |
49 | } |
|
49 | } | |
50 |
|
50 | |||
51 | match self.rev { |
|
51 | match self.rev { | |
52 | Some(rev) => { |
|
52 | Some(rev) => { | |
53 |
let |
|
53 | let data = cat(&root, rev, &files) | |
54 | .map_err(|e| map_rev_error(rev, e))?; |
|
54 | .map_err(|e| map_rev_error(rev, e))?; | |
55 | let data = |
|
|||
56 | operation.run().map_err(|e| map_rev_error(rev, e))?; |
|
|||
57 | self.display(ui, &data) |
|
55 | self.display(ui, &data) | |
58 | } |
|
56 | } | |
59 | None => Err(CommandErrorKind::Unimplemented.into()), |
|
57 | None => Err(CommandErrorKind::Unimplemented.into()), | |
60 | } |
|
58 | } | |
61 | } |
|
59 | } | |
62 | } |
|
60 | } | |
63 |
|
61 | |||
64 | /// Convert `CatRevErrorKind` to `CommandError` |
|
62 | /// Convert `CatRevErrorKind` to `CommandError` | |
65 | fn map_rev_error(rev: &str, err: CatRevError) -> CommandError { |
|
63 | fn map_rev_error(rev: &str, err: CatRevError) -> CommandError { | |
66 | CommandError { |
|
64 | CommandError { | |
67 | kind: match err.kind { |
|
65 | kind: match err.kind { | |
68 | CatRevErrorKind::IoError(err) => CommandErrorKind::Abort(Some( |
|
66 | CatRevErrorKind::IoError(err) => CommandErrorKind::Abort(Some( | |
69 | utf8_to_local(&format!("abort: {}\n", err)).into(), |
|
67 | utf8_to_local(&format!("abort: {}\n", err)).into(), | |
70 | )), |
|
68 | )), | |
71 | CatRevErrorKind::InvalidRevision => CommandErrorKind::Abort(Some( |
|
69 | CatRevErrorKind::InvalidRevision => CommandErrorKind::Abort(Some( | |
72 | utf8_to_local(&format!( |
|
70 | utf8_to_local(&format!( | |
73 | "abort: invalid revision identifier {}\n", |
|
71 | "abort: invalid revision identifier {}\n", | |
74 | rev |
|
72 | rev | |
75 | )) |
|
73 | )) | |
76 | .into(), |
|
74 | .into(), | |
77 | )), |
|
75 | )), | |
78 | CatRevErrorKind::AmbiguousPrefix => CommandErrorKind::Abort(Some( |
|
76 | CatRevErrorKind::AmbiguousPrefix => CommandErrorKind::Abort(Some( | |
79 | utf8_to_local(&format!( |
|
77 | utf8_to_local(&format!( | |
80 | "abort: ambiguous revision identifier {}\n", |
|
78 | "abort: ambiguous revision identifier {}\n", | |
81 | rev |
|
79 | rev | |
82 | )) |
|
80 | )) | |
83 | .into(), |
|
81 | .into(), | |
84 | )), |
|
82 | )), | |
85 | CatRevErrorKind::UnsuportedRevlogVersion(version) => { |
|
83 | CatRevErrorKind::UnsuportedRevlogVersion(version) => { | |
86 | CommandErrorKind::Abort(Some( |
|
84 | CommandErrorKind::Abort(Some( | |
87 | utf8_to_local(&format!( |
|
85 | utf8_to_local(&format!( | |
88 | "abort: unsupported revlog version {}\n", |
|
86 | "abort: unsupported revlog version {}\n", | |
89 | version |
|
87 | version | |
90 | )) |
|
88 | )) | |
91 | .into(), |
|
89 | .into(), | |
92 | )) |
|
90 | )) | |
93 | } |
|
91 | } | |
94 | CatRevErrorKind::CorruptedRevlog => CommandErrorKind::Abort(Some( |
|
92 | CatRevErrorKind::CorruptedRevlog => CommandErrorKind::Abort(Some( | |
95 | "abort: corrupted revlog\n".into(), |
|
93 | "abort: corrupted revlog\n".into(), | |
96 | )), |
|
94 | )), | |
97 | CatRevErrorKind::UnknowRevlogDataFormat(format) => { |
|
95 | CatRevErrorKind::UnknowRevlogDataFormat(format) => { | |
98 | CommandErrorKind::Abort(Some( |
|
96 | CommandErrorKind::Abort(Some( | |
99 | utf8_to_local(&format!( |
|
97 | utf8_to_local(&format!( | |
100 | "abort: unknow revlog dataformat {:?}\n", |
|
98 | "abort: unknow revlog dataformat {:?}\n", | |
101 | format |
|
99 | format | |
102 | )) |
|
100 | )) | |
103 | .into(), |
|
101 | .into(), | |
104 | )) |
|
102 | )) | |
105 | } |
|
103 | } | |
106 | }, |
|
104 | }, | |
107 | } |
|
105 | } | |
108 | } |
|
106 | } |
@@ -1,91 +1,91 b'' | |||||
1 | use crate::commands::Command; |
|
1 | use crate::commands::Command; | |
2 | use crate::error::{CommandError, CommandErrorKind}; |
|
2 | use crate::error::{CommandError, CommandErrorKind}; | |
3 | use crate::ui::utf8_to_local; |
|
3 | use crate::ui::utf8_to_local; | |
4 | use crate::ui::Ui; |
|
4 | use crate::ui::Ui; | |
|
5 | use hg::operations::find_root; | |||
5 | use hg::operations::{ |
|
6 | use hg::operations::{ | |
6 |
|
|
7 | debug_data, DebugDataError, DebugDataErrorKind, DebugDataKind, | |
7 | }; |
|
8 | }; | |
8 | use micro_timer::timed; |
|
9 | use micro_timer::timed; | |
9 |
|
10 | |||
10 | pub const HELP_TEXT: &str = " |
|
11 | pub const HELP_TEXT: &str = " | |
11 | Dump the contents of a data file revision |
|
12 | Dump the contents of a data file revision | |
12 | "; |
|
13 | "; | |
13 |
|
14 | |||
14 | pub struct DebugDataCommand<'a> { |
|
15 | pub struct DebugDataCommand<'a> { | |
15 | rev: &'a str, |
|
16 | rev: &'a str, | |
16 | kind: DebugDataKind, |
|
17 | kind: DebugDataKind, | |
17 | } |
|
18 | } | |
18 |
|
19 | |||
19 | impl<'a> DebugDataCommand<'a> { |
|
20 | impl<'a> DebugDataCommand<'a> { | |
20 | pub fn new(rev: &'a str, kind: DebugDataKind) -> Self { |
|
21 | pub fn new(rev: &'a str, kind: DebugDataKind) -> Self { | |
21 | DebugDataCommand { rev, kind } |
|
22 | DebugDataCommand { rev, kind } | |
22 | } |
|
23 | } | |
23 | } |
|
24 | } | |
24 |
|
25 | |||
25 | impl<'a> Command for DebugDataCommand<'a> { |
|
26 | impl<'a> Command for DebugDataCommand<'a> { | |
26 | #[timed] |
|
27 | #[timed] | |
27 | fn run(&self, ui: &Ui) -> Result<(), CommandError> { |
|
28 | fn run(&self, ui: &Ui) -> Result<(), CommandError> { | |
28 | let mut operation = DebugData::new(self.rev, self.kind); |
|
29 | let root = find_root()?; | |
29 | let data = |
|
30 | let data = debug_data(&root, self.rev, self.kind) | |
30 |
|
|
31 | .map_err(|e| to_command_error(self.rev, e))?; | |
31 |
|
32 | |||
32 | let mut stdout = ui.stdout_buffer(); |
|
33 | let mut stdout = ui.stdout_buffer(); | |
33 | stdout.write_all(&data)?; |
|
34 | stdout.write_all(&data)?; | |
34 | stdout.flush()?; |
|
35 | stdout.flush()?; | |
35 |
|
36 | |||
36 | Ok(()) |
|
37 | Ok(()) | |
37 | } |
|
38 | } | |
38 | } |
|
39 | } | |
39 |
|
40 | |||
40 | /// Convert operation errors to command errors |
|
41 | /// Convert operation errors to command errors | |
41 | fn to_command_error(rev: &str, err: DebugDataError) -> CommandError { |
|
42 | fn to_command_error(rev: &str, err: DebugDataError) -> CommandError { | |
42 | match err.kind { |
|
43 | match err.kind { | |
43 | DebugDataErrorKind::FindRootError(err) => CommandError::from(err), |
|
|||
44 | DebugDataErrorKind::IoError(err) => CommandError { |
|
44 | DebugDataErrorKind::IoError(err) => CommandError { | |
45 | kind: CommandErrorKind::Abort(Some( |
|
45 | kind: CommandErrorKind::Abort(Some( | |
46 | utf8_to_local(&format!("abort: {}\n", err)).into(), |
|
46 | utf8_to_local(&format!("abort: {}\n", err)).into(), | |
47 | )), |
|
47 | )), | |
48 | }, |
|
48 | }, | |
49 | DebugDataErrorKind::InvalidRevision => CommandError { |
|
49 | DebugDataErrorKind::InvalidRevision => CommandError { | |
50 | kind: CommandErrorKind::Abort(Some( |
|
50 | kind: CommandErrorKind::Abort(Some( | |
51 | utf8_to_local(&format!( |
|
51 | utf8_to_local(&format!( | |
52 | "abort: invalid revision identifier{}\n", |
|
52 | "abort: invalid revision identifier{}\n", | |
53 | rev |
|
53 | rev | |
54 | )) |
|
54 | )) | |
55 | .into(), |
|
55 | .into(), | |
56 | )), |
|
56 | )), | |
57 | }, |
|
57 | }, | |
58 | DebugDataErrorKind::AmbiguousPrefix => CommandError { |
|
58 | DebugDataErrorKind::AmbiguousPrefix => CommandError { | |
59 | kind: CommandErrorKind::Abort(Some( |
|
59 | kind: CommandErrorKind::Abort(Some( | |
60 | utf8_to_local(&format!( |
|
60 | utf8_to_local(&format!( | |
61 | "abort: ambiguous revision identifier{}\n", |
|
61 | "abort: ambiguous revision identifier{}\n", | |
62 | rev |
|
62 | rev | |
63 | )) |
|
63 | )) | |
64 | .into(), |
|
64 | .into(), | |
65 | )), |
|
65 | )), | |
66 | }, |
|
66 | }, | |
67 | DebugDataErrorKind::UnsuportedRevlogVersion(version) => CommandError { |
|
67 | DebugDataErrorKind::UnsuportedRevlogVersion(version) => CommandError { | |
68 | kind: CommandErrorKind::Abort(Some( |
|
68 | kind: CommandErrorKind::Abort(Some( | |
69 | utf8_to_local(&format!( |
|
69 | utf8_to_local(&format!( | |
70 | "abort: unsupported revlog version {}\n", |
|
70 | "abort: unsupported revlog version {}\n", | |
71 | version |
|
71 | version | |
72 | )) |
|
72 | )) | |
73 | .into(), |
|
73 | .into(), | |
74 | )), |
|
74 | )), | |
75 | }, |
|
75 | }, | |
76 | DebugDataErrorKind::CorruptedRevlog => CommandError { |
|
76 | DebugDataErrorKind::CorruptedRevlog => CommandError { | |
77 | kind: CommandErrorKind::Abort(Some( |
|
77 | kind: CommandErrorKind::Abort(Some( | |
78 | "abort: corrupted revlog\n".into(), |
|
78 | "abort: corrupted revlog\n".into(), | |
79 | )), |
|
79 | )), | |
80 | }, |
|
80 | }, | |
81 | DebugDataErrorKind::UnknowRevlogDataFormat(format) => CommandError { |
|
81 | DebugDataErrorKind::UnknowRevlogDataFormat(format) => CommandError { | |
82 | kind: CommandErrorKind::Abort(Some( |
|
82 | kind: CommandErrorKind::Abort(Some( | |
83 | utf8_to_local(&format!( |
|
83 | utf8_to_local(&format!( | |
84 | "abort: unknow revlog dataformat {:?}\n", |
|
84 | "abort: unknow revlog dataformat {:?}\n", | |
85 | format |
|
85 | format | |
86 | )) |
|
86 | )) | |
87 | .into(), |
|
87 | .into(), | |
88 | )), |
|
88 | )), | |
89 | }, |
|
89 | }, | |
90 | } |
|
90 | } | |
91 | } |
|
91 | } |
@@ -1,30 +1,30 b'' | |||||
1 | use crate::commands::Command; |
|
1 | use crate::commands::Command; | |
2 | use crate::error::CommandError; |
|
2 | use crate::error::CommandError; | |
3 | use crate::ui::Ui; |
|
3 | use crate::ui::Ui; | |
4 |
use hg::operations:: |
|
4 | use hg::operations::find_root; | |
5 | use hg::requirements; |
|
5 | use hg::requirements; | |
6 |
|
6 | |||
7 | pub const HELP_TEXT: &str = " |
|
7 | pub const HELP_TEXT: &str = " | |
8 | Print the current repo requirements. |
|
8 | Print the current repo requirements. | |
9 | "; |
|
9 | "; | |
10 |
|
10 | |||
11 | pub struct DebugRequirementsCommand {} |
|
11 | pub struct DebugRequirementsCommand {} | |
12 |
|
12 | |||
13 | impl DebugRequirementsCommand { |
|
13 | impl DebugRequirementsCommand { | |
14 | pub fn new() -> Self { |
|
14 | pub fn new() -> Self { | |
15 | DebugRequirementsCommand {} |
|
15 | DebugRequirementsCommand {} | |
16 | } |
|
16 | } | |
17 | } |
|
17 | } | |
18 |
|
18 | |||
19 | impl Command for DebugRequirementsCommand { |
|
19 | impl Command for DebugRequirementsCommand { | |
20 | fn run(&self, ui: &Ui) -> Result<(), CommandError> { |
|
20 | fn run(&self, ui: &Ui) -> Result<(), CommandError> { | |
21 |
let root = |
|
21 | let root = find_root()?; | |
22 | let mut output = String::new(); |
|
22 | let mut output = String::new(); | |
23 | for req in requirements::load(&root)? { |
|
23 | for req in requirements::load(&root)? { | |
24 | output.push_str(&req); |
|
24 | output.push_str(&req); | |
25 | output.push('\n'); |
|
25 | output.push('\n'); | |
26 | } |
|
26 | } | |
27 | ui.write_stdout(output.as_bytes())?; |
|
27 | ui.write_stdout(output.as_bytes())?; | |
28 | Ok(()) |
|
28 | Ok(()) | |
29 | } |
|
29 | } | |
30 | } |
|
30 | } |
@@ -1,147 +1,144 b'' | |||||
1 | use crate::commands::Command; |
|
1 | use crate::commands::Command; | |
2 | use crate::error::{CommandError, CommandErrorKind}; |
|
2 | use crate::error::{CommandError, CommandErrorKind}; | |
3 | use crate::ui::utf8_to_local; |
|
3 | use crate::ui::utf8_to_local; | |
4 | use crate::ui::Ui; |
|
4 | use crate::ui::Ui; | |
5 |
use hg::operations:: |
|
5 | use hg::operations::find_root; | |
6 | use hg::operations::{ |
|
6 | use hg::operations::{ | |
7 |
|
|
7 | list_rev_tracked_files, ListRevTrackedFilesError, | |
8 |
List |
|
8 | ListRevTrackedFilesErrorKind, | |
9 | }; |
|
9 | }; | |
10 | use hg::operations::{ |
|
10 | use hg::operations::{ | |
11 | ListRevTrackedFiles, ListRevTrackedFilesError, |
|
11 | Dirstate, ListDirstateTrackedFilesError, ListDirstateTrackedFilesErrorKind, | |
12 | ListRevTrackedFilesErrorKind, |
|
|||
13 | }; |
|
12 | }; | |
14 | use hg::requirements; |
|
13 | use hg::requirements; | |
15 | use hg::utils::files::{get_bytes_from_path, relativize_path}; |
|
14 | use hg::utils::files::{get_bytes_from_path, relativize_path}; | |
16 | use hg::utils::hg_path::{HgPath, HgPathBuf}; |
|
15 | use hg::utils::hg_path::{HgPath, HgPathBuf}; | |
17 | use std::path::Path; |
|
16 | use std::path::Path; | |
18 |
|
17 | |||
19 | pub const HELP_TEXT: &str = " |
|
18 | pub const HELP_TEXT: &str = " | |
20 | List tracked files. |
|
19 | List tracked files. | |
21 |
|
20 | |||
22 | Returns 0 on success. |
|
21 | Returns 0 on success. | |
23 | "; |
|
22 | "; | |
24 |
|
23 | |||
25 | pub struct FilesCommand<'a> { |
|
24 | pub struct FilesCommand<'a> { | |
26 | rev: Option<&'a str>, |
|
25 | rev: Option<&'a str>, | |
27 | } |
|
26 | } | |
28 |
|
27 | |||
29 | impl<'a> FilesCommand<'a> { |
|
28 | impl<'a> FilesCommand<'a> { | |
30 | pub fn new(rev: Option<&'a str>) -> Self { |
|
29 | pub fn new(rev: Option<&'a str>) -> Self { | |
31 | FilesCommand { rev } |
|
30 | FilesCommand { rev } | |
32 | } |
|
31 | } | |
33 |
|
32 | |||
34 | fn display_files( |
|
33 | fn display_files( | |
35 | &self, |
|
34 | &self, | |
36 | ui: &Ui, |
|
35 | ui: &Ui, | |
37 | root: &Path, |
|
36 | root: &Path, | |
38 | files: impl IntoIterator<Item = &'a HgPath>, |
|
37 | files: impl IntoIterator<Item = &'a HgPath>, | |
39 | ) -> Result<(), CommandError> { |
|
38 | ) -> Result<(), CommandError> { | |
40 | let cwd = std::env::current_dir() |
|
39 | let cwd = std::env::current_dir() | |
41 | .or_else(|e| Err(CommandErrorKind::CurrentDirNotFound(e)))?; |
|
40 | .or_else(|e| Err(CommandErrorKind::CurrentDirNotFound(e)))?; | |
42 | let rooted_cwd = cwd |
|
41 | let rooted_cwd = cwd | |
43 | .strip_prefix(root) |
|
42 | .strip_prefix(root) | |
44 | .expect("cwd was already checked within the repository"); |
|
43 | .expect("cwd was already checked within the repository"); | |
45 | let rooted_cwd = HgPathBuf::from(get_bytes_from_path(rooted_cwd)); |
|
44 | let rooted_cwd = HgPathBuf::from(get_bytes_from_path(rooted_cwd)); | |
46 |
|
45 | |||
47 | let mut stdout = ui.stdout_buffer(); |
|
46 | let mut stdout = ui.stdout_buffer(); | |
48 |
|
47 | |||
49 | for file in files { |
|
48 | for file in files { | |
50 | stdout.write_all(relativize_path(file, &rooted_cwd).as_ref())?; |
|
49 | stdout.write_all(relativize_path(file, &rooted_cwd).as_ref())?; | |
51 | stdout.write_all(b"\n")?; |
|
50 | stdout.write_all(b"\n")?; | |
52 | } |
|
51 | } | |
53 | stdout.flush()?; |
|
52 | stdout.flush()?; | |
54 | Ok(()) |
|
53 | Ok(()) | |
55 | } |
|
54 | } | |
56 | } |
|
55 | } | |
57 |
|
56 | |||
58 | impl<'a> Command for FilesCommand<'a> { |
|
57 | impl<'a> Command for FilesCommand<'a> { | |
59 | fn run(&self, ui: &Ui) -> Result<(), CommandError> { |
|
58 | fn run(&self, ui: &Ui) -> Result<(), CommandError> { | |
60 |
let root = |
|
59 | let root = find_root()?; | |
61 | requirements::check(&root)?; |
|
60 | requirements::check(&root)?; | |
62 | if let Some(rev) = self.rev { |
|
61 | if let Some(rev) = self.rev { | |
63 |
let |
|
62 | let files = list_rev_tracked_files(&root, rev) | |
64 | .map_err(|e| map_rev_error(rev, e))?; |
|
63 | .map_err(|e| map_rev_error(rev, e))?; | |
65 | let files = operation.run().map_err(|e| map_rev_error(rev, e))?; |
|
64 | self.display_files(ui, &root, files.iter()) | |
66 | self.display_files(ui, &root, files) |
|
|||
67 | } else { |
|
65 | } else { | |
68 | let mut operation = ListDirstateTrackedFiles::new(&root) |
|
66 | let distate = Dirstate::new(&root).map_err(map_dirstate_error)?; | |
69 |
|
|
67 | let files = distate.tracked_files().map_err(map_dirstate_error)?; | |
70 | let files = operation.run().map_err(map_dirstate_error)?; |
|
|||
71 | self.display_files(ui, &root, files) |
|
68 | self.display_files(ui, &root, files) | |
72 | } |
|
69 | } | |
73 | } |
|
70 | } | |
74 | } |
|
71 | } | |
75 |
|
72 | |||
76 | /// Convert `ListRevTrackedFilesErrorKind` to `CommandError` |
|
73 | /// Convert `ListRevTrackedFilesErrorKind` to `CommandError` | |
77 | fn map_rev_error(rev: &str, err: ListRevTrackedFilesError) -> CommandError { |
|
74 | fn map_rev_error(rev: &str, err: ListRevTrackedFilesError) -> CommandError { | |
78 | CommandError { |
|
75 | CommandError { | |
79 | kind: match err.kind { |
|
76 | kind: match err.kind { | |
80 | ListRevTrackedFilesErrorKind::IoError(err) => { |
|
77 | ListRevTrackedFilesErrorKind::IoError(err) => { | |
81 | CommandErrorKind::Abort(Some( |
|
78 | CommandErrorKind::Abort(Some( | |
82 | utf8_to_local(&format!("abort: {}\n", err)).into(), |
|
79 | utf8_to_local(&format!("abort: {}\n", err)).into(), | |
83 | )) |
|
80 | )) | |
84 | } |
|
81 | } | |
85 | ListRevTrackedFilesErrorKind::InvalidRevision => { |
|
82 | ListRevTrackedFilesErrorKind::InvalidRevision => { | |
86 | CommandErrorKind::Abort(Some( |
|
83 | CommandErrorKind::Abort(Some( | |
87 | utf8_to_local(&format!( |
|
84 | utf8_to_local(&format!( | |
88 | "abort: invalid revision identifier {}\n", |
|
85 | "abort: invalid revision identifier {}\n", | |
89 | rev |
|
86 | rev | |
90 | )) |
|
87 | )) | |
91 | .into(), |
|
88 | .into(), | |
92 | )) |
|
89 | )) | |
93 | } |
|
90 | } | |
94 | ListRevTrackedFilesErrorKind::AmbiguousPrefix => { |
|
91 | ListRevTrackedFilesErrorKind::AmbiguousPrefix => { | |
95 | CommandErrorKind::Abort(Some( |
|
92 | CommandErrorKind::Abort(Some( | |
96 | utf8_to_local(&format!( |
|
93 | utf8_to_local(&format!( | |
97 | "abort: ambiguous revision identifier {}\n", |
|
94 | "abort: ambiguous revision identifier {}\n", | |
98 | rev |
|
95 | rev | |
99 | )) |
|
96 | )) | |
100 | .into(), |
|
97 | .into(), | |
101 | )) |
|
98 | )) | |
102 | } |
|
99 | } | |
103 | ListRevTrackedFilesErrorKind::UnsuportedRevlogVersion(version) => { |
|
100 | ListRevTrackedFilesErrorKind::UnsuportedRevlogVersion(version) => { | |
104 | CommandErrorKind::Abort(Some( |
|
101 | CommandErrorKind::Abort(Some( | |
105 | utf8_to_local(&format!( |
|
102 | utf8_to_local(&format!( | |
106 | "abort: unsupported revlog version {}\n", |
|
103 | "abort: unsupported revlog version {}\n", | |
107 | version |
|
104 | version | |
108 | )) |
|
105 | )) | |
109 | .into(), |
|
106 | .into(), | |
110 | )) |
|
107 | )) | |
111 | } |
|
108 | } | |
112 | ListRevTrackedFilesErrorKind::CorruptedRevlog => { |
|
109 | ListRevTrackedFilesErrorKind::CorruptedRevlog => { | |
113 | CommandErrorKind::Abort(Some( |
|
110 | CommandErrorKind::Abort(Some( | |
114 | "abort: corrupted revlog\n".into(), |
|
111 | "abort: corrupted revlog\n".into(), | |
115 | )) |
|
112 | )) | |
116 | } |
|
113 | } | |
117 | ListRevTrackedFilesErrorKind::UnknowRevlogDataFormat(format) => { |
|
114 | ListRevTrackedFilesErrorKind::UnknowRevlogDataFormat(format) => { | |
118 | CommandErrorKind::Abort(Some( |
|
115 | CommandErrorKind::Abort(Some( | |
119 | utf8_to_local(&format!( |
|
116 | utf8_to_local(&format!( | |
120 | "abort: unknow revlog dataformat {:?}\n", |
|
117 | "abort: unknow revlog dataformat {:?}\n", | |
121 | format |
|
118 | format | |
122 | )) |
|
119 | )) | |
123 | .into(), |
|
120 | .into(), | |
124 | )) |
|
121 | )) | |
125 | } |
|
122 | } | |
126 | }, |
|
123 | }, | |
127 | } |
|
124 | } | |
128 | } |
|
125 | } | |
129 |
|
126 | |||
130 | /// Convert `ListDirstateTrackedFilesError` to `CommandError` |
|
127 | /// Convert `ListDirstateTrackedFilesError` to `CommandError` | |
131 | fn map_dirstate_error(err: ListDirstateTrackedFilesError) -> CommandError { |
|
128 | fn map_dirstate_error(err: ListDirstateTrackedFilesError) -> CommandError { | |
132 | CommandError { |
|
129 | CommandError { | |
133 | kind: match err.kind { |
|
130 | kind: match err.kind { | |
134 | ListDirstateTrackedFilesErrorKind::IoError(err) => { |
|
131 | ListDirstateTrackedFilesErrorKind::IoError(err) => { | |
135 | CommandErrorKind::Abort(Some( |
|
132 | CommandErrorKind::Abort(Some( | |
136 | utf8_to_local(&format!("abort: {}\n", err)).into(), |
|
133 | utf8_to_local(&format!("abort: {}\n", err)).into(), | |
137 | )) |
|
134 | )) | |
138 | } |
|
135 | } | |
139 | ListDirstateTrackedFilesErrorKind::ParseError(_) => { |
|
136 | ListDirstateTrackedFilesErrorKind::ParseError(_) => { | |
140 | CommandErrorKind::Abort(Some( |
|
137 | CommandErrorKind::Abort(Some( | |
141 | // TODO find a better error message |
|
138 | // TODO find a better error message | |
142 | b"abort: parse error\n".to_vec(), |
|
139 | b"abort: parse error\n".to_vec(), | |
143 | )) |
|
140 | )) | |
144 | } |
|
141 | } | |
145 | }, |
|
142 | }, | |
146 | } |
|
143 | } | |
147 | } |
|
144 | } |
@@ -1,32 +1,32 b'' | |||||
1 | use crate::commands::Command; |
|
1 | use crate::commands::Command; | |
2 | use crate::error::CommandError; |
|
2 | use crate::error::CommandError; | |
3 | use crate::ui::Ui; |
|
3 | use crate::ui::Ui; | |
4 | use format_bytes::format_bytes; |
|
4 | use format_bytes::format_bytes; | |
5 |
use hg::operations:: |
|
5 | use hg::operations::find_root; | |
6 | use hg::utils::files::get_bytes_from_path; |
|
6 | use hg::utils::files::get_bytes_from_path; | |
7 |
|
7 | |||
8 | pub const HELP_TEXT: &str = " |
|
8 | pub const HELP_TEXT: &str = " | |
9 | Print the root directory of the current repository. |
|
9 | Print the root directory of the current repository. | |
10 |
|
10 | |||
11 | Returns 0 on success. |
|
11 | Returns 0 on success. | |
12 | "; |
|
12 | "; | |
13 |
|
13 | |||
14 | pub struct RootCommand {} |
|
14 | pub struct RootCommand {} | |
15 |
|
15 | |||
16 | impl RootCommand { |
|
16 | impl RootCommand { | |
17 | pub fn new() -> Self { |
|
17 | pub fn new() -> Self { | |
18 | RootCommand {} |
|
18 | RootCommand {} | |
19 | } |
|
19 | } | |
20 | } |
|
20 | } | |
21 |
|
21 | |||
22 | impl Command for RootCommand { |
|
22 | impl Command for RootCommand { | |
23 | fn run(&self, ui: &Ui) -> Result<(), CommandError> { |
|
23 | fn run(&self, ui: &Ui) -> Result<(), CommandError> { | |
24 |
let path_buf = |
|
24 | let path_buf = find_root()?; | |
25 |
|
25 | |||
26 | let bytes = get_bytes_from_path(path_buf); |
|
26 | let bytes = get_bytes_from_path(path_buf); | |
27 |
|
27 | |||
28 | ui.write_stdout(&format_bytes!(b"{}\n", bytes.as_slice()))?; |
|
28 | ui.write_stdout(&format_bytes!(b"{}\n", bytes.as_slice()))?; | |
29 |
|
29 | |||
30 | Ok(()) |
|
30 | Ok(()) | |
31 | } |
|
31 | } | |
32 | } |
|
32 | } |
General Comments 0
You need to be logged in to leave comments.
Login now