use std::{collections::BTreeSet, path::PathBuf};
#[derive(Clone, Debug)]
pub(crate) struct DepfileSpec {
pub output_module: String,
pub depfile_path: PathBuf,
}
impl DepfileSpec {
pub fn write(&self, deps: &BTreeSet<Box<str>>) -> std::io::Result<()> {
std::fs::write(&self.depfile_path, self.to_string(deps))
}
fn to_string(&self, deps: &BTreeSet<Box<str>>) -> String {
let escape = |s: &str| s.replace('\\', "\\\\").replace(' ', "\\ ");
let mut buf = format!("{}:", escape(&self.output_module));
for file in deps {
buf = format!("{buf} {}", escape(file));
}
buf
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn escaping_depfile() {
let spec = DepfileSpec {
output_module: "Mod Name".to_owned(),
depfile_path: PathBuf::new(),
};
let deps: BTreeSet<_> = vec![
r"/absolute/path".into(),
r"C:\win\absolute\path".into(),
r"../relative/path".into(),
r"..\win\relative\path".into(),
r"../path/with spaces/in/it".into(),
r"..\win\path\with spaces\in\it".into(),
r"path\with/mixed\separators".into(),
]
.into_iter()
.collect();
assert_eq!(
spec.to_string(&deps),
"Mod\\ Name: \
../path/with\\ spaces/in/it \
../relative/path \
..\\\\win\\\\path\\\\with\\ spaces\\\\in\\\\it \
..\\\\win\\\\relative\\\\path \
/absolute/path \
C:\\\\win\\\\absolute\\\\path \
path\\\\with/mixed\\\\separators"
);
}
}