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