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 | 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 | mod cat; | |
|
5 | 6 | mod debugdata; |
|
6 | 7 | mod dirstate_status; |
|
7 | 8 | mod find_root; |
|
8 | 9 | mod list_tracked_files; |
|
10 | pub use cat::{CatRev, CatRevError, CatRevErrorKind}; | |
|
9 | 11 | pub use debugdata::{ |
|
10 | 12 | DebugData, DebugDataError, DebugDataErrorKind, DebugDataKind, |
|
11 | 13 | }; |
General Comments 0
You need to be logged in to leave comments.
Login now