Show More
@@ -1,5 +1,6 b'' | |||
|
1 | 1 | use crate::errors::{HgError, HgResultExt}; |
|
2 | 2 | use crate::repo::{Repo, Vfs}; |
|
3 | use crate::utils::join_display; | |
|
3 | 4 | use std::collections::HashSet; |
|
4 | 5 | |
|
5 | 6 | fn parse(bytes: &[u8]) -> Result<HashSet<String>, HgError> { |
@@ -42,34 +43,48 b' pub(crate) fn load_if_exists(hg_vfs: Vfs' | |||
|
42 | 43 | } |
|
43 | 44 | |
|
44 | 45 | pub(crate) fn check(repo: &Repo) -> Result<(), HgError> { |
|
45 | for feature in repo.requirements() { | |
|
46 | if !SUPPORTED.contains(&feature.as_str()) { | |
|
47 | // TODO: collect and all unknown features and include them in the | |
|
48 | // error message? | |
|
49 | return Err(HgError::UnsupportedFeature(format!( | |
|
50 | "repository requires feature unknown to this Mercurial: {}", | |
|
51 | feature | |
|
52 |
|
|
|
53 | } | |
|
46 | let unknown: Vec<_> = repo | |
|
47 | .requirements() | |
|
48 | .iter() | |
|
49 | .map(String::as_str) | |
|
50 | // .filter(|feature| !ALL_SUPPORTED.contains(feature.as_str())) | |
|
51 | .filter(|feature| { | |
|
52 | !REQUIRED.contains(feature) && !SUPPORTED.contains(feature) | |
|
53 | }) | |
|
54 | .collect(); | |
|
55 | if !unknown.is_empty() { | |
|
56 | return Err(HgError::unsupported(format!( | |
|
57 | "repository requires feature unknown to this Mercurial: {}", | |
|
58 | join_display(&unknown, ", ") | |
|
59 | ))); | |
|
60 | } | |
|
61 | let missing: Vec<_> = REQUIRED | |
|
62 | .iter() | |
|
63 | .filter(|&&feature| !repo.requirements().contains(feature)) | |
|
64 | .collect(); | |
|
65 | if !missing.is_empty() { | |
|
66 | return Err(HgError::unsupported(format!( | |
|
67 | "repository is missing feature required by this Mercurial: {}", | |
|
68 | join_display(&missing, ", ") | |
|
69 | ))); | |
|
54 | 70 | } |
|
55 | 71 | Ok(()) |
|
56 | 72 | } |
|
57 | 73 | |
|
58 | // TODO: set this to actually-supported features | |
|
74 | /// rhg does not support repositories that are *missing* any of these features | |
|
75 | const REQUIRED: &[&str] = &["revlogv1", "store", "fncache", "dotencode"]; | |
|
76 | ||
|
77 | /// rhg supports repository with or without these | |
|
59 | 78 | const SUPPORTED: &[&str] = &[ |
|
60 | "dotencode", | |
|
61 | "fncache", | |
|
62 | 79 | "generaldelta", |
|
63 | "revlogv1", | |
|
64 | 80 | SHARED_REQUIREMENT, |
|
65 | 81 | SHARESAFE_REQUIREMENT, |
|
66 | 82 | SPARSEREVLOG_REQUIREMENT, |
|
67 | 83 | RELATIVE_SHARED_REQUIREMENT, |
|
68 | "store", | |
|
69 | 84 | // As of this writing everything rhg does is read-only. |
|
70 | 85 | // When it starts writing to the repository, it’ll need to either keep the |
|
71 | 86 | // persistent nodemap up to date or remove this entry: |
|
72 | "persistent-nodemap", | |
|
87 | NODEMAP_REQUIREMENT, | |
|
73 | 88 | ]; |
|
74 | 89 | |
|
75 | 90 | // Copied from mercurial/requirements.py: |
@@ -11,6 +11,8 b' use crate::errors::{HgError, IoErrorCont' | |||
|
11 | 11 | use crate::utils::hg_path::HgPath; |
|
12 | 12 | use im_rc::ordmap::DiffItem; |
|
13 | 13 | use im_rc::ordmap::OrdMap; |
|
14 | use std::cell::Cell; | |
|
15 | use std::fmt; | |
|
14 | 16 | use std::{io::Write, ops::Deref}; |
|
15 | 17 | |
|
16 | 18 | pub mod files; |
@@ -378,3 +380,43 b' where' | |||
|
378 | 380 | right |
|
379 | 381 | } |
|
380 | 382 | } |
|
383 | ||
|
384 | /// Join items of the iterable with the given separator, similar to Python’s | |
|
385 | /// `separator.join(iter)`. | |
|
386 | /// | |
|
387 | /// Formatting the return value consumes the iterator. | |
|
388 | /// Formatting it again will produce an empty string. | |
|
389 | pub fn join_display( | |
|
390 | iter: impl IntoIterator<Item = impl fmt::Display>, | |
|
391 | separator: impl fmt::Display, | |
|
392 | ) -> impl fmt::Display { | |
|
393 | JoinDisplay { | |
|
394 | iter: Cell::new(Some(iter.into_iter())), | |
|
395 | separator, | |
|
396 | } | |
|
397 | } | |
|
398 | ||
|
399 | struct JoinDisplay<I, S> { | |
|
400 | iter: Cell<Option<I>>, | |
|
401 | separator: S, | |
|
402 | } | |
|
403 | ||
|
404 | impl<I, T, S> fmt::Display for JoinDisplay<I, S> | |
|
405 | where | |
|
406 | I: Iterator<Item = T>, | |
|
407 | T: fmt::Display, | |
|
408 | S: fmt::Display, | |
|
409 | { | |
|
410 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
|
411 | if let Some(mut iter) = self.iter.take() { | |
|
412 | if let Some(first) = iter.next() { | |
|
413 | first.fmt(f)?; | |
|
414 | } | |
|
415 | for value in iter { | |
|
416 | self.separator.fmt(f)?; | |
|
417 | value.fmt(f)?; | |
|
418 | } | |
|
419 | } | |
|
420 | Ok(()) | |
|
421 | } | |
|
422 | } |
General Comments 0
You need to be logged in to leave comments.
Login now