Show More
@@ -0,0 +1,145 b'' | |||||
|
1 | // list_tracked_files.rs | |||
|
2 | // | |||
|
3 | // Copyright 2020 Antoine Cezar <antoine.cezar@octobus.net> | |||
|
4 | // | |||
|
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. | |||
|
7 | ||||
|
8 | use std::convert::From; | |||
|
9 | use std::path::PathBuf; | |||
|
10 | ||||
|
11 | use crate::revlog::changelog::Changelog; | |||
|
12 | use crate::revlog::manifest::{Manifest, ManifestEntry}; | |||
|
13 | use crate::revlog::path_encode::path_encode; | |||
|
14 | use crate::revlog::revlog::Revlog; | |||
|
15 | use crate::revlog::revlog::RevlogError; | |||
|
16 | use crate::revlog::Revision; | |||
|
17 | use crate::utils::hg_path::HgPathBuf; | |||
|
18 | ||||
|
19 | /// Kind of error encountered by `CatRev` | |||
|
20 | #[derive(Debug)] | |||
|
21 | pub enum CatRevErrorKind { | |||
|
22 | /// Error when reading a `revlog` file. | |||
|
23 | IoError(std::io::Error), | |||
|
24 | /// The revision has not been found. | |||
|
25 | InvalidRevision, | |||
|
26 | /// A `revlog` file is corrupted. | |||
|
27 | CorruptedRevlog, | |||
|
28 | /// The `revlog` format version is not supported. | |||
|
29 | UnsuportedRevlogVersion(u16), | |||
|
30 | /// The `revlog` data format is not supported. | |||
|
31 | UnknowRevlogDataFormat(u8), | |||
|
32 | } | |||
|
33 | ||||
|
34 | /// A `CatRev` error | |||
|
35 | #[derive(Debug)] | |||
|
36 | pub struct CatRevError { | |||
|
37 | /// Kind of error encountered by `CatRev` | |||
|
38 | pub kind: CatRevErrorKind, | |||
|
39 | } | |||
|
40 | ||||
|
41 | impl From<CatRevErrorKind> for CatRevError { | |||
|
42 | fn from(kind: CatRevErrorKind) -> Self { | |||
|
43 | CatRevError { kind } | |||
|
44 | } | |||
|
45 | } | |||
|
46 | ||||
|
47 | impl From<RevlogError> for CatRevError { | |||
|
48 | fn from(err: RevlogError) -> Self { | |||
|
49 | match err { | |||
|
50 | RevlogError::IoError(err) => CatRevErrorKind::IoError(err), | |||
|
51 | RevlogError::UnsuportedVersion(version) => { | |||
|
52 | CatRevErrorKind::UnsuportedRevlogVersion(version) | |||
|
53 | } | |||
|
54 | RevlogError::InvalidRevision => CatRevErrorKind::InvalidRevision, | |||
|
55 | RevlogError::Corrupted => CatRevErrorKind::CorruptedRevlog, | |||
|
56 | RevlogError::UnknowDataFormat(format) => { | |||
|
57 | CatRevErrorKind::UnknowRevlogDataFormat(format) | |||
|
58 | } | |||
|
59 | } | |||
|
60 | .into() | |||
|
61 | } | |||
|
62 | } | |||
|
63 | ||||
|
64 | /// List files under Mercurial control at a given revision. | |||
|
65 | pub struct CatRev<'a> { | |||
|
66 | root: &'a PathBuf, | |||
|
67 | /// The revision to cat the files from. | |||
|
68 | rev: &'a str, | |||
|
69 | /// The files to output. | |||
|
70 | files: &'a [HgPathBuf], | |||
|
71 | /// The changelog file | |||
|
72 | changelog: Changelog, | |||
|
73 | /// The manifest file | |||
|
74 | manifest: Manifest, | |||
|
75 | /// The manifest entry corresponding to the revision. | |||
|
76 | /// | |||
|
77 | /// Used to hold the owner of the returned references. | |||
|
78 | manifest_entry: Option<ManifestEntry>, | |||
|
79 | } | |||
|
80 | ||||
|
81 | impl<'a> CatRev<'a> { | |||
|
82 | pub fn new( | |||
|
83 | root: &'a PathBuf, | |||
|
84 | rev: &'a str, | |||
|
85 | files: &'a [HgPathBuf], | |||
|
86 | ) -> Result<Self, CatRevError> { | |||
|
87 | let changelog = Changelog::open(&root)?; | |||
|
88 | let manifest = Manifest::open(&root)?; | |||
|
89 | let manifest_entry = None; | |||
|
90 | ||||
|
91 | Ok(Self { | |||
|
92 | root, | |||
|
93 | rev, | |||
|
94 | files, | |||
|
95 | changelog, | |||
|
96 | manifest, | |||
|
97 | manifest_entry, | |||
|
98 | }) | |||
|
99 | } | |||
|
100 | ||||
|
101 | pub fn run(&mut self) -> Result<Vec<u8>, CatRevError> { | |||
|
102 | let changelog_entry = match self.rev.parse::<Revision>() { | |||
|
103 | Ok(rev) => self.changelog.get_rev(rev)?, | |||
|
104 | _ => { | |||
|
105 | let changelog_node = hex::decode(&self.rev) | |||
|
106 | .map_err(|_| CatRevErrorKind::InvalidRevision)?; | |||
|
107 | self.changelog.get_node(&changelog_node)? | |||
|
108 | } | |||
|
109 | }; | |||
|
110 | let manifest_node = hex::decode(&changelog_entry.manifest_node()?) | |||
|
111 | .map_err(|_| CatRevErrorKind::CorruptedRevlog)?; | |||
|
112 | ||||
|
113 | self.manifest_entry = Some(self.manifest.get_node(&manifest_node)?); | |||
|
114 | if let Some(ref manifest_entry) = self.manifest_entry { | |||
|
115 | let mut bytes = vec![]; | |||
|
116 | ||||
|
117 | for (manifest_file, node_bytes) in | |||
|
118 | manifest_entry.files_with_nodes() | |||
|
119 | { | |||
|
120 | for cat_file in self.files.iter() { | |||
|
121 | if cat_file.as_bytes() == manifest_file.as_bytes() { | |||
|
122 | let encoded_bytes = | |||
|
123 | path_encode(manifest_file.as_bytes()); | |||
|
124 | let revlog_index_string = format!( | |||
|
125 | ".hg/store/data/{}.i", | |||
|
126 | String::from_utf8_lossy(&encoded_bytes), | |||
|
127 | ); | |||
|
128 | let revlog_index_path = | |||
|
129 | self.root.join(&revlog_index_string); | |||
|
130 | let file_log = Revlog::open(&revlog_index_path)?; | |||
|
131 | let file_node = hex::decode(&node_bytes) | |||
|
132 | .map_err(|_| CatRevErrorKind::CorruptedRevlog)?; | |||
|
133 | let file_rev = file_log.get_node_rev(&file_node)?; | |||
|
134 | let data = file_log.get_rev_data(file_rev)?; | |||
|
135 | bytes.extend(data); | |||
|
136 | } | |||
|
137 | } | |||
|
138 | } | |||
|
139 | ||||
|
140 | Ok(bytes) | |||
|
141 | } else { | |||
|
142 | unreachable!("manifest_entry should have been stored"); | |||
|
143 | } | |||
|
144 | } | |||
|
145 | } |
@@ -2,10 +2,12 b'' | |||||
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 debugdata; |
|
6 | mod debugdata; | |
6 | mod dirstate_status; |
|
7 | mod dirstate_status; | |
7 | mod find_root; |
|
8 | mod find_root; | |
8 | mod list_tracked_files; |
|
9 | mod list_tracked_files; | |
|
10 | pub use cat::{CatRev, CatRevError, CatRevErrorKind}; | |||
9 | pub use debugdata::{ |
|
11 | pub use debugdata::{ | |
10 | DebugData, DebugDataError, DebugDataErrorKind, DebugDataKind, |
|
12 | DebugData, DebugDataError, DebugDataErrorKind, DebugDataKind, | |
11 | }; |
|
13 | }; |
General Comments 0
You need to be logged in to leave comments.
Login now