requirements.rs
76 lines
| 2.5 KiB
| application/rls-services+xml
|
RustLexer
|
r46536 | 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, | ||||
r46570 | /// The repository requires a feature that we don't support | |||
|
r46536 | 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 | ||||
|
r46550 | if line[0].is_ascii_alphanumeric() && line.is_ascii() { | ||
|
r46536 | 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))?, | ||||
} | ||||
} | ||||
|
r46549 | |||
pub fn check(repo_root: &Path) -> Result<(), RequirementsError> { | ||||
for feature in load(repo_root)? { | ||||
if !SUPPORTED.contains(&&*feature) { | ||||
r46570 | return Err(RequirementsError::Unsupported { feature }); | |||
|
r46549 | } | ||
} | ||||
Ok(()) | ||||
} | ||||
// TODO: set this to actually-supported features | ||||
const SUPPORTED: &[&str] = &[ | ||||
"dotencode", | ||||
"fncache", | ||||
"generaldelta", | ||||
"revlogv1", | ||||
"sparserevlog", | ||||
"store", | ||||
|
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: | ||||
"persistent-nodemap", | ||||
|
r46549 | ]; | ||