Mercurial > public > mercurial-scm > hg-stable
diff rust/hg-core/src/requirements.rs @ 45939:a2eda1ff22aa
requirements: move loading to hg-core and add parsing
No functional change, checking comes later.
Differential Revision: https://phab.mercurial-scm.org/D9398
author | Simon Sapin <simon-commits@exyr.org> |
---|---|
date | Tue, 24 Nov 2020 17:49:16 +0100 |
parents | |
children | 2ad2745e0be9 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/hg-core/src/requirements.rs Tue Nov 24 17:49:16 2020 +0100 @@ -0,0 +1,53 @@ +use std::io; +use std::path::Path; + +#[derive(Debug)] +pub enum RequirementsError { + // TODO: include a path? + Io(io::Error), + /// The `requires` file is corrupted + Corrupted, + /// The repository requires a feature that we don’t support + Unsupported { + feature: String, + }, +} + +fn parse(bytes: &[u8]) -> Result<Vec<String>, ()> { + // 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 + if line[0].is_ascii_alphanumeric() { + Ok(String::from_utf8(line.into()).unwrap()) + } else { + Err(()) + } + }) + .collect() +} + +pub fn load(repo_root: &Path) -> Result<Vec<String>, RequirementsError> { + match std::fs::read(repo_root.join(".hg").join("requires")) { + Ok(bytes) => parse(&bytes).map_err(|()| RequirementsError::Corrupted), + + // 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. + Err(error) if error.kind() == std::io::ErrorKind::NotFound => { + Ok(Vec::new()) + } + + Err(error) => Err(RequirementsError::Io(error))?, + } +}