Show More
@@ -175,7 +175,7 b' impl<G: Graph> MissingAncestors<G> {' | |||||
175 | /// |
|
175 | /// | |
176 | /// This is useful in unit tests, but also setdiscovery.py does |
|
176 | /// This is useful in unit tests, but also setdiscovery.py does | |
177 | /// read the bases attribute of a ancestor.missingancestors instance. |
|
177 | /// read the bases attribute of a ancestor.missingancestors instance. | |
178 |
pub fn get_bases |
|
178 | pub fn get_bases(&self) -> &HashSet<Revision> { | |
179 | &self.bases |
|
179 | &self.bases | |
180 | } |
|
180 | } | |
181 |
|
181 | |||
@@ -288,7 +288,7 b' impl<G: Graph> MissingAncestors<G> {' | |||||
288 | .collect(); |
|
288 | .collect(); | |
289 | let revs_visit = &mut revs; |
|
289 | let revs_visit = &mut revs; | |
290 | let mut both_visit: HashSet<Revision> = |
|
290 | let mut both_visit: HashSet<Revision> = | |
291 |
revs_visit.intersection( |
|
291 | revs_visit.intersection(bases_visit).cloned().collect(); | |
292 | if revs_visit.is_empty() { |
|
292 | if revs_visit.is_empty() { | |
293 | return Ok(Vec::new()); |
|
293 | return Ok(Vec::new()); | |
294 | } |
|
294 | } | |
@@ -503,18 +503,18 b' mod tests {' | |||||
503 | MissingAncestors::new(SampleGraph, [5, 3, 1, 3].iter().cloned()); |
|
503 | MissingAncestors::new(SampleGraph, [5, 3, 1, 3].iter().cloned()); | |
504 | let mut as_vec: Vec<Revision> = |
|
504 | let mut as_vec: Vec<Revision> = | |
505 | missing_ancestors.get_bases().iter().cloned().collect(); |
|
505 | missing_ancestors.get_bases().iter().cloned().collect(); | |
506 | as_vec.sort(); |
|
506 | as_vec.sort_unstable(); | |
507 | assert_eq!(as_vec, [1, 3, 5]); |
|
507 | assert_eq!(as_vec, [1, 3, 5]); | |
508 | assert_eq!(missing_ancestors.max_base, 5); |
|
508 | assert_eq!(missing_ancestors.max_base, 5); | |
509 |
|
509 | |||
510 | missing_ancestors.add_bases([3, 7, 8].iter().cloned()); |
|
510 | missing_ancestors.add_bases([3, 7, 8].iter().cloned()); | |
511 | as_vec = missing_ancestors.get_bases().iter().cloned().collect(); |
|
511 | as_vec = missing_ancestors.get_bases().iter().cloned().collect(); | |
512 | as_vec.sort(); |
|
512 | as_vec.sort_unstable(); | |
513 | assert_eq!(as_vec, [1, 3, 5, 7, 8]); |
|
513 | assert_eq!(as_vec, [1, 3, 5, 7, 8]); | |
514 | assert_eq!(missing_ancestors.max_base, 8); |
|
514 | assert_eq!(missing_ancestors.max_base, 8); | |
515 |
|
515 | |||
516 | as_vec = missing_ancestors.bases_heads()?.iter().cloned().collect(); |
|
516 | as_vec = missing_ancestors.bases_heads()?.iter().cloned().collect(); | |
517 | as_vec.sort(); |
|
517 | as_vec.sort_unstable(); | |
518 | assert_eq!(as_vec, [3, 5, 7, 8]); |
|
518 | assert_eq!(as_vec, [3, 5, 7, 8]); | |
519 | Ok(()) |
|
519 | Ok(()) | |
520 | } |
|
520 | } | |
@@ -531,7 +531,7 b' mod tests {' | |||||
531 | .remove_ancestors_from(&mut revset) |
|
531 | .remove_ancestors_from(&mut revset) | |
532 | .unwrap(); |
|
532 | .unwrap(); | |
533 | let mut as_vec: Vec<Revision> = revset.into_iter().collect(); |
|
533 | let mut as_vec: Vec<Revision> = revset.into_iter().collect(); | |
534 | as_vec.sort(); |
|
534 | as_vec.sort_unstable(); | |
535 | assert_eq!(as_vec.as_slice(), expected); |
|
535 | assert_eq!(as_vec.as_slice(), expected); | |
536 | } |
|
536 | } | |
537 |
|
537 | |||
@@ -572,6 +572,7 b' mod tests {' | |||||
572 | /// the one in test-ancestor.py. An early version of Rust MissingAncestors |
|
572 | /// the one in test-ancestor.py. An early version of Rust MissingAncestors | |
573 | /// failed this, yet none of the integration tests of the whole suite |
|
573 | /// failed this, yet none of the integration tests of the whole suite | |
574 | /// catched it. |
|
574 | /// catched it. | |
|
575 | #[allow(clippy::unnecessary_cast)] | |||
575 | #[test] |
|
576 | #[test] | |
576 | fn test_remove_ancestors_from_case1() { |
|
577 | fn test_remove_ancestors_from_case1() { | |
577 | let graph: VecGraph = vec![ |
|
578 | let graph: VecGraph = vec![ |
@@ -117,7 +117,7 b' fn should_ignore(plain: &PlainInfo, sect' | |||||
117 | } |
|
117 | } | |
118 | let sections_to_delete: &[&[u8]] = |
|
118 | let sections_to_delete: &[&[u8]] = | |
119 | &[b"defaults", b"commands", b"command-templates"]; |
|
119 | &[b"defaults", b"commands", b"command-templates"]; | |
120 |
|
|
120 | sections_to_delete.contains(§ion) | |
121 | } |
|
121 | } | |
122 |
|
122 | |||
123 | impl Config { |
|
123 | impl Config { | |
@@ -207,7 +207,7 b' impl Config {' | |||||
207 | file_paths.sort(); |
|
207 | file_paths.sort(); | |
208 | for file_path in &file_paths { |
|
208 | for file_path in &file_paths { | |
209 | if file_path.extension() == Some(std::ffi::OsStr::new("rc")) { |
|
209 | if file_path.extension() == Some(std::ffi::OsStr::new("rc")) { | |
210 |
self.add_trusted_file( |
|
210 | self.add_trusted_file(file_path)? | |
211 | } |
|
211 | } | |
212 | } |
|
212 | } | |
213 | } |
|
213 | } | |
@@ -259,7 +259,7 b' impl Config {' | |||||
259 | // `mercurial/helptext/config.txt` suggests it should be reversed |
|
259 | // `mercurial/helptext/config.txt` suggests it should be reversed | |
260 | if let Some(installation_prefix) = hg.parent().and_then(Path::parent) { |
|
260 | if let Some(installation_prefix) = hg.parent().and_then(Path::parent) { | |
261 | if installation_prefix != root { |
|
261 | if installation_prefix != root { | |
262 |
add_for_prefix( |
|
262 | add_for_prefix(installation_prefix)? | |
263 | } |
|
263 | } | |
264 | } |
|
264 | } | |
265 | add_for_prefix(root)?; |
|
265 | add_for_prefix(root)?; | |
@@ -348,7 +348,7 b' impl Config {' | |||||
348 | expected_type: &'static str, |
|
348 | expected_type: &'static str, | |
349 | parse: impl Fn(&'config [u8]) -> Option<T>, |
|
349 | parse: impl Fn(&'config [u8]) -> Option<T>, | |
350 | ) -> Result<Option<T>, ConfigValueParseError> { |
|
350 | ) -> Result<Option<T>, ConfigValueParseError> { | |
351 |
match self.get_inner( |
|
351 | match self.get_inner(section, item) { | |
352 | Some((layer, v)) => match parse(&v.bytes) { |
|
352 | Some((layer, v)) => match parse(&v.bytes) { | |
353 | Some(b) => Ok(Some(b)), |
|
353 | Some(b) => Ok(Some(b)), | |
354 | None => Err(ConfigValueParseError { |
|
354 | None => Err(ConfigValueParseError { | |
@@ -463,7 +463,7 b' impl Config {' | |||||
463 | ) -> Option<(&ConfigLayer, &ConfigValue)> { |
|
463 | ) -> Option<(&ConfigLayer, &ConfigValue)> { | |
464 | // Filter out the config items that are hidden by [PLAIN]. |
|
464 | // Filter out the config items that are hidden by [PLAIN]. | |
465 | // This differs from python hg where we delete them from the config. |
|
465 | // This differs from python hg where we delete them from the config. | |
466 |
let should_ignore = should_ignore(&self.plain, |
|
466 | let should_ignore = should_ignore(&self.plain, section, item); | |
467 | for layer in self.layers.iter().rev() { |
|
467 | for layer in self.layers.iter().rev() { | |
468 | if !layer.trusted { |
|
468 | if !layer.trusted { | |
469 | continue; |
|
469 | continue; | |
@@ -480,8 +480,8 b' impl Config {' | |||||
480 | { |
|
480 | { | |
481 | continue; |
|
481 | continue; | |
482 | } |
|
482 | } | |
483 |
if let Some(v) = layer.get( |
|
483 | if let Some(v) = layer.get(section, item) { | |
484 |
return Some(( |
|
484 | return Some((layer, v)); | |
485 | } |
|
485 | } | |
486 | } |
|
486 | } | |
487 | None |
|
487 | None | |
@@ -561,7 +561,7 b' impl Config {' | |||||
561 | fn get_all(&self, section: &[u8], item: &[u8]) -> Vec<&[u8]> { |
|
561 | fn get_all(&self, section: &[u8], item: &[u8]) -> Vec<&[u8]> { | |
562 | let mut res = vec![]; |
|
562 | let mut res = vec![]; | |
563 | for layer in self.layers.iter().rev() { |
|
563 | for layer in self.layers.iter().rev() { | |
564 |
if let Some(v) = layer.get( |
|
564 | if let Some(v) = layer.get(section, item) { | |
565 | res.push(v.bytes.as_ref()); |
|
565 | res.push(v.bytes.as_ref()); | |
566 | } |
|
566 | } | |
567 | } |
|
567 | } | |
@@ -592,11 +592,11 b' impl Config {' | |||||
592 | add(b"git", b"git", b"1"); |
|
592 | add(b"git", b"git", b"1"); | |
593 | add(b"git", b"showfunc", b"1"); |
|
593 | add(b"git", b"showfunc", b"1"); | |
594 | add(b"git", b"word-diff", b"1"); |
|
594 | add(b"git", b"word-diff", b"1"); | |
595 |
|
|
595 | layer | |
596 | } |
|
596 | } | |
597 |
|
597 | |||
598 | // introduce the tweaked defaults as implied by ui.tweakdefaults |
|
598 | // introduce the tweaked defaults as implied by ui.tweakdefaults | |
599 |
pub fn tweakdefaults |
|
599 | pub fn tweakdefaults(&mut self) { | |
600 | self.layers.insert(0, Config::tweakdefaults_layer()); |
|
600 | self.layers.insert(0, Config::tweakdefaults_layer()); | |
601 | } |
|
601 | } | |
602 | } |
|
602 | } |
@@ -94,11 +94,7 b' impl ConfigLayer {' | |||||
94 |
|
94 | |||
95 | /// Returns whether this layer comes from `--config` CLI arguments |
|
95 | /// Returns whether this layer comes from `--config` CLI arguments | |
96 | pub(crate) fn is_from_command_line(&self) -> bool { |
|
96 | pub(crate) fn is_from_command_line(&self) -> bool { | |
97 |
|
|
97 | matches!(self.origin, ConfigOrigin::CommandLine) | |
98 | true |
|
|||
99 | } else { |
|
|||
100 | false |
|
|||
101 | } |
|
|||
102 | } |
|
98 | } | |
103 |
|
99 | |||
104 | /// Add an entry to the config, overwriting the old one if already present. |
|
100 | /// Add an entry to the config, overwriting the old one if already present. | |
@@ -111,13 +107,13 b' impl ConfigLayer {' | |||||
111 | ) { |
|
107 | ) { | |
112 | self.sections |
|
108 | self.sections | |
113 | .entry(section) |
|
109 | .entry(section) | |
114 |
.or_insert_with( |
|
110 | .or_insert_with(HashMap::new) | |
115 | .insert(item, ConfigValue { bytes: value, line }); |
|
111 | .insert(item, ConfigValue { bytes: value, line }); | |
116 | } |
|
112 | } | |
117 |
|
113 | |||
118 | /// Returns the config value in `<section>.<item>` if it exists |
|
114 | /// Returns the config value in `<section>.<item>` if it exists | |
119 | pub fn get(&self, section: &[u8], item: &[u8]) -> Option<&ConfigValue> { |
|
115 | pub fn get(&self, section: &[u8], item: &[u8]) -> Option<&ConfigValue> { | |
120 |
|
|
116 | self.sections.get(section)?.get(item) | |
121 | } |
|
117 | } | |
122 |
|
118 | |||
123 | /// Returns the keys defined in the given section |
|
119 | /// Returns the keys defined in the given section | |
@@ -171,7 +167,7 b' impl ConfigLayer {' | |||||
171 |
|
167 | |||
172 | while let Some((index, bytes)) = lines_iter.next() { |
|
168 | while let Some((index, bytes)) = lines_iter.next() { | |
173 | let line = Some(index + 1); |
|
169 | let line = Some(index + 1); | |
174 |
if let Some(m) = INCLUDE_RE.captures( |
|
170 | if let Some(m) = INCLUDE_RE.captures(bytes) { | |
175 | let filename_bytes = &m[1]; |
|
171 | let filename_bytes = &m[1]; | |
176 | let filename_bytes = crate::utils::expand_vars(filename_bytes); |
|
172 | let filename_bytes = crate::utils::expand_vars(filename_bytes); | |
177 | // `Path::parent` only fails for the root directory, |
|
173 | // `Path::parent` only fails for the root directory, | |
@@ -205,18 +201,18 b' impl ConfigLayer {' | |||||
205 | } |
|
201 | } | |
206 | } |
|
202 | } | |
207 | } |
|
203 | } | |
208 |
} else if |
|
204 | } else if EMPTY_RE.captures(bytes).is_some() { | |
209 |
} else if let Some(m) = SECTION_RE.captures( |
|
205 | } else if let Some(m) = SECTION_RE.captures(bytes) { | |
210 | section = m[1].to_vec(); |
|
206 | section = m[1].to_vec(); | |
211 |
} else if let Some(m) = ITEM_RE.captures( |
|
207 | } else if let Some(m) = ITEM_RE.captures(bytes) { | |
212 | let item = m[1].to_vec(); |
|
208 | let item = m[1].to_vec(); | |
213 | let mut value = m[2].to_vec(); |
|
209 | let mut value = m[2].to_vec(); | |
214 | loop { |
|
210 | loop { | |
215 | match lines_iter.peek() { |
|
211 | match lines_iter.peek() { | |
216 | None => break, |
|
212 | None => break, | |
217 | Some((_, v)) => { |
|
213 | Some((_, v)) => { | |
218 |
if |
|
214 | if COMMENT_RE.captures(v).is_some() { | |
219 |
} else if |
|
215 | } else if CONT_RE.captures(v).is_some() { | |
220 | value.extend(b"\n"); |
|
216 | value.extend(b"\n"); | |
221 | value.extend(&m[1]); |
|
217 | value.extend(&m[1]); | |
222 | } else { |
|
218 | } else { | |
@@ -227,7 +223,7 b' impl ConfigLayer {' | |||||
227 | lines_iter.next(); |
|
223 | lines_iter.next(); | |
228 | } |
|
224 | } | |
229 | current_layer.add(section.clone(), item, value, line); |
|
225 | current_layer.add(section.clone(), item, value, line); | |
230 |
} else if let Some(m) = UNSET_RE.captures( |
|
226 | } else if let Some(m) = UNSET_RE.captures(bytes) { | |
231 | if let Some(map) = current_layer.sections.get_mut(§ion) { |
|
227 | if let Some(map) = current_layer.sections.get_mut(§ion) { | |
232 | map.remove(&m[1]); |
|
228 | map.remove(&m[1]); | |
233 | } |
|
229 | } | |
@@ -261,7 +257,7 b' impl DisplayBytes for ConfigLayer {' | |||||
261 | sections.sort_by(|e0, e1| e0.0.cmp(e1.0)); |
|
257 | sections.sort_by(|e0, e1| e0.0.cmp(e1.0)); | |
262 |
|
258 | |||
263 | for (section, items) in sections.into_iter() { |
|
259 | for (section, items) in sections.into_iter() { | |
264 |
let mut items: Vec<_> = items. |
|
260 | let mut items: Vec<_> = items.iter().collect(); | |
265 | items.sort_by(|e0, e1| e0.0.cmp(e1.0)); |
|
261 | items.sort_by(|e0, e1| e0.0.cmp(e1.0)); | |
266 |
|
262 | |||
267 | for (item, config_entry) in items { |
|
263 | for (item, config_entry) in items { |
@@ -200,11 +200,7 b' fn parse_list_without_trim_start(input: ' | |||||
200 |
|
200 | |||
201 | // https://docs.python.org/3/library/stdtypes.html?#bytes.isspace |
|
201 | // https://docs.python.org/3/library/stdtypes.html?#bytes.isspace | |
202 | fn is_space(byte: u8) -> bool { |
|
202 | fn is_space(byte: u8) -> bool { | |
203 |
|
|
203 | matches!(byte, b' ' | b'\t' | b'\n' | b'\r' | b'\x0b' | b'\x0c') | |
204 | true |
|
|||
205 | } else { |
|
|||
206 | false |
|
|||
207 | } |
|
|||
208 | } |
|
204 | } | |
209 | } |
|
205 | } | |
210 |
|
206 |
@@ -59,7 +59,7 b' impl CopySource {' | |||||
59 | Self { |
|
59 | Self { | |
60 | rev, |
|
60 | rev, | |
61 | path: winner.path, |
|
61 | path: winner.path, | |
62 |
overwritten |
|
62 | overwritten, | |
63 | } |
|
63 | } | |
64 | } |
|
64 | } | |
65 |
|
65 | |||
@@ -489,7 +489,7 b" fn chain_changes<'a>(" | |||||
489 | if cs1 == cs2 { |
|
489 | if cs1 == cs2 { | |
490 | cs1.mark_delete(current_rev); |
|
490 | cs1.mark_delete(current_rev); | |
491 | } else { |
|
491 | } else { | |
492 |
cs1.mark_delete_with_pair(current_rev, |
|
492 | cs1.mark_delete_with_pair(current_rev, cs2); | |
493 | } |
|
493 | } | |
494 | e2.insert(cs1.clone()); |
|
494 | e2.insert(cs1.clone()); | |
495 | } |
|
495 | } | |
@@ -513,15 +513,14 b' fn add_one_copy(' | |||||
513 | ) { |
|
513 | ) { | |
514 | let dest = path_map.tokenize(path_dest); |
|
514 | let dest = path_map.tokenize(path_dest); | |
515 | let source = path_map.tokenize(path_source); |
|
515 | let source = path_map.tokenize(path_source); | |
516 | let entry; |
|
516 | let entry = if let Some(v) = base_copies.get(&source) { | |
517 | if let Some(v) = base_copies.get(&source) { |
|
517 | match &v.path { | |
518 | entry = match &v.path { |
|
|||
519 | Some(path) => Some((*(path)).to_owned()), |
|
518 | Some(path) => Some((*(path)).to_owned()), | |
520 | None => Some(source.to_owned()), |
|
519 | None => Some(source.to_owned()), | |
521 | } |
|
520 | } | |
522 | } else { |
|
521 | } else { | |
523 |
|
|
522 | Some(source.to_owned()) | |
524 | } |
|
523 | }; | |
525 | // Each new entry is introduced by the children, we |
|
524 | // Each new entry is introduced by the children, we | |
526 | // record this information as we will need it to take |
|
525 | // record this information as we will need it to take | |
527 | // the right decision when merging conflicting copy |
|
526 | // the right decision when merging conflicting copy | |
@@ -563,17 +562,15 b' fn merge_copies_dict(' | |||||
563 | MergePick::Major | MergePick::Any => (src_major, src_minor), |
|
562 | MergePick::Major | MergePick::Any => (src_major, src_minor), | |
564 | MergePick::Minor => (src_minor, src_major), |
|
563 | MergePick::Minor => (src_minor, src_major), | |
565 | }; |
|
564 | }; | |
566 |
MergeResult:: |
|
565 | MergeResult::NewValue(CopySource::new_from_merge( | |
567 | current_merge, |
|
566 | current_merge, | |
568 | winner, |
|
567 | winner, | |
569 | loser, |
|
568 | loser, | |
570 | )) |
|
569 | )) | |
571 | } else { |
|
570 | } else { | |
572 | match pick { |
|
571 | match pick { | |
573 |
MergePick::Any | MergePick::Major => |
|
572 | MergePick::Any | MergePick::Major => MergeResult::RightValue, | |
574 |
|
|
573 | MergePick::Minor => MergeResult::LeftValue, | |
575 | } |
|
|||
576 | MergePick::Minor => MergeResult::UseLeftValue, |
|
|||
577 | } |
|
574 | } | |
578 | } |
|
575 | } | |
579 | }) |
|
576 | }) |
@@ -181,7 +181,7 b' mod tests {' | |||||
181 | let mut revs: HashSet<Revision> = revs.iter().cloned().collect(); |
|
181 | let mut revs: HashSet<Revision> = revs.iter().cloned().collect(); | |
182 | retain_heads(graph, &mut revs)?; |
|
182 | retain_heads(graph, &mut revs)?; | |
183 | let mut as_vec: Vec<Revision> = revs.iter().cloned().collect(); |
|
183 | let mut as_vec: Vec<Revision> = revs.iter().cloned().collect(); | |
184 | as_vec.sort(); |
|
184 | as_vec.sort_unstable(); | |
185 | Ok(as_vec) |
|
185 | Ok(as_vec) | |
186 | } |
|
186 | } | |
187 |
|
187 | |||
@@ -206,7 +206,7 b' mod tests {' | |||||
206 | ) -> Result<Vec<Revision>, GraphError> { |
|
206 | ) -> Result<Vec<Revision>, GraphError> { | |
207 | let heads = heads(graph, revs.iter())?; |
|
207 | let heads = heads(graph, revs.iter())?; | |
208 | let mut as_vec: Vec<Revision> = heads.iter().cloned().collect(); |
|
208 | let mut as_vec: Vec<Revision> = heads.iter().cloned().collect(); | |
209 | as_vec.sort(); |
|
209 | as_vec.sort_unstable(); | |
210 | Ok(as_vec) |
|
210 | Ok(as_vec) | |
211 | } |
|
211 | } | |
212 |
|
212 | |||
@@ -231,7 +231,7 b' mod tests {' | |||||
231 | ) -> Result<Vec<Revision>, GraphError> { |
|
231 | ) -> Result<Vec<Revision>, GraphError> { | |
232 | let set: HashSet<_> = revs.iter().cloned().collect(); |
|
232 | let set: HashSet<_> = revs.iter().cloned().collect(); | |
233 | let mut as_vec = roots(graph, &set)?; |
|
233 | let mut as_vec = roots(graph, &set)?; | |
234 | as_vec.sort(); |
|
234 | as_vec.sort_unstable(); | |
235 | Ok(as_vec) |
|
235 | Ok(as_vec) | |
236 | } |
|
236 | } | |
237 |
|
237 |
@@ -32,7 +32,7 b' impl DirstateParents {' | |||||
32 | }; |
|
32 | }; | |
33 |
|
33 | |||
34 | pub fn is_merge(&self) -> bool { |
|
34 | pub fn is_merge(&self) -> bool { | |
35 |
|
|
35 | !(self.p2 == NULL_NODE) | |
36 | } |
|
36 | } | |
37 | } |
|
37 | } | |
38 |
|
38 |
@@ -232,7 +232,7 b' mod tests {' | |||||
232 | #[test] |
|
232 | #[test] | |
233 | fn test_delete_path_empty_path() { |
|
233 | fn test_delete_path_empty_path() { | |
234 | let mut map = |
|
234 | let mut map = | |
235 |
DirsMultiset::from_manifest(& |
|
235 | DirsMultiset::from_manifest(&[HgPathBuf::new()]).unwrap(); | |
236 | let path = HgPath::new(b""); |
|
236 | let path = HgPath::new(b""); | |
237 | assert_eq!(Ok(()), map.delete_path(path)); |
|
237 | assert_eq!(Ok(()), map.delete_path(path)); | |
238 | assert_eq!( |
|
238 | assert_eq!( |
@@ -180,11 +180,7 b' impl TruncatedTimestamp {' | |||||
180 | if self.truncated_seconds != other.truncated_seconds { |
|
180 | if self.truncated_seconds != other.truncated_seconds { | |
181 | false |
|
181 | false | |
182 | } else if self.nanoseconds == 0 || other.nanoseconds == 0 { |
|
182 | } else if self.nanoseconds == 0 || other.nanoseconds == 0 { | |
183 |
|
|
183 | !self.second_ambiguous | |
184 | false |
|
|||
185 | } else { |
|
|||
186 | true |
|
|||
187 | } |
|
|||
188 | } else { |
|
184 | } else { | |
189 | self.nanoseconds == other.nanoseconds |
|
185 | self.nanoseconds == other.nanoseconds | |
190 | } |
|
186 | } | |
@@ -706,9 +702,9 b' impl TryFrom<u8> for EntryState {' | |||||
706 | } |
|
702 | } | |
707 | } |
|
703 | } | |
708 |
|
704 | |||
709 |
impl |
|
705 | impl From<EntryState> for u8 { | |
710 | fn into(self) -> u8 { |
|
706 | fn from(val: EntryState) -> Self { | |
711 |
match |
|
707 | match val { | |
712 | EntryState::Normal => b'n', |
|
708 | EntryState::Normal => b'n', | |
713 | EntryState::Added => b'a', |
|
709 | EntryState::Added => b'a', | |
714 | EntryState::Removed => b'r', |
|
710 | EntryState::Removed => b'r', |
@@ -320,9 +320,7 b" impl<'tree, 'on_disk> NodeRef<'tree, 'on" | |||||
320 | on_disk: &'on_disk [u8], |
|
320 | on_disk: &'on_disk [u8], | |
321 | ) -> Result<Option<&'tree HgPath>, DirstateV2ParseError> { |
|
321 | ) -> Result<Option<&'tree HgPath>, DirstateV2ParseError> { | |
322 | match self { |
|
322 | match self { | |
323 |
NodeRef::InMemory(_path, node) => |
|
323 | NodeRef::InMemory(_path, node) => Ok(node.copy_source.as_deref()), | |
324 | Ok(node.copy_source.as_ref().map(|s| &**s)) |
|
|||
325 | } |
|
|||
326 | NodeRef::OnDisk(node) => node.copy_source(on_disk), |
|
324 | NodeRef::OnDisk(node) => node.copy_source(on_disk), | |
327 | } |
|
325 | } | |
328 | } |
|
326 | } | |
@@ -340,9 +338,9 b" impl<'tree, 'on_disk> NodeRef<'tree, 'on" | |||||
340 | Cow::Owned(in_memory) => BorrowedPath::InMemory(in_memory), |
|
338 | Cow::Owned(in_memory) => BorrowedPath::InMemory(in_memory), | |
341 | }) |
|
339 | }) | |
342 | } |
|
340 | } | |
343 |
NodeRef::OnDisk(node) => |
|
341 | NodeRef::OnDisk(node) => { | |
344 | .copy_source(on_disk)? |
|
342 | node.copy_source(on_disk)?.map(BorrowedPath::OnDisk) | |
345 | .map(|source| BorrowedPath::OnDisk(source)), |
|
343 | } | |
346 | }) |
|
344 | }) | |
347 | } |
|
345 | } | |
348 |
|
346 | |||
@@ -418,10 +416,7 b' impl Default for NodeData {' | |||||
418 |
|
416 | |||
419 | impl NodeData { |
|
417 | impl NodeData { | |
420 | fn has_entry(&self) -> bool { |
|
418 | fn has_entry(&self) -> bool { | |
421 | match self { |
|
419 | matches!(self, NodeData::Entry(_)) | |
422 | NodeData::Entry(_) => true, |
|
|||
423 | _ => false, |
|
|||
424 | } |
|
|||
425 | } |
|
420 | } | |
426 |
|
421 | |||
427 | fn as_entry(&self) -> Option<&DirstateEntry> { |
|
422 | fn as_entry(&self) -> Option<&DirstateEntry> { | |
@@ -509,7 +504,7 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
509 | Ok(()) |
|
504 | Ok(()) | |
510 | }, |
|
505 | }, | |
511 | )?; |
|
506 | )?; | |
512 |
let parents = Some(parents |
|
507 | let parents = Some(*parents); | |
513 |
|
508 | |||
514 | Ok((map, parents)) |
|
509 | Ok((map, parents)) | |
515 | } |
|
510 | } | |
@@ -681,11 +676,9 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
681 | .checked_sub(1) |
|
676 | .checked_sub(1) | |
682 | .expect("tracked count to be >= 0"); |
|
677 | .expect("tracked count to be >= 0"); | |
683 | } |
|
678 | } | |
684 | } else { |
|
679 | } else if wc_tracked { | |
685 | if wc_tracked { |
|
|||
686 |
|
|
680 | ancestor.tracked_descendants_count += 1; | |
687 |
|
|
681 | } | |
688 | } |
|
|||
689 | })?; |
|
682 | })?; | |
690 |
|
683 | |||
691 | let v2_data = if let Some(parent_file_data) = parent_file_data_opt { |
|
684 | let v2_data = if let Some(parent_file_data) = parent_file_data_opt { | |
@@ -734,7 +727,7 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
734 | ancestor.tracked_descendants_count += tracked_count_increment; |
|
727 | ancestor.tracked_descendants_count += tracked_count_increment; | |
735 | })?; |
|
728 | })?; | |
736 | if let Some(old_entry) = old_entry_opt { |
|
729 | if let Some(old_entry) = old_entry_opt { | |
737 |
let mut e = old_entry |
|
730 | let mut e = old_entry; | |
738 | if e.tracked() { |
|
731 | if e.tracked() { | |
739 | // XXX |
|
732 | // XXX | |
740 | // This is probably overkill for more case, but we need this to |
|
733 | // This is probably overkill for more case, but we need this to | |
@@ -775,7 +768,7 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
775 | .expect("tracked_descendants_count should be >= 0"); |
|
768 | .expect("tracked_descendants_count should be >= 0"); | |
776 | })? |
|
769 | })? | |
777 | .expect("node should exist"); |
|
770 | .expect("node should exist"); | |
778 |
let mut new_entry = old_entry |
|
771 | let mut new_entry = old_entry; | |
779 | new_entry.set_untracked(); |
|
772 | new_entry.set_untracked(); | |
780 | node.data = NodeData::Entry(new_entry); |
|
773 | node.data = NodeData::Entry(new_entry); | |
781 | Ok(()) |
|
774 | Ok(()) | |
@@ -803,7 +796,7 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
803 | } |
|
796 | } | |
804 | })? |
|
797 | })? | |
805 | .expect("node should exist"); |
|
798 | .expect("node should exist"); | |
806 |
let mut new_entry = old_entry |
|
799 | let mut new_entry = old_entry; | |
807 | new_entry.set_clean(mode, size, mtime); |
|
800 | new_entry.set_clean(mode, size, mtime); | |
808 | node.data = NodeData::Entry(new_entry); |
|
801 | node.data = NodeData::Entry(new_entry); | |
809 | Ok(()) |
|
802 | Ok(()) | |
@@ -1364,7 +1357,7 b' impl OwningDirstateMap {' | |||||
1364 | value: &HgPath, |
|
1357 | value: &HgPath, | |
1365 | ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> { |
|
1358 | ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> { | |
1366 | self.with_dmap_mut(|map| { |
|
1359 | self.with_dmap_mut(|map| { | |
1367 |
let node = map.get_or_insert_node( |
|
1360 | let node = map.get_or_insert_node(key, |_ancestor| {})?; | |
1368 | let had_copy_source = node.copy_source.is_none(); |
|
1361 | let had_copy_source = node.copy_source.is_none(); | |
1369 | let old = node |
|
1362 | let old = node | |
1370 | .copy_source |
|
1363 | .copy_source | |
@@ -1864,12 +1857,9 b' mod tests {' | |||||
1864 | map.set_untracked(p(b"some/nested/removed"))?; |
|
1857 | map.set_untracked(p(b"some/nested/removed"))?; | |
1865 | assert_eq!(map.get_map().unreachable_bytes, 0); |
|
1858 | assert_eq!(map.get_map().unreachable_bytes, 0); | |
1866 |
|
1859 | |||
1867 |
|
|
1860 | if let ChildNodes::InMemory(_) = map.get_map().root { | |
1868 | ChildNodes::InMemory(_) => { |
|
|||
1869 |
|
|
1861 | panic!("root should not have been mutated") | |
1870 |
|
|
1862 | } | |
1871 | _ => (), |
|
|||
1872 | } |
|
|||
1873 | // We haven't mutated enough (nothing, actually), we should still be in |
|
1863 | // We haven't mutated enough (nothing, actually), we should still be in | |
1874 | // the append strategy |
|
1864 | // the append strategy | |
1875 | assert!(map.get_map().write_should_append()); |
|
1865 | assert!(map.get_map().write_should_append()); | |
@@ -1879,9 +1869,8 b' mod tests {' | |||||
1879 | let unreachable_bytes = map.get_map().unreachable_bytes; |
|
1869 | let unreachable_bytes = map.get_map().unreachable_bytes; | |
1880 | assert!(unreachable_bytes > 0); |
|
1870 | assert!(unreachable_bytes > 0); | |
1881 |
|
1871 | |||
1882 |
|
|
1872 | if let ChildNodes::OnDisk(_) = map.get_map().root { | |
1883 |
|
|
1873 | panic!("root should have been mutated") | |
1884 | _ => (), |
|
|||
1885 | } |
|
1874 | } | |
1886 |
|
1875 | |||
1887 | // This should not mutate the structure either, since `root` has |
|
1876 | // This should not mutate the structure either, since `root` has | |
@@ -1889,23 +1878,21 b' mod tests {' | |||||
1889 | map.set_untracked(p(b"merged"))?; |
|
1878 | map.set_untracked(p(b"merged"))?; | |
1890 | assert_eq!(map.get_map().unreachable_bytes, unreachable_bytes); |
|
1879 | assert_eq!(map.get_map().unreachable_bytes, unreachable_bytes); | |
1891 |
|
1880 | |||
1892 | match map.get_map().get_node(p(b"other/added_with_p2"))?.unwrap() { |
|
1881 | if let NodeRef::InMemory(_, _) = | |
1893 | NodeRef::InMemory(_, _) => { |
|
1882 | map.get_map().get_node(p(b"other/added_with_p2"))?.unwrap() | |
|
1883 | { | |||
1894 |
|
|
1884 | panic!("'other/added_with_p2' should not have been mutated") | |
1895 |
|
|
1885 | } | |
1896 | _ => (), |
|
|||
1897 | } |
|
|||
1898 | // But this should, since it's in a different path |
|
1886 | // But this should, since it's in a different path | |
1899 | // than `<root>some/nested/add` |
|
1887 | // than `<root>some/nested/add` | |
1900 | map.set_untracked(p(b"other/added_with_p2"))?; |
|
1888 | map.set_untracked(p(b"other/added_with_p2"))?; | |
1901 | assert!(map.get_map().unreachable_bytes > unreachable_bytes); |
|
1889 | assert!(map.get_map().unreachable_bytes > unreachable_bytes); | |
1902 |
|
1890 | |||
1903 | match map.get_map().get_node(p(b"other/added_with_p2"))?.unwrap() { |
|
1891 | if let NodeRef::OnDisk(_) = | |
1904 | NodeRef::OnDisk(_) => { |
|
1892 | map.get_map().get_node(p(b"other/added_with_p2"))?.unwrap() | |
|
1893 | { | |||
1905 |
|
|
1894 | panic!("'other/added_with_p2' should have been mutated") | |
1906 |
|
|
1895 | } | |
1907 | _ => (), |
|
|||
1908 | } |
|
|||
1909 |
|
1896 | |||
1910 | // We have rewritten most of the tree, we should create a new file |
|
1897 | // We have rewritten most of the tree, we should create a new file | |
1911 | assert!(!map.get_map().write_should_append()); |
|
1898 | assert!(!map.get_map().write_should_append()); |
@@ -246,11 +246,9 b" impl<'on_disk> Docket<'on_disk> {" | |||||
246 | pub fn parents(&self) -> DirstateParents { |
|
246 | pub fn parents(&self) -> DirstateParents { | |
247 | use crate::Node; |
|
247 | use crate::Node; | |
248 | let p1 = Node::try_from(&self.header.parent_1[..USED_NODE_ID_BYTES]) |
|
248 | let p1 = Node::try_from(&self.header.parent_1[..USED_NODE_ID_BYTES]) | |
249 | .unwrap() |
|
249 | .unwrap(); | |
250 | .clone(); |
|
|||
251 | let p2 = Node::try_from(&self.header.parent_2[..USED_NODE_ID_BYTES]) |
|
250 | let p2 = Node::try_from(&self.header.parent_2[..USED_NODE_ID_BYTES]) | |
252 | .unwrap() |
|
251 | .unwrap(); | |
253 | .clone(); |
|
|||
254 | DirstateParents { p1, p2 } |
|
252 | DirstateParents { p1, p2 } | |
255 | } |
|
253 | } | |
256 |
|
254 | |||
@@ -322,7 +320,7 b' impl Node {' | |||||
322 | read_hg_path(on_disk, self.full_path) |
|
320 | read_hg_path(on_disk, self.full_path) | |
323 | } |
|
321 | } | |
324 |
|
322 | |||
325 |
pub(super) fn base_name_start |
|
323 | pub(super) fn base_name_start( | |
326 | &self, |
|
324 | &self, | |
327 | ) -> Result<usize, DirstateV2ParseError> { |
|
325 | ) -> Result<usize, DirstateV2ParseError> { | |
328 | let start = self.base_name_start.get(); |
|
326 | let start = self.base_name_start.get(); | |
@@ -355,7 +353,7 b' impl Node {' | |||||
355 | )) |
|
353 | )) | |
356 | } |
|
354 | } | |
357 |
|
355 | |||
358 |
pub(super) fn has_copy_source |
|
356 | pub(super) fn has_copy_source(&self) -> bool { | |
359 | self.copy_source.start.get() != 0 |
|
357 | self.copy_source.start.get() != 0 | |
360 | } |
|
358 | } | |
361 |
|
359 | |||
@@ -414,12 +412,12 b' impl Node {' | |||||
414 | } else { |
|
412 | } else { | |
415 | libc::S_IFREG |
|
413 | libc::S_IFREG | |
416 | }; |
|
414 | }; | |
417 | let permisions = if self.flags().contains(Flags::MODE_EXEC_PERM) { |
|
415 | let permissions = if self.flags().contains(Flags::MODE_EXEC_PERM) { | |
418 | 0o755 |
|
416 | 0o755 | |
419 | } else { |
|
417 | } else { | |
420 | 0o644 |
|
418 | 0o644 | |
421 | }; |
|
419 | }; | |
422 |
|
|
420 | file_type | permissions | |
423 | } |
|
421 | } | |
424 |
|
422 | |||
425 | fn mtime(&self) -> Result<TruncatedTimestamp, DirstateV2ParseError> { |
|
423 | fn mtime(&self) -> Result<TruncatedTimestamp, DirstateV2ParseError> { |
@@ -24,7 +24,7 b' impl OwningDirstateMap {' | |||||
24 |
|
24 | |||
25 | OwningDirstateMapBuilder { |
|
25 | OwningDirstateMapBuilder { | |
26 | on_disk, |
|
26 | on_disk, | |
27 |
map_builder: |bytes| DirstateMap::empty( |
|
27 | map_builder: |bytes| DirstateMap::empty(bytes), | |
28 | } |
|
28 | } | |
29 | .build() |
|
29 | .build() | |
30 | } |
|
30 | } | |
@@ -42,7 +42,7 b' impl OwningDirstateMap {' | |||||
42 | OwningDirstateMapTryBuilder { |
|
42 | OwningDirstateMapTryBuilder { | |
43 | on_disk, |
|
43 | on_disk, | |
44 | map_builder: |bytes| { |
|
44 | map_builder: |bytes| { | |
45 |
DirstateMap::new_v1( |
|
45 | DirstateMap::new_v1(bytes).map(|(dmap, p)| { | |
46 | parents = p.unwrap_or(DirstateParents::NULL); |
|
46 | parents = p.unwrap_or(DirstateParents::NULL); | |
47 | dmap |
|
47 | dmap | |
48 | }) |
|
48 | }) | |
@@ -66,7 +66,7 b' impl OwningDirstateMap {' | |||||
66 | OwningDirstateMapTryBuilder { |
|
66 | OwningDirstateMapTryBuilder { | |
67 | on_disk, |
|
67 | on_disk, | |
68 | map_builder: |bytes| { |
|
68 | map_builder: |bytes| { | |
69 |
DirstateMap::new_v2( |
|
69 | DirstateMap::new_v2(bytes, data_size, metadata) | |
70 | }, |
|
70 | }, | |
71 | } |
|
71 | } | |
72 | .try_build() |
|
72 | .try_build() |
@@ -154,7 +154,7 b" pub fn status<'dirstate>(" | |||||
154 | hg_path, |
|
154 | hg_path, | |
155 | &DirEntry { |
|
155 | &DirEntry { | |
156 | hg_path: Cow::Borrowed(HgPath::new(b"")), |
|
156 | hg_path: Cow::Borrowed(HgPath::new(b"")), | |
157 |
fs_path: Cow::Borrowed( |
|
157 | fs_path: Cow::Borrowed(root_dir), | |
158 | symlink_metadata: None, |
|
158 | symlink_metadata: None, | |
159 | file_type: FakeFileType::Directory, |
|
159 | file_type: FakeFileType::Directory, | |
160 | }, |
|
160 | }, | |
@@ -245,7 +245,7 b" impl<'a> HasIgnoredAncestor<'a> {" | |||||
245 | None => false, |
|
245 | None => false, | |
246 | Some(parent) => { |
|
246 | Some(parent) => { | |
247 | *(parent.cache.get_or_init(|| { |
|
247 | *(parent.cache.get_or_init(|| { | |
248 |
parent.force(ignore_fn) || ignore_fn( |
|
248 | parent.force(ignore_fn) || ignore_fn(self.path) | |
249 | })) |
|
249 | })) | |
250 | } |
|
250 | } | |
251 | } |
|
251 | } | |
@@ -402,7 +402,7 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||||
402 | let entry = DirEntry { |
|
402 | let entry = DirEntry { | |
403 | hg_path: Cow::Borrowed( |
|
403 | hg_path: Cow::Borrowed( | |
404 | dirstate_node |
|
404 | dirstate_node | |
405 |
.full_path( |
|
405 | .full_path(self.dmap.on_disk)?, | |
406 | ), |
|
406 | ), | |
407 | fs_path: Cow::Borrowed(&fs_path), |
|
407 | fs_path: Cow::Borrowed(&fs_path), | |
408 | symlink_metadata: Some(fs_metadata), |
|
408 | symlink_metadata: Some(fs_metadata), | |
@@ -420,7 +420,8 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||||
420 | Err(error) => { |
|
420 | Err(error) => { | |
421 | let hg_path = |
|
421 | let hg_path = | |
422 | dirstate_node.full_path(self.dmap.on_disk)?; |
|
422 | dirstate_node.full_path(self.dmap.on_disk)?; | |
423 |
|
|
423 | self.io_error(error, hg_path); | |
|
424 | Ok(()) | |||
424 | } |
|
425 | } | |
425 | } |
|
426 | } | |
426 | }) |
|
427 | }) | |
@@ -472,28 +473,25 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||||
472 | .par_bridge() |
|
473 | .par_bridge() | |
473 | .map(|pair| { |
|
474 | .map(|pair| { | |
474 | use itertools::EitherOrBoth::*; |
|
475 | use itertools::EitherOrBoth::*; | |
475 |
let has_dirstate_node_or_is_ignored |
|
476 | let has_dirstate_node_or_is_ignored = match pair { | |
476 | match pair { |
|
|||
477 | Both(dirstate_node, fs_entry) => { |
|
477 | Both(dirstate_node, fs_entry) => { | |
478 | self.traverse_fs_and_dirstate( |
|
478 | self.traverse_fs_and_dirstate( | |
479 |
|
|
479 | fs_entry, | |
480 | dirstate_node, |
|
480 | dirstate_node, | |
481 | has_ignored_ancestor, |
|
481 | has_ignored_ancestor, | |
482 | )?; |
|
482 | )?; | |
483 | has_dirstate_node_or_is_ignored = true |
|
483 | true | |
484 | } |
|
484 | } | |
485 | Left(dirstate_node) => { |
|
485 | Left(dirstate_node) => { | |
486 | self.traverse_dirstate_only(dirstate_node)?; |
|
486 | self.traverse_dirstate_only(dirstate_node)?; | |
487 | has_dirstate_node_or_is_ignored = true; |
|
487 | true | |
488 | } |
|
488 | } | |
489 |
Right(fs_entry) => |
|
489 | Right(fs_entry) => self.traverse_fs_only( | |
490 | has_dirstate_node_or_is_ignored = self.traverse_fs_only( |
|
|||
491 |
|
|
490 | has_ignored_ancestor.force(&self.ignore_fn), | |
492 |
|
|
491 | directory_hg_path, | |
493 |
|
|
492 | fs_entry, | |
494 |
|
|
493 | ), | |
495 |
|
|
494 | }; | |
496 | } |
|
|||
497 | Ok(has_dirstate_node_or_is_ignored) |
|
495 | Ok(has_dirstate_node_or_is_ignored) | |
498 | }) |
|
496 | }) | |
499 | .try_reduce(|| true, |a, b| Ok(a && b)) |
|
497 | .try_reduce(|| true, |a, b| Ok(a && b)) | |
@@ -524,7 +522,7 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||||
524 | .push(hg_path.detach_from_tree()) |
|
522 | .push(hg_path.detach_from_tree()) | |
525 | } |
|
523 | } | |
526 | let is_ignored = HasIgnoredAncestor::create( |
|
524 | let is_ignored = HasIgnoredAncestor::create( | |
527 |
Some( |
|
525 | Some(has_ignored_ancestor), | |
528 | hg_path, |
|
526 | hg_path, | |
529 | ); |
|
527 | ); | |
530 | let is_at_repo_root = false; |
|
528 | let is_at_repo_root = false; | |
@@ -544,14 +542,14 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||||
544 | outdated_dircache, |
|
542 | outdated_dircache, | |
545 | )? |
|
543 | )? | |
546 | } else { |
|
544 | } else { | |
547 |
if file_or_symlink && self.matcher.matches( |
|
545 | if file_or_symlink && self.matcher.matches(hg_path) { | |
548 | if let Some(entry) = dirstate_node.entry()? { |
|
546 | if let Some(entry) = dirstate_node.entry()? { | |
549 | if !entry.any_tracked() { |
|
547 | if !entry.any_tracked() { | |
550 | // Forward-compat if we start tracking unknown/ignored |
|
548 | // Forward-compat if we start tracking unknown/ignored | |
551 | // files for caching reasons |
|
549 | // files for caching reasons | |
552 | self.mark_unknown_or_ignored( |
|
550 | self.mark_unknown_or_ignored( | |
553 | has_ignored_ancestor.force(&self.ignore_fn), |
|
551 | has_ignored_ancestor.force(&self.ignore_fn), | |
554 |
|
|
552 | hg_path, | |
555 | ); |
|
553 | ); | |
556 | } |
|
554 | } | |
557 | if entry.added() { |
|
555 | if entry.added() { | |
@@ -620,12 +618,13 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||||
620 | Ok(meta) => meta, |
|
618 | Ok(meta) => meta, | |
621 | Err(_) => return Ok(()), |
|
619 | Err(_) => return Ok(()), | |
622 | }; |
|
620 | }; | |
623 | let directory_mtime = if let Ok(option) = |
|
621 | ||
624 |
TruncatedTimestamp::for_reliable_mtime_of( |
|
622 | let directory_mtime = match TruncatedTimestamp::for_reliable_mtime_of( | |
625 | { |
|
623 | &metadata, | |
626 | if let Some(directory_mtime) = option { |
|
624 | status_start, | |
627 | directory_mtime |
|
625 | ) { | |
628 | } else { |
|
626 | Ok(Some(directory_mtime)) => directory_mtime, | |
|
627 | Ok(None) => { | |||
629 | // The directory was modified too recently, |
|
628 | // The directory was modified too recently, | |
630 | // don’t cache its `read_dir` results. |
|
629 | // don’t cache its `read_dir` results. | |
631 | // |
|
630 | // | |
@@ -643,9 +642,10 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||||
643 | // by the same script. |
|
642 | // by the same script. | |
644 | return Ok(()); |
|
643 | return Ok(()); | |
645 | } |
|
644 | } | |
646 | } else { |
|
645 | Err(_) => { | |
647 | // OS/libc does not support mtime? |
|
646 | // OS/libc does not support mtime? | |
648 | return Ok(()); |
|
647 | return Ok(()); | |
|
648 | } | |||
649 | }; |
|
649 | }; | |
650 | // We’ve observed (through `status_start`) that time has |
|
650 | // We’ve observed (through `status_start`) that time has | |
651 | // “progressed” since `directory_mtime`, so any further |
|
651 | // “progressed” since `directory_mtime`, so any further | |
@@ -713,8 +713,9 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||||
713 | { |
|
713 | { | |
714 | self.push_outcome(Outcome::Modified, dirstate_node)? |
|
714 | self.push_outcome(Outcome::Modified, dirstate_node)? | |
715 | } else { |
|
715 | } else { | |
716 |
let mtime_looks_clean |
|
716 | let mtime_looks_clean = if let Some(dirstate_mtime) = | |
717 |
|
|
717 | entry.truncated_mtime() | |
|
718 | { | |||
718 | let fs_mtime = TruncatedTimestamp::for_mtime_of(&fs_metadata) |
|
719 | let fs_mtime = TruncatedTimestamp::for_mtime_of(&fs_metadata) | |
719 | .expect("OS/libc does not support mtime?"); |
|
720 | .expect("OS/libc does not support mtime?"); | |
720 | // There might be a change in the future if for example the |
|
721 | // There might be a change in the future if for example the | |
@@ -722,10 +723,10 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||||
722 | // case where the issues the user would face |
|
723 | // case where the issues the user would face | |
723 | // would be a lot worse and there is nothing we |
|
724 | // would be a lot worse and there is nothing we | |
724 | // can really do. |
|
725 | // can really do. | |
725 |
|
|
726 | fs_mtime.likely_equal(dirstate_mtime) | |
726 | } else { |
|
727 | } else { | |
727 | // No mtime in the dirstate entry |
|
728 | // No mtime in the dirstate entry | |
728 |
|
|
729 | false | |
729 | }; |
|
730 | }; | |
730 | if !mtime_looks_clean { |
|
731 | if !mtime_looks_clean { | |
731 | self.push_outcome(Outcome::Unsure, dirstate_node)? |
|
732 | self.push_outcome(Outcome::Unsure, dirstate_node)? | |
@@ -769,7 +770,7 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||||
769 | if entry.removed() { |
|
770 | if entry.removed() { | |
770 | self.push_outcome(Outcome::Removed, dirstate_node)? |
|
771 | self.push_outcome(Outcome::Removed, dirstate_node)? | |
771 | } else { |
|
772 | } else { | |
772 |
self.push_outcome(Outcome::Deleted, |
|
773 | self.push_outcome(Outcome::Deleted, dirstate_node)? | |
773 | } |
|
774 | } | |
774 | } |
|
775 | } | |
775 | } |
|
776 | } | |
@@ -816,8 +817,7 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||||
816 | } |
|
817 | } | |
817 | } |
|
818 | } | |
818 | is_ignored |
|
819 | is_ignored | |
819 | } else { |
|
820 | } else if file_or_symlink { | |
820 | if file_or_symlink { |
|
|||
821 |
|
|
821 | if self.matcher.matches(&hg_path) { | |
822 |
|
|
822 | self.mark_unknown_or_ignored( | |
823 |
|
|
823 | has_ignored_ancestor, | |
@@ -837,7 +837,6 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||||
837 |
|
|
837 | true | |
838 |
|
|
838 | } | |
839 |
|
|
839 | } | |
840 | } |
|
|||
841 |
|
840 | |||
842 | /// Returns whether that path is ignored |
|
841 | /// Returns whether that path is ignored | |
843 | fn mark_unknown_or_ignored( |
|
842 | fn mark_unknown_or_ignored( | |
@@ -845,7 +844,7 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||||
845 | has_ignored_ancestor: bool, |
|
844 | has_ignored_ancestor: bool, | |
846 | hg_path: &BorrowedPath<'_, 'on_disk>, |
|
845 | hg_path: &BorrowedPath<'_, 'on_disk>, | |
847 | ) -> bool { |
|
846 | ) -> bool { | |
848 |
let is_ignored = has_ignored_ancestor || (self.ignore_fn)( |
|
847 | let is_ignored = has_ignored_ancestor || (self.ignore_fn)(hg_path); | |
849 | if is_ignored { |
|
848 | if is_ignored { | |
850 | if self.options.list_ignored { |
|
849 | if self.options.list_ignored { | |
851 | self.push_outcome_without_copy_source( |
|
850 | self.push_outcome_without_copy_source( | |
@@ -853,13 +852,8 b" impl<'a, 'tree, 'on_disk> StatusCommon<'" | |||||
853 | hg_path, |
|
852 | hg_path, | |
854 | ) |
|
853 | ) | |
855 | } |
|
854 | } | |
856 | } else { |
|
855 | } else if self.options.list_unknown { | |
857 | if self.options.list_unknown { |
|
856 | self.push_outcome_without_copy_source(Outcome::Unknown, hg_path) | |
858 | self.push_outcome_without_copy_source( |
|
|||
859 | Outcome::Unknown, |
|
|||
860 | hg_path, |
|
|||
861 | ) |
|
|||
862 | } |
|
|||
863 | } |
|
857 | } | |
864 | is_ignored |
|
858 | is_ignored | |
865 | } |
|
859 | } |
@@ -194,7 +194,7 b' impl<G: Graph + Clone> PartialDiscovery<' | |||||
194 | size: usize, |
|
194 | size: usize, | |
195 | ) -> Vec<Revision> { |
|
195 | ) -> Vec<Revision> { | |
196 | if !self.randomize { |
|
196 | if !self.randomize { | |
197 | sample.sort(); |
|
197 | sample.sort_unstable(); | |
198 | sample.truncate(size); |
|
198 | sample.truncate(size); | |
199 | return sample; |
|
199 | return sample; | |
200 | } |
|
200 | } | |
@@ -513,14 +513,14 b' mod tests {' | |||||
513 | ) -> Vec<Revision> { |
|
513 | ) -> Vec<Revision> { | |
514 | let mut as_vec: Vec<Revision> = |
|
514 | let mut as_vec: Vec<Revision> = | |
515 | disco.undecided.as_ref().unwrap().iter().cloned().collect(); |
|
515 | disco.undecided.as_ref().unwrap().iter().cloned().collect(); | |
516 | as_vec.sort(); |
|
516 | as_vec.sort_unstable(); | |
517 | as_vec |
|
517 | as_vec | |
518 | } |
|
518 | } | |
519 |
|
519 | |||
520 | fn sorted_missing(disco: &PartialDiscovery<SampleGraph>) -> Vec<Revision> { |
|
520 | fn sorted_missing(disco: &PartialDiscovery<SampleGraph>) -> Vec<Revision> { | |
521 | let mut as_vec: Vec<Revision> = |
|
521 | let mut as_vec: Vec<Revision> = | |
522 | disco.missing.iter().cloned().collect(); |
|
522 | disco.missing.iter().cloned().collect(); | |
523 | as_vec.sort(); |
|
523 | as_vec.sort_unstable(); | |
524 | as_vec |
|
524 | as_vec | |
525 | } |
|
525 | } | |
526 |
|
526 | |||
@@ -529,7 +529,7 b' mod tests {' | |||||
529 | ) -> Result<Vec<Revision>, GraphError> { |
|
529 | ) -> Result<Vec<Revision>, GraphError> { | |
530 | let mut as_vec: Vec<Revision> = |
|
530 | let mut as_vec: Vec<Revision> = | |
531 | disco.common_heads()?.iter().cloned().collect(); |
|
531 | disco.common_heads()?.iter().cloned().collect(); | |
532 | as_vec.sort(); |
|
532 | as_vec.sort_unstable(); | |
533 | Ok(as_vec) |
|
533 | Ok(as_vec) | |
534 | } |
|
534 | } | |
535 |
|
535 | |||
@@ -621,7 +621,7 b' mod tests {' | |||||
621 | disco.undecided = Some((1..=13).collect()); |
|
621 | disco.undecided = Some((1..=13).collect()); | |
622 |
|
622 | |||
623 | let mut sample_vec = disco.take_quick_sample(vec![], 4)?; |
|
623 | let mut sample_vec = disco.take_quick_sample(vec![], 4)?; | |
624 | sample_vec.sort(); |
|
624 | sample_vec.sort_unstable(); | |
625 | assert_eq!(sample_vec, vec![10, 11, 12, 13]); |
|
625 | assert_eq!(sample_vec, vec![10, 11, 12, 13]); | |
626 | Ok(()) |
|
626 | Ok(()) | |
627 | } |
|
627 | } | |
@@ -632,7 +632,7 b' mod tests {' | |||||
632 | disco.ensure_undecided()?; |
|
632 | disco.ensure_undecided()?; | |
633 |
|
633 | |||
634 | let mut sample_vec = disco.take_quick_sample(vec![12], 4)?; |
|
634 | let mut sample_vec = disco.take_quick_sample(vec![12], 4)?; | |
635 | sample_vec.sort(); |
|
635 | sample_vec.sort_unstable(); | |
636 | // r12's only parent is r9, whose unique grand-parent through the |
|
636 | // r12's only parent is r9, whose unique grand-parent through the | |
637 | // diamond shape is r4. This ends there because the distance from r4 |
|
637 | // diamond shape is r4. This ends there because the distance from r4 | |
638 | // to the root is only 3. |
|
638 | // to the root is only 3. | |
@@ -650,11 +650,11 b' mod tests {' | |||||
650 | assert_eq!(cache.get(&10).cloned(), None); |
|
650 | assert_eq!(cache.get(&10).cloned(), None); | |
651 |
|
651 | |||
652 | let mut children_4 = cache.get(&4).cloned().unwrap(); |
|
652 | let mut children_4 = cache.get(&4).cloned().unwrap(); | |
653 | children_4.sort(); |
|
653 | children_4.sort_unstable(); | |
654 | assert_eq!(children_4, vec![5, 6, 7]); |
|
654 | assert_eq!(children_4, vec![5, 6, 7]); | |
655 |
|
655 | |||
656 | let mut children_7 = cache.get(&7).cloned().unwrap(); |
|
656 | let mut children_7 = cache.get(&7).cloned().unwrap(); | |
657 | children_7.sort(); |
|
657 | children_7.sort_unstable(); | |
658 | assert_eq!(children_7, vec![9, 11]); |
|
658 | assert_eq!(children_7, vec![9, 11]); | |
659 |
|
659 | |||
660 | Ok(()) |
|
660 | Ok(()) | |
@@ -684,7 +684,7 b' mod tests {' | |||||
684 | let (sample_set, size) = disco.bidirectional_sample(7)?; |
|
684 | let (sample_set, size) = disco.bidirectional_sample(7)?; | |
685 | assert_eq!(size, 7); |
|
685 | assert_eq!(size, 7); | |
686 | let mut sample: Vec<Revision> = sample_set.into_iter().collect(); |
|
686 | let mut sample: Vec<Revision> = sample_set.into_iter().collect(); | |
687 | sample.sort(); |
|
687 | sample.sort_unstable(); | |
688 | // our DAG is a bit too small for the results to be really interesting |
|
688 | // our DAG is a bit too small for the results to be really interesting | |
689 | // at least it shows that |
|
689 | // at least it shows that | |
690 | // - we went both ways |
|
690 | // - we went both ways |
@@ -313,7 +313,7 b' pub fn build_single_regex(' | |||||
313 | PatternSyntax::RootGlob |
|
313 | PatternSyntax::RootGlob | |
314 | | PatternSyntax::Path |
|
314 | | PatternSyntax::Path | |
315 | | PatternSyntax::RelGlob |
|
315 | | PatternSyntax::RelGlob | |
316 |
| PatternSyntax::RootFiles => normalize_path_bytes( |
|
316 | | PatternSyntax::RootFiles => normalize_path_bytes(pattern), | |
317 | PatternSyntax::Include | PatternSyntax::SubInclude => { |
|
317 | PatternSyntax::Include | PatternSyntax::SubInclude => { | |
318 | return Err(PatternError::NonRegexPattern(entry.clone())) |
|
318 | return Err(PatternError::NonRegexPattern(entry.clone())) | |
319 | } |
|
319 | } | |
@@ -368,7 +368,7 b' pub fn parse_pattern_file_contents(' | |||||
368 | let mut warnings: Vec<PatternFileWarning> = vec![]; |
|
368 | let mut warnings: Vec<PatternFileWarning> = vec![]; | |
369 |
|
369 | |||
370 | let mut current_syntax = |
|
370 | let mut current_syntax = | |
371 | default_syntax_override.unwrap_or(b"relre:".as_ref()); |
|
371 | default_syntax_override.unwrap_or_else(|| b"relre:".as_ref()); | |
372 |
|
372 | |||
373 | for (line_number, mut line) in lines.split(|c| *c == b'\n').enumerate() { |
|
373 | for (line_number, mut line) in lines.split(|c| *c == b'\n').enumerate() { | |
374 | let line_number = line_number + 1; |
|
374 | let line_number = line_number + 1; | |
@@ -402,7 +402,7 b' pub fn parse_pattern_file_contents(' | |||||
402 | continue; |
|
402 | continue; | |
403 | } |
|
403 | } | |
404 |
|
404 | |||
405 |
let mut line_syntax: &[u8] = |
|
405 | let mut line_syntax: &[u8] = current_syntax; | |
406 |
|
406 | |||
407 | for (s, rels) in SYNTAXES.iter() { |
|
407 | for (s, rels) in SYNTAXES.iter() { | |
408 | if let Some(rest) = line.drop_prefix(rels) { |
|
408 | if let Some(rest) = line.drop_prefix(rels) { | |
@@ -418,7 +418,7 b' pub fn parse_pattern_file_contents(' | |||||
418 | } |
|
418 | } | |
419 |
|
419 | |||
420 | inputs.push(IgnorePattern::new( |
|
420 | inputs.push(IgnorePattern::new( | |
421 |
parse_pattern_syntax( |
|
421 | parse_pattern_syntax(line_syntax).map_err(|e| match e { | |
422 | PatternError::UnsupportedSyntax(syntax) => { |
|
422 | PatternError::UnsupportedSyntax(syntax) => { | |
423 | PatternError::UnsupportedSyntaxInFile( |
|
423 | PatternError::UnsupportedSyntaxInFile( | |
424 | syntax, |
|
424 | syntax, | |
@@ -428,7 +428,7 b' pub fn parse_pattern_file_contents(' | |||||
428 | } |
|
428 | } | |
429 | _ => e, |
|
429 | _ => e, | |
430 | })?, |
|
430 | })?, | |
431 |
|
|
431 | line, | |
432 | file_path, |
|
432 | file_path, | |
433 | )); |
|
433 | )); | |
434 | } |
|
434 | } | |
@@ -502,7 +502,7 b' pub fn get_patterns_from_file(' | |||||
502 | } |
|
502 | } | |
503 | PatternSyntax::SubInclude => { |
|
503 | PatternSyntax::SubInclude => { | |
504 | let mut sub_include = SubInclude::new( |
|
504 | let mut sub_include = SubInclude::new( | |
505 |
|
|
505 | root_dir, | |
506 | &entry.pattern, |
|
506 | &entry.pattern, | |
507 | &entry.source, |
|
507 | &entry.source, | |
508 | )?; |
|
508 | )?; | |
@@ -564,11 +564,11 b' impl SubInclude {' | |||||
564 | let prefix = canonical_path(root_dir, root_dir, new_root)?; |
|
564 | let prefix = canonical_path(root_dir, root_dir, new_root)?; | |
565 |
|
565 | |||
566 | Ok(Self { |
|
566 | Ok(Self { | |
567 |
prefix: path_to_hg_path_buf(prefix). |
|
567 | prefix: path_to_hg_path_buf(prefix).map(|mut p| { | |
568 | if !p.is_empty() { |
|
568 | if !p.is_empty() { | |
569 | p.push_byte(b'/'); |
|
569 | p.push_byte(b'/'); | |
570 | } |
|
570 | } | |
571 |
|
|
571 | p | |
572 | })?, |
|
572 | })?, | |
573 | path: path.to_owned(), |
|
573 | path: path.to_owned(), | |
574 | root: new_root.to_owned(), |
|
574 | root: new_root.to_owned(), |
@@ -107,7 +107,7 b' fn unlock(hg_vfs: Vfs, lock_filename: &s' | |||||
107 | fn lock_should_be_broken(data: &Option<String>) -> bool { |
|
107 | fn lock_should_be_broken(data: &Option<String>) -> bool { | |
108 | (|| -> Option<bool> { |
|
108 | (|| -> Option<bool> { | |
109 | let (prefix, pid) = data.as_ref()?.split_once(':')?; |
|
109 | let (prefix, pid) = data.as_ref()?.split_once(':')?; | |
110 |
if prefix != |
|
110 | if prefix != *LOCK_PREFIX { | |
111 | return Some(false); |
|
111 | return Some(false); | |
112 | } |
|
112 | } | |
113 | let process_is_running; |
|
113 | let process_is_running; | |
@@ -144,6 +144,8 b' lazy_static::lazy_static! {' | |||||
144 |
|
144 | |||
145 | /// Same as https://github.com/python/cpython/blob/v3.10.0/Modules/socketmodule.c#L5414 |
|
145 | /// Same as https://github.com/python/cpython/blob/v3.10.0/Modules/socketmodule.c#L5414 | |
146 | const BUFFER_SIZE: usize = 1024; |
|
146 | const BUFFER_SIZE: usize = 1024; | |
|
147 | // This cast is *needed* for platforms with signed chars | |||
|
148 | #[allow(clippy::unnecessary_cast)] | |||
147 | let mut buffer = [0 as libc::c_char; BUFFER_SIZE]; |
|
149 | let mut buffer = [0 as libc::c_char; BUFFER_SIZE]; | |
148 | let hostname_bytes = unsafe { |
|
150 | let hostname_bytes = unsafe { | |
149 | let result = libc::gethostname(buffer.as_mut_ptr(), BUFFER_SIZE); |
|
151 | let result = libc::gethostname(buffer.as_mut_ptr(), BUFFER_SIZE); |
@@ -302,11 +302,11 b" impl<'a> Matcher for IncludeMatcher<'a> " | |||||
302 | } |
|
302 | } | |
303 |
|
303 | |||
304 | fn matches(&self, filename: &HgPath) -> bool { |
|
304 | fn matches(&self, filename: &HgPath) -> bool { | |
305 |
(self.match_fn)(filename |
|
305 | (self.match_fn)(filename) | |
306 | } |
|
306 | } | |
307 |
|
307 | |||
308 | fn visit_children_set(&self, directory: &HgPath) -> VisitChildrenSet { |
|
308 | fn visit_children_set(&self, directory: &HgPath) -> VisitChildrenSet { | |
309 |
let dir = directory |
|
309 | let dir = directory; | |
310 | if self.prefix && self.roots.contains(dir) { |
|
310 | if self.prefix && self.roots.contains(dir) { | |
311 | return VisitChildrenSet::Recursive; |
|
311 | return VisitChildrenSet::Recursive; | |
312 | } |
|
312 | } | |
@@ -318,11 +318,11 b" impl<'a> Matcher for IncludeMatcher<'a> " | |||||
318 | return VisitChildrenSet::This; |
|
318 | return VisitChildrenSet::This; | |
319 | } |
|
319 | } | |
320 |
|
320 | |||
321 |
if self.parents.contains(dir |
|
321 | if self.parents.contains(dir.as_ref()) { | |
322 | let multiset = self.get_all_parents_children(); |
|
322 | let multiset = self.get_all_parents_children(); | |
323 | if let Some(children) = multiset.get(dir) { |
|
323 | if let Some(children) = multiset.get(dir) { | |
324 | return VisitChildrenSet::Set( |
|
324 | return VisitChildrenSet::Set( | |
325 |
children. |
|
325 | children.iter().map(HgPathBuf::from).collect(), | |
326 | ); |
|
326 | ); | |
327 | } |
|
327 | } | |
328 | } |
|
328 | } | |
@@ -446,7 +446,7 b' impl Matcher for IntersectionMatcher {' | |||||
446 | VisitChildrenSet::This |
|
446 | VisitChildrenSet::This | |
447 | } |
|
447 | } | |
448 | (VisitChildrenSet::Set(m1), VisitChildrenSet::Set(m2)) => { |
|
448 | (VisitChildrenSet::Set(m1), VisitChildrenSet::Set(m2)) => { | |
449 |
let set: HashSet<_> = m1.intersection( |
|
449 | let set: HashSet<_> = m1.intersection(m2).cloned().collect(); | |
450 | if set.is_empty() { |
|
450 | if set.is_empty() { | |
451 | VisitChildrenSet::Empty |
|
451 | VisitChildrenSet::Empty | |
452 | } else { |
|
452 | } else { | |
@@ -699,10 +699,9 b' fn roots_and_dirs(' | |||||
699 | PatternSyntax::RootGlob | PatternSyntax::Glob => { |
|
699 | PatternSyntax::RootGlob | PatternSyntax::Glob => { | |
700 | let mut root = HgPathBuf::new(); |
|
700 | let mut root = HgPathBuf::new(); | |
701 | for p in pattern.split(|c| *c == b'/') { |
|
701 | for p in pattern.split(|c| *c == b'/') { | |
702 |
if p.iter() |
|
702 | if p.iter() | |
703 |
b'[' | b'{' | b'*' | b'?' |
|
703 | .any(|c| matches!(*c, b'[' | b'{' | b'*' | b'?')) | |
704 |
|
|
704 | { | |
705 | }) { |
|
|||
706 | break; |
|
705 | break; | |
707 | } |
|
706 | } | |
708 | root.push(HgPathBuf::from_bytes(p).as_ref()); |
|
707 | root.push(HgPathBuf::from_bytes(p).as_ref()); | |
@@ -780,10 +779,10 b' fn roots_dirs_and_parents(' | |||||
780 |
|
779 | |||
781 | /// Returns a function that checks whether a given file (in the general sense) |
|
780 | /// Returns a function that checks whether a given file (in the general sense) | |
782 | /// should be matched. |
|
781 | /// should be matched. | |
783 |
fn build_match<'a |
|
782 | fn build_match<'a>( | |
784 | ignore_patterns: Vec<IgnorePattern>, |
|
783 | ignore_patterns: Vec<IgnorePattern>, | |
785 |
) -> PatternResult<(Vec<u8>, IgnoreFnType<' |
|
784 | ) -> PatternResult<(Vec<u8>, IgnoreFnType<'a>)> { | |
786 |
let mut match_funcs: Vec<IgnoreFnType<' |
|
785 | let mut match_funcs: Vec<IgnoreFnType<'a>> = vec![]; | |
787 | // For debugging and printing |
|
786 | // For debugging and printing | |
788 | let mut patterns = vec![]; |
|
787 | let mut patterns = vec![]; | |
789 |
|
788 | |||
@@ -921,9 +920,8 b" impl<'a> IncludeMatcher<'a> {" | |||||
921 | dirs, |
|
920 | dirs, | |
922 | parents, |
|
921 | parents, | |
923 | } = roots_dirs_and_parents(&ignore_patterns)?; |
|
922 | } = roots_dirs_and_parents(&ignore_patterns)?; | |
924 |
let prefix = ignore_patterns.iter().all(|k| |
|
923 | let prefix = ignore_patterns.iter().all(|k| { | |
925 |
PatternSyntax::Path | PatternSyntax::RelPath |
|
924 | matches!(k.syntax, PatternSyntax::Path | PatternSyntax::RelPath) | |
926 | _ => false, |
|
|||
927 | }); |
|
925 | }); | |
928 | let (patterns, match_fn) = build_match(ignore_patterns)?; |
|
926 | let (patterns, match_fn) = build_match(ignore_patterns)?; | |
929 |
|
927 |
@@ -37,9 +37,11 b' pub fn matcher(' | |||||
37 | } |
|
37 | } | |
38 | // Treat "narrowspec does not exist" the same as "narrowspec file exists |
|
38 | // Treat "narrowspec does not exist" the same as "narrowspec file exists | |
39 | // and is empty". |
|
39 | // and is empty". | |
40 |
let store_spec = repo.store_vfs().try_read(FILENAME)?.unwrap_or( |
|
40 | let store_spec = repo.store_vfs().try_read(FILENAME)?.unwrap_or_default(); | |
41 | let working_copy_spec = |
|
41 | let working_copy_spec = repo | |
42 | repo.hg_vfs().try_read(DIRSTATE_FILENAME)?.unwrap_or(vec![]); |
|
42 | .hg_vfs() | |
|
43 | .try_read(DIRSTATE_FILENAME)? | |||
|
44 | .unwrap_or_default(); | |||
43 | if store_spec != working_copy_spec { |
|
45 | if store_spec != working_copy_spec { | |
44 | return Err(HgError::abort( |
|
46 | return Err(HgError::abort( | |
45 | "working copy's narrowspec is stale", |
|
47 | "working copy's narrowspec is stale", |
@@ -70,7 +70,7 b" fn find_files_in_manifest<'query>(" | |||||
70 | Some(item) => res.push((file, item)), |
|
70 | Some(item) => res.push((file, item)), | |
71 | } |
|
71 | } | |
72 | } |
|
72 | } | |
73 |
|
|
73 | Ok((res, missing)) | |
74 | } |
|
74 | } | |
75 |
|
75 | |||
76 | /// Output the given revision of files |
|
76 | /// Output the given revision of files | |
@@ -94,10 +94,8 b" pub fn cat<'a>(" | |||||
94 |
|
94 | |||
95 | files.sort_unstable(); |
|
95 | files.sort_unstable(); | |
96 |
|
96 | |||
97 |
let (found, missing) = |
|
97 | let (found, missing) = | |
98 | &manifest, |
|
98 | find_files_in_manifest(&manifest, files.into_iter())?; | |
99 | files.into_iter().map(|f| f.as_ref()), |
|
|||
100 | )?; |
|
|||
101 |
|
99 | |||
102 | for (file_path, file_node) in found { |
|
100 | for (file_path, file_node) in found { | |
103 | found_any = true; |
|
101 | found_any = true; |
@@ -68,9 +68,9 b' impl Repo {' | |||||
68 | return Ok(ancestor.to_path_buf()); |
|
68 | return Ok(ancestor.to_path_buf()); | |
69 | } |
|
69 | } | |
70 | } |
|
70 | } | |
71 |
|
|
71 | Err(RepoError::NotFound { | |
72 | at: current_directory, |
|
72 | at: current_directory, | |
73 |
}) |
|
73 | }) | |
74 | } |
|
74 | } | |
75 |
|
75 | |||
76 | /// Find a repository, either at the given path (which must contain a `.hg` |
|
76 | /// Find a repository, either at the given path (which must contain a `.hg` | |
@@ -87,13 +87,11 b' impl Repo {' | |||||
87 | ) -> Result<Self, RepoError> { |
|
87 | ) -> Result<Self, RepoError> { | |
88 | if let Some(root) = explicit_path { |
|
88 | if let Some(root) = explicit_path { | |
89 | if is_dir(root.join(".hg"))? { |
|
89 | if is_dir(root.join(".hg"))? { | |
90 |
Self::new_at_path(root |
|
90 | Self::new_at_path(root, config) | |
91 | } else if is_file(&root)? { |
|
91 | } else if is_file(&root)? { | |
92 | Err(HgError::unsupported("bundle repository").into()) |
|
92 | Err(HgError::unsupported("bundle repository").into()) | |
93 | } else { |
|
93 | } else { | |
94 | Err(RepoError::NotFound { |
|
94 | Err(RepoError::NotFound { at: root }) | |
95 | at: root.to_owned(), |
|
|||
96 | }) |
|
|||
97 | } |
|
95 | } | |
98 | } else { |
|
96 | } else { | |
99 | let root = Self::find_repo_root()?; |
|
97 | let root = Self::find_repo_root()?; | |
@@ -108,9 +106,8 b' impl Repo {' | |||||
108 | ) -> Result<Self, RepoError> { |
|
106 | ) -> Result<Self, RepoError> { | |
109 | let dot_hg = working_directory.join(".hg"); |
|
107 | let dot_hg = working_directory.join(".hg"); | |
110 |
|
108 | |||
111 |
let mut repo_config_files = |
|
109 | let mut repo_config_files = | |
112 | repo_config_files.push(dot_hg.join("hgrc")); |
|
110 | vec![dot_hg.join("hgrc"), dot_hg.join("hgrc-not-shared")]; | |
113 | repo_config_files.push(dot_hg.join("hgrc-not-shared")); |
|
|||
114 |
|
111 | |||
115 | let hg_vfs = Vfs { base: &dot_hg }; |
|
112 | let hg_vfs = Vfs { base: &dot_hg }; | |
116 | let mut reqs = requirements::load_if_exists(hg_vfs)?; |
|
113 | let mut reqs = requirements::load_if_exists(hg_vfs)?; | |
@@ -254,7 +251,7 b' impl Repo {' | |||||
254 | .hg_vfs() |
|
251 | .hg_vfs() | |
255 | .read("dirstate") |
|
252 | .read("dirstate") | |
256 | .io_not_found_as_none()? |
|
253 | .io_not_found_as_none()? | |
257 |
.unwrap_or |
|
254 | .unwrap_or_default()) | |
258 | } |
|
255 | } | |
259 |
|
256 | |||
260 | pub fn dirstate_parents(&self) -> Result<DirstateParents, HgError> { |
|
257 | pub fn dirstate_parents(&self) -> Result<DirstateParents, HgError> { | |
@@ -277,8 +274,7 b' impl Repo {' | |||||
277 | .set(Some(docket.uuid.to_owned())); |
|
274 | .set(Some(docket.uuid.to_owned())); | |
278 | docket.parents() |
|
275 | docket.parents() | |
279 | } else { |
|
276 | } else { | |
280 | crate::dirstate::parsers::parse_dirstate_parents(&dirstate)? |
|
277 | *crate::dirstate::parsers::parse_dirstate_parents(&dirstate)? | |
281 | .clone() |
|
|||
282 | }; |
|
278 | }; | |
283 | self.dirstate_parents.set(parents); |
|
279 | self.dirstate_parents.set(parents); | |
284 | Ok(parents) |
|
280 | Ok(parents) |
@@ -165,7 +165,7 b" impl<'changelog> ChangelogRevisionData<'" | |||||
165 | pub fn files(&self) -> impl Iterator<Item = &HgPath> { |
|
165 | pub fn files(&self) -> impl Iterator<Item = &HgPath> { | |
166 | self.bytes[self.timestamp_end + 1..self.files_end] |
|
166 | self.bytes[self.timestamp_end + 1..self.files_end] | |
167 | .split(|b| b == &b'\n') |
|
167 | .split(|b| b == &b'\n') | |
168 |
.map( |
|
168 | .map(HgPath::new) | |
169 | } |
|
169 | } | |
170 |
|
170 | |||
171 | /// The change description. |
|
171 | /// The change description. |
@@ -49,7 +49,7 b' impl Filelog {' | |||||
49 | file_rev: Revision, |
|
49 | file_rev: Revision, | |
50 | ) -> Result<FilelogRevisionData, RevlogError> { |
|
50 | ) -> Result<FilelogRevisionData, RevlogError> { | |
51 | let data: Vec<u8> = self.revlog.get_rev_data(file_rev)?.into_owned(); |
|
51 | let data: Vec<u8> = self.revlog.get_rev_data(file_rev)?.into_owned(); | |
52 |
Ok(FilelogRevisionData(data |
|
52 | Ok(FilelogRevisionData(data)) | |
53 | } |
|
53 | } | |
54 |
|
54 | |||
55 | /// The given node ID is that of the file as found in a filelog, not of a |
|
55 | /// The given node ID is that of the file as found in a filelog, not of a | |
@@ -161,7 +161,7 b" impl FilelogEntry<'_> {" | |||||
161 | // this `FilelogEntry` does not have such metadata: |
|
161 | // this `FilelogEntry` does not have such metadata: | |
162 | let file_data_len = uncompressed_len; |
|
162 | let file_data_len = uncompressed_len; | |
163 |
|
163 | |||
164 |
|
|
164 | file_data_len != other_len | |
165 | } |
|
165 | } | |
166 |
|
166 | |||
167 | pub fn data(&self) -> Result<FilelogRevisionData, HgError> { |
|
167 | pub fn data(&self) -> Result<FilelogRevisionData, HgError> { |
@@ -21,11 +21,11 b' pub struct IndexHeaderFlags {' | |||||
21 | impl IndexHeaderFlags { |
|
21 | impl IndexHeaderFlags { | |
22 | /// Corresponds to FLAG_INLINE_DATA in python |
|
22 | /// Corresponds to FLAG_INLINE_DATA in python | |
23 | pub fn is_inline(self) -> bool { |
|
23 | pub fn is_inline(self) -> bool { | |
24 |
|
|
24 | self.flags & 1 != 0 | |
25 | } |
|
25 | } | |
26 | /// Corresponds to FLAG_GENERALDELTA in python |
|
26 | /// Corresponds to FLAG_GENERALDELTA in python | |
27 | pub fn uses_generaldelta(self) -> bool { |
|
27 | pub fn uses_generaldelta(self) -> bool { | |
28 |
|
|
28 | self.flags & 2 != 0 | |
29 | } |
|
29 | } | |
30 | } |
|
30 | } | |
31 |
|
31 | |||
@@ -35,9 +35,9 b' impl IndexHeader {' | |||||
35 | fn format_flags(&self) -> IndexHeaderFlags { |
|
35 | fn format_flags(&self) -> IndexHeaderFlags { | |
36 | // No "unknown flags" check here, unlike in python. Maybe there should |
|
36 | // No "unknown flags" check here, unlike in python. Maybe there should | |
37 | // be. |
|
37 | // be. | |
38 |
|
|
38 | IndexHeaderFlags { | |
39 | flags: BigEndian::read_u16(&self.header_bytes[0..2]), |
|
39 | flags: BigEndian::read_u16(&self.header_bytes[0..2]), | |
40 |
} |
|
40 | } | |
41 | } |
|
41 | } | |
42 |
|
42 | |||
43 | /// The only revlog version currently supported by rhg. |
|
43 | /// The only revlog version currently supported by rhg. | |
@@ -45,7 +45,7 b' impl IndexHeader {' | |||||
45 |
|
45 | |||
46 | /// Corresponds to `_format_version` in Python. |
|
46 | /// Corresponds to `_format_version` in Python. | |
47 | fn format_version(&self) -> u16 { |
|
47 | fn format_version(&self) -> u16 { | |
48 |
|
|
48 | BigEndian::read_u16(&self.header_bytes[2..4]) | |
49 | } |
|
49 | } | |
50 |
|
50 | |||
51 | const EMPTY_INDEX_HEADER: IndexHeader = IndexHeader { |
|
51 | const EMPTY_INDEX_HEADER: IndexHeader = IndexHeader { | |
@@ -59,7 +59,7 b' impl IndexHeader {' | |||||
59 | }; |
|
59 | }; | |
60 |
|
60 | |||
61 | fn parse(index_bytes: &[u8]) -> Result<IndexHeader, HgError> { |
|
61 | fn parse(index_bytes: &[u8]) -> Result<IndexHeader, HgError> { | |
62 |
if index_bytes. |
|
62 | if index_bytes.is_empty() { | |
63 | return Ok(IndexHeader::EMPTY_INDEX_HEADER); |
|
63 | return Ok(IndexHeader::EMPTY_INDEX_HEADER); | |
64 | } |
|
64 | } | |
65 | if index_bytes.len() < 4 { |
|
65 | if index_bytes.len() < 4 { | |
@@ -67,13 +67,13 b' impl IndexHeader {' | |||||
67 | "corrupted revlog: can't read the index format header", |
|
67 | "corrupted revlog: can't read the index format header", | |
68 | )); |
|
68 | )); | |
69 | } |
|
69 | } | |
70 |
|
|
70 | Ok(IndexHeader { | |
71 | header_bytes: { |
|
71 | header_bytes: { | |
72 | let bytes: [u8; 4] = |
|
72 | let bytes: [u8; 4] = | |
73 | index_bytes[0..4].try_into().expect("impossible"); |
|
73 | index_bytes[0..4].try_into().expect("impossible"); | |
74 | bytes |
|
74 | bytes | |
75 | }, |
|
75 | }, | |
76 |
}) |
|
76 | }) | |
77 | } |
|
77 | } | |
78 | } |
|
78 | } | |
79 |
|
79 | |||
@@ -127,8 +127,7 b' impl Index {' | |||||
127 | uses_generaldelta, |
|
127 | uses_generaldelta, | |
128 | }) |
|
128 | }) | |
129 | } else { |
|
129 | } else { | |
130 | Err(HgError::corrupted("unexpected inline revlog length") |
|
130 | Err(HgError::corrupted("unexpected inline revlog length")) | |
131 | .into()) |
|
|||
132 | } |
|
131 | } | |
133 | } else { |
|
132 | } else { | |
134 | Ok(Self { |
|
133 | Ok(Self { | |
@@ -466,8 +465,8 b' mod tests {' | |||||
466 | .with_inline(false) |
|
465 | .with_inline(false) | |
467 | .build(); |
|
466 | .build(); | |
468 |
|
467 | |||
469 |
assert |
|
468 | assert!(!is_inline(&bytes)); | |
470 |
assert |
|
469 | assert!(!uses_generaldelta(&bytes)); | |
471 | } |
|
470 | } | |
472 |
|
471 | |||
473 | #[test] |
|
472 | #[test] | |
@@ -478,8 +477,8 b' mod tests {' | |||||
478 | .with_inline(true) |
|
477 | .with_inline(true) | |
479 | .build(); |
|
478 | .build(); | |
480 |
|
479 | |||
481 |
assert |
|
480 | assert!(is_inline(&bytes)); | |
482 |
assert |
|
481 | assert!(!uses_generaldelta(&bytes)); | |
483 | } |
|
482 | } | |
484 |
|
483 | |||
485 | #[test] |
|
484 | #[test] | |
@@ -490,8 +489,8 b' mod tests {' | |||||
490 | .with_inline(true) |
|
489 | .with_inline(true) | |
491 | .build(); |
|
490 | .build(); | |
492 |
|
491 | |||
493 |
assert |
|
492 | assert!(is_inline(&bytes)); | |
494 |
assert |
|
493 | assert!(uses_generaldelta(&bytes)); | |
495 | } |
|
494 | } | |
496 |
|
495 | |||
497 | #[test] |
|
496 | #[test] |
@@ -71,7 +71,7 b' pub trait NodeMap {' | |||||
71 | /// |
|
71 | /// | |
72 | /// If several Revisions match the given prefix, a [`MultipleResults`] |
|
72 | /// If several Revisions match the given prefix, a [`MultipleResults`] | |
73 | /// error is returned. |
|
73 | /// error is returned. | |
74 |
fn find_bin |
|
74 | fn find_bin( | |
75 | &self, |
|
75 | &self, | |
76 | idx: &impl RevlogIndex, |
|
76 | idx: &impl RevlogIndex, | |
77 | prefix: NodePrefix, |
|
77 | prefix: NodePrefix, | |
@@ -88,7 +88,7 b' pub trait NodeMap {' | |||||
88 | /// |
|
88 | /// | |
89 | /// If several Revisions match the given prefix, a [`MultipleResults`] |
|
89 | /// If several Revisions match the given prefix, a [`MultipleResults`] | |
90 | /// error is returned. |
|
90 | /// error is returned. | |
91 |
fn unique_prefix_len_bin |
|
91 | fn unique_prefix_len_bin( | |
92 | &self, |
|
92 | &self, | |
93 | idx: &impl RevlogIndex, |
|
93 | idx: &impl RevlogIndex, | |
94 | node_prefix: NodePrefix, |
|
94 | node_prefix: NodePrefix, | |
@@ -249,7 +249,7 b' fn has_prefix_or_none(' | |||||
249 | rev: Revision, |
|
249 | rev: Revision, | |
250 | ) -> Result<Option<Revision>, NodeMapError> { |
|
250 | ) -> Result<Option<Revision>, NodeMapError> { | |
251 | idx.node(rev) |
|
251 | idx.node(rev) | |
252 |
.ok_or |
|
252 | .ok_or(NodeMapError::RevisionNotInIndex(rev)) | |
253 | .map(|node| { |
|
253 | .map(|node| { | |
254 | if prefix.is_prefix_of(node) { |
|
254 | if prefix.is_prefix_of(node) { | |
255 | Some(rev) |
|
255 | Some(rev) | |
@@ -468,7 +468,7 b' impl NodeTree {' | |||||
468 | if let Element::Rev(old_rev) = deepest.element { |
|
468 | if let Element::Rev(old_rev) = deepest.element { | |
469 | let old_node = index |
|
469 | let old_node = index | |
470 | .node(old_rev) |
|
470 | .node(old_rev) | |
471 |
.ok_or |
|
471 | .ok_or(NodeMapError::RevisionNotInIndex(old_rev))?; | |
472 | if old_node == node { |
|
472 | if old_node == node { | |
473 | return Ok(()); // avoid creating lots of useless blocks |
|
473 | return Ok(()); // avoid creating lots of useless blocks | |
474 | } |
|
474 | } | |
@@ -865,7 +865,7 b' mod tests {' | |||||
865 | hex: &str, |
|
865 | hex: &str, | |
866 | ) -> Result<(), NodeMapError> { |
|
866 | ) -> Result<(), NodeMapError> { | |
867 | let node = pad_node(hex); |
|
867 | let node = pad_node(hex); | |
868 |
self.index.insert(rev, node |
|
868 | self.index.insert(rev, node); | |
869 | self.nt.insert(&self.index, &node, rev)?; |
|
869 | self.nt.insert(&self.index, &node, rev)?; | |
870 | Ok(()) |
|
870 | Ok(()) | |
871 | } |
|
871 | } | |
@@ -887,13 +887,13 b' mod tests {' | |||||
887 | /// Drain `added` and restart a new one |
|
887 | /// Drain `added` and restart a new one | |
888 | fn commit(self) -> Self { |
|
888 | fn commit(self) -> Self { | |
889 | let mut as_vec: Vec<Block> = |
|
889 | let mut as_vec: Vec<Block> = | |
890 |
self.nt.readonly.iter(). |
|
890 | self.nt.readonly.iter().copied().collect(); | |
891 | as_vec.extend(self.nt.growable); |
|
891 | as_vec.extend(self.nt.growable); | |
892 | as_vec.push(self.nt.root); |
|
892 | as_vec.push(self.nt.root); | |
893 |
|
893 | |||
894 | Self { |
|
894 | Self { | |
895 | index: self.index, |
|
895 | index: self.index, | |
896 |
nt: NodeTree::from(as_vec) |
|
896 | nt: NodeTree::from(as_vec), | |
897 | } |
|
897 | } | |
898 | } |
|
898 | } | |
899 | } |
|
899 | } | |
@@ -967,15 +967,15 b' mod tests {' | |||||
967 | let idx = &mut nt_idx.index; |
|
967 | let idx = &mut nt_idx.index; | |
968 |
|
968 | |||
969 | let node0_hex = hex_pad_right("444444"); |
|
969 | let node0_hex = hex_pad_right("444444"); | |
970 |
let mut node1_hex = hex_pad_right("444444") |
|
970 | let mut node1_hex = hex_pad_right("444444"); | |
971 | node1_hex.pop(); |
|
971 | node1_hex.pop(); | |
972 | node1_hex.push('5'); |
|
972 | node1_hex.push('5'); | |
973 | let node0 = Node::from_hex(&node0_hex).unwrap(); |
|
973 | let node0 = Node::from_hex(&node0_hex).unwrap(); | |
974 | let node1 = Node::from_hex(&node1_hex).unwrap(); |
|
974 | let node1 = Node::from_hex(&node1_hex).unwrap(); | |
975 |
|
975 | |||
976 |
idx.insert(0, node0 |
|
976 | idx.insert(0, node0); | |
977 | nt.insert(idx, &node0, 0)?; |
|
977 | nt.insert(idx, &node0, 0)?; | |
978 |
idx.insert(1, node1 |
|
978 | idx.insert(1, node1); | |
979 | nt.insert(idx, &node1, 1)?; |
|
979 | nt.insert(idx, &node1, 1)?; | |
980 |
|
980 | |||
981 | assert_eq!(nt.find_bin(idx, (&node0).into())?, Some(0)); |
|
981 | assert_eq!(nt.find_bin(idx, (&node0).into())?, Some(0)); |
@@ -2,6 +2,7 b' use sha1::{Digest, Sha1};' | |||||
2 |
|
2 | |||
3 | #[derive(PartialEq, Debug)] |
|
3 | #[derive(PartialEq, Debug)] | |
4 | #[allow(non_camel_case_types)] |
|
4 | #[allow(non_camel_case_types)] | |
|
5 | #[allow(clippy::upper_case_acronyms)] | |||
5 | enum path_state { |
|
6 | enum path_state { | |
6 | START, /* first byte of a path component */ |
|
7 | START, /* first byte of a path component */ | |
7 | A, /* "AUX" */ |
|
8 | A, /* "AUX" */ | |
@@ -27,6 +28,7 b' enum path_state {' | |||||
27 |
|
28 | |||
28 | /* state machine for dir-encoding */ |
|
29 | /* state machine for dir-encoding */ | |
29 | #[allow(non_camel_case_types)] |
|
30 | #[allow(non_camel_case_types)] | |
|
31 | #[allow(clippy::upper_case_acronyms)] | |||
30 | enum dir_state { |
|
32 | enum dir_state { | |
31 | DDOT, |
|
33 | DDOT, | |
32 | DH, |
|
34 | DH, | |
@@ -61,7 +63,7 b" fn rewrap_option<'a, 'b: 'a>(" | |||||
61 | } |
|
63 | } | |
62 | } |
|
64 | } | |
63 |
|
65 | |||
64 |
fn hexencode |
|
66 | fn hexencode(mut dest: Option<&mut [u8]>, destlen: &mut usize, c: u8) { | |
65 | let hexdigit = b"0123456789abcdef"; |
|
67 | let hexdigit = b"0123456789abcdef"; | |
66 | charcopy( |
|
68 | charcopy( | |
67 | rewrap_option(&mut dest), |
|
69 | rewrap_option(&mut dest), | |
@@ -534,10 +536,7 b' fn hash_mangle(src: &[u8], sha: &[u8]) -' | |||||
534 | let last_slash = src.iter().rposition(|b| *b == b'/'); |
|
536 | let last_slash = src.iter().rposition(|b| *b == b'/'); | |
535 | let last_dot: Option<usize> = { |
|
537 | let last_dot: Option<usize> = { | |
536 | let s = last_slash.unwrap_or(0); |
|
538 | let s = last_slash.unwrap_or(0); | |
537 | src[s..] |
|
539 | src[s..].iter().rposition(|b| *b == b'.').map(|i| i + s) | |
538 | .iter() |
|
|||
539 | .rposition(|b| *b == b'.') |
|
|||
540 | .and_then(|i| Some(i + s)) |
|
|||
541 | }; |
|
540 | }; | |
542 |
|
541 | |||
543 | let mut dest = vec![0; MAXSTOREPATHLEN]; |
|
542 | let mut dest = vec![0; MAXSTOREPATHLEN]; | |
@@ -545,8 +544,8 b' fn hash_mangle(src: &[u8], sha: &[u8]) -' | |||||
545 |
|
544 | |||
546 | { |
|
545 | { | |
547 | let mut first = true; |
|
546 | let mut first = true; | |
548 | for slice in src[..last_slash.unwrap_or_else(|| src.len())] |
|
547 | for slice in | |
549 | .split(|b| *b == b'/') |
|
548 | src[..last_slash.unwrap_or(src.len())].split(|b| *b == b'/') | |
550 | { |
|
549 | { | |
551 | let slice = &slice[..std::cmp::min(slice.len(), dirprefixlen)]; |
|
550 | let slice = &slice[..std::cmp::min(slice.len(), dirprefixlen)]; | |
552 | if destlen + (slice.len() + if first { 0 } else { 1 }) |
|
551 | if destlen + (slice.len() + if first { 0 } else { 1 }) | |
@@ -641,6 +640,6 b' pub fn path_encode(path: &[u8]) -> Vec<u' | |||||
641 | res |
|
640 | res | |
642 | } |
|
641 | } | |
643 | } else { |
|
642 | } else { | |
644 |
hash_encode( |
|
643 | hash_encode(path) | |
645 | } |
|
644 | } | |
646 | } |
|
645 | } |
@@ -174,10 +174,11 b' impl Revlog {' | |||||
174 | // optimize these cases. |
|
174 | // optimize these cases. | |
175 | let mut found_by_prefix = None; |
|
175 | let mut found_by_prefix = None; | |
176 | for rev in (0..self.len() as Revision).rev() { |
|
176 | for rev in (0..self.len() as Revision).rev() { | |
177 | let index_entry = |
|
177 | let index_entry = self.index.get_entry(rev).ok_or_else(|| { | |
178 |
|
|
178 | HgError::corrupted( | |
179 | "revlog references a revision not in the index", |
|
179 | "revlog references a revision not in the index", | |
180 |
) |
|
180 | ) | |
|
181 | })?; | |||
181 | if node == *index_entry.hash() { |
|
182 | if node == *index_entry.hash() { | |
182 | return Ok(rev); |
|
183 | return Ok(rev); | |
183 | } |
|
184 | } | |
@@ -230,7 +231,7 b' impl Revlog {' | |||||
230 | None => &NULL_NODE, |
|
231 | None => &NULL_NODE, | |
231 | }; |
|
232 | }; | |
232 |
|
233 | |||
233 |
|
|
234 | hash(data, h1.as_bytes(), h2.as_bytes()) == expected | |
234 | } |
|
235 | } | |
235 |
|
236 | |||
236 | /// Build the full data of a revision out its snapshot |
|
237 | /// Build the full data of a revision out its snapshot | |
@@ -253,8 +254,8 b' impl Revlog {' | |||||
253 |
|
254 | |||
254 | /// Return the revlog data. |
|
255 | /// Return the revlog data. | |
255 | fn data(&self) -> &[u8] { |
|
256 | fn data(&self) -> &[u8] { | |
256 | match self.data_bytes { |
|
257 | match &self.data_bytes { | |
257 |
Some( |
|
258 | Some(data_bytes) => data_bytes, | |
258 | None => panic!( |
|
259 | None => panic!( | |
259 | "forgot to load the data or trying to access inline data" |
|
260 | "forgot to load the data or trying to access inline data" | |
260 | ), |
|
261 | ), |
@@ -21,7 +21,7 b' pub fn resolve_single(' | |||||
21 | match input { |
|
21 | match input { | |
22 | "." => { |
|
22 | "." => { | |
23 | let p1 = repo.dirstate_parents()?.p1; |
|
23 | let p1 = repo.dirstate_parents()?.p1; | |
24 |
return |
|
24 | return changelog.revlog.rev_from_node(p1.into()); | |
25 | } |
|
25 | } | |
26 | "null" => return Ok(NULL_REVISION), |
|
26 | "null" => return Ok(NULL_REVISION), | |
27 | _ => {} |
|
27 | _ => {} | |
@@ -33,7 +33,7 b' pub fn resolve_single(' | |||||
33 | let msg = format!("cannot parse revset '{}'", input); |
|
33 | let msg = format!("cannot parse revset '{}'", input); | |
34 | Err(HgError::unsupported(msg).into()) |
|
34 | Err(HgError::unsupported(msg).into()) | |
35 | } |
|
35 | } | |
36 |
result => |
|
36 | result => result, | |
37 | } |
|
37 | } | |
38 | } |
|
38 | } | |
39 |
|
39 |
@@ -164,7 +164,7 b' pub(crate) fn parse_config(' | |||||
164 | fn read_temporary_includes( |
|
164 | fn read_temporary_includes( | |
165 | repo: &Repo, |
|
165 | repo: &Repo, | |
166 | ) -> Result<Vec<Vec<u8>>, SparseConfigError> { |
|
166 | ) -> Result<Vec<Vec<u8>>, SparseConfigError> { | |
167 |
let raw = repo.hg_vfs().try_read("tempsparse")?.unwrap_or( |
|
167 | let raw = repo.hg_vfs().try_read("tempsparse")?.unwrap_or_default(); | |
168 | if raw.is_empty() { |
|
168 | if raw.is_empty() { | |
169 | return Ok(vec![]); |
|
169 | return Ok(vec![]); | |
170 | } |
|
170 | } | |
@@ -179,7 +179,7 b' fn patterns_for_rev(' | |||||
179 | if !repo.has_sparse() { |
|
179 | if !repo.has_sparse() { | |
180 | return Ok(None); |
|
180 | return Ok(None); | |
181 | } |
|
181 | } | |
182 |
let raw = repo.hg_vfs().try_read("sparse")?.unwrap_or( |
|
182 | let raw = repo.hg_vfs().try_read("sparse")?.unwrap_or_default(); | |
183 |
|
183 | |||
184 | if raw.is_empty() { |
|
184 | if raw.is_empty() { | |
185 | return Ok(None); |
|
185 | return Ok(None); | |
@@ -200,9 +200,10 b' fn patterns_for_rev(' | |||||
200 | let output = |
|
200 | let output = | |
201 | cat(repo, &rev.to_string(), vec![HgPath::new(&profile)]) |
|
201 | cat(repo, &rev.to_string(), vec![HgPath::new(&profile)]) | |
202 | .map_err(|_| { |
|
202 | .map_err(|_| { | |
203 |
HgError::corrupted( |
|
203 | HgError::corrupted( | |
204 | "dirstate points to non-existent parent node" |
|
204 | "dirstate points to non-existent parent node" | |
205 |
) |
|
205 | .to_string(), | |
|
206 | ) | |||
206 | })?; |
|
207 | })?; | |
207 | if output.results.is_empty() { |
|
208 | if output.results.is_empty() { | |
208 | config.warnings.push(SparseWarning::ProfileNotFound { |
|
209 | config.warnings.push(SparseWarning::ProfileNotFound { | |
@@ -252,9 +253,9 b' pub fn matcher(' | |||||
252 | repo.changelog()? |
|
253 | repo.changelog()? | |
253 | .rev_from_node(parents.p1.into()) |
|
254 | .rev_from_node(parents.p1.into()) | |
254 | .map_err(|_| { |
|
255 | .map_err(|_| { | |
255 |
HgError::corrupted( |
|
256 | HgError::corrupted( | |
256 | "dirstate points to non-existent parent node" |
|
257 | "dirstate points to non-existent parent node".to_string(), | |
257 |
) |
|
258 | ) | |
258 | })?; |
|
259 | })?; | |
259 | if p1_rev != NULL_REVISION { |
|
260 | if p1_rev != NULL_REVISION { | |
260 | revs.push(p1_rev) |
|
261 | revs.push(p1_rev) | |
@@ -263,9 +264,9 b' pub fn matcher(' | |||||
263 | repo.changelog()? |
|
264 | repo.changelog()? | |
264 | .rev_from_node(parents.p2.into()) |
|
265 | .rev_from_node(parents.p2.into()) | |
265 | .map_err(|_| { |
|
266 | .map_err(|_| { | |
266 |
HgError::corrupted( |
|
267 | HgError::corrupted( | |
267 | "dirstate points to non-existent parent node" |
|
268 | "dirstate points to non-existent parent node".to_string(), | |
268 |
) |
|
269 | ) | |
269 | })?; |
|
270 | })?; | |
270 | if p2_rev != NULL_REVISION { |
|
271 | if p2_rev != NULL_REVISION { | |
271 | revs.push(p2_rev) |
|
272 | revs.push(p2_rev) | |
@@ -325,7 +326,7 b' fn force_include_matcher(' | |||||
325 | } |
|
326 | } | |
326 | let forced_include_matcher = IncludeMatcher::new( |
|
327 | let forced_include_matcher = IncludeMatcher::new( | |
327 | temp_includes |
|
328 | temp_includes | |
328 |
. |
|
329 | .iter() | |
329 | .map(|include| { |
|
330 | .map(|include| { | |
330 | IgnorePattern::new(PatternSyntax::Path, include, Path::new("")) |
|
331 | IgnorePattern::new(PatternSyntax::Path, include, Path::new("")) | |
331 | }) |
|
332 | }) |
@@ -137,11 +137,8 b' impl SliceExt for [u8] {' | |||||
137 | } |
|
137 | } | |
138 |
|
138 | |||
139 | fn split_2_by_slice(&self, separator: &[u8]) -> Option<(&[u8], &[u8])> { |
|
139 | fn split_2_by_slice(&self, separator: &[u8]) -> Option<(&[u8], &[u8])> { | |
140 |
|
|
140 | find_slice_in_slice(self, separator) | |
141 |
|
|
141 | .map(|pos| (&self[..pos], &self[pos + separator.len()..])) | |
142 | } else { |
|
|||
143 | None |
|
|||
144 | } |
|
|||
145 | } |
|
142 | } | |
146 | } |
|
143 | } | |
147 |
|
144 | |||
@@ -369,7 +366,7 b' where' | |||||
369 | MergeResult::RightValue => { |
|
366 | MergeResult::RightValue => { | |
370 | left.insert(key, right_value); |
|
367 | left.insert(key, right_value); | |
371 | } |
|
368 | } | |
372 |
MergeResult:: |
|
369 | MergeResult::NewValue(new_value) => { | |
373 | left.insert(key, new_value); |
|
370 | left.insert(key, new_value); | |
374 | } |
|
371 | } | |
375 | }, |
|
372 | }, |
@@ -230,7 +230,7 b' pub fn canonical_path(' | |||||
230 | // TODO hint to the user about using --cwd |
|
230 | // TODO hint to the user about using --cwd | |
231 | // Bubble up the responsibility to Python for now |
|
231 | // Bubble up the responsibility to Python for now | |
232 | Err(HgPathError::NotUnderRoot { |
|
232 | Err(HgPathError::NotUnderRoot { | |
233 |
path: original_name |
|
233 | path: original_name, | |
234 | root: root.to_owned(), |
|
234 | root: root.to_owned(), | |
235 | }) |
|
235 | }) | |
236 | } |
|
236 | } | |
@@ -424,7 +424,7 b' mod tests {' | |||||
424 | assert_eq!( |
|
424 | assert_eq!( | |
425 | canonical_path(&root, Path::new(""), &beneath_repo), |
|
425 | canonical_path(&root, Path::new(""), &beneath_repo), | |
426 | Err(HgPathError::NotUnderRoot { |
|
426 | Err(HgPathError::NotUnderRoot { | |
427 |
path: beneath_repo |
|
427 | path: beneath_repo, | |
428 | root: root.to_owned() |
|
428 | root: root.to_owned() | |
429 | }) |
|
429 | }) | |
430 | ); |
|
430 | ); |
@@ -205,7 +205,7 b' impl HgPath {' | |||||
205 | /// ``` |
|
205 | /// ``` | |
206 | pub fn split_filename(&self) -> (&Self, &Self) { |
|
206 | pub fn split_filename(&self) -> (&Self, &Self) { | |
207 | match &self.inner.iter().rposition(|c| *c == b'/') { |
|
207 | match &self.inner.iter().rposition(|c| *c == b'/') { | |
208 |
None => (HgPath::new(""), |
|
208 | None => (HgPath::new(""), self), | |
209 | Some(size) => ( |
|
209 | Some(size) => ( | |
210 | HgPath::new(&self.inner[..*size]), |
|
210 | HgPath::new(&self.inner[..*size]), | |
211 | HgPath::new(&self.inner[*size + 1..]), |
|
211 | HgPath::new(&self.inner[*size + 1..]), | |
@@ -326,7 +326,7 b' impl HgPath {' | |||||
326 | #[cfg(unix)] |
|
326 | #[cfg(unix)] | |
327 | /// Split a pathname into drive and path. On Posix, drive is always empty. |
|
327 | /// Split a pathname into drive and path. On Posix, drive is always empty. | |
328 | pub fn split_drive(&self) -> (&HgPath, &HgPath) { |
|
328 | pub fn split_drive(&self) -> (&HgPath, &HgPath) { | |
329 |
(HgPath::new(b""), |
|
329 | (HgPath::new(b""), self) | |
330 | } |
|
330 | } | |
331 |
|
331 | |||
332 | /// Checks for errors in the path, short-circuiting at the first one. |
|
332 | /// Checks for errors in the path, short-circuiting at the first one. | |
@@ -396,7 +396,7 b' impl HgPathBuf {' | |||||
396 | Default::default() |
|
396 | Default::default() | |
397 | } |
|
397 | } | |
398 |
|
398 | |||
399 |
pub fn push<T: ?Sized + AsRef<HgPath>>(&mut self, other: &T) |
|
399 | pub fn push<T: ?Sized + AsRef<HgPath>>(&mut self, other: &T) { | |
400 | if !self.inner.is_empty() && self.inner.last() != Some(&b'/') { |
|
400 | if !self.inner.is_empty() && self.inner.last() != Some(&b'/') { | |
401 | self.inner.push(b'/'); |
|
401 | self.inner.push(b'/'); | |
402 | } |
|
402 | } | |
@@ -431,7 +431,7 b' impl Deref for HgPathBuf {' | |||||
431 |
|
431 | |||
432 | #[inline] |
|
432 | #[inline] | |
433 | fn deref(&self) -> &HgPath { |
|
433 | fn deref(&self) -> &HgPath { | |
434 |
|
|
434 | HgPath::new(&self.inner) | |
435 | } |
|
435 | } | |
436 | } |
|
436 | } | |
437 |
|
437 | |||
@@ -441,15 +441,15 b' impl<T: ?Sized + AsRef<HgPath>> From<&T>' | |||||
441 | } |
|
441 | } | |
442 | } |
|
442 | } | |
443 |
|
443 | |||
444 | impl Into<Vec<u8>> for HgPathBuf { |
|
444 | impl From<HgPathBuf> for Vec<u8> { | |
445 | fn into(self) -> Vec<u8> { |
|
445 | fn from(val: HgPathBuf) -> Self { | |
446 |
|
|
446 | val.inner | |
447 | } |
|
447 | } | |
448 | } |
|
448 | } | |
449 |
|
449 | |||
450 | impl Borrow<HgPath> for HgPathBuf { |
|
450 | impl Borrow<HgPath> for HgPathBuf { | |
451 | fn borrow(&self) -> &HgPath { |
|
451 | fn borrow(&self) -> &HgPath { | |
452 |
|
|
452 | HgPath::new(self.as_bytes()) | |
453 | } |
|
453 | } | |
454 | } |
|
454 | } | |
455 |
|
455 | |||
@@ -491,7 +491,7 b' pub fn hg_path_to_os_string<P: AsRef<HgP' | |||||
491 | #[cfg(unix)] |
|
491 | #[cfg(unix)] | |
492 | { |
|
492 | { | |
493 | use std::os::unix::ffi::OsStrExt; |
|
493 | use std::os::unix::ffi::OsStrExt; | |
494 |
os_str = std::ffi::OsStr::from_bytes( |
|
494 | os_str = std::ffi::OsStr::from_bytes(hg_path.as_ref().as_bytes()); | |
495 | } |
|
495 | } | |
496 | // TODO Handle other platforms |
|
496 | // TODO Handle other platforms | |
497 | // TODO: convert from WTF8 to Windows MBCS (ANSI encoding). |
|
497 | // TODO: convert from WTF8 to Windows MBCS (ANSI encoding). | |
@@ -511,7 +511,7 b' pub fn os_string_to_hg_path_buf<S: AsRef' | |||||
511 | #[cfg(unix)] |
|
511 | #[cfg(unix)] | |
512 | { |
|
512 | { | |
513 | use std::os::unix::ffi::OsStrExt; |
|
513 | use std::os::unix::ffi::OsStrExt; | |
514 |
buf = HgPathBuf::from_bytes( |
|
514 | buf = HgPathBuf::from_bytes(os_string.as_ref().as_bytes()); | |
515 | } |
|
515 | } | |
516 | // TODO Handle other platforms |
|
516 | // TODO Handle other platforms | |
517 | // TODO: convert from WTF8 to Windows MBCS (ANSI encoding). |
|
517 | // TODO: convert from WTF8 to Windows MBCS (ANSI encoding). | |
@@ -528,7 +528,7 b' pub fn path_to_hg_path_buf<P: AsRef<Path' | |||||
528 | #[cfg(unix)] |
|
528 | #[cfg(unix)] | |
529 | { |
|
529 | { | |
530 | use std::os::unix::ffi::OsStrExt; |
|
530 | use std::os::unix::ffi::OsStrExt; | |
531 |
buf = HgPathBuf::from_bytes( |
|
531 | buf = HgPathBuf::from_bytes(os_str.as_bytes()); | |
532 | } |
|
532 | } | |
533 | // TODO Handle other platforms |
|
533 | // TODO Handle other platforms | |
534 | // TODO: convert from WTF8 to Windows MBCS (ANSI encoding). |
|
534 | // TODO: convert from WTF8 to Windows MBCS (ANSI encoding). |
@@ -53,7 +53,7 b' fn build_random_graph(' | |||||
53 | /// Compute the ancestors set of all revisions of a VecGraph |
|
53 | /// Compute the ancestors set of all revisions of a VecGraph | |
54 | fn ancestors_sets(vg: &VecGraph) -> Vec<HashSet<Revision>> { |
|
54 | fn ancestors_sets(vg: &VecGraph) -> Vec<HashSet<Revision>> { | |
55 | let mut ancs: Vec<HashSet<Revision>> = Vec::new(); |
|
55 | let mut ancs: Vec<HashSet<Revision>> = Vec::new(); | |
56 | for i in 0..vg.len() { |
|
56 | (0..vg.len()).for_each(|i| { | |
57 | let mut ancs_i = HashSet::new(); |
|
57 | let mut ancs_i = HashSet::new(); | |
58 | ancs_i.insert(i as Revision); |
|
58 | ancs_i.insert(i as Revision); | |
59 | for p in vg[i].iter().cloned() { |
|
59 | for p in vg[i].iter().cloned() { | |
@@ -62,7 +62,7 b' fn ancestors_sets(vg: &VecGraph) -> Vec<' | |||||
62 | } |
|
62 | } | |
63 | } |
|
63 | } | |
64 | ancs.push(ancs_i); |
|
64 | ancs.push(ancs_i); | |
65 | } |
|
65 | }); | |
66 | ancs |
|
66 | ancs | |
67 | } |
|
67 | } | |
68 |
|
68 |
General Comments 0
You need to be logged in to leave comments.
Login now