##// END OF EJS Templates
rhg: strip copied files metadata from `cat` output...
Antoine cezar -
r46395:056aeed4 default draft
parent child Browse files
Show More
@@ -1,145 +1,158 b''
1 1 // list_tracked_files.rs
2 2 //
3 3 // Copyright 2020 Antoine Cezar <antoine.cezar@octobus.net>
4 4 //
5 5 // This software may be used and distributed according to the terms of the
6 6 // GNU General Public License version 2 or any later version.
7 7
8 8 use std::convert::From;
9 9 use std::path::PathBuf;
10 10
11 11 use crate::revlog::changelog::Changelog;
12 12 use crate::revlog::manifest::{Manifest, ManifestEntry};
13 13 use crate::revlog::path_encode::path_encode;
14 14 use crate::revlog::revlog::Revlog;
15 15 use crate::revlog::revlog::RevlogError;
16 16 use crate::revlog::Revision;
17 17 use crate::utils::hg_path::HgPathBuf;
18 18
19 const METADATA_DELIMITER: [u8; 2] = [b'\x01', b'\n'];
20
19 21 /// Kind of error encountered by `CatRev`
20 22 #[derive(Debug)]
21 23 pub enum CatRevErrorKind {
22 24 /// Error when reading a `revlog` file.
23 25 IoError(std::io::Error),
24 26 /// The revision has not been found.
25 27 InvalidRevision,
26 28 /// A `revlog` file is corrupted.
27 29 CorruptedRevlog,
28 30 /// The `revlog` format version is not supported.
29 31 UnsuportedRevlogVersion(u16),
30 32 /// The `revlog` data format is not supported.
31 33 UnknowRevlogDataFormat(u8),
32 34 }
33 35
34 36 /// A `CatRev` error
35 37 #[derive(Debug)]
36 38 pub struct CatRevError {
37 39 /// Kind of error encountered by `CatRev`
38 40 pub kind: CatRevErrorKind,
39 41 }
40 42
41 43 impl From<CatRevErrorKind> for CatRevError {
42 44 fn from(kind: CatRevErrorKind) -> Self {
43 45 CatRevError { kind }
44 46 }
45 47 }
46 48
47 49 impl From<RevlogError> for CatRevError {
48 50 fn from(err: RevlogError) -> Self {
49 51 match err {
50 52 RevlogError::IoError(err) => CatRevErrorKind::IoError(err),
51 53 RevlogError::UnsuportedVersion(version) => {
52 54 CatRevErrorKind::UnsuportedRevlogVersion(version)
53 55 }
54 56 RevlogError::InvalidRevision => CatRevErrorKind::InvalidRevision,
55 57 RevlogError::Corrupted => CatRevErrorKind::CorruptedRevlog,
56 58 RevlogError::UnknowDataFormat(format) => {
57 59 CatRevErrorKind::UnknowRevlogDataFormat(format)
58 60 }
59 61 }
60 62 .into()
61 63 }
62 64 }
63 65
64 66 /// List files under Mercurial control at a given revision.
65 67 pub struct CatRev<'a> {
66 68 root: &'a PathBuf,
67 69 /// The revision to cat the files from.
68 70 rev: &'a str,
69 71 /// The files to output.
70 72 files: &'a [HgPathBuf],
71 73 /// The changelog file
72 74 changelog: Changelog,
73 75 /// The manifest file
74 76 manifest: Manifest,
75 77 /// The manifest entry corresponding to the revision.
76 78 ///
77 79 /// Used to hold the owner of the returned references.
78 80 manifest_entry: Option<ManifestEntry>,
79 81 }
80 82
81 83 impl<'a> CatRev<'a> {
82 84 pub fn new(
83 85 root: &'a PathBuf,
84 86 rev: &'a str,
85 87 files: &'a [HgPathBuf],
86 88 ) -> Result<Self, CatRevError> {
87 89 let changelog = Changelog::open(&root)?;
88 90 let manifest = Manifest::open(&root)?;
89 91 let manifest_entry = None;
90 92
91 93 Ok(Self {
92 94 root,
93 95 rev,
94 96 files,
95 97 changelog,
96 98 manifest,
97 99 manifest_entry,
98 100 })
99 101 }
100 102
101 103 pub fn run(&mut self) -> Result<Vec<u8>, CatRevError> {
102 104 let changelog_entry = match self.rev.parse::<Revision>() {
103 105 Ok(rev) => self.changelog.get_rev(rev)?,
104 106 _ => {
105 107 let changelog_node = hex::decode(&self.rev)
106 108 .map_err(|_| CatRevErrorKind::InvalidRevision)?;
107 109 self.changelog.get_node(&changelog_node)?
108 110 }
109 111 };
110 112 let manifest_node = hex::decode(&changelog_entry.manifest_node()?)
111 113 .map_err(|_| CatRevErrorKind::CorruptedRevlog)?;
112 114
113 115 self.manifest_entry = Some(self.manifest.get_node(&manifest_node)?);
114 116 if let Some(ref manifest_entry) = self.manifest_entry {
115 117 let mut bytes = vec![];
116 118
117 119 for (manifest_file, node_bytes) in
118 120 manifest_entry.files_with_nodes()
119 121 {
120 122 for cat_file in self.files.iter() {
121 123 if cat_file.as_bytes() == manifest_file.as_bytes() {
122 124 let encoded_bytes =
123 125 path_encode(manifest_file.as_bytes());
124 126 let revlog_index_string = format!(
125 127 ".hg/store/data/{}.i",
126 128 String::from_utf8_lossy(&encoded_bytes),
127 129 );
128 130 let revlog_index_path =
129 131 self.root.join(&revlog_index_string);
130 132 let file_log = Revlog::open(&revlog_index_path)?;
131 133 let file_node = hex::decode(&node_bytes)
132 134 .map_err(|_| CatRevErrorKind::CorruptedRevlog)?;
133 135 let file_rev = file_log.get_node_rev(&file_node)?;
134 136 let data = file_log.get_rev_data(file_rev)?;
135 bytes.extend(data);
137 if data.starts_with(&METADATA_DELIMITER) {
138 let end_delimiter_position = data
139 [METADATA_DELIMITER.len()..]
140 .windows(METADATA_DELIMITER.len())
141 .position(|bytes| bytes == METADATA_DELIMITER);
142 if let Some(position) = end_delimiter_position {
143 let offset = METADATA_DELIMITER.len() * 2;
144 bytes.extend(data[position + offset..].iter());
145 }
146 } else {
147 bytes.extend(data);
148 }
136 149 }
137 150 }
138 151 }
139 152
140 153 Ok(bytes)
141 154 } else {
142 155 unreachable!("manifest_entry should have been stored");
143 156 }
144 157 }
145 158 }
@@ -1,92 +1,108 b''
1 1 #require rust
2 2
3 3 Define an rhg function that will only run if rhg exists
4 4 $ rhg() {
5 5 > if [ -f "$RUNTESTDIR/../rust/target/debug/rhg" ]; then
6 6 > "$RUNTESTDIR/../rust/target/debug/rhg" "$@"
7 7 > else
8 8 > echo "skipped: Cannot find rhg. Try to run cargo build in rust/rhg."
9 9 > exit 80
10 10 > fi
11 11 > }
12 12
13 13 Unimplemented command
14 14 $ rhg unimplemented-command
15 15 error: Found argument 'unimplemented-command' which wasn't expected, or isn't valid in this context
16 16
17 17 USAGE:
18 18 rhg <SUBCOMMAND>
19 19
20 20 For more information try --help
21 21 [252]
22 22
23 23 Finding root
24 24 $ rhg root
25 25 abort: no repository found in '$TESTTMP' (.hg not found)!
26 26 [255]
27 27
28 28 $ hg init repository
29 29 $ cd repository
30 30 $ rhg root
31 31 $TESTTMP/repository
32 32
33 33 Unwritable file descriptor
34 34 $ rhg root > /dev/full
35 35 abort: No space left on device (os error 28)
36 36 [255]
37 37
38 38 Deleted repository
39 39 $ rm -rf `pwd`
40 40 $ rhg root
41 41 abort: error getting current working directory: $ENOENT$
42 42 [255]
43 43
44 44 Listing tracked files
45 45 $ cd $TESTTMP
46 46 $ hg init repository
47 47 $ cd repository
48 48 $ for i in 1 2 3; do
49 49 > echo $i >> file$i
50 50 > hg add file$i
51 51 > done
52 52 > hg commit -m "commit $i" -q
53 53
54 54 Listing tracked files from root
55 55 $ rhg files
56 56 file1
57 57 file2
58 58 file3
59 59
60 60 Listing tracked files from subdirectory
61 61 $ mkdir -p path/to/directory
62 62 $ cd path/to/directory
63 63 $ rhg files
64 64 ../../../file1
65 65 ../../../file2
66 66 ../../../file3
67 67
68 68 Listing tracked files through broken pipe
69 69 $ rhg files | head -n 1
70 70 ../../../file1
71 71
72 72 Debuging data in inline index
73 73 $ cd $TESTTMP
74 74 $ rm -rf repository
75 75 $ hg init repository
76 76 $ cd repository
77 77 $ for i in 1 2 3; do
78 78 > echo $i >> file$i
79 79 > hg add file$i
80 80 > hg commit -m "commit $i" -q
81 81 > done
82 82 $ rhg debugdata -c 2
83 83 e36fa63d37a576b27a69057598351db6ee5746bd
84 84 test
85 85 0 0
86 86 file3
87 87
88 88 commit 3 (no-eol)
89 89 $ rhg debugdata -m 2
90 90 file1\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
91 91 file2\x005d9299349fc01ddd25d0070d149b124d8f10411e (esc)
92 92 file3\x002661d26c649684b482d10f91960cc3db683c38b4 (esc)
93
94 Cat files
95 $ cd $TESTTMP
96 $ rm -rf repository
97 $ hg init repository
98 $ cd repository
99 $ echo "original content" > original
100 $ hg add original
101 $ hg commit -m "add original" original
102 $ rhg cat -r 0 original
103 original content
104 Cat copied file should not display copy metadata
105 $ hg copy original copy_of_original
106 $ hg commit -m "add copy of original"
107 $ rhg cat -r 1 copy_of_original
108 original content
General Comments 0
You need to be logged in to leave comments. Login now