Skip to content

Commit 2288aed

Browse files
authored
Merge pull request #210 from oli-obk/librarification
Lots of cleanups
2 parents df8246c + 245b589 commit 2288aed

File tree

11 files changed

+1042
-1111
lines changed

11 files changed

+1042
-1111
lines changed

src/config.rs

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@ use regex::bytes::Regex;
22
use spanned::{Span, Spanned};
33

44
use crate::{
5-
dependencies::build_dependencies, per_test_config::Comments, CommandBuilder, Match, Mode,
6-
RustfixMode,
5+
dependencies::build_dependencies,
6+
filter::Match,
7+
per_test_config::{Comments, Condition},
8+
CommandBuilder, Mode, RustfixMode,
79
};
810
pub use color_eyre;
911
use color_eyre::eyre::Result;
@@ -259,8 +261,12 @@ impl Config {
259261
}
260262

261263
/// Check whether the host is the specified string
262-
pub fn host_matches(&self, target: &str) -> bool {
263-
self.host.as_ref().expect("host should have been filled in") == target
264+
pub fn host_matches_target(&self) -> bool {
265+
self.host.as_ref().expect("host should have been filled in")
266+
== self
267+
.target
268+
.as_ref()
269+
.expect("target should have been filled in")
264270
}
265271

266272
pub(crate) fn has_asm_support(&self) -> bool {
@@ -274,6 +280,56 @@ impl Config {
274280
.iter()
275281
.any(|arch| self.target.as_ref().unwrap().contains(arch))
276282
}
283+
284+
pub(crate) fn get_pointer_width(&self) -> u8 {
285+
// Taken 1:1 from compiletest-rs
286+
fn get_pointer_width(triple: &str) -> u8 {
287+
if (triple.contains("64")
288+
&& !triple.ends_with("gnux32")
289+
&& !triple.ends_with("gnu_ilp32"))
290+
|| triple.starts_with("s390x")
291+
{
292+
64
293+
} else if triple.starts_with("avr") {
294+
16
295+
} else {
296+
32
297+
}
298+
}
299+
get_pointer_width(self.target.as_ref().unwrap())
300+
}
301+
302+
pub(crate) fn test_condition(&self, condition: &Condition) -> bool {
303+
let target = self.target.as_ref().unwrap();
304+
match condition {
305+
Condition::Bitwidth(bits) => self.get_pointer_width() == *bits,
306+
Condition::Target(t) => target.contains(t),
307+
Condition::Host(t) => self.host.as_ref().unwrap().contains(t),
308+
Condition::OnHost => self.host_matches_target(),
309+
}
310+
}
311+
312+
/// Returns whether according to the in-file conditions, this file should be run.
313+
pub fn test_file_conditions(&self, comments: &Comments, revision: &str) -> bool {
314+
if comments
315+
.for_revision(revision)
316+
.flat_map(|r| r.ignore.iter())
317+
.any(|c| self.test_condition(c))
318+
{
319+
return self.run_only_ignored;
320+
}
321+
if comments
322+
.for_revision(revision)
323+
.any(|r| r.needs_asm_support && !self.has_asm_support())
324+
{
325+
return self.run_only_ignored;
326+
}
327+
comments
328+
.for_revision(revision)
329+
.flat_map(|r| r.only.iter())
330+
.all(|c| self.test_condition(c))
331+
^ self.run_only_ignored
332+
}
277333
}
278334

279335
#[derive(Debug, Clone)]

src/dependencies.rs

Lines changed: 110 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,23 @@
1+
use bstr::ByteSlice;
12
use cargo_metadata::{camino::Utf8PathBuf, DependencyKind};
23
use cargo_platform::Cfg;
34
use color_eyre::eyre::{bail, eyre, Result};
45
use std::{
56
collections::{hash_map::Entry, HashMap, HashSet},
67
ffi::OsString,
7-
path::PathBuf,
8+
path::{Path, PathBuf},
89
process::Command,
910
str::FromStr,
1011
sync::{Arc, OnceLock, RwLock},
1112
};
1213

1314
use crate::{
14-
build_aux, status_emitter::StatusEmitter, Config, Errored, Mode, OutputConflictHandling,
15+
crate_type, default_per_file_config,
16+
per_test_config::{Comments, TestConfig},
17+
rustc_stderr,
18+
status_emitter::StatusEmitter,
19+
test_result::Errored,
20+
Config, CrateType, Error, Mode, OutputConflictHandling,
1521
};
1622

1723
#[derive(Default, Debug)]
@@ -290,7 +296,7 @@ impl<'a> BuildManager<'a> {
290296
Err(())
291297
}
292298
},
293-
Build::Aux { aux_file } => match build_aux(aux_file, config, self) {
299+
Build::Aux { aux_file } => match self.build_aux(aux_file, config) {
294300
Ok(args) => Ok(args.iter().map(Into::into).collect()),
295301
Err(e) => {
296302
err = Some(e);
@@ -300,7 +306,7 @@ impl<'a> BuildManager<'a> {
300306
};
301307
build.done(
302308
&res.as_ref()
303-
.map(|_| crate::TestOk::Ok)
309+
.map(|_| crate::test_result::TestOk::Ok)
304310
.map_err(|()| Errored {
305311
command: Command::new(what.description()),
306312
errors: vec![],
@@ -320,4 +326,104 @@ impl<'a> BuildManager<'a> {
320326
})
321327
})
322328
}
329+
330+
fn build_aux(
331+
&self,
332+
aux_file: &Path,
333+
config: &Config,
334+
) -> std::result::Result<Vec<OsString>, Errored> {
335+
let file_contents = std::fs::read(aux_file).map_err(|err| Errored {
336+
command: Command::new(format!("reading aux file `{}`", aux_file.display())),
337+
errors: vec![],
338+
stderr: err.to_string().into_bytes(),
339+
stdout: vec![],
340+
})?;
341+
let comments = Comments::parse(&file_contents, config.comment_defaults.clone(), aux_file)
342+
.map_err(|errors| Errored::new(errors, "parse aux comments"))?;
343+
assert_eq!(
344+
comments.revisions, None,
345+
"aux builds cannot specify revisions"
346+
);
347+
348+
let mut config = config.clone();
349+
350+
// Strip any `crate-type` flags from the args, as we need to set our own,
351+
// and they may conflict (e.g. `lib` vs `proc-macro`);
352+
let mut prev_was_crate_type = false;
353+
config.program.args.retain(|arg| {
354+
if prev_was_crate_type {
355+
prev_was_crate_type = false;
356+
return false;
357+
}
358+
if arg == "--test" {
359+
false
360+
} else if arg == "--crate-type" {
361+
prev_was_crate_type = true;
362+
false
363+
} else if let Some(arg) = arg.to_str() {
364+
!arg.starts_with("--crate-type=")
365+
} else {
366+
true
367+
}
368+
});
369+
370+
default_per_file_config(&mut config, aux_file, &file_contents);
371+
372+
match crate_type(&file_contents) {
373+
// Proc macros must be run on the host
374+
CrateType::ProcMacro => config.target = config.host.clone(),
375+
CrateType::Test | CrateType::Bin | CrateType::Lib => {}
376+
}
377+
378+
let mut config = TestConfig {
379+
config,
380+
revision: "",
381+
comments: &comments,
382+
path: aux_file,
383+
};
384+
385+
config.patch_out_dir();
386+
387+
let mut aux_cmd = config.build_command()?;
388+
389+
let mut extra_args = config.build_aux_files(aux_file.parent().unwrap(), self)?;
390+
// Make sure we see our dependencies
391+
aux_cmd.args(extra_args.iter());
392+
393+
aux_cmd.arg("--emit=link");
394+
let filename = aux_file.file_stem().unwrap().to_str().unwrap();
395+
let output = aux_cmd.output().unwrap();
396+
if !output.status.success() {
397+
let error = Error::Command {
398+
kind: "compilation of aux build failed".to_string(),
399+
status: output.status,
400+
};
401+
return Err(Errored {
402+
command: aux_cmd,
403+
errors: vec![error],
404+
stderr: rustc_stderr::process(aux_file, &output.stderr).rendered,
405+
stdout: output.stdout,
406+
});
407+
}
408+
409+
// Now run the command again to fetch the output filenames
410+
aux_cmd.arg("--print").arg("file-names");
411+
let output = aux_cmd.output().unwrap();
412+
assert!(output.status.success());
413+
414+
for file in output.stdout.lines() {
415+
let file = std::str::from_utf8(file).unwrap();
416+
let crate_name = filename.replace('-', "_");
417+
let path = config.config.out_dir.join(file);
418+
extra_args.push("--extern".into());
419+
let mut cname = OsString::from(&crate_name);
420+
cname.push("=");
421+
cname.push(path);
422+
extra_args.push(cname);
423+
// Help cargo find the crates added with `--extern`.
424+
extra_args.push("-L".into());
425+
extra_args.push(config.config.out_dir.as_os_str().to_os_string());
426+
}
427+
Ok(extra_args)
428+
}
323429
}

src/filter.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
//! Datastructures and operations used for normalizing test output.
2+
3+
use bstr::ByteSlice;
4+
use lazy_static::lazy_static;
5+
use regex::bytes::{Captures, Regex};
6+
use std::borrow::Cow;
7+
use std::path::Path;
8+
9+
/// A filter's match rule.
10+
#[derive(Clone, Debug)]
11+
pub enum Match {
12+
/// If the regex matches, the filter applies
13+
Regex(Regex),
14+
/// If the exact byte sequence is found, the filter applies
15+
Exact(Vec<u8>),
16+
/// Uses a heuristic to find backslashes in windows style paths
17+
PathBackslash,
18+
}
19+
20+
impl Match {
21+
pub(crate) fn replace_all<'a>(&self, text: &'a [u8], replacement: &[u8]) -> Cow<'a, [u8]> {
22+
match self {
23+
Match::Regex(regex) => regex.replace_all(text, replacement),
24+
Match::Exact(needle) => text.replace(needle, replacement).into(),
25+
Match::PathBackslash => {
26+
lazy_static! {
27+
static ref PATH_RE: Regex = Regex::new(
28+
r"(?x)
29+
(?:
30+
# Match paths to files with extensions that don't include spaces
31+
\\(?:[\pL\pN.\-_']+[/\\])*[\pL\pN.\-_']+\.\pL+
32+
|
33+
# Allow spaces in absolute paths
34+
[A-Z]:\\(?:[\pL\pN.\-_'\ ]+[/\\])+
35+
)",
36+
)
37+
.unwrap();
38+
}
39+
40+
PATH_RE.replace_all(text, |caps: &Captures<'_>| {
41+
caps[0].replace(r"\", replacement)
42+
})
43+
}
44+
}
45+
}
46+
}
47+
48+
impl From<&'_ Path> for Match {
49+
fn from(v: &Path) -> Self {
50+
let mut v = v.display().to_string();
51+
// Normalize away windows canonicalized paths.
52+
if v.starts_with(r"\\?\") {
53+
v.drain(0..4);
54+
}
55+
let mut v = v.into_bytes();
56+
// Normalize paths on windows to use slashes instead of backslashes,
57+
// So that paths are rendered the same on all systems.
58+
for c in &mut v {
59+
if *c == b'\\' {
60+
*c = b'/';
61+
}
62+
}
63+
Self::Exact(v)
64+
}
65+
}
66+
67+
impl From<Regex> for Match {
68+
fn from(v: Regex) -> Self {
69+
Self::Regex(v)
70+
}
71+
}

0 commit comments

Comments
 (0)