Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make all CLIs async using tokio #601

Merged
merged 2 commits into from
Sep 6, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/cli-tools/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

### Major

- Change all actions requiring a connection to use async
- Change API to be async using tokio

### Minor

Expand Down
11 changes: 11 additions & 0 deletions crates/cli-tools/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions crates/cli-tools/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ toml = { version = "0.8.13", default-features = false, features = ["display", "p
wasefire-protocol = { version = "0.1.1-git", path = "../protocol", features = ["host"] }
wasefire-wire = { version = "0.1.1-git", path = "../wire" }

[dependencies.tokio]
version = "1.37.0"
default-features = false
features = ["fs", "io-std", "process", "rt"]

[dependencies.wasefire-protocol-tokio]
version = "0.1.0-git"
path = "../protocol-tokio"
Expand Down
66 changes: 36 additions & 30 deletions crates/cli-tools/src/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@

use std::fmt::Display;
use std::path::{Path, PathBuf};
use std::process::Command;

use anyhow::{bail, ensure, Result};
use cargo_metadata::{Metadata, MetadataCommand};
use clap::{ValueEnum, ValueHint};
use rusb::GlobalContext;
use tokio::process::Command;
use wasefire_protocol::{self as service, applet, Api, Connection, ConnectionExt};

use crate::{cmd, fs};
Expand Down Expand Up @@ -65,17 +65,17 @@ pub struct Rpc {
}

impl Rpc {
fn read(&self) -> Result<Vec<u8>> {
async fn read(&self) -> Result<Vec<u8>> {
match &self.input {
Some(path) => fs::read(path),
None => fs::read_stdin(),
Some(path) => fs::read(path).await,
None => fs::read_stdin().await,
}
}

fn write(&self, response: &[u8]) -> Result<()> {
async fn write(&self, response: &[u8]) -> Result<()> {
match &self.output {
Some(path) => fs::write(path, response),
None => fs::write_stdout(response),
Some(path) => fs::write(path, response).await,
None => fs::write_stdout(response).await,
}
}
}
Expand All @@ -101,12 +101,12 @@ impl AppletRpc {
Some(_) => bail!("applet identifiers are not supported yet"),
None => applet::AppletId,
};
let request = applet::Request { applet_id, request: &rpc.read()? };
let request = applet::Request { applet_id, request: &rpc.read().await? };
connection.call::<service::AppletRequest>(request).await?.get();
for _ in 0 .. retries {
let response = connection.call::<service::AppletResponse>(applet_id).await?;
if let Some(response) = response.get().response {
return rpc.write(response);
return rpc.write(response).await;
}
}
bail!("did not receive a response after {retries} retries");
Expand Down Expand Up @@ -168,7 +168,9 @@ pub struct PlatformRpc {
impl PlatformRpc {
pub async fn run(self, connection: &mut dyn Connection) -> Result<()> {
let PlatformRpc { rpc } = self;
rpc.write(connection.call::<service::PlatformVendor>(&rpc.read()?).await?.get())
let request = rpc.read().await?;
let response = connection.call::<service::PlatformVendor>(&request).await?;
rpc.write(response.get()).await
}
}

Expand All @@ -185,25 +187,25 @@ pub struct RustAppletNew {
}

impl RustAppletNew {
pub fn run(&self) -> Result<()> {
pub async fn run(&self) -> Result<()> {
let RustAppletNew { path, name } = self;
let mut cargo = Command::new("cargo");
cargo.args(["new", "--lib"]).arg(path);
if let Some(name) = name {
cargo.arg(format!("--name={name}"));
}
cmd::execute(&mut cargo)?;
cmd::execute(Command::new("cargo").args(["add", "wasefire"]).current_dir(path))?;
cmd::execute(&mut cargo).await?;
cmd::execute(Command::new("cargo").args(["add", "wasefire"]).current_dir(path)).await?;
let mut cargo = Command::new("cargo");
cargo.args(["add", "wasefire-stub", "--optional"]);
cmd::execute(cargo.current_dir(path))?;
cmd::execute(cargo.current_dir(path)).await?;
let mut sed = Command::new("sed");
sed.arg("-i");
sed.arg("s#^wasefire-stub\\( = .\"dep:wasefire-stub\"\\)#test\\1, \"wasefire/test\"#");
sed.arg("Cargo.toml");
cmd::execute(sed.current_dir(path))?;
std::fs::remove_file(path.join("src/lib.rs"))?;
fs::write(path.join("src/lib.rs"), include_str!("data/lib.rs"))?;
cmd::execute(sed.current_dir(path)).await?;
tokio::fs::remove_file(path.join("src/lib.rs")).await?;
fs::write(path.join("src/lib.rs"), include_str!("data/lib.rs")).await?;
Ok(())
}
}
Expand Down Expand Up @@ -241,10 +243,11 @@ pub struct RustAppletBuild {
}

impl RustAppletBuild {
pub fn run(&self, dir: impl AsRef<Path>) -> Result<()> {
let metadata = metadata(dir.as_ref())?;
pub async fn run(&self, dir: impl AsRef<Path>) -> Result<()> {
let metadata = metadata(dir.as_ref()).await?;
let package = &metadata.packages[0];
let target_dir = fs::try_relative(std::env::current_dir()?, &metadata.target_directory)?;
let target_dir =
fs::try_relative(std::env::current_dir()?, &metadata.target_directory).await?;
let name = package.name.replace('-', "_");
let mut cargo = Command::new("cargo");
let mut rustflags = Vec::new();
Expand Down Expand Up @@ -284,7 +287,7 @@ impl RustAppletBuild {
}
cargo.env("RUSTFLAGS", rustflags.join(" "));
cargo.current_dir(dir);
cmd::execute(&mut cargo)?;
cmd::execute(&mut cargo).await?;
let out_dir = match &self.output {
Some(x) => x.clone(),
None => "target/wasefire".into(),
Expand All @@ -294,8 +297,8 @@ impl RustAppletBuild {
Some(target) => (format!("{target}/{profile}/lib{name}.a"), "libapplet.a"),
};
let applet = out_dir.join(dst);
if fs::copy_if_changed(target_dir.join(src), &applet)? && dst.ends_with(".wasm") {
optimize_wasm(&applet, self.opt_level)?;
if fs::copy_if_changed(target_dir.join(src), &applet).await? && dst.ends_with(".wasm") {
optimize_wasm(&applet, self.opt_level).await?;
}
Ok(())
}
Expand All @@ -310,8 +313,8 @@ pub struct RustAppletTest {
}

impl RustAppletTest {
pub fn run(&self, dir: impl AsRef<Path>) -> Result<()> {
let metadata = metadata(dir.as_ref())?;
pub async fn run(&self, dir: impl AsRef<Path>) -> Result<()> {
let metadata = metadata(dir.as_ref()).await?;
let package = &metadata.packages[0];
ensure!(package.features.contains_key("test"), "missing test feature");
let mut cargo = Command::new("cargo");
Expand Down Expand Up @@ -357,10 +360,10 @@ impl Display for OptLevel {
}

/// Strips and optimizes a WASM applet.
pub fn optimize_wasm(applet: impl AsRef<Path>, opt_level: Option<OptLevel>) -> Result<()> {
pub async fn optimize_wasm(applet: impl AsRef<Path>, opt_level: Option<OptLevel>) -> Result<()> {
let mut strip = Command::new("wasm-strip");
strip.arg(applet.as_ref());
cmd::execute(&mut strip)?;
cmd::execute(&mut strip).await?;
let mut opt = Command::new("wasm-opt");
opt.args(["--enable-bulk-memory", "--enable-sign-ext", "--enable-mutable-globals"]);
match opt_level {
Expand All @@ -370,12 +373,15 @@ pub fn optimize_wasm(applet: impl AsRef<Path>, opt_level: Option<OptLevel>) -> R
opt.arg(applet.as_ref());
opt.arg("-o");
opt.arg(applet.as_ref());
cmd::execute(&mut opt)?;
cmd::execute(&mut opt).await?;
Ok(())
}

fn metadata(dir: impl Into<PathBuf>) -> Result<Metadata> {
let metadata = MetadataCommand::new().current_dir(dir).no_deps().exec()?;
async fn metadata(dir: impl Into<PathBuf>) -> Result<Metadata> {
let dir = dir.into();
let metadata =
tokio::task::spawn_blocking(|| MetadataCommand::new().current_dir(dir).no_deps().exec())
ia0 marked this conversation as resolved.
Show resolved Hide resolved
.await??;
ensure!(metadata.packages.len() == 1, "not exactly one package");
Ok(metadata)
}
Expand Down
25 changes: 13 additions & 12 deletions crates/cli-tools/src/cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,38 +12,39 @@
// See the License for the specific language governing permissions and
// limitations under the License.

//! Helpers around `std::process::Command`.
//! Helpers around `tokio::process::Command`.

use std::os::unix::process::CommandExt;
use std::process::{Command, Output};
use std::process::Output;

use anyhow::{ensure, Context, Result};
use tokio::process::Command;

/// Executes a command making sure it's successful.
pub fn execute(command: &mut Command) -> Result<()> {
debug!("{command:?}");
let code = command.spawn()?.wait()?.code().context("no error code")?;
pub async fn execute(command: &mut Command) -> Result<()> {
debug!("{:?}", command.as_std());
let code = command.spawn()?.wait().await?.code().context("no error code")?;
ensure!(code == 0, "failed with code {code}");
Ok(())
}

/// Replaces the current program with the command.
pub fn replace(mut command: Command) -> ! {
debug!("{command:?}");
panic!("{}", command.exec());
debug!("{:?}", command.as_std());
panic!("{}", command.as_std_mut().exec());
}

/// Executes the command making sure it's successful and returns its output.
pub fn output(command: &mut Command) -> Result<Output> {
debug!("{command:?}");
let output = command.output()?;
pub async fn output(command: &mut Command) -> Result<Output> {
debug!("{:?}", command.as_std());
let output = command.output().await?;
ensure!(output.status.success(), "failed with status {}", output.status);
Ok(output)
}

/// Executes the command making sure it's successful and returns exactly one line.
pub fn output_line(command: &mut Command) -> Result<String> {
let mut output = output(command)?;
pub async fn output_line(command: &mut Command) -> Result<String> {
let mut output = output(command).await?;
assert!(output.stderr.is_empty());
assert_eq!(output.stdout.pop(), Some(b'\n'));
Ok(String::from_utf8(output.stdout)?)
Expand Down
Loading
Loading