1/// Generating build depfiles from parsed bindings.
2use std::{collections::BTreeSet, path::PathBuf};
3
4#[derive(Clone, Debug)]
5pub(crate) struct DepfileSpec {
6 pub output_module: String,
7 pub depfile_path: PathBuf,
8}
9
10impl DepfileSpec {
11 pub fn write(&self, deps: &BTreeSet<Box<str>>) -> std::io::Result<()> {
12 std::fs::write(&self.depfile_path, self.to_string(deps))
13 }
14
15 fn to_string(&self, deps: &BTreeSet<Box<str>>) -> String {
16 // Transforms a string by escaping spaces and backslashes.
17 let escape: impl Fn(&str) -> String = |s: &str| s.replace('\\', "\\\\").replace(from:' ', to:"\\ ");
18
19 let mut buf: String = format!("{}:", escape(&self.output_module));
20 for file: &Box in deps {
21 buf = format!("{} {}", buf, escape(file));
22 }
23 buf
24 }
25}
26
27#[cfg(test)]
28mod tests {
29 use super::*;
30
31 #[test]
32 fn escaping_depfile() {
33 let spec = DepfileSpec {
34 output_module: "Mod Name".to_owned(),
35 depfile_path: PathBuf::new(),
36 };
37
38 let deps: BTreeSet<_> = vec![
39 r"/absolute/path".into(),
40 r"C:\win\absolute\path".into(),
41 r"../relative/path".into(),
42 r"..\win\relative\path".into(),
43 r"../path/with spaces/in/it".into(),
44 r"..\win\path\with spaces\in\it".into(),
45 r"path\with/mixed\separators".into(),
46 ]
47 .into_iter()
48 .collect();
49 assert_eq!(
50 spec.to_string(&deps),
51 "Mod\\ Name: \
52 ../path/with\\ spaces/in/it \
53 ../relative/path \
54 ..\\\\win\\\\path\\\\with\\ spaces\\\\in\\\\it \
55 ..\\\\win\\\\relative\\\\path \
56 /absolute/path \
57 C:\\\\win\\\\absolute\\\\path \
58 path\\\\with/mixed\\\\separators"
59 );
60 }
61}
62