7 |
7 |
8 use crate::repo::Repo; |
8 use crate::repo::Repo; |
9 use crate::revlog::revlog::RevlogError; |
9 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::HgPathBuf; |
13 use crate::utils::hg_path::HgPathBuf; |
13 |
14 |
14 use itertools::EitherOrBoth::{Both, Left, Right}; |
15 use itertools::put_back; |
15 use itertools::Itertools; |
16 use itertools::PutBack; |
|
17 use std::cmp::Ordering; |
16 |
18 |
17 pub struct CatOutput { |
19 pub struct CatOutput { |
18 /// Whether any file in the manifest matched the paths given as CLI |
20 /// Whether any file in the manifest matched the paths given as CLI |
19 /// arguments |
21 /// arguments |
20 pub found_any: bool, |
22 pub found_any: bool, |
22 pub concatenated: Vec<u8>, |
24 pub concatenated: Vec<u8>, |
23 /// Which of the CLI arguments did not match any manifest file |
25 /// Which of the CLI arguments did not match any manifest file |
24 pub missing: Vec<HgPathBuf>, |
26 pub missing: Vec<HgPathBuf>, |
25 /// The node ID that the given revset was resolved to |
27 /// The node ID that the given revset was resolved to |
26 pub node: Node, |
28 pub node: Node, |
|
29 } |
|
30 |
|
31 // Find an item in an iterator over a sorted collection. |
|
32 fn find_item<'a, 'b, 'c, D, I: Iterator<Item = (&'a HgPath, D)>>( |
|
33 i: &mut PutBack<I>, |
|
34 needle: &'b HgPath, |
|
35 ) -> Option<I::Item> { |
|
36 loop { |
|
37 match i.next() { |
|
38 None => return None, |
|
39 Some(val) => match needle.as_bytes().cmp(val.0.as_bytes()) { |
|
40 Ordering::Less => { |
|
41 i.put_back(val); |
|
42 return None; |
|
43 } |
|
44 Ordering::Greater => continue, |
|
45 Ordering::Equal => return Some(val), |
|
46 }, |
|
47 } |
|
48 } |
|
49 } |
|
50 |
|
51 fn find_files_in_manifest< |
|
52 'a, |
|
53 'b, |
|
54 D, |
|
55 I: Iterator<Item = (&'a HgPath, D)>, |
|
56 J: Iterator<Item = &'b HgPath>, |
|
57 >( |
|
58 manifest: I, |
|
59 files: J, |
|
60 ) -> (Vec<(&'a HgPath, D)>, Vec<&'b HgPath>) { |
|
61 let mut manifest = put_back(manifest); |
|
62 let mut res = vec![]; |
|
63 let mut missing = vec![]; |
|
64 |
|
65 for file in files { |
|
66 match find_item(&mut manifest, file) { |
|
67 None => missing.push(file), |
|
68 Some(item) => res.push(item), |
|
69 } |
|
70 } |
|
71 return (res, missing); |
27 } |
72 } |
28 |
73 |
29 /// Output the given revision of files |
74 /// Output the given revision of files |
30 /// |
75 /// |
31 /// * `root`: Repository root |
76 /// * `root`: Repository root |
40 let manifest = repo.manifest_for_rev(rev)?; |
85 let manifest = repo.manifest_for_rev(rev)?; |
41 let node = *repo |
86 let node = *repo |
42 .changelog()? |
87 .changelog()? |
43 .node_from_rev(rev) |
88 .node_from_rev(rev) |
44 .expect("should succeed when repo.manifest did"); |
89 .expect("should succeed when repo.manifest did"); |
45 let mut bytes = vec![]; |
90 let mut bytes: Vec<u8> = vec![]; |
46 let mut found_any = false; |
91 let mut found_any = false; |
|
92 |
47 files.sort_unstable(); |
93 files.sort_unstable(); |
48 |
94 |
49 let mut missing = vec![]; |
95 let (found, missing) = find_files_in_manifest( |
|
96 manifest.files_with_nodes(), |
|
97 files.iter().map(|f| f.as_ref()), |
|
98 ); |
50 |
99 |
51 for entry in manifest |
100 for (manifest_file, node_bytes) in found { |
52 .files_with_nodes() |
101 found_any = true; |
53 .merge_join_by(files.iter(), |(manifest_file, _), file| { |
102 let file_log = repo.filelog(manifest_file)?; |
54 manifest_file.cmp(&file.as_ref()) |
103 let file_node = Node::from_hex_for_repo(node_bytes)?; |
55 }) |
104 bytes.extend(file_log.data_for_node(file_node)?.data()?); |
56 { |
|
57 match entry { |
|
58 Left(_) => (), |
|
59 Right(path) => missing.push(path), |
|
60 Both((manifest_file, node_bytes), _) => { |
|
61 found_any = true; |
|
62 let file_log = repo.filelog(manifest_file)?; |
|
63 let file_node = Node::from_hex_for_repo(node_bytes)?; |
|
64 let entry = file_log.data_for_node(file_node)?; |
|
65 bytes.extend(entry.data()?) |
|
66 } |
|
67 } |
|
68 } |
105 } |
69 |
106 |
70 let missing: Vec<HgPathBuf> = missing |
107 let missing: Vec<HgPathBuf> = missing |
71 .iter() |
108 .iter() |
72 .map(|file| (*(file.as_ref())).to_owned()) |
109 .map(|file| (*file).to_owned()) |
73 .collect(); |
110 .collect(); |
74 Ok(CatOutput { |
111 Ok(CatOutput { |
75 found_any, |
112 found_any, |
76 concatenated: bytes, |
113 concatenated: bytes, |
77 missing, |
114 missing, |