##// END OF EJS Templates
hg-core: add a `CatRev` operation...
Antoine Cezar -
r46112:522ec3dc default
parent child Browse files
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