-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcargo.rs
101 lines (95 loc) · 2.88 KB
/
cargo.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use anyhow::Result;
pub use cargo_metadata::{
libtest::SuiteEvent, libtest::TestEvent, Message, TestMessage as RawTestMessage,
};
use crossbeam::channel::bounded;
use crossbeam::channel::Receiver;
use serde_derive::Deserialize;
use std::path::Path;
use std::{
io::Read,
process::{Command, Stdio},
};
#[derive(Debug)]
pub enum TestMessage {
CompilerEvent(Message),
Event(RawTestMessage),
Finished,
}
pub fn test(at: Option<&Path>) -> Result<Receiver<TestMessage>> {
let (tx, rx) = bounded(10);
let mut proc = Command::new("cargo");
if let Some(at) = at {
proc.arg("-C");
proc.arg(at.as_os_str());
}
// proc.env("RUSTFLAGS", format!("--diagnostic-width={width}"));
proc.args([
"-Zunstable-options",
"test",
"--message-format",
"json",
"--",
"-Zunstable-options",
"--report-time",
"--show-output",
"--format",
"json",
]);
log::trace!("running {proc:?}");
let mut proc = proc.stdout(Stdio::piped()).stderr(Stdio::null()).spawn()?;
let mut out = proc.stdout.take().unwrap();
let mut tmp = Vec::with_capacity(32);
let mut stdout = [0; 4096];
macro_rules! handle {
($n:expr) => {
let n = $n;
for &byte in &stdout[..n] {
match byte {
b'\n' => {
let val = serde_json::from_slice::<serde_json::Value>(&tmp).unwrap();
log::debug!("got val: {}", serde_json::to_string_pretty(&val).unwrap());
let event = match serde_json::value::from_value::<Message>(val.clone()) {
Err(_) => TestMessage::Event(
serde_json::value::from_value::<RawTestMessage>(val).unwrap(),
),
Ok(v) => TestMessage::CompilerEvent(v),
};
tmp.clear();
tx.send(event).unwrap();
}
b => tmp.push(b),
}
}
};
}
std::thread::spawn(move || loop {
handle!(out.read(&mut stdout).unwrap());
if let Ok(Some(_)) = proc.try_wait() {
while let Ok(n) = out.read(&mut stdout) {
if n == 0 {
break;
}
handle!(n);
}
tx.send(TestMessage::Finished).unwrap();
log::debug!("proc exited, joining thread");
break;
}
std::thread::sleep(std::time::Duration::from_millis(50));
});
Ok(rx)
}
#[derive(Deserialize)]
pub struct Package {
pub name: String,
}
#[derive(Deserialize)]
pub struct Metadata {
pub package: Package,
}
pub fn meta(at: &Path) -> Result<Metadata> {
Ok(toml::from_str(&std::fs::read_to_string(
at.join("Cargo.toml"),
)?)?)
}