##// END OF EJS Templates
rhg: Exit with an error code if `files` finds nothing...
rhg: Exit with an error code if `files` finds nothing This matches the behavior of Python-based hg. Differential Revision: https://phab.mercurial-scm.org/D10143

File last commit:

r47358:a0696397 default
r47479:63bfcddd default
Show More
requirements.rs
153 lines | 5.8 KiB | application/rls-services+xml | RustLexer
Simon Sapin
rust: use HgError in RevlogError and Vfs...
r47172 use crate::errors::{HgError, HgResultExt};
Simon Sapin
rhg: initial support for shared repositories...
r47190 use crate::repo::{Repo, Vfs};
Simon Sapin
rhg: Check .hg/requires for absence of required features...
r47358 use crate::utils::join_display;
Simon Sapin
rhg: initial support for shared repositories...
r47190 use std::collections::HashSet;
Simon Sapin
requirements: move loading to hg-core and add parsing...
r46536
Simon Sapin
rhg: initial support for shared repositories...
r47190 fn parse(bytes: &[u8]) -> Result<HashSet<String>, HgError> {
Simon Sapin
requirements: move loading to hg-core and add parsing...
r46536 // The Python code reading this file uses `str.splitlines`
// which looks for a number of line separators (even including a couple of
// non-ASCII ones), but Python code writing it always uses `\n`.
let lines = bytes.split(|&byte| byte == b'\n');
lines
.filter(|line| !line.is_empty())
.map(|line| {
// Python uses Unicode `str.isalnum` but feature names are all
// ASCII
Simon Sapin
rhg: check that .hg/requires is ASCII...
r46550 if line[0].is_ascii_alphanumeric() && line.is_ascii() {
Simon Sapin
requirements: move loading to hg-core and add parsing...
r46536 Ok(String::from_utf8(line.into()).unwrap())
} else {
Simon Sapin
rust: replace RequirementsError with HgError...
r47171 Err(HgError::corrupted("parse error in 'requires' file"))
Simon Sapin
requirements: move loading to hg-core and add parsing...
r46536 }
})
.collect()
}
Simon Sapin
rhg: add support for share-safe...
r47191 pub(crate) fn load(hg_vfs: Vfs) -> Result<HashSet<String>, HgError> {
parse(&hg_vfs.read("requires")?)
}
Simon Sapin
rhg: initial support for shared repositories...
r47190 pub(crate) fn load_if_exists(hg_vfs: Vfs) -> Result<HashSet<String>, HgError> {
if let Some(bytes) = hg_vfs.read("requires").io_not_found_as_none()? {
Simon Sapin
rust: replace RequirementsError with HgError...
r47171 parse(&bytes)
} else {
Simon Sapin
requirements: move loading to hg-core and add parsing...
r46536 // Treat a missing file the same as an empty file.
// From `mercurial/localrepo.py`:
// > requires file contains a newline-delimited list of
// > features/capabilities the opener (us) must have in order to use
// > the repository. This file was introduced in Mercurial 0.9.2,
// > which means very old repositories may not have one. We assume
// > a missing file translates to no requirements.
Simon Sapin
rhg: initial support for shared repositories...
r47190 Ok(HashSet::new())
Simon Sapin
requirements: move loading to hg-core and add parsing...
r46536 }
}
Simon Sapin
rhg: exit with relevant code for unsupported requirements...
r46549
Simon Sapin
rhg: initial support for shared repositories...
r47190 pub(crate) fn check(repo: &Repo) -> Result<(), HgError> {
Simon Sapin
rhg: Check .hg/requires for absence of required features...
r47358 let unknown: Vec<_> = repo
.requirements()
.iter()
.map(String::as_str)
// .filter(|feature| !ALL_SUPPORTED.contains(feature.as_str()))
.filter(|feature| {
!REQUIRED.contains(feature) && !SUPPORTED.contains(feature)
})
.collect();
if !unknown.is_empty() {
return Err(HgError::unsupported(format!(
"repository requires feature unknown to this Mercurial: {}",
join_display(&unknown, ", ")
)));
}
let missing: Vec<_> = REQUIRED
.iter()
.filter(|&&feature| !repo.requirements().contains(feature))
.collect();
if !missing.is_empty() {
return Err(HgError::unsupported(format!(
"repository is missing feature required by this Mercurial: {}",
join_display(&missing, ", ")
)));
Simon Sapin
rhg: exit with relevant code for unsupported requirements...
r46549 }
Ok(())
}
Simon Sapin
rhg: Check .hg/requires for absence of required features...
r47358 /// rhg does not support repositories that are *missing* any of these features
const REQUIRED: &[&str] = &["revlogv1", "store", "fncache", "dotencode"];
/// rhg supports repository with or without these
Simon Sapin
rhg: exit with relevant code for unsupported requirements...
r46549 const SUPPORTED: &[&str] = &[
"generaldelta",
Simon Sapin
rhg: initial support for shared repositories...
r47190 SHARED_REQUIREMENT,
Simon Sapin
rhg: add support for share-safe...
r47191 SHARESAFE_REQUIREMENT,
Simon Sapin
rhg: initial support for shared repositories...
r47190 SPARSEREVLOG_REQUIREMENT,
RELATIVE_SHARED_REQUIREMENT,
Simon Sapin
rhg: use persistent nodemap when available...
r46706 // As of this writing everything rhg does is read-only.
// When it starts writing to the repository, it’ll need to either keep the
// persistent nodemap up to date or remove this entry:
Simon Sapin
rhg: Check .hg/requires for absence of required features...
r47358 NODEMAP_REQUIREMENT,
Simon Sapin
rhg: exit with relevant code for unsupported requirements...
r46549 ];
Simon Sapin
rhg: initial support for shared repositories...
r47190
// Copied from mercurial/requirements.py:
/// When narrowing is finalized and no longer subject to format changes,
/// we should move this to just "narrow" or similar.
#[allow(unused)]
pub(crate) const NARROW_REQUIREMENT: &str = "narrowhg-experimental";
/// Enables sparse working directory usage
#[allow(unused)]
pub(crate) const SPARSE_REQUIREMENT: &str = "exp-sparse";
/// Enables the internal phase which is used to hide changesets instead
/// of stripping them
#[allow(unused)]
pub(crate) const INTERNAL_PHASE_REQUIREMENT: &str = "internal-phase";
/// Stores manifest in Tree structure
#[allow(unused)]
pub(crate) const TREEMANIFEST_REQUIREMENT: &str = "treemanifest";
/// Increment the sub-version when the revlog v2 format changes to lock out old
/// clients.
#[allow(unused)]
pub(crate) const REVLOGV2_REQUIREMENT: &str = "exp-revlogv2.1";
/// A repository with the sparserevlog feature will have delta chains that
/// can spread over a larger span. Sparse reading cuts these large spans into
/// pieces, so that each piece isn't too big.
/// Without the sparserevlog capability, reading from the repository could use
/// huge amounts of memory, because the whole span would be read at once,
/// including all the intermediate revisions that aren't pertinent for the
/// chain. This is why once a repository has enabled sparse-read, it becomes
/// required.
#[allow(unused)]
pub(crate) const SPARSEREVLOG_REQUIREMENT: &str = "sparserevlog";
/// A repository with the sidedataflag requirement will allow to store extra
/// information for revision without altering their original hashes.
#[allow(unused)]
pub(crate) const SIDEDATA_REQUIREMENT: &str = "exp-sidedata-flag";
/// A repository with the the copies-sidedata-changeset requirement will store
/// copies related information in changeset's sidedata.
#[allow(unused)]
pub(crate) const COPIESSDC_REQUIREMENT: &str = "exp-copies-sidedata-changeset";
/// The repository use persistent nodemap for the changelog and the manifest.
#[allow(unused)]
pub(crate) const NODEMAP_REQUIREMENT: &str = "persistent-nodemap";
/// Denotes that the current repository is a share
#[allow(unused)]
pub(crate) const SHARED_REQUIREMENT: &str = "shared";
/// Denotes that current repository is a share and the shared source path is
/// relative to the current repository root path
#[allow(unused)]
pub(crate) const RELATIVE_SHARED_REQUIREMENT: &str = "relshared";
/// A repository with share implemented safely. The repository has different
/// store and working copy requirements i.e. both `.hg/requires` and
/// `.hg/store/requires` are present.
#[allow(unused)]
Simon Sapin
rhg: add support for share-safe...
r47191 pub(crate) const SHARESAFE_REQUIREMENT: &str = "share-safe";