integration-test: shuttle stdio to user

Trampoline cargo-in-cargo stdio through cargo:warning to ensure the user
sees all the output.

Use bpf-linker from git in CI so we can see what's going on there.
pull/669/head
Tamir Duberstein 1 year ago
parent ff11c65734
commit 74fc50bf7e
No known key found for this signature in database

@ -120,7 +120,7 @@ jobs:
- uses: Swatinem/rust-cache@v2
- name: Prereqs
run: cargo install bpf-linker
run: cargo install bpf-linker --git https://github.com/aya-rs/bpf-linker.git
- uses: taiki-e/install-action@cargo-hack
- name: Build

@ -1,9 +1,8 @@
use std::{
env,
ffi::OsString,
fmt::Write as _,
fs,
io::BufReader,
io::{BufRead as _, BufReader},
path::PathBuf,
process::{Child, Command, Stdio},
};
@ -134,14 +133,25 @@ fn main() {
let mut child = cmd
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.unwrap_or_else(|err| panic!("failed to spawn {cmd:?}: {err}"));
let Child { stdout, .. } = &mut child;
let Child { stdout, stderr, .. } = &mut child;
// Trampoline stdout to cargo warnings.
let stderr = stderr.take().unwrap();
let stderr = BufReader::new(stderr);
let stderr = std::thread::spawn(move || {
for line in stderr.lines() {
let line = line.unwrap();
println!("cargo:warning={line}");
}
});
let stdout = stdout.take().unwrap();
let reader = BufReader::new(stdout);
let stdout = BufReader::new(stdout);
let mut executables = Vec::new();
let mut compiler_messages = String::new();
for message in Message::parse_stream(reader) {
for message in Message::parse_stream(stdout) {
#[allow(clippy::collapsible_match)]
match message.expect("valid JSON") {
Message::CompilerArtifact(Artifact {
@ -154,7 +164,10 @@ fn main() {
}
}
Message::CompilerMessage(CompilerMessage { message, .. }) => {
writeln!(&mut compiler_messages, "{message}").unwrap()
println!("cargo:warning={message}");
}
Message::TextLine(line) => {
println!("cargo:warning={line}");
}
_ => {}
}
@ -163,15 +176,16 @@ fn main() {
let status = child
.wait()
.unwrap_or_else(|err| panic!("failed to wait for {cmd:?}: {err}"));
match status.code() {
Some(code) => match code {
0 => {}
code => panic!("{cmd:?} exited with status code {code}:\n{compiler_messages}"),
code => panic!("{cmd:?} exited with status code {code}"),
},
None => panic!("{cmd:?} terminated by signal"),
}
stderr.join().map_err(std::panic::resume_unwind).unwrap();
for (name, binary) in executables {
let dst = out_dir.join(name);
let _: u64 = fs::copy(&binary, &dst)

@ -196,7 +196,7 @@ EOF
exec_vm 'curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- \
-y --profile minimal --default-toolchain nightly --component rust-src --component clippy'
exec_vm 'echo source ~/.cargo/env >> ~/.bashrc'
exec_vm cargo install bpf-linker --no-default-features
exec_vm cargo install bpf-linker --git https://github.com/aya-rs/bpf-linker.git
}
scp_vm() {

@ -2,10 +2,10 @@ use std::{
fmt::Write as _,
io::BufReader,
path::PathBuf,
process::{Command, Stdio},
process::{Child, Command, Stdio},
};
use anyhow::{Context as _, Result};
use anyhow::{bail, Context as _, Result};
use cargo_metadata::{Artifact, CompilerMessage, Message, Target};
use clap::Parser;
use xtask::AYA_BUILD_INTEGRATION_BPF;
@ -48,15 +48,17 @@ pub fn build(opts: BuildOptions) -> Result<Vec<(String, PathBuf)>> {
if let Some(target) = target {
cmd.args(["--target", &target]);
}
let mut cmd = cmd
let mut child = cmd
.stdout(Stdio::piped())
.spawn()
.with_context(|| format!("failed to spawn {cmd:?}"))?;
let Child { stdout, .. } = &mut child;
let reader = BufReader::new(cmd.stdout.take().unwrap());
let stdout = stdout.take().unwrap();
let stdout = BufReader::new(stdout);
let mut executables = Vec::new();
let mut compiler_messages = String::new();
for message in Message::parse_stream(reader) {
for message in Message::parse_stream(stdout) {
#[allow(clippy::collapsible_match)]
match message.context("valid JSON")? {
Message::CompilerArtifact(Artifact {
@ -69,26 +71,27 @@ pub fn build(opts: BuildOptions) -> Result<Vec<(String, PathBuf)>> {
}
}
Message::CompilerMessage(CompilerMessage { message, .. }) => {
writeln!(&mut compiler_messages, "{message}").context("String write failed")?
println!("{message}");
}
Message::TextLine(line) => {
println!("{line}");
}
_ => {}
}
}
let status = cmd
let status = child
.wait()
.with_context(|| format!("failed to wait for {cmd:?}"))?;
match status.code() {
Some(code) => match code {
0 => Ok(executables),
code => Err(anyhow::anyhow!(
"{cmd:?} exited with status code {code}:\n{compiler_messages}"
)),
0 => {}
code => bail!("{cmd:?} exited with status code {code}"),
},
None => Err(anyhow::anyhow!("{cmd:?} terminated by signal")),
None => bail!("{cmd:?} terminated by signal"),
}
Ok(executables)
}
/// Build and run the project

Loading…
Cancel
Save