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 - uses: Swatinem/rust-cache@v2
- name: Prereqs - 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 - uses: taiki-e/install-action@cargo-hack
- name: Build - name: Build

@ -1,9 +1,8 @@
use std::{ use std::{
env, env,
ffi::OsString, ffi::OsString,
fmt::Write as _,
fs, fs,
io::BufReader, io::{BufRead as _, BufReader},
path::PathBuf, path::PathBuf,
process::{Child, Command, Stdio}, process::{Child, Command, Stdio},
}; };
@ -134,14 +133,25 @@ fn main() {
let mut child = cmd let mut child = cmd
.stdout(Stdio::piped()) .stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn() .spawn()
.unwrap_or_else(|err| panic!("failed to spawn {cmd:?}: {err}")); .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 stdout = stdout.take().unwrap();
let reader = BufReader::new(stdout); let stdout = BufReader::new(stdout);
let mut executables = Vec::new(); let mut executables = Vec::new();
let mut compiler_messages = String::new(); for message in Message::parse_stream(stdout) {
for message in Message::parse_stream(reader) {
#[allow(clippy::collapsible_match)] #[allow(clippy::collapsible_match)]
match message.expect("valid JSON") { match message.expect("valid JSON") {
Message::CompilerArtifact(Artifact { Message::CompilerArtifact(Artifact {
@ -154,7 +164,10 @@ fn main() {
} }
} }
Message::CompilerMessage(CompilerMessage { message, .. }) => { 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 let status = child
.wait() .wait()
.unwrap_or_else(|err| panic!("failed to wait for {cmd:?}: {err}")); .unwrap_or_else(|err| panic!("failed to wait for {cmd:?}: {err}"));
match status.code() { match status.code() {
Some(code) => match code { Some(code) => match code {
0 => {} 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"), None => panic!("{cmd:?} terminated by signal"),
} }
stderr.join().map_err(std::panic::resume_unwind).unwrap();
for (name, binary) in executables { for (name, binary) in executables {
let dst = out_dir.join(name); let dst = out_dir.join(name);
let _: u64 = fs::copy(&binary, &dst) 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 -- \ 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' -y --profile minimal --default-toolchain nightly --component rust-src --component clippy'
exec_vm 'echo source ~/.cargo/env >> ~/.bashrc' 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() { scp_vm() {

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

Loading…
Cancel
Save