##// END OF EJS Templates
rhg: internally, return a structured representation from hg cat...
Arseniy Alekseyev -
r49051:027ebad9 default
parent child Browse files
Show More
@@ -10,20 +10,19 b' use crate::revlog::revlog::RevlogError;'
10 use crate::revlog::Node;
10 use crate::revlog::Node;
11
11
12 use crate::utils::hg_path::HgPath;
12 use crate::utils::hg_path::HgPath;
13 use crate::utils::hg_path::HgPathBuf;
14
13
15 use itertools::put_back;
14 use itertools::put_back;
16 use itertools::PutBack;
15 use itertools::PutBack;
17 use std::cmp::Ordering;
16 use std::cmp::Ordering;
18
17
19 pub struct CatOutput {
18 pub struct CatOutput<'a> {
20 /// Whether any file in the manifest matched the paths given as CLI
19 /// Whether any file in the manifest matched the paths given as CLI
21 /// arguments
20 /// arguments
22 pub found_any: bool,
21 pub found_any: bool,
23 /// The contents of matching files, in manifest order
22 /// The contents of matching files, in manifest order
24 pub concatenated: Vec<u8>,
23 pub results: Vec<(&'a HgPath, Vec<u8>)>,
25 /// Which of the CLI arguments did not match any manifest file
24 /// Which of the CLI arguments did not match any manifest file
26 pub missing: Vec<HgPathBuf>,
25 pub missing: Vec<&'a HgPath>,
27 /// The node ID that the given revset was resolved to
26 /// The node ID that the given revset was resolved to
28 pub node: Node,
27 pub node: Node,
29 }
28 }
@@ -32,7 +31,7 b' pub struct CatOutput {'
32 fn find_item<'a, 'b, 'c, D, I: Iterator<Item = (&'a HgPath, D)>>(
31 fn find_item<'a, 'b, 'c, D, I: Iterator<Item = (&'a HgPath, D)>>(
33 i: &mut PutBack<I>,
32 i: &mut PutBack<I>,
34 needle: &'b HgPath,
33 needle: &'b HgPath,
35 ) -> Option<I::Item> {
34 ) -> Option<D> {
36 loop {
35 loop {
37 match i.next() {
36 match i.next() {
38 None => return None,
37 None => return None,
@@ -42,30 +41,30 b" fn find_item<'a, 'b, 'c, D, I: Iterator<"
42 return None;
41 return None;
43 }
42 }
44 Ordering::Greater => continue,
43 Ordering::Greater => continue,
45 Ordering::Equal => return Some(val),
44 Ordering::Equal => return Some(val.1),
46 },
45 },
47 }
46 }
48 }
47 }
49 }
48 }
50
49
51 fn find_files_in_manifest<
50 fn find_files_in_manifest<
52 'a,
51 'manifest,
53 'b,
52 'query,
54 D,
53 Data,
55 I: Iterator<Item = (&'a HgPath, D)>,
54 Manifest: Iterator<Item = (&'manifest HgPath, Data)>,
56 J: Iterator<Item = &'b HgPath>,
55 Query: Iterator<Item = &'query HgPath>,
57 >(
56 >(
58 manifest: I,
57 manifest: Manifest,
59 files: J,
58 query: Query,
60 ) -> (Vec<(&'a HgPath, D)>, Vec<&'b HgPath>) {
59 ) -> (Vec<(&'query HgPath, Data)>, Vec<&'query HgPath>) {
61 let mut manifest = put_back(manifest);
60 let mut manifest = put_back(manifest);
62 let mut res = vec![];
61 let mut res = vec![];
63 let mut missing = vec![];
62 let mut missing = vec![];
64
63
65 for file in files {
64 for file in query {
66 match find_item(&mut manifest, file) {
65 match find_item(&mut manifest, file) {
67 None => missing.push(file),
66 None => missing.push(file),
68 Some(item) => res.push(item),
67 Some(item) => res.push((file, item)),
69 }
68 }
70 }
69 }
71 return (res, missing);
70 return (res, missing);
@@ -79,36 +78,37 b' fn find_files_in_manifest<'
79 pub fn cat<'a>(
78 pub fn cat<'a>(
80 repo: &Repo,
79 repo: &Repo,
81 revset: &str,
80 revset: &str,
82 mut files: Vec<HgPathBuf>,
81 mut files: Vec<&'a HgPath>,
83 ) -> Result<CatOutput, RevlogError> {
82 ) -> Result<CatOutput<'a>, RevlogError> {
84 let rev = crate::revset::resolve_single(revset, repo)?;
83 let rev = crate::revset::resolve_single(revset, repo)?;
85 let manifest = repo.manifest_for_rev(rev)?;
84 let manifest = repo.manifest_for_rev(rev)?;
86 let node = *repo
85 let node = *repo
87 .changelog()?
86 .changelog()?
88 .node_from_rev(rev)
87 .node_from_rev(rev)
89 .expect("should succeed when repo.manifest did");
88 .expect("should succeed when repo.manifest did");
90 let mut bytes: Vec<u8> = vec![];
89 let mut results: Vec<(&'a HgPath, Vec<u8>)> = vec![];
91 let mut found_any = false;
90 let mut found_any = false;
92
91
93 files.sort_unstable();
92 files.sort_unstable();
94
93
95 let (found, missing) = find_files_in_manifest(
94 let (found, missing) = find_files_in_manifest(
96 manifest.files_with_nodes(),
95 manifest.files_with_nodes(),
97 files.iter().map(|f| f.as_ref()),
96 files.into_iter().map(|f| f.as_ref()),
98 );
97 );
99
98
100 for (manifest_file, node_bytes) in found {
99 for (file_path, node_bytes) in found {
101 found_any = true;
100 found_any = true;
102 let file_log = repo.filelog(manifest_file)?;
101 let file_log = repo.filelog(file_path)?;
103 let file_node = Node::from_hex_for_repo(node_bytes)?;
102 let file_node = Node::from_hex_for_repo(node_bytes)?;
104 bytes.extend(file_log.data_for_node(file_node)?.data()?);
103 results.push((
104 file_path,
105 file_log.data_for_node(file_node)?.into_data()?,
106 ));
105 }
107 }
106
108
107 let missing: Vec<HgPathBuf> =
108 missing.iter().map(|file| (*file).to_owned()).collect();
109 Ok(CatOutput {
109 Ok(CatOutput {
110 found_any,
110 found_any,
111 concatenated: bytes,
111 results,
112 missing,
112 missing,
113 node,
113 node,
114 })
114 })
@@ -7,7 +7,6 b' use crate::revlog::Revision;'
7 use crate::utils::files::get_path_from_bytes;
7 use crate::utils::files::get_path_from_bytes;
8 use crate::utils::hg_path::HgPath;
8 use crate::utils::hg_path::HgPath;
9 use crate::utils::SliceExt;
9 use crate::utils::SliceExt;
10 use std::borrow::Cow;
11 use std::path::PathBuf;
10 use std::path::PathBuf;
12
11
13 /// A specialized `Revlog` to work with file data logs.
12 /// A specialized `Revlog` to work with file data logs.
@@ -40,7 +39,7 b' impl Filelog {'
40 &self,
39 &self,
41 file_rev: Revision,
40 file_rev: Revision,
42 ) -> Result<FilelogEntry, RevlogError> {
41 ) -> Result<FilelogEntry, RevlogError> {
43 let data = self.revlog.get_rev_data(file_rev)?;
42 let data: Vec<u8> = self.revlog.get_rev_data(file_rev)?;
44 Ok(FilelogEntry(data.into()))
43 Ok(FilelogEntry(data.into()))
45 }
44 }
46 }
45 }
@@ -51,22 +50,32 b' fn store_path(hg_path: &HgPath, suffix: '
51 get_path_from_bytes(&encoded_bytes).into()
50 get_path_from_bytes(&encoded_bytes).into()
52 }
51 }
53
52
54 pub struct FilelogEntry<'filelog>(Cow<'filelog, [u8]>);
53 pub struct FilelogEntry(Vec<u8>);
55
54
56 impl<'filelog> FilelogEntry<'filelog> {
55 impl FilelogEntry {
57 /// Split into metadata and data
56 /// Split into metadata and data
58 pub fn split(&self) -> Result<(Option<&[u8]>, &[u8]), HgError> {
57 /// Returns None if there is no metadata, so the entire entry is data.
58 fn split_metadata(&self) -> Result<Option<(&[u8], &[u8])>, HgError> {
59 const DELIMITER: &[u8; 2] = &[b'\x01', b'\n'];
59 const DELIMITER: &[u8; 2] = &[b'\x01', b'\n'];
60
60
61 if let Some(rest) = self.0.drop_prefix(DELIMITER) {
61 if let Some(rest) = self.0.drop_prefix(DELIMITER) {
62 if let Some((metadata, data)) = rest.split_2_by_slice(DELIMITER) {
62 if let Some((metadata, data)) = rest.split_2_by_slice(DELIMITER) {
63 Ok((Some(metadata), data))
63 Ok(Some((metadata, data)))
64 } else {
64 } else {
65 Err(HgError::corrupted(
65 Err(HgError::corrupted(
66 "Missing metadata end delimiter in filelog entry",
66 "Missing metadata end delimiter in filelog entry",
67 ))
67 ))
68 }
68 }
69 } else {
69 } else {
70 Ok(None)
71 }
72 }
73
74 /// Split into metadata and data
75 pub fn split(&self) -> Result<(Option<&[u8]>, &[u8]), HgError> {
76 if let Some((metadata, data)) = self.split_metadata()? {
77 Ok((Some(metadata), data))
78 } else {
70 Ok((None, &self.0))
79 Ok((None, &self.0))
71 }
80 }
72 }
81 }
@@ -76,4 +85,14 b" impl<'filelog> FilelogEntry<'filelog> {"
76 let (_metadata, data) = self.split()?;
85 let (_metadata, data) = self.split()?;
77 Ok(data)
86 Ok(data)
78 }
87 }
88
89 /// Consume the entry, and convert it into data, discarding any metadata,
90 /// if present.
91 pub fn into_data(self) -> Result<Vec<u8>, HgError> {
92 if let Some((_metadata, data)) = self.split_metadata()? {
93 Ok(data.to_owned())
94 } else {
95 Ok(self.0)
96 }
97 }
79 }
98 }
@@ -66,6 +66,7 b' pub fn run(invocation: &crate::CliInvoca'
66 .map_err(|e| CommandError::abort(e.to_string()))?;
66 .map_err(|e| CommandError::abort(e.to_string()))?;
67 files.push(hg_file);
67 files.push(hg_file);
68 }
68 }
69 let files = files.iter().map(|file| file.as_ref()).collect();
69 // TODO probably move this to a util function like `repo.default_rev` or
70 // TODO probably move this to a util function like `repo.default_rev` or
70 // something when it's used somewhere else
71 // something when it's used somewhere else
71 let rev = match rev {
72 let rev = match rev {
@@ -74,7 +75,9 b' pub fn run(invocation: &crate::CliInvoca'
74 };
75 };
75
76
76 let output = cat(&repo, &rev, files).map_err(|e| (e, rev.as_str()))?;
77 let output = cat(&repo, &rev, files).map_err(|e| (e, rev.as_str()))?;
77 invocation.ui.write_stdout(&output.concatenated)?;
78 for (_file, contents) in output.results {
79 invocation.ui.write_stdout(&contents)?;
80 }
78 if !output.missing.is_empty() {
81 if !output.missing.is_empty() {
79 let short = format!("{:x}", output.node.short()).into_bytes();
82 let short = format!("{:x}", output.node.short()).into_bytes();
80 for path in &output.missing {
83 for path in &output.missing {
General Comments 0
You need to be logged in to leave comments. Login now