##// END OF EJS Templates
rhg: Check .hg/requires for absence of required features...
Simon Sapin -
r47358:a0696397 default
parent child Browse files
Show More
@@ -1,5 +1,6 b''
1 use crate::errors::{HgError, HgResultExt};
1 use crate::errors::{HgError, HgResultExt};
2 use crate::repo::{Repo, Vfs};
2 use crate::repo::{Repo, Vfs};
3 use crate::utils::join_display;
3 use std::collections::HashSet;
4 use std::collections::HashSet;
4
5
5 fn parse(bytes: &[u8]) -> Result<HashSet<String>, HgError> {
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 pub(crate) fn check(repo: &Repo) -> Result<(), HgError> {
45 pub(crate) fn check(repo: &Repo) -> Result<(), HgError> {
45 for feature in repo.requirements() {
46 let unknown: Vec<_> = repo
46 if !SUPPORTED.contains(&feature.as_str()) {
47 .requirements()
47 // TODO: collect and all unknown features and include them in the
48 .iter()
48 // error message?
49 .map(String::as_str)
49 return Err(HgError::UnsupportedFeature(format!(
50 // .filter(|feature| !ALL_SUPPORTED.contains(feature.as_str()))
50 "repository requires feature unknown to this Mercurial: {}",
51 .filter(|feature| {
51 feature
52 !REQUIRED.contains(feature) && !SUPPORTED.contains(feature)
52 )));
53 })
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 Ok(())
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 const SUPPORTED: &[&str] = &[
78 const SUPPORTED: &[&str] = &[
60 "dotencode",
61 "fncache",
62 "generaldelta",
79 "generaldelta",
63 "revlogv1",
64 SHARED_REQUIREMENT,
80 SHARED_REQUIREMENT,
65 SHARESAFE_REQUIREMENT,
81 SHARESAFE_REQUIREMENT,
66 SPARSEREVLOG_REQUIREMENT,
82 SPARSEREVLOG_REQUIREMENT,
67 RELATIVE_SHARED_REQUIREMENT,
83 RELATIVE_SHARED_REQUIREMENT,
68 "store",
69 // As of this writing everything rhg does is read-only.
84 // As of this writing everything rhg does is read-only.
70 // When it starts writing to the repository, it’ll need to either keep the
85 // When it starts writing to the repository, it’ll need to either keep the
71 // persistent nodemap up to date or remove this entry:
86 // persistent nodemap up to date or remove this entry:
72 "persistent-nodemap",
87 NODEMAP_REQUIREMENT,
73 ];
88 ];
74
89
75 // Copied from mercurial/requirements.py:
90 // Copied from mercurial/requirements.py:
@@ -11,6 +11,8 b' use crate::errors::{HgError, IoErrorCont'
11 use crate::utils::hg_path::HgPath;
11 use crate::utils::hg_path::HgPath;
12 use im_rc::ordmap::DiffItem;
12 use im_rc::ordmap::DiffItem;
13 use im_rc::ordmap::OrdMap;
13 use im_rc::ordmap::OrdMap;
14 use std::cell::Cell;
15 use std::fmt;
14 use std::{io::Write, ops::Deref};
16 use std::{io::Write, ops::Deref};
15
17
16 pub mod files;
18 pub mod files;
@@ -378,3 +380,43 b' where'
378 right
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