4
0

run.rs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. use std::{
  2. ffi::OsString,
  3. fmt::Write as _,
  4. io::BufReader,
  5. path::PathBuf,
  6. process::{Child, Command, Stdio},
  7. };
  8. use anyhow::{bail, Context as _, Result};
  9. use cargo_metadata::{Artifact, CompilerMessage, Message, Target};
  10. use clap::Parser;
  11. use xtask::AYA_BUILD_INTEGRATION_BPF;
  12. #[derive(Debug, Parser)]
  13. pub struct BuildOptions {
  14. /// Arguments to pass to `cargo build`.
  15. #[clap(long)]
  16. pub cargo_arg: Vec<OsString>,
  17. }
  18. #[derive(Debug, Parser)]
  19. pub struct Options {
  20. #[command(flatten)]
  21. pub build_options: BuildOptions,
  22. /// The command used to wrap your application.
  23. #[clap(short, long, default_value = "sudo -E")]
  24. pub runner: String,
  25. /// Arguments to pass to your application.
  26. #[clap(last = true)]
  27. pub run_args: Vec<OsString>,
  28. }
  29. /// Build the project
  30. pub fn build(opts: BuildOptions) -> Result<Vec<(String, PathBuf)>> {
  31. let BuildOptions { cargo_arg } = opts;
  32. let mut cmd = Command::new("cargo");
  33. cmd.env(AYA_BUILD_INTEGRATION_BPF, "true")
  34. .args([
  35. "build",
  36. "--tests",
  37. "--message-format=json",
  38. "--package=integration-test",
  39. ])
  40. .args(cargo_arg);
  41. let mut child = cmd
  42. .stdout(Stdio::piped())
  43. .spawn()
  44. .with_context(|| format!("failed to spawn {cmd:?}"))?;
  45. let Child { stdout, .. } = &mut child;
  46. let stdout = stdout.take().unwrap();
  47. let stdout = BufReader::new(stdout);
  48. let mut executables = Vec::new();
  49. for message in Message::parse_stream(stdout) {
  50. #[allow(clippy::collapsible_match)]
  51. match message.context("valid JSON")? {
  52. Message::CompilerArtifact(Artifact {
  53. executable,
  54. target: Target { name, .. },
  55. ..
  56. }) => {
  57. if let Some(executable) = executable {
  58. executables.push((name, executable.into()));
  59. }
  60. }
  61. Message::CompilerMessage(CompilerMessage { message, .. }) => {
  62. println!("{message}");
  63. }
  64. Message::TextLine(line) => {
  65. println!("{line}");
  66. }
  67. _ => {}
  68. }
  69. }
  70. let status = child
  71. .wait()
  72. .with_context(|| format!("failed to wait for {cmd:?}"))?;
  73. match status.code() {
  74. Some(code) => match code {
  75. 0 => {}
  76. code => bail!("{cmd:?} exited with status code {code}"),
  77. },
  78. None => bail!("{cmd:?} terminated by signal"),
  79. }
  80. Ok(executables)
  81. }
  82. /// Build and run the project
  83. pub fn run(opts: Options) -> Result<()> {
  84. let Options {
  85. build_options,
  86. runner,
  87. run_args,
  88. } = opts;
  89. let binaries = build(build_options).context("error while building userspace application")?;
  90. let mut args = runner.trim().split_terminator(' ');
  91. let runner = args.next().ok_or(anyhow::anyhow!("no first argument"))?;
  92. let args = args.collect::<Vec<_>>();
  93. let mut failures = String::new();
  94. for (name, binary) in binaries {
  95. let mut cmd = Command::new(runner);
  96. let cmd = cmd
  97. .args(args.iter())
  98. .arg(binary)
  99. .args(run_args.iter())
  100. .arg("--test-threads=1");
  101. println!("{} running {cmd:?}", name);
  102. let status = cmd
  103. .status()
  104. .with_context(|| format!("failed to run {cmd:?}"))?;
  105. match status.code() {
  106. Some(code) => match code {
  107. 0 => {}
  108. code => writeln!(&mut failures, "{} exited with status code {code}", name)
  109. .context("String write failed")?,
  110. },
  111. None => writeln!(&mut failures, "{} terminated by signal", name)
  112. .context("String write failed")?,
  113. }
  114. }
  115. if failures.is_empty() {
  116. Ok(())
  117. } else {
  118. Err(anyhow::anyhow!("failures:\n{}", failures))
  119. }
  120. }