Lot more brittle than I would like, can't really use cargo as a library (especially paired with guppy
) but everything seems to be working well so far, and can finally start analyzing the data.
LOR3KOXGQ2VYGDHXQ6MG22ZME5TMPFTUW7A5OG36IAVQANOCXBRAC
use std::io::{BufRead, BufReader};
use std::process::{Command, Stdio};
use cargo_metadata::{PackageId, Target};
use serde::{Deserialize, Serialize};
// Use an alternative profile so clean-building is "sandboxed" to this tool
const CARGO_CUSOTM_PROFILE: [&str; 2] = ["--config", r#"profile.depwiz.inherits="dev""#];
/// See https://docs.rs/cargo/latest/cargo/core/compiler/enum.CompileMode.html
/// These are the only two cases we are interested in
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
enum Mode {
Build,
RunCustomBuild,
}
/// See https://docs.rs/cargo/latest/cargo/util/machine_message/struct.TimingInfo.html
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Message {
reason: String,
package_id: PackageId,
target: Target,
mode: Mode,
duration: f64,
rmeta_time: Option<f64>,
}
pub fn generate() -> Vec<Message> {
// TODO: `cargo build --timings=json` seems to only work on a clean build
Command::new("cargo")
.arg("clean")
.args(CARGO_CUSOTM_PROFILE)
.args(&["--profile", "depwiz"])
.stdout(Stdio::inherit())
.stderr(Stdio::inherit())
.output()
.unwrap();
let timings_ouput = Command::new("cargo")
.arg("build")
.args(CARGO_CUSOTM_PROFILE)
.args(&[
"--profile",
"depwiz",
"-Zunstable-options",
"--timings=json",
])
.stderr(Stdio::inherit())
.output()
.unwrap();
let mut timings = Vec::new();
let mut timings_buffer = BufReader::new(timings_ouput.stdout.as_slice());
let mut message_buffer = Vec::new();
loop {
timings_buffer
.read_until(b'\n', &mut message_buffer)
.unwrap();
let json_message: Message = match serde_json::from_slice(&message_buffer) {
Ok(message) => message,
Err(err) => {
use serde_json::error::Category;
match err.classify() {
Category::Eof => break,
Category::Data => todo!(
"JSON object not properly handled, got `{err:?}` for message: `{}`",
String::from_utf8(message_buffer.clone()).unwrap()
),
_ => {
panic!("Unexpected error while parsing: {err:?}");
}
}
}
};
// Make sure it's actually a timings message
assert_eq!(json_message.reason, "timing-info");
timings.push(json_message);
message_buffer.clear();
}
timings
}
serde = { version = "1.0.198", features = ["serde_derive"] }
serde_json = "1.0.116"