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 = if line.contains('#') {
100                let l: Vec<&str> = line.splitn(2, '#').collect();
101                l[0].to_string()
102            } else {
103                line
104            };
105
106            let line = line.trim().to_string();
107
108            // If the lines contains ` ` it means the test should be ignored
109            // on the features exposed
110            if line.contains(' ') {
111                let l: Vec<&str> = line.splitn(2, ' ').collect();
112                let mut os: Option<String> = None;
113                let mut arch: Option<String> = None;
114                let mut target_env: Option<String> = None;
115                let mut engine: Option<String> = None;
116                let mut compiler: Option<String> = None;
117                for alias in l[0].trim().split('+') {
118                    match alias {
119                        // Operating Systems
120                        "windows" | "macos" | "linux" => {
121                            os = Some(alias.to_string());
122                        }
123                        // Environments
124                        "musl" => {
125                            target_env = Some(alias.to_string());
126                        }
127                        // Chipset architectures
128                        "aarch64" | "x86" | "x64" | "riscv64" | "loongarch64" => {
129                            arch = Some(alias.to_string());
130                        }
131                        // Engines
132                        "universal" | "engine" => {
133                            engine = Some(alias.to_string());
134                        }
135                        // Compilers
136                        "cranelift" | "llvm" | "singlepass" => {
137                            compiler = Some(alias.to_string());
138                        }
139                        other => {
140                            panic!(
141                                "Alias {:?} not currently supported (defined in ignores.txt in line {})",
142                                other,
143                                i + 1
144                            );
145                        }
146                    }
147                }
148                let pattern_to_ignore = l[1].trim().to_string();
149                patterns.push(IgnorePattern {
150                    os,
151                    arch,
152                    target_env,
153                    engine,
154                    compiler,
155                    pattern_to_ignore,
156                });
157            } else {
158                if line.is_empty() {
159                    continue;
160                }
161                patterns.push(IgnorePattern {
162                    os: None,
163                    arch: None,
164                    target_env: None,
165                    engine: None,
166                    compiler: None,
167                    pattern_to_ignore: line,
168                });
169            };
170        }
171        Ignores { patterns }
172    }
173}
174
175#[cfg(test)]
176mod tests {
177    use super::*;
178
179    #[test]
180    fn features_match() -> Result<(), ()> {
181        assert!(
182            IgnorePattern {
183                os: None,
184                arch: None,
185                target_env: None,
186                engine: None,
187                compiler: None,
188                pattern_to_ignore: "*".to_string()
189            }
190            .should_ignore(
191                "unknown",
192                "unknown",
193                "",
194                "engine",
195                "compiler",
196                "some::random::text"
197            )
198        );
199        assert!(
200            IgnorePattern {
201                os: None,
202                arch: None,
203                target_env: None,
204                engine: None,
205                compiler: None,
206                pattern_to_ignore: "some::random".to_string()
207            }
208            .should_ignore(
209                "unknown",
210                "unknown",
211                "",
212                "engine",
213                "compiler",
214                "some::random::text"
215            )
216        );
217        assert!(
218            !IgnorePattern {
219                os: Some("macos".to_string()),
220                arch: None,
221                target_env: None,
222                engine: None,
223                compiler: None,
224                pattern_to_ignore: "other".to_string()
225            }
226            .should_ignore(
227                "unknown",
228                "unknown",
229                "",
230                "engine",
231                "compiler",
232                "some::random::text"
233            )
234        );
235        assert!(
236            !IgnorePattern {
237                os: Some("macos".to_string()),
238                arch: None,
239                target_env: None,
240                engine: Some("universal".to_string()),
241                compiler: None,
242                pattern_to_ignore: "other".to_string()
243            }
244            .should_ignore(
245                "macos",
246                "unknown",
247                "",
248                "universal",
249                "compiler",
250                "some::random::text"
251            )
252        );
253        Ok(())
254    }
255}