compiler_test_derive/
ignores.rs

1use std::env;
2use std::fs::File;
3use std::path::PathBuf;
4
5use std::io::{BufRead, BufReader};
6use std::sync::OnceLock;
7
8#[derive(Debug, Clone)]
9struct IgnorePattern {
10    os: Option<String>,
11    arch: Option<String>,
12    target_env: Option<String>,
13    engine: Option<String>,
14    compiler: Option<String>,
15    pattern_to_ignore: String,
16}
17
18impl IgnorePattern {
19    fn should_ignore(
20        &self,
21        os: &str,
22        arch: &str,
23        target_env: &str,
24        engine: &str,
25        compiler: &str,
26        canonical_path: &str,
27    ) -> bool {
28        self.os.as_ref().is_none_or(|val| val == os)
29            && self.arch.as_ref().is_none_or(|val| val == arch)
30            && self.target_env.as_ref().is_none_or(|val| val == target_env)
31            && self.engine.as_ref().is_none_or(|val| val == engine)
32            && self.compiler.as_ref().is_none_or(|val| val == compiler)
33            && (self.pattern_to_ignore == "*" || canonical_path.contains(&*self.pattern_to_ignore))
34    }
35}
36
37#[derive(Debug, Clone)]
38pub struct Ignores {
39    /// The canonical path, and the set of features
40    patterns: Vec<IgnorePattern>,
41}
42
43impl Ignores {
44    /// If the path matches any of the paths on the list
45    pub fn should_ignore(
46        &self,
47        os: &str,
48        arch: &str,
49        target_env: &str,
50        engine: &str,
51        compiler: &str,
52        canonical_path: &str,
53    ) -> bool {
54        self.patterns.iter().any(|p| {
55            // println!(" -> {:?}", p);
56            p.should_ignore(os, arch, target_env, engine, compiler, canonical_path)
57        })
58    }
59
60    pub fn should_ignore_host(&self, engine: &str, compiler: &str, canonical_path: &str) -> bool {
61        static CFG_TARGET_OS: OnceLock<String> = OnceLock::new();
62        let target_os = CFG_TARGET_OS.get_or_init(|| {
63            env::var("CFG_TARGET_OS")
64                .expect("CFG_TARGET_OS variable expected from build.rs")
65                .to_string()
66        });
67        static CFG_TARGET_ARCH: OnceLock<String> = OnceLock::new();
68        let target_arch = CFG_TARGET_ARCH.get_or_init(|| {
69            env::var("CFG_TARGET_ARCH")
70                .expect("CFG_TARGET_ARCH variable expected from build.rs")
71                .to_string()
72        });
73        static CFG_TARGET_ENV: OnceLock<String> = OnceLock::new();
74        let target_env = CFG_TARGET_ENV.get_or_init(|| {
75            env::var("CFG_TARGET_ENV")
76                .expect("CFG_TARGET_ENV variable expected from build.rs")
77                .to_string()
78        });
79
80        self.should_ignore(
81            target_os,
82            target_arch,
83            target_env,
84            engine,
85            compiler,
86            canonical_path,
87        )
88    }
89
90    /// Build a Ignore structure from a file path
91    pub fn build_from_path(path: PathBuf) -> Ignores {
92        let file = File::open(path).unwrap();
93        let reader = BufReader::new(file);
94        let mut patterns = Vec::new();
95
96        for (i, line) in reader.lines().enumerate() {
97            let line = line.unwrap();
98            // If the line has a `#` we discard all the content that comes after
99            let line = line
100                .split_once("#")
101                .map(|(line, _comment)| line)
102                .unwrap_or_else(|| &line)
103                .trim()
104                .to_string();
105
106            // If the lines contains ` ` it means the test should be ignored
107            // on the features exposed
108            if let Some((platform_specifier, pattern_to_ignore)) = line.split_once(" ") {
109                let mut os: Option<String> = None;
110                let mut arch: Option<String> = None;
111                let mut target_env: Option<String> = None;
112                let mut engine: Option<String> = None;
113                let mut compiler: Option<String> = None;
114                for alias in platform_specifier.trim().split('+') {
115                    match alias {
116                        // Operating Systems
117                        "windows" | "macos" | "linux" => {
118                            os = Some(alias.to_string());
119                        }
120                        // Environments
121                        "musl" => {
122                            target_env = Some(alias.to_string());
123                        }
124                        // Chipset architectures
125                        "aarch64" | "x86" | "x64" | "riscv64" | "loongarch64" => {
126                            arch = Some(alias.to_string());
127                        }
128                        // Engines
129                        "engine" => {
130                            engine = Some(alias.to_string());
131                        }
132                        // Compilers
133                        "cranelift" | "llvm" | "singlepass" | "v8" => {
134                            compiler = Some(alias.to_string());
135                        }
136                        other => {
137                            panic!(
138                                "Alias {:?} not currently supported (defined in ignores.txt in line {})",
139                                other,
140                                i + 1
141                            );
142                        }
143                    }
144                }
145                let pattern_to_ignore = pattern_to_ignore.trim().to_string();
146                patterns.push(IgnorePattern {
147                    os,
148                    arch,
149                    target_env,
150                    engine,
151                    compiler,
152                    pattern_to_ignore,
153                });
154            } else {
155                if line.is_empty() {
156                    continue;
157                }
158                patterns.push(IgnorePattern {
159                    os: None,
160                    arch: None,
161                    target_env: None,
162                    engine: None,
163                    compiler: None,
164                    pattern_to_ignore: line,
165                });
166            };
167        }
168        Ignores { patterns }
169    }
170}
171
172#[cfg(test)]
173mod tests {
174    use super::*;
175
176    #[test]
177    fn features_match() -> Result<(), ()> {
178        assert!(
179            IgnorePattern {
180                os: None,
181                arch: None,
182                target_env: None,
183                engine: None,
184                compiler: None,
185                pattern_to_ignore: "*".to_string()
186            }
187            .should_ignore(
188                "unknown",
189                "unknown",
190                "",
191                "engine",
192                "compiler",
193                "some::random::text"
194            )
195        );
196        assert!(
197            IgnorePattern {
198                os: None,
199                arch: None,
200                target_env: None,
201                engine: None,
202                compiler: None,
203                pattern_to_ignore: "some::random".to_string()
204            }
205            .should_ignore(
206                "unknown",
207                "unknown",
208                "",
209                "engine",
210                "compiler",
211                "some::random::text"
212            )
213        );
214        assert!(
215            !IgnorePattern {
216                os: Some("macos".to_string()),
217                arch: None,
218                target_env: None,
219                engine: None,
220                compiler: None,
221                pattern_to_ignore: "other".to_string()
222            }
223            .should_ignore(
224                "unknown",
225                "unknown",
226                "",
227                "engine",
228                "compiler",
229                "some::random::text"
230            )
231        );
232        assert!(
233            !IgnorePattern {
234                os: Some("macos".to_string()),
235                arch: None,
236                target_env: None,
237                engine: Some("engine".to_string()),
238                compiler: None,
239                pattern_to_ignore: "other".to_string()
240            }
241            .should_ignore(
242                "macos",
243                "unknown",
244                "",
245                "engine",
246                "compiler",
247                "some::random::text"
248            )
249        );
250        Ok(())
251    }
252}