use super::NinjaGenError;
use crate::ir::BuildGraph;
use crate::localization::{self, keys};
use camino::Utf8PathBuf;
pub(crate) fn escape_ninja_path(path: &str) -> Result<String, NinjaGenError> {
validate_path(path)?;
Ok(escape_validated_ninja_path(path))
}
pub(super) fn escape_validated_ninja_path(path: &str) -> String {
let mut out = String::with_capacity(path.len());
for ch in path.chars() {
match ch {
' ' => out.push_str("$ "),
'$' => out.push_str("$$"),
':' => out.push_str("$:"),
_ => out.push(ch),
}
}
out
}
pub(crate) fn reject_unsupported_path_characters(graph: &BuildGraph) -> Result<(), NinjaGenError> {
for edge in graph.targets.values() {
for path in edge
.explicit_outputs
.iter()
.chain(&edge.implicit_outputs)
.chain(&edge.inputs)
.chain(&edge.implicit_deps)
.chain(&edge.order_only_deps)
{
validate_path(path.as_str())?;
}
}
for path in &graph.default_targets {
validate_path(path.as_str())?;
}
Ok(())
}
fn validate_path(path: &str) -> Result<(), NinjaGenError> {
if let Some(character) = unsupported_character(path) {
return Err(unsupported_path_character(path, character));
}
Ok(())
}
fn unsupported_character(path: &str) -> Option<char> {
path.chars()
.find(|character| matches!(character, '|' | '\t' | '\r' | '\n'))
}
fn unsupported_path_character(path: &str, character: char) -> NinjaGenError {
NinjaGenError::UnsupportedPathCharacter {
path: Utf8PathBuf::from(path),
character,
message: localization::message(keys::NINJA_GEN_UNSUPPORTED_PATH_CHARACTER)
.with_arg("path", path)
.with_arg("character", character),
}
}