Repository: rust-cross/cargo-zigbuild (language: python)

Issue:
Can a wrapper for `cargo run` be added, too?
It would be helpful if a wrapper for `cargo run` was added, like how `cargo zigbuild` wraps `cargo build`.  I'm running the cross-compiled binaries using qemu, and it would be a lot more seamless if something like `cargo zigbuild run` or `cargo zig run` worked.  Thanks!


Discussion / hints:

Fix patch:
diff --git a/src/bin/cargo-zigbuild.rs b/src/bin/cargo-zigbuild.rs
index c83db41..986bed5 100644
--- a/src/bin/cargo-zigbuild.rs
+++ b/src/bin/cargo-zigbuild.rs
@@ -1,4 +1,6 @@
+use cargo_zigbuild::run::Run;
 use cargo_zigbuild::rustc::Rustc;
+use cargo_zigbuild::test::Test;
 use cargo_zigbuild::{Build, Zig};
 use clap::Parser;
 
@@ -14,6 +16,10 @@ pub enum Opt {
     Build(Build),
     #[clap(name = "rustc")]
     Rustc(Rustc),
+    #[clap(name = "run")]
+    Run(Run),
+    #[clap(name = "test")]
+    Test(Test),
     #[clap(subcommand)]
     Zig(Zig),
 }
@@ -23,6 +29,8 @@ fn main() -> anyhow::Result<()> {
     match opt {
         Opt::Build(build) => build.execute()?,
         Opt::Rustc(rustc) => rustc.execute()?,
+        Opt::Run(run) => run.execute()?,
+        Opt::Test(test) => test.execute()?,
         Opt::Zig(zig) => zig.execute()?,
     }
     Ok(())
diff --git a/src/lib.rs b/src/lib.rs
index 4e00577..de3c41d 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,7 +1,9 @@
 mod build;
 pub mod linux;
 pub mod macos;
+pub mod run;
 pub mod rustc;
+pub mod test;
 pub mod zig;
 
 pub use build::Build;
diff --git a/src/run.rs b/src/run.rs
new file mode 100644
index 0000000..b24a4f2
--- /dev/null
+++ b/src/run.rs
@@ -0,0 +1,73 @@
+use std::ops::{Deref, DerefMut};
+use std::path::PathBuf;
+use std::process;
+
+use anyhow::{Context, Result};
+use clap::Parser;
+
+use crate::Build;
+
+/// Run a binary or example of the local package
+#[derive(Clone, Debug, Default, Parser)]
+#[clap(
+    setting = clap::AppSettings::DeriveDisplayOrder,
+    trailing_var_arg = true,
+    after_help = "Run `cargo help run` for more detailed information.")
+]
+pub struct Run {
+    #[clap(flatten)]
+    pub cargo: cargo_options::Run,
+}
+
+impl Run {
+    /// Create a new run from manifest path
+    #[allow(clippy::field_reassign_with_default)]
+    pub fn new(manifest_path: Option<PathBuf>) -> Self {
+        let mut build = Self::default();
+        build.manifest_path = manifest_path;
+        build
+    }
+
+    /// Execute `cargo run` command
+    pub fn execute(&self) -> Result<()> {
+        let build = Build {
+            cargo: self.cargo.clone().into(),
+            ..Default::default()
+        };
+        let mut run = build.build_command("run")?;
+        if !self.cargo.args.is_empty() {
+            run.arg("--");
+            run.args(&self.cargo.args);
+        }
+
+        let mut child = run.spawn().context("Failed to run cargo run")?;
+        let status = child.wait().expect("Failed to wait on cargo run process");
+        if !status.success() {
+            process::exit(status.code().unwrap_or(1));
+        }
+        Ok(())
+    }
+}
+
+impl Deref for Run {
+    type Target = cargo_options::Run;
+
+    fn deref(&self) -> &Self::Target {
+        &self.cargo
+    }
+}
+
+impl DerefMut for Run {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.cargo
+    }
+}
+
+impl From<cargo_options::Run> for Run {
+    fn from(cargo: cargo_options::Run) -> Self {
+        Self {
+            cargo,
+            ..Default::default()
+        }
+    }
+}


Test patch:
diff --git a/src/test.rs b/src/test.rs
new file mode 100644
index 0000000..efe1827
--- /dev/null
+++ b/src/test.rs
@@ -0,0 +1,85 @@
+use std::ops::{Deref, DerefMut};
+use std::path::PathBuf;
+use std::process;
+
+use anyhow::{Context, Result};
+use clap::Parser;
+
+use crate::Build;
+
+/// Execute all unit and integration tests and build examples of a local package
+#[derive(Clone, Debug, Default, Parser)]
+#[clap(
+    setting = clap::AppSettings::DeriveDisplayOrder,
+    trailing_var_arg = true,
+    after_help = "Run `cargo help test` for more detailed information.\nRun `cargo test -- --help` for test binary options.")
+]
+pub struct Test {
+    #[clap(flatten)]
+    pub cargo: cargo_options::Test,
+}
+
+impl Test {
+    /// Create a new test from manifest path
+    #[allow(clippy::field_reassign_with_default)]
+    pub fn new(manifest_path: Option<PathBuf>) -> Self {
+        let mut build = Self::default();
+        build.manifest_path = manifest_path;
+        build
+    }
+
+    /// Execute `cargo test` command
+    pub fn execute(&self) -> Result<()> {
+        let build = Build {
+            cargo: self.cargo.clone().into(),
+            ..Default::default()
+        };
+        let mut test = build.build_command("test")?;
+        if self.cargo.doc {
+            test.arg("--doc");
+        }
+        if self.cargo.no_run {
+            test.arg("--no-run");
+        }
+        if self.cargo.no_fail_fast {
+            test.arg("--no-fail-fast");
+        }
+        if let Some(test_name) = self.cargo.test_name.as_ref() {
+            test.arg(test_name);
+        }
+        if !self.cargo.args.is_empty() {
+            test.arg("--");
+            test.args(&self.cargo.args);
+        }
+
+        let mut child = test.spawn().context("Failed to run cargo test")?;
+        let status = child.wait().expect("Failed to wait on cargo test process");
+        if !status.success() {
+            process::exit(status.code().unwrap_or(1));
+        }
+        Ok(())
+    }
+}
+
+impl Deref for Test {
+    type Target = cargo_options::Test;
+
+    fn deref(&self) -> &Self::Target {
+        &self.cargo
+    }
+}
+
+impl DerefMut for Test {
+    fn deref_mut(&mut self) -> &mut Self::Target {
+        &mut self.cargo
+    }
+}
+
+impl From<cargo_options::Test> for Test {
+    fn from(cargo: cargo_options::Test) -> Self {
+        Self {
+            cargo,
+            ..Default::default()
+        }
+    }
+}