##// END OF EJS Templates
rhg: fix `hg cat` interaction with null revision...
Arseniy Alekseyev -
r49050:f8dc7871 default
parent child Browse files
Show More
@@ -1,434 +1,437
1 use std::borrow::Cow;
1 use std::borrow::Cow;
2 use std::io::Read;
2 use std::io::Read;
3 use std::ops::Deref;
3 use std::ops::Deref;
4 use std::path::Path;
4 use std::path::Path;
5
5
6 use byteorder::{BigEndian, ByteOrder};
6 use byteorder::{BigEndian, ByteOrder};
7 use flate2::read::ZlibDecoder;
7 use flate2::read::ZlibDecoder;
8 use micro_timer::timed;
8 use micro_timer::timed;
9 use sha1::{Digest, Sha1};
9 use sha1::{Digest, Sha1};
10 use zstd;
10 use zstd;
11
11
12 use super::index::Index;
12 use super::index::Index;
13 use super::node::{NodePrefix, NODE_BYTES_LENGTH, NULL_NODE};
13 use super::node::{NodePrefix, NODE_BYTES_LENGTH, NULL_NODE};
14 use super::nodemap;
14 use super::nodemap;
15 use super::nodemap::{NodeMap, NodeMapError};
15 use super::nodemap::{NodeMap, NodeMapError};
16 use super::nodemap_docket::NodeMapDocket;
16 use super::nodemap_docket::NodeMapDocket;
17 use super::patch;
17 use super::patch;
18 use crate::errors::HgError;
18 use crate::errors::HgError;
19 use crate::repo::Repo;
19 use crate::repo::Repo;
20 use crate::revlog::Revision;
20 use crate::revlog::Revision;
21 use crate::{Node, NULL_REVISION};
21 use crate::{Node, NULL_REVISION};
22
22
23 #[derive(derive_more::From)]
23 #[derive(derive_more::From)]
24 pub enum RevlogError {
24 pub enum RevlogError {
25 InvalidRevision,
25 InvalidRevision,
26 /// Working directory is not supported
26 /// Working directory is not supported
27 WDirUnsupported,
27 WDirUnsupported,
28 /// Found more than one entry whose ID match the requested prefix
28 /// Found more than one entry whose ID match the requested prefix
29 AmbiguousPrefix,
29 AmbiguousPrefix,
30 #[from]
30 #[from]
31 Other(HgError),
31 Other(HgError),
32 }
32 }
33
33
34 impl From<NodeMapError> for RevlogError {
34 impl From<NodeMapError> for RevlogError {
35 fn from(error: NodeMapError) -> Self {
35 fn from(error: NodeMapError) -> Self {
36 match error {
36 match error {
37 NodeMapError::MultipleResults => RevlogError::AmbiguousPrefix,
37 NodeMapError::MultipleResults => RevlogError::AmbiguousPrefix,
38 NodeMapError::RevisionNotInIndex(_) => RevlogError::corrupted(),
38 NodeMapError::RevisionNotInIndex(_) => RevlogError::corrupted(),
39 }
39 }
40 }
40 }
41 }
41 }
42
42
43 impl RevlogError {
43 impl RevlogError {
44 fn corrupted() -> Self {
44 fn corrupted() -> Self {
45 RevlogError::Other(HgError::corrupted("corrupted revlog"))
45 RevlogError::Other(HgError::corrupted("corrupted revlog"))
46 }
46 }
47 }
47 }
48
48
49 /// Read only implementation of revlog.
49 /// Read only implementation of revlog.
50 pub struct Revlog {
50 pub struct Revlog {
51 /// When index and data are not interleaved: bytes of the revlog index.
51 /// When index and data are not interleaved: bytes of the revlog index.
52 /// When index and data are interleaved: bytes of the revlog index and
52 /// When index and data are interleaved: bytes of the revlog index and
53 /// data.
53 /// data.
54 index: Index,
54 index: Index,
55 /// When index and data are not interleaved: bytes of the revlog data
55 /// When index and data are not interleaved: bytes of the revlog data
56 data_bytes: Option<Box<dyn Deref<Target = [u8]> + Send>>,
56 data_bytes: Option<Box<dyn Deref<Target = [u8]> + Send>>,
57 /// When present on disk: the persistent nodemap for this revlog
57 /// When present on disk: the persistent nodemap for this revlog
58 nodemap: Option<nodemap::NodeTree>,
58 nodemap: Option<nodemap::NodeTree>,
59 }
59 }
60
60
61 impl Revlog {
61 impl Revlog {
62 /// Open a revlog index file.
62 /// Open a revlog index file.
63 ///
63 ///
64 /// It will also open the associated data file if index and data are not
64 /// It will also open the associated data file if index and data are not
65 /// interleaved.
65 /// interleaved.
66 #[timed]
66 #[timed]
67 pub fn open(
67 pub fn open(
68 repo: &Repo,
68 repo: &Repo,
69 index_path: impl AsRef<Path>,
69 index_path: impl AsRef<Path>,
70 data_path: Option<&Path>,
70 data_path: Option<&Path>,
71 ) -> Result<Self, HgError> {
71 ) -> Result<Self, HgError> {
72 let index_path = index_path.as_ref();
72 let index_path = index_path.as_ref();
73 let index = {
73 let index = {
74 match repo.store_vfs().mmap_open_opt(&index_path)? {
74 match repo.store_vfs().mmap_open_opt(&index_path)? {
75 None => Index::new(Box::new(vec![])),
75 None => Index::new(Box::new(vec![])),
76 Some(index_mmap) => {
76 Some(index_mmap) => {
77 let version = get_version(&index_mmap)?;
77 let version = get_version(&index_mmap)?;
78 if version != 1 {
78 if version != 1 {
79 // A proper new version should have had a repo/store
79 // A proper new version should have had a repo/store
80 // requirement.
80 // requirement.
81 return Err(HgError::corrupted("corrupted revlog"));
81 return Err(HgError::corrupted("corrupted revlog"));
82 }
82 }
83
83
84 let index = Index::new(Box::new(index_mmap))?;
84 let index = Index::new(Box::new(index_mmap))?;
85 Ok(index)
85 Ok(index)
86 }
86 }
87 }
87 }
88 }?;
88 }?;
89
89
90 let default_data_path = index_path.with_extension("d");
90 let default_data_path = index_path.with_extension("d");
91
91
92 // type annotation required
92 // type annotation required
93 // won't recognize Mmap as Deref<Target = [u8]>
93 // won't recognize Mmap as Deref<Target = [u8]>
94 let data_bytes: Option<Box<dyn Deref<Target = [u8]> + Send>> =
94 let data_bytes: Option<Box<dyn Deref<Target = [u8]> + Send>> =
95 if index.is_inline() {
95 if index.is_inline() {
96 None
96 None
97 } else {
97 } else {
98 let data_path = data_path.unwrap_or(&default_data_path);
98 let data_path = data_path.unwrap_or(&default_data_path);
99 let data_mmap = repo.store_vfs().mmap_open(data_path)?;
99 let data_mmap = repo.store_vfs().mmap_open(data_path)?;
100 Some(Box::new(data_mmap))
100 Some(Box::new(data_mmap))
101 };
101 };
102
102
103 let nodemap = if index.is_inline() {
103 let nodemap = if index.is_inline() {
104 None
104 None
105 } else {
105 } else {
106 NodeMapDocket::read_from_file(repo, index_path)?.map(
106 NodeMapDocket::read_from_file(repo, index_path)?.map(
107 |(docket, data)| {
107 |(docket, data)| {
108 nodemap::NodeTree::load_bytes(
108 nodemap::NodeTree::load_bytes(
109 Box::new(data),
109 Box::new(data),
110 docket.data_length,
110 docket.data_length,
111 )
111 )
112 },
112 },
113 )
113 )
114 };
114 };
115
115
116 Ok(Revlog {
116 Ok(Revlog {
117 index,
117 index,
118 data_bytes,
118 data_bytes,
119 nodemap,
119 nodemap,
120 })
120 })
121 }
121 }
122
122
123 /// Return number of entries of the `Revlog`.
123 /// Return number of entries of the `Revlog`.
124 pub fn len(&self) -> usize {
124 pub fn len(&self) -> usize {
125 self.index.len()
125 self.index.len()
126 }
126 }
127
127
128 /// Returns `true` if the `Revlog` has zero `entries`.
128 /// Returns `true` if the `Revlog` has zero `entries`.
129 pub fn is_empty(&self) -> bool {
129 pub fn is_empty(&self) -> bool {
130 self.index.is_empty()
130 self.index.is_empty()
131 }
131 }
132
132
133 /// Returns the node ID for the given revision number, if it exists in this
133 /// Returns the node ID for the given revision number, if it exists in this
134 /// revlog
134 /// revlog
135 pub fn node_from_rev(&self, rev: Revision) -> Option<&Node> {
135 pub fn node_from_rev(&self, rev: Revision) -> Option<&Node> {
136 if rev == NULL_REVISION {
137 return Some(&NULL_NODE);
138 }
136 Some(self.index.get_entry(rev)?.hash())
139 Some(self.index.get_entry(rev)?.hash())
137 }
140 }
138
141
139 /// Return the revision number for the given node ID, if it exists in this
142 /// Return the revision number for the given node ID, if it exists in this
140 /// revlog
143 /// revlog
141 #[timed]
144 #[timed]
142 pub fn rev_from_node(
145 pub fn rev_from_node(
143 &self,
146 &self,
144 node: NodePrefix,
147 node: NodePrefix,
145 ) -> Result<Revision, RevlogError> {
148 ) -> Result<Revision, RevlogError> {
146 if node.is_prefix_of(&NULL_NODE) {
149 if node.is_prefix_of(&NULL_NODE) {
147 return Ok(NULL_REVISION);
150 return Ok(NULL_REVISION);
148 }
151 }
149
152
150 if let Some(nodemap) = &self.nodemap {
153 if let Some(nodemap) = &self.nodemap {
151 return nodemap
154 return nodemap
152 .find_bin(&self.index, node)?
155 .find_bin(&self.index, node)?
153 .ok_or(RevlogError::InvalidRevision);
156 .ok_or(RevlogError::InvalidRevision);
154 }
157 }
155
158
156 // Fallback to linear scan when a persistent nodemap is not present.
159 // Fallback to linear scan when a persistent nodemap is not present.
157 // This happens when the persistent-nodemap experimental feature is not
160 // This happens when the persistent-nodemap experimental feature is not
158 // enabled, or for small revlogs.
161 // enabled, or for small revlogs.
159 //
162 //
160 // TODO: consider building a non-persistent nodemap in memory to
163 // TODO: consider building a non-persistent nodemap in memory to
161 // optimize these cases.
164 // optimize these cases.
162 let mut found_by_prefix = None;
165 let mut found_by_prefix = None;
163 for rev in (0..self.len() as Revision).rev() {
166 for rev in (0..self.len() as Revision).rev() {
164 let index_entry =
167 let index_entry =
165 self.index.get_entry(rev).ok_or(HgError::corrupted(
168 self.index.get_entry(rev).ok_or(HgError::corrupted(
166 "revlog references a revision not in the index",
169 "revlog references a revision not in the index",
167 ))?;
170 ))?;
168 if node == *index_entry.hash() {
171 if node == *index_entry.hash() {
169 return Ok(rev);
172 return Ok(rev);
170 }
173 }
171 if node.is_prefix_of(index_entry.hash()) {
174 if node.is_prefix_of(index_entry.hash()) {
172 if found_by_prefix.is_some() {
175 if found_by_prefix.is_some() {
173 return Err(RevlogError::AmbiguousPrefix);
176 return Err(RevlogError::AmbiguousPrefix);
174 }
177 }
175 found_by_prefix = Some(rev)
178 found_by_prefix = Some(rev)
176 }
179 }
177 }
180 }
178 found_by_prefix.ok_or(RevlogError::InvalidRevision)
181 found_by_prefix.ok_or(RevlogError::InvalidRevision)
179 }
182 }
180
183
181 /// Returns whether the given revision exists in this revlog.
184 /// Returns whether the given revision exists in this revlog.
182 pub fn has_rev(&self, rev: Revision) -> bool {
185 pub fn has_rev(&self, rev: Revision) -> bool {
183 self.index.get_entry(rev).is_some()
186 self.index.get_entry(rev).is_some()
184 }
187 }
185
188
186 /// Return the full data associated to a revision.
189 /// Return the full data associated to a revision.
187 ///
190 ///
188 /// All entries required to build the final data out of deltas will be
191 /// All entries required to build the final data out of deltas will be
189 /// retrieved as needed, and the deltas will be applied to the inital
192 /// retrieved as needed, and the deltas will be applied to the inital
190 /// snapshot to rebuild the final data.
193 /// snapshot to rebuild the final data.
191 #[timed]
194 #[timed]
192 pub fn get_rev_data(&self, rev: Revision) -> Result<Vec<u8>, RevlogError> {
195 pub fn get_rev_data(&self, rev: Revision) -> Result<Vec<u8>, RevlogError> {
193 if rev == NULL_REVISION {
196 if rev == NULL_REVISION {
194 return Ok(vec![]);
197 return Ok(vec![]);
195 };
198 };
196 // Todo return -> Cow
199 // Todo return -> Cow
197 let mut entry = self.get_entry(rev)?;
200 let mut entry = self.get_entry(rev)?;
198 let mut delta_chain = vec![];
201 let mut delta_chain = vec![];
199 while let Some(base_rev) = entry.base_rev {
202 while let Some(base_rev) = entry.base_rev {
200 delta_chain.push(entry);
203 delta_chain.push(entry);
201 entry = self
204 entry = self
202 .get_entry(base_rev)
205 .get_entry(base_rev)
203 .map_err(|_| RevlogError::corrupted())?;
206 .map_err(|_| RevlogError::corrupted())?;
204 }
207 }
205
208
206 // TODO do not look twice in the index
209 // TODO do not look twice in the index
207 let index_entry = self
210 let index_entry = self
208 .index
211 .index
209 .get_entry(rev)
212 .get_entry(rev)
210 .ok_or(RevlogError::InvalidRevision)?;
213 .ok_or(RevlogError::InvalidRevision)?;
211
214
212 let data: Vec<u8> = if delta_chain.is_empty() {
215 let data: Vec<u8> = if delta_chain.is_empty() {
213 entry.data()?.into()
216 entry.data()?.into()
214 } else {
217 } else {
215 Revlog::build_data_from_deltas(entry, &delta_chain)?
218 Revlog::build_data_from_deltas(entry, &delta_chain)?
216 };
219 };
217
220
218 if self.check_hash(
221 if self.check_hash(
219 index_entry.p1(),
222 index_entry.p1(),
220 index_entry.p2(),
223 index_entry.p2(),
221 index_entry.hash().as_bytes(),
224 index_entry.hash().as_bytes(),
222 &data,
225 &data,
223 ) {
226 ) {
224 Ok(data)
227 Ok(data)
225 } else {
228 } else {
226 Err(RevlogError::corrupted())
229 Err(RevlogError::corrupted())
227 }
230 }
228 }
231 }
229
232
230 /// Check the hash of some given data against the recorded hash.
233 /// Check the hash of some given data against the recorded hash.
231 pub fn check_hash(
234 pub fn check_hash(
232 &self,
235 &self,
233 p1: Revision,
236 p1: Revision,
234 p2: Revision,
237 p2: Revision,
235 expected: &[u8],
238 expected: &[u8],
236 data: &[u8],
239 data: &[u8],
237 ) -> bool {
240 ) -> bool {
238 let e1 = self.index.get_entry(p1);
241 let e1 = self.index.get_entry(p1);
239 let h1 = match e1 {
242 let h1 = match e1 {
240 Some(ref entry) => entry.hash(),
243 Some(ref entry) => entry.hash(),
241 None => &NULL_NODE,
244 None => &NULL_NODE,
242 };
245 };
243 let e2 = self.index.get_entry(p2);
246 let e2 = self.index.get_entry(p2);
244 let h2 = match e2 {
247 let h2 = match e2 {
245 Some(ref entry) => entry.hash(),
248 Some(ref entry) => entry.hash(),
246 None => &NULL_NODE,
249 None => &NULL_NODE,
247 };
250 };
248
251
249 &hash(data, h1.as_bytes(), h2.as_bytes()) == expected
252 &hash(data, h1.as_bytes(), h2.as_bytes()) == expected
250 }
253 }
251
254
252 /// Build the full data of a revision out its snapshot
255 /// Build the full data of a revision out its snapshot
253 /// and its deltas.
256 /// and its deltas.
254 #[timed]
257 #[timed]
255 fn build_data_from_deltas(
258 fn build_data_from_deltas(
256 snapshot: RevlogEntry,
259 snapshot: RevlogEntry,
257 deltas: &[RevlogEntry],
260 deltas: &[RevlogEntry],
258 ) -> Result<Vec<u8>, RevlogError> {
261 ) -> Result<Vec<u8>, RevlogError> {
259 let snapshot = snapshot.data()?;
262 let snapshot = snapshot.data()?;
260 let deltas = deltas
263 let deltas = deltas
261 .iter()
264 .iter()
262 .rev()
265 .rev()
263 .map(RevlogEntry::data)
266 .map(RevlogEntry::data)
264 .collect::<Result<Vec<Cow<'_, [u8]>>, RevlogError>>()?;
267 .collect::<Result<Vec<Cow<'_, [u8]>>, RevlogError>>()?;
265 let patches: Vec<_> =
268 let patches: Vec<_> =
266 deltas.iter().map(|d| patch::PatchList::new(d)).collect();
269 deltas.iter().map(|d| patch::PatchList::new(d)).collect();
267 let patch = patch::fold_patch_lists(&patches);
270 let patch = patch::fold_patch_lists(&patches);
268 Ok(patch.apply(&snapshot))
271 Ok(patch.apply(&snapshot))
269 }
272 }
270
273
271 /// Return the revlog data.
274 /// Return the revlog data.
272 fn data(&self) -> &[u8] {
275 fn data(&self) -> &[u8] {
273 match self.data_bytes {
276 match self.data_bytes {
274 Some(ref data_bytes) => &data_bytes,
277 Some(ref data_bytes) => &data_bytes,
275 None => panic!(
278 None => panic!(
276 "forgot to load the data or trying to access inline data"
279 "forgot to load the data or trying to access inline data"
277 ),
280 ),
278 }
281 }
279 }
282 }
280
283
281 /// Get an entry of the revlog.
284 /// Get an entry of the revlog.
282 fn get_entry(&self, rev: Revision) -> Result<RevlogEntry, RevlogError> {
285 fn get_entry(&self, rev: Revision) -> Result<RevlogEntry, RevlogError> {
283 let index_entry = self
286 let index_entry = self
284 .index
287 .index
285 .get_entry(rev)
288 .get_entry(rev)
286 .ok_or(RevlogError::InvalidRevision)?;
289 .ok_or(RevlogError::InvalidRevision)?;
287 let start = index_entry.offset();
290 let start = index_entry.offset();
288 let end = start + index_entry.compressed_len();
291 let end = start + index_entry.compressed_len();
289 let data = if self.index.is_inline() {
292 let data = if self.index.is_inline() {
290 self.index.data(start, end)
293 self.index.data(start, end)
291 } else {
294 } else {
292 &self.data()[start..end]
295 &self.data()[start..end]
293 };
296 };
294 let entry = RevlogEntry {
297 let entry = RevlogEntry {
295 rev,
298 rev,
296 bytes: data,
299 bytes: data,
297 compressed_len: index_entry.compressed_len(),
300 compressed_len: index_entry.compressed_len(),
298 uncompressed_len: index_entry.uncompressed_len(),
301 uncompressed_len: index_entry.uncompressed_len(),
299 base_rev: if index_entry.base_revision() == rev {
302 base_rev: if index_entry.base_revision() == rev {
300 None
303 None
301 } else {
304 } else {
302 Some(index_entry.base_revision())
305 Some(index_entry.base_revision())
303 },
306 },
304 };
307 };
305 Ok(entry)
308 Ok(entry)
306 }
309 }
307 }
310 }
308
311
309 /// The revlog entry's bytes and the necessary informations to extract
312 /// The revlog entry's bytes and the necessary informations to extract
310 /// the entry's data.
313 /// the entry's data.
311 #[derive(Debug)]
314 #[derive(Debug)]
312 pub struct RevlogEntry<'a> {
315 pub struct RevlogEntry<'a> {
313 rev: Revision,
316 rev: Revision,
314 bytes: &'a [u8],
317 bytes: &'a [u8],
315 compressed_len: usize,
318 compressed_len: usize,
316 uncompressed_len: usize,
319 uncompressed_len: usize,
317 base_rev: Option<Revision>,
320 base_rev: Option<Revision>,
318 }
321 }
319
322
320 impl<'a> RevlogEntry<'a> {
323 impl<'a> RevlogEntry<'a> {
321 pub fn revision(&self) -> Revision {
324 pub fn revision(&self) -> Revision {
322 self.rev
325 self.rev
323 }
326 }
324
327
325 /// Extract the data contained in the entry.
328 /// Extract the data contained in the entry.
326 pub fn data(&self) -> Result<Cow<'_, [u8]>, RevlogError> {
329 pub fn data(&self) -> Result<Cow<'_, [u8]>, RevlogError> {
327 if self.bytes.is_empty() {
330 if self.bytes.is_empty() {
328 return Ok(Cow::Borrowed(&[]));
331 return Ok(Cow::Borrowed(&[]));
329 }
332 }
330 match self.bytes[0] {
333 match self.bytes[0] {
331 // Revision data is the entirety of the entry, including this
334 // Revision data is the entirety of the entry, including this
332 // header.
335 // header.
333 b'\0' => Ok(Cow::Borrowed(self.bytes)),
336 b'\0' => Ok(Cow::Borrowed(self.bytes)),
334 // Raw revision data follows.
337 // Raw revision data follows.
335 b'u' => Ok(Cow::Borrowed(&self.bytes[1..])),
338 b'u' => Ok(Cow::Borrowed(&self.bytes[1..])),
336 // zlib (RFC 1950) data.
339 // zlib (RFC 1950) data.
337 b'x' => Ok(Cow::Owned(self.uncompressed_zlib_data()?)),
340 b'x' => Ok(Cow::Owned(self.uncompressed_zlib_data()?)),
338 // zstd data.
341 // zstd data.
339 b'\x28' => Ok(Cow::Owned(self.uncompressed_zstd_data()?)),
342 b'\x28' => Ok(Cow::Owned(self.uncompressed_zstd_data()?)),
340 // A proper new format should have had a repo/store requirement.
343 // A proper new format should have had a repo/store requirement.
341 _format_type => Err(RevlogError::corrupted()),
344 _format_type => Err(RevlogError::corrupted()),
342 }
345 }
343 }
346 }
344
347
345 fn uncompressed_zlib_data(&self) -> Result<Vec<u8>, RevlogError> {
348 fn uncompressed_zlib_data(&self) -> Result<Vec<u8>, RevlogError> {
346 let mut decoder = ZlibDecoder::new(self.bytes);
349 let mut decoder = ZlibDecoder::new(self.bytes);
347 if self.is_delta() {
350 if self.is_delta() {
348 let mut buf = Vec::with_capacity(self.compressed_len);
351 let mut buf = Vec::with_capacity(self.compressed_len);
349 decoder
352 decoder
350 .read_to_end(&mut buf)
353 .read_to_end(&mut buf)
351 .map_err(|_| RevlogError::corrupted())?;
354 .map_err(|_| RevlogError::corrupted())?;
352 Ok(buf)
355 Ok(buf)
353 } else {
356 } else {
354 let mut buf = vec![0; self.uncompressed_len];
357 let mut buf = vec![0; self.uncompressed_len];
355 decoder
358 decoder
356 .read_exact(&mut buf)
359 .read_exact(&mut buf)
357 .map_err(|_| RevlogError::corrupted())?;
360 .map_err(|_| RevlogError::corrupted())?;
358 Ok(buf)
361 Ok(buf)
359 }
362 }
360 }
363 }
361
364
362 fn uncompressed_zstd_data(&self) -> Result<Vec<u8>, RevlogError> {
365 fn uncompressed_zstd_data(&self) -> Result<Vec<u8>, RevlogError> {
363 if self.is_delta() {
366 if self.is_delta() {
364 let mut buf = Vec::with_capacity(self.compressed_len);
367 let mut buf = Vec::with_capacity(self.compressed_len);
365 zstd::stream::copy_decode(self.bytes, &mut buf)
368 zstd::stream::copy_decode(self.bytes, &mut buf)
366 .map_err(|_| RevlogError::corrupted())?;
369 .map_err(|_| RevlogError::corrupted())?;
367 Ok(buf)
370 Ok(buf)
368 } else {
371 } else {
369 let mut buf = vec![0; self.uncompressed_len];
372 let mut buf = vec![0; self.uncompressed_len];
370 let len = zstd::block::decompress_to_buffer(self.bytes, &mut buf)
373 let len = zstd::block::decompress_to_buffer(self.bytes, &mut buf)
371 .map_err(|_| RevlogError::corrupted())?;
374 .map_err(|_| RevlogError::corrupted())?;
372 if len != self.uncompressed_len {
375 if len != self.uncompressed_len {
373 Err(RevlogError::corrupted())
376 Err(RevlogError::corrupted())
374 } else {
377 } else {
375 Ok(buf)
378 Ok(buf)
376 }
379 }
377 }
380 }
378 }
381 }
379
382
380 /// Tell if the entry is a snapshot or a delta
383 /// Tell if the entry is a snapshot or a delta
381 /// (influences on decompression).
384 /// (influences on decompression).
382 fn is_delta(&self) -> bool {
385 fn is_delta(&self) -> bool {
383 self.base_rev.is_some()
386 self.base_rev.is_some()
384 }
387 }
385 }
388 }
386
389
387 /// Format version of the revlog.
390 /// Format version of the revlog.
388 pub fn get_version(index_bytes: &[u8]) -> Result<u16, HgError> {
391 pub fn get_version(index_bytes: &[u8]) -> Result<u16, HgError> {
389 if index_bytes.len() == 0 {
392 if index_bytes.len() == 0 {
390 return Ok(1);
393 return Ok(1);
391 };
394 };
392 if index_bytes.len() < 4 {
395 if index_bytes.len() < 4 {
393 return Err(HgError::corrupted(
396 return Err(HgError::corrupted(
394 "corrupted revlog: can't read the index format header",
397 "corrupted revlog: can't read the index format header",
395 ));
398 ));
396 };
399 };
397 Ok(BigEndian::read_u16(&index_bytes[2..=3]))
400 Ok(BigEndian::read_u16(&index_bytes[2..=3]))
398 }
401 }
399
402
400 /// Calculate the hash of a revision given its data and its parents.
403 /// Calculate the hash of a revision given its data and its parents.
401 fn hash(
404 fn hash(
402 data: &[u8],
405 data: &[u8],
403 p1_hash: &[u8],
406 p1_hash: &[u8],
404 p2_hash: &[u8],
407 p2_hash: &[u8],
405 ) -> [u8; NODE_BYTES_LENGTH] {
408 ) -> [u8; NODE_BYTES_LENGTH] {
406 let mut hasher = Sha1::new();
409 let mut hasher = Sha1::new();
407 let (a, b) = (p1_hash, p2_hash);
410 let (a, b) = (p1_hash, p2_hash);
408 if a > b {
411 if a > b {
409 hasher.update(b);
412 hasher.update(b);
410 hasher.update(a);
413 hasher.update(a);
411 } else {
414 } else {
412 hasher.update(a);
415 hasher.update(a);
413 hasher.update(b);
416 hasher.update(b);
414 }
417 }
415 hasher.update(data);
418 hasher.update(data);
416 *hasher.finalize().as_ref()
419 *hasher.finalize().as_ref()
417 }
420 }
418
421
419 #[cfg(test)]
422 #[cfg(test)]
420 mod tests {
423 mod tests {
421 use super::*;
424 use super::*;
422
425
423 use super::super::index::IndexEntryBuilder;
426 use super::super::index::IndexEntryBuilder;
424
427
425 #[test]
428 #[test]
426 fn version_test() {
429 fn version_test() {
427 let bytes = IndexEntryBuilder::new()
430 let bytes = IndexEntryBuilder::new()
428 .is_first(true)
431 .is_first(true)
429 .with_version(1)
432 .with_version(1)
430 .build();
433 .build();
431
434
432 assert_eq!(get_version(&bytes).map_err(|_err| ()), Ok(1))
435 assert_eq!(get_version(&bytes).map_err(|_err| ()), Ok(1))
433 }
436 }
434 }
437 }
@@ -1,383 +1,383
1 #require rhg
1 #require rhg
2
2
3 $ NO_FALLBACK="env RHG_ON_UNSUPPORTED=abort"
3 $ NO_FALLBACK="env RHG_ON_UNSUPPORTED=abort"
4
4
5 Unimplemented command
5 Unimplemented command
6 $ $NO_FALLBACK rhg unimplemented-command
6 $ $NO_FALLBACK rhg unimplemented-command
7 unsupported feature: error: Found argument 'unimplemented-command' which wasn't expected, or isn't valid in this context
7 unsupported feature: error: Found argument 'unimplemented-command' which wasn't expected, or isn't valid in this context
8
8
9 USAGE:
9 USAGE:
10 rhg [OPTIONS] <SUBCOMMAND>
10 rhg [OPTIONS] <SUBCOMMAND>
11
11
12 For more information try --help
12 For more information try --help
13
13
14 [252]
14 [252]
15 $ rhg unimplemented-command --config rhg.on-unsupported=abort-silent
15 $ rhg unimplemented-command --config rhg.on-unsupported=abort-silent
16 [252]
16 [252]
17
17
18 Finding root
18 Finding root
19 $ $NO_FALLBACK rhg root
19 $ $NO_FALLBACK rhg root
20 abort: no repository found in '$TESTTMP' (.hg not found)!
20 abort: no repository found in '$TESTTMP' (.hg not found)!
21 [255]
21 [255]
22
22
23 $ hg init repository
23 $ hg init repository
24 $ cd repository
24 $ cd repository
25 $ $NO_FALLBACK rhg root
25 $ $NO_FALLBACK rhg root
26 $TESTTMP/repository
26 $TESTTMP/repository
27
27
28 Reading and setting configuration
28 Reading and setting configuration
29 $ echo "[ui]" >> $HGRCPATH
29 $ echo "[ui]" >> $HGRCPATH
30 $ echo "username = user1" >> $HGRCPATH
30 $ echo "username = user1" >> $HGRCPATH
31 $ $NO_FALLBACK rhg config ui.username
31 $ $NO_FALLBACK rhg config ui.username
32 user1
32 user1
33 $ echo "[ui]" >> .hg/hgrc
33 $ echo "[ui]" >> .hg/hgrc
34 $ echo "username = user2" >> .hg/hgrc
34 $ echo "username = user2" >> .hg/hgrc
35 $ $NO_FALLBACK rhg config ui.username
35 $ $NO_FALLBACK rhg config ui.username
36 user2
36 user2
37 $ $NO_FALLBACK rhg --config ui.username=user3 config ui.username
37 $ $NO_FALLBACK rhg --config ui.username=user3 config ui.username
38 user3
38 user3
39
39
40 Unwritable file descriptor
40 Unwritable file descriptor
41 $ $NO_FALLBACK rhg root > /dev/full
41 $ $NO_FALLBACK rhg root > /dev/full
42 abort: No space left on device (os error 28)
42 abort: No space left on device (os error 28)
43 [255]
43 [255]
44
44
45 Deleted repository
45 Deleted repository
46 $ rm -rf `pwd`
46 $ rm -rf `pwd`
47 $ $NO_FALLBACK rhg root
47 $ $NO_FALLBACK rhg root
48 abort: error getting current working directory: $ENOENT$
48 abort: error getting current working directory: $ENOENT$
49 [255]
49 [255]
50
50
51 Listing tracked files
51 Listing tracked files
52 $ cd $TESTTMP
52 $ cd $TESTTMP
53 $ hg init repository
53 $ hg init repository
54 $ cd repository
54 $ cd repository
55 $ for i in 1 2 3; do
55 $ for i in 1 2 3; do
56 > echo $i >> file$i
56 > echo $i >> file$i
57 > hg add file$i
57 > hg add file$i
58 > done
58 > done
59 > hg commit -m "commit $i" -q
59 > hg commit -m "commit $i" -q
60
60
61 Listing tracked files from root
61 Listing tracked files from root
62 $ $NO_FALLBACK rhg files
62 $ $NO_FALLBACK rhg files
63 file1
63 file1
64 file2
64 file2
65 file3
65 file3
66
66
67 Listing tracked files from subdirectory
67 Listing tracked files from subdirectory
68 $ mkdir -p path/to/directory
68 $ mkdir -p path/to/directory
69 $ cd path/to/directory
69 $ cd path/to/directory
70 $ $NO_FALLBACK rhg files
70 $ $NO_FALLBACK rhg files
71 ../../../file1
71 ../../../file1
72 ../../../file2
72 ../../../file2
73 ../../../file3
73 ../../../file3
74
74
75 Listing tracked files through broken pipe
75 Listing tracked files through broken pipe
76 $ $NO_FALLBACK rhg files | head -n 1
76 $ $NO_FALLBACK rhg files | head -n 1
77 ../../../file1
77 ../../../file1
78
78
79 Debuging data in inline index
79 Debuging data in inline index
80 $ cd $TESTTMP
80 $ cd $TESTTMP
81 $ rm -rf repository
81 $ rm -rf repository
82 $ hg init repository
82 $ hg init repository
83 $ cd repository
83 $ cd repository
84 $ for i in 1 2 3 4 5 6; do
84 $ for i in 1 2 3 4 5 6; do
85 > echo $i >> file-$i
85 > echo $i >> file-$i
86 > hg add file-$i
86 > hg add file-$i
87 > hg commit -m "Commit $i" -q
87 > hg commit -m "Commit $i" -q
88 > done
88 > done
89 $ $NO_FALLBACK rhg debugdata -c 2
89 $ $NO_FALLBACK rhg debugdata -c 2
90 8d0267cb034247ebfa5ee58ce59e22e57a492297
90 8d0267cb034247ebfa5ee58ce59e22e57a492297
91 test
91 test
92 0 0
92 0 0
93 file-3
93 file-3
94
94
95 Commit 3 (no-eol)
95 Commit 3 (no-eol)
96 $ $NO_FALLBACK rhg debugdata -m 2
96 $ $NO_FALLBACK rhg debugdata -m 2
97 file-1\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
97 file-1\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc)
98 file-2\x005d9299349fc01ddd25d0070d149b124d8f10411e (esc)
98 file-2\x005d9299349fc01ddd25d0070d149b124d8f10411e (esc)
99 file-3\x002661d26c649684b482d10f91960cc3db683c38b4 (esc)
99 file-3\x002661d26c649684b482d10f91960cc3db683c38b4 (esc)
100
100
101 Debuging with full node id
101 Debuging with full node id
102 $ $NO_FALLBACK rhg debugdata -c `hg log -r 0 -T '{node}'`
102 $ $NO_FALLBACK rhg debugdata -c `hg log -r 0 -T '{node}'`
103 d1d1c679d3053e8926061b6f45ca52009f011e3f
103 d1d1c679d3053e8926061b6f45ca52009f011e3f
104 test
104 test
105 0 0
105 0 0
106 file-1
106 file-1
107
107
108 Commit 1 (no-eol)
108 Commit 1 (no-eol)
109
109
110 Specifying revisions by changeset ID
110 Specifying revisions by changeset ID
111 $ hg log -T '{node}\n'
111 $ hg log -T '{node}\n'
112 c6ad58c44207b6ff8a4fbbca7045a5edaa7e908b
112 c6ad58c44207b6ff8a4fbbca7045a5edaa7e908b
113 d654274993d0149eecc3cc03214f598320211900
113 d654274993d0149eecc3cc03214f598320211900
114 f646af7e96481d3a5470b695cf30ad8e3ab6c575
114 f646af7e96481d3a5470b695cf30ad8e3ab6c575
115 cf8b83f14ead62b374b6e91a0e9303b85dfd9ed7
115 cf8b83f14ead62b374b6e91a0e9303b85dfd9ed7
116 91c6f6e73e39318534dc415ea4e8a09c99cd74d6
116 91c6f6e73e39318534dc415ea4e8a09c99cd74d6
117 6ae9681c6d30389694d8701faf24b583cf3ccafe
117 6ae9681c6d30389694d8701faf24b583cf3ccafe
118 $ $NO_FALLBACK rhg files -r cf8b83
118 $ $NO_FALLBACK rhg files -r cf8b83
119 file-1
119 file-1
120 file-2
120 file-2
121 file-3
121 file-3
122 $ $NO_FALLBACK rhg cat -r cf8b83 file-2
122 $ $NO_FALLBACK rhg cat -r cf8b83 file-2
123 2
123 2
124 $ $NO_FALLBACK rhg cat --rev cf8b83 file-2
124 $ $NO_FALLBACK rhg cat --rev cf8b83 file-2
125 2
125 2
126 $ $NO_FALLBACK rhg cat -r c file-2
126 $ $NO_FALLBACK rhg cat -r c file-2
127 abort: ambiguous revision identifier: c
127 abort: ambiguous revision identifier: c
128 [255]
128 [255]
129 $ $NO_FALLBACK rhg cat -r d file-2
129 $ $NO_FALLBACK rhg cat -r d file-2
130 2
130 2
131 $ $NO_FALLBACK rhg cat -r 0000 file-2
131 $ $NO_FALLBACK rhg cat -r 0000 file-2
132 abort: invalid revision identifier: 0000
132 file-2: no such file in rev 000000000000
133 [255]
133 [1]
134
134
135 Cat files
135 Cat files
136 $ cd $TESTTMP
136 $ cd $TESTTMP
137 $ rm -rf repository
137 $ rm -rf repository
138 $ hg init repository
138 $ hg init repository
139 $ cd repository
139 $ cd repository
140 $ echo "original content" > original
140 $ echo "original content" > original
141 $ hg add original
141 $ hg add original
142 $ hg commit -m "add original" original
142 $ hg commit -m "add original" original
143 Without `--rev`
143 Without `--rev`
144 $ $NO_FALLBACK rhg cat original
144 $ $NO_FALLBACK rhg cat original
145 original content
145 original content
146 With `--rev`
146 With `--rev`
147 $ $NO_FALLBACK rhg cat -r 0 original
147 $ $NO_FALLBACK rhg cat -r 0 original
148 original content
148 original content
149 Cat copied file should not display copy metadata
149 Cat copied file should not display copy metadata
150 $ hg copy original copy_of_original
150 $ hg copy original copy_of_original
151 $ hg commit -m "add copy of original"
151 $ hg commit -m "add copy of original"
152 $ $NO_FALLBACK rhg cat original
152 $ $NO_FALLBACK rhg cat original
153 original content
153 original content
154 $ $NO_FALLBACK rhg cat -r 1 copy_of_original
154 $ $NO_FALLBACK rhg cat -r 1 copy_of_original
155 original content
155 original content
156
156
157
157
158 Fallback to Python
158 Fallback to Python
159 $ $NO_FALLBACK rhg cat original --exclude="*.rs"
159 $ $NO_FALLBACK rhg cat original --exclude="*.rs"
160 unsupported feature: error: Found argument '--exclude' which wasn't expected, or isn't valid in this context
160 unsupported feature: error: Found argument '--exclude' which wasn't expected, or isn't valid in this context
161
161
162 USAGE:
162 USAGE:
163 rhg cat [OPTIONS] <FILE>...
163 rhg cat [OPTIONS] <FILE>...
164
164
165 For more information try --help
165 For more information try --help
166
166
167 [252]
167 [252]
168 $ rhg cat original --exclude="*.rs"
168 $ rhg cat original --exclude="*.rs"
169 original content
169 original content
170
170
171 $ FALLBACK_EXE="$RHG_FALLBACK_EXECUTABLE"
171 $ FALLBACK_EXE="$RHG_FALLBACK_EXECUTABLE"
172 $ unset RHG_FALLBACK_EXECUTABLE
172 $ unset RHG_FALLBACK_EXECUTABLE
173 $ rhg cat original --exclude="*.rs"
173 $ rhg cat original --exclude="*.rs"
174 abort: 'rhg.on-unsupported=fallback' without 'rhg.fallback-executable' set.
174 abort: 'rhg.on-unsupported=fallback' without 'rhg.fallback-executable' set.
175 [255]
175 [255]
176 $ RHG_FALLBACK_EXECUTABLE="$FALLBACK_EXE"
176 $ RHG_FALLBACK_EXECUTABLE="$FALLBACK_EXE"
177 $ export RHG_FALLBACK_EXECUTABLE
177 $ export RHG_FALLBACK_EXECUTABLE
178
178
179 $ rhg cat original --exclude="*.rs" --config rhg.fallback-executable=false
179 $ rhg cat original --exclude="*.rs" --config rhg.fallback-executable=false
180 [1]
180 [1]
181
181
182 $ rhg cat original --exclude="*.rs" --config rhg.fallback-executable=hg-non-existent
182 $ rhg cat original --exclude="*.rs" --config rhg.fallback-executable=hg-non-existent
183 tried to fall back to a 'hg-non-existent' sub-process but got error $ENOENT$
183 tried to fall back to a 'hg-non-existent' sub-process but got error $ENOENT$
184 unsupported feature: error: Found argument '--exclude' which wasn't expected, or isn't valid in this context
184 unsupported feature: error: Found argument '--exclude' which wasn't expected, or isn't valid in this context
185
185
186 USAGE:
186 USAGE:
187 rhg cat [OPTIONS] <FILE>...
187 rhg cat [OPTIONS] <FILE>...
188
188
189 For more information try --help
189 For more information try --help
190
190
191 [252]
191 [252]
192
192
193 $ rhg cat original --exclude="*.rs" --config rhg.fallback-executable=rhg
193 $ rhg cat original --exclude="*.rs" --config rhg.fallback-executable=rhg
194 Blocking recursive fallback. The 'rhg.fallback-executable = rhg' config points to `rhg` itself.
194 Blocking recursive fallback. The 'rhg.fallback-executable = rhg' config points to `rhg` itself.
195 unsupported feature: error: Found argument '--exclude' which wasn't expected, or isn't valid in this context
195 unsupported feature: error: Found argument '--exclude' which wasn't expected, or isn't valid in this context
196
196
197 USAGE:
197 USAGE:
198 rhg cat [OPTIONS] <FILE>...
198 rhg cat [OPTIONS] <FILE>...
199
199
200 For more information try --help
200 For more information try --help
201
201
202 [252]
202 [252]
203
203
204 Fallback with shell path segments
204 Fallback with shell path segments
205 $ $NO_FALLBACK rhg cat .
205 $ $NO_FALLBACK rhg cat .
206 unsupported feature: `..` or `.` path segment
206 unsupported feature: `..` or `.` path segment
207 [252]
207 [252]
208 $ $NO_FALLBACK rhg cat ..
208 $ $NO_FALLBACK rhg cat ..
209 unsupported feature: `..` or `.` path segment
209 unsupported feature: `..` or `.` path segment
210 [252]
210 [252]
211 $ $NO_FALLBACK rhg cat ../..
211 $ $NO_FALLBACK rhg cat ../..
212 unsupported feature: `..` or `.` path segment
212 unsupported feature: `..` or `.` path segment
213 [252]
213 [252]
214
214
215 Fallback with filesets
215 Fallback with filesets
216 $ $NO_FALLBACK rhg cat "set:c or b"
216 $ $NO_FALLBACK rhg cat "set:c or b"
217 unsupported feature: fileset
217 unsupported feature: fileset
218 [252]
218 [252]
219
219
220 Fallback with generic hooks
220 Fallback with generic hooks
221 $ $NO_FALLBACK rhg cat original --config hooks.pre-cat=something
221 $ $NO_FALLBACK rhg cat original --config hooks.pre-cat=something
222 unsupported feature: pre-cat hook defined
222 unsupported feature: pre-cat hook defined
223 [252]
223 [252]
224
224
225 $ $NO_FALLBACK rhg cat original --config hooks.post-cat=something
225 $ $NO_FALLBACK rhg cat original --config hooks.post-cat=something
226 unsupported feature: post-cat hook defined
226 unsupported feature: post-cat hook defined
227 [252]
227 [252]
228
228
229 $ $NO_FALLBACK rhg cat original --config hooks.fail-cat=something
229 $ $NO_FALLBACK rhg cat original --config hooks.fail-cat=something
230 unsupported feature: fail-cat hook defined
230 unsupported feature: fail-cat hook defined
231 [252]
231 [252]
232
232
233 Fallback with [defaults]
233 Fallback with [defaults]
234 $ $NO_FALLBACK rhg cat original --config "defaults.cat=-r null"
234 $ $NO_FALLBACK rhg cat original --config "defaults.cat=-r null"
235 unsupported feature: `defaults` config set
235 unsupported feature: `defaults` config set
236 [252]
236 [252]
237
237
238
238
239 Requirements
239 Requirements
240 $ $NO_FALLBACK rhg debugrequirements
240 $ $NO_FALLBACK rhg debugrequirements
241 dotencode
241 dotencode
242 fncache
242 fncache
243 generaldelta
243 generaldelta
244 persistent-nodemap
244 persistent-nodemap
245 revlog-compression-zstd (zstd !)
245 revlog-compression-zstd (zstd !)
246 revlogv1
246 revlogv1
247 sparserevlog
247 sparserevlog
248 store
248 store
249
249
250 $ echo indoor-pool >> .hg/requires
250 $ echo indoor-pool >> .hg/requires
251 $ $NO_FALLBACK rhg files
251 $ $NO_FALLBACK rhg files
252 unsupported feature: repository requires feature unknown to this Mercurial: indoor-pool
252 unsupported feature: repository requires feature unknown to this Mercurial: indoor-pool
253 [252]
253 [252]
254
254
255 $ $NO_FALLBACK rhg cat -r 1 copy_of_original
255 $ $NO_FALLBACK rhg cat -r 1 copy_of_original
256 unsupported feature: repository requires feature unknown to this Mercurial: indoor-pool
256 unsupported feature: repository requires feature unknown to this Mercurial: indoor-pool
257 [252]
257 [252]
258
258
259 $ $NO_FALLBACK rhg debugrequirements
259 $ $NO_FALLBACK rhg debugrequirements
260 unsupported feature: repository requires feature unknown to this Mercurial: indoor-pool
260 unsupported feature: repository requires feature unknown to this Mercurial: indoor-pool
261 [252]
261 [252]
262
262
263 $ echo -e '\xFF' >> .hg/requires
263 $ echo -e '\xFF' >> .hg/requires
264 $ $NO_FALLBACK rhg debugrequirements
264 $ $NO_FALLBACK rhg debugrequirements
265 abort: parse error in 'requires' file
265 abort: parse error in 'requires' file
266 [255]
266 [255]
267
267
268 Persistent nodemap
268 Persistent nodemap
269 $ cd $TESTTMP
269 $ cd $TESTTMP
270 $ rm -rf repository
270 $ rm -rf repository
271 $ hg --config format.use-persistent-nodemap=no init repository
271 $ hg --config format.use-persistent-nodemap=no init repository
272 $ cd repository
272 $ cd repository
273 $ $NO_FALLBACK rhg debugrequirements | grep nodemap
273 $ $NO_FALLBACK rhg debugrequirements | grep nodemap
274 [1]
274 [1]
275 $ hg debugbuilddag .+5000 --overwritten-file --config "storage.revlog.nodemap.mode=warn"
275 $ hg debugbuilddag .+5000 --overwritten-file --config "storage.revlog.nodemap.mode=warn"
276 $ hg id -r tip
276 $ hg id -r tip
277 c3ae8dec9fad tip
277 c3ae8dec9fad tip
278 $ ls .hg/store/00changelog*
278 $ ls .hg/store/00changelog*
279 .hg/store/00changelog.d
279 .hg/store/00changelog.d
280 .hg/store/00changelog.i
280 .hg/store/00changelog.i
281 $ $NO_FALLBACK rhg files -r c3ae8dec9fad
281 $ $NO_FALLBACK rhg files -r c3ae8dec9fad
282 of
282 of
283
283
284 $ cd $TESTTMP
284 $ cd $TESTTMP
285 $ rm -rf repository
285 $ rm -rf repository
286 $ hg --config format.use-persistent-nodemap=True init repository
286 $ hg --config format.use-persistent-nodemap=True init repository
287 $ cd repository
287 $ cd repository
288 $ $NO_FALLBACK rhg debugrequirements | grep nodemap
288 $ $NO_FALLBACK rhg debugrequirements | grep nodemap
289 persistent-nodemap
289 persistent-nodemap
290 $ hg debugbuilddag .+5000 --overwritten-file --config "storage.revlog.nodemap.mode=warn"
290 $ hg debugbuilddag .+5000 --overwritten-file --config "storage.revlog.nodemap.mode=warn"
291 $ hg id -r tip
291 $ hg id -r tip
292 c3ae8dec9fad tip
292 c3ae8dec9fad tip
293 $ ls .hg/store/00changelog*
293 $ ls .hg/store/00changelog*
294 .hg/store/00changelog-*.nd (glob)
294 .hg/store/00changelog-*.nd (glob)
295 .hg/store/00changelog.d
295 .hg/store/00changelog.d
296 .hg/store/00changelog.i
296 .hg/store/00changelog.i
297 .hg/store/00changelog.n
297 .hg/store/00changelog.n
298
298
299 Specifying revisions by changeset ID
299 Specifying revisions by changeset ID
300 $ $NO_FALLBACK rhg files -r c3ae8dec9fad
300 $ $NO_FALLBACK rhg files -r c3ae8dec9fad
301 of
301 of
302 $ $NO_FALLBACK rhg cat -r c3ae8dec9fad of
302 $ $NO_FALLBACK rhg cat -r c3ae8dec9fad of
303 r5000
303 r5000
304
304
305 Crate a shared repository
305 Crate a shared repository
306
306
307 $ echo "[extensions]" >> $HGRCPATH
307 $ echo "[extensions]" >> $HGRCPATH
308 $ echo "share = " >> $HGRCPATH
308 $ echo "share = " >> $HGRCPATH
309
309
310 $ cd $TESTTMP
310 $ cd $TESTTMP
311 $ hg init repo1
311 $ hg init repo1
312 $ echo a > repo1/a
312 $ echo a > repo1/a
313 $ hg -R repo1 commit -A -m'init'
313 $ hg -R repo1 commit -A -m'init'
314 adding a
314 adding a
315
315
316 $ hg share repo1 repo2
316 $ hg share repo1 repo2
317 updating working directory
317 updating working directory
318 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
318 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
319
319
320 And check that basic rhg commands work with sharing
320 And check that basic rhg commands work with sharing
321
321
322 $ $NO_FALLBACK rhg files -R repo2
322 $ $NO_FALLBACK rhg files -R repo2
323 repo2/a
323 repo2/a
324 $ $NO_FALLBACK rhg -R repo2 cat -r 0 repo2/a
324 $ $NO_FALLBACK rhg -R repo2 cat -r 0 repo2/a
325 a
325 a
326
326
327 Same with relative sharing
327 Same with relative sharing
328
328
329 $ hg share repo2 repo3 --relative
329 $ hg share repo2 repo3 --relative
330 updating working directory
330 updating working directory
331 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
331 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
332
332
333 $ $NO_FALLBACK rhg files -R repo3
333 $ $NO_FALLBACK rhg files -R repo3
334 repo3/a
334 repo3/a
335 $ $NO_FALLBACK rhg -R repo3 cat -r 0 repo3/a
335 $ $NO_FALLBACK rhg -R repo3 cat -r 0 repo3/a
336 a
336 a
337
337
338 Same with share-safe
338 Same with share-safe
339
339
340 $ echo "[format]" >> $HGRCPATH
340 $ echo "[format]" >> $HGRCPATH
341 $ echo "use-share-safe = True" >> $HGRCPATH
341 $ echo "use-share-safe = True" >> $HGRCPATH
342
342
343 $ cd $TESTTMP
343 $ cd $TESTTMP
344 $ hg init repo4
344 $ hg init repo4
345 $ cd repo4
345 $ cd repo4
346 $ echo a > a
346 $ echo a > a
347 $ hg commit -A -m'init'
347 $ hg commit -A -m'init'
348 adding a
348 adding a
349
349
350 $ cd ..
350 $ cd ..
351 $ hg share repo4 repo5
351 $ hg share repo4 repo5
352 updating working directory
352 updating working directory
353 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
353 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
354
354
355 And check that basic rhg commands work with sharing
355 And check that basic rhg commands work with sharing
356
356
357 $ cd repo5
357 $ cd repo5
358 $ $NO_FALLBACK rhg files
358 $ $NO_FALLBACK rhg files
359 a
359 a
360 $ $NO_FALLBACK rhg cat -r 0 a
360 $ $NO_FALLBACK rhg cat -r 0 a
361 a
361 a
362
362
363 The blackbox extension is supported
363 The blackbox extension is supported
364
364
365 $ echo "[extensions]" >> $HGRCPATH
365 $ echo "[extensions]" >> $HGRCPATH
366 $ echo "blackbox =" >> $HGRCPATH
366 $ echo "blackbox =" >> $HGRCPATH
367 $ echo "[blackbox]" >> $HGRCPATH
367 $ echo "[blackbox]" >> $HGRCPATH
368 $ echo "maxsize = 1" >> $HGRCPATH
368 $ echo "maxsize = 1" >> $HGRCPATH
369 $ $NO_FALLBACK rhg files > /dev/null
369 $ $NO_FALLBACK rhg files > /dev/null
370 $ cat .hg/blackbox.log
370 $ cat .hg/blackbox.log
371 ????/??/?? ??:??:??.??? * @d3873e73d99ef67873dac33fbcc66268d5d2b6f4 (*)> (rust) files exited 0 after 0.??? seconds (glob)
371 ????/??/?? ??:??:??.??? * @d3873e73d99ef67873dac33fbcc66268d5d2b6f4 (*)> (rust) files exited 0 after 0.??? seconds (glob)
372 $ cat .hg/blackbox.log.1
372 $ cat .hg/blackbox.log.1
373 ????/??/?? ??:??:??.??? * @d3873e73d99ef67873dac33fbcc66268d5d2b6f4 (*)> (rust) files (glob)
373 ????/??/?? ??:??:??.??? * @d3873e73d99ef67873dac33fbcc66268d5d2b6f4 (*)> (rust) files (glob)
374
374
375 Subrepos are not supported
375 Subrepos are not supported
376
376
377 $ touch .hgsub
377 $ touch .hgsub
378 $ $NO_FALLBACK rhg files
378 $ $NO_FALLBACK rhg files
379 unsupported feature: subrepos (.hgsub is present)
379 unsupported feature: subrepos (.hgsub is present)
380 [252]
380 [252]
381 $ rhg files
381 $ rhg files
382 a
382 a
383 $ rm .hgsub
383 $ rm .hgsub
General Comments 0
You need to be logged in to leave comments. Login now