Skip to content

Commit

Permalink
Batch of CLI fixes and improvements (#629)
Browse files Browse the repository at this point in the history
  • Loading branch information
ia0 authored Oct 2, 2024
1 parent 2b9f548 commit 1ff81cc
Show file tree
Hide file tree
Showing 20 changed files with 199 additions and 72 deletions.
6 changes: 5 additions & 1 deletion crates/cli-tools/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

### Minor

- Extend `fs::write()` first parameter to set the `OpenOptions` too
- Add `error::root_cause_is()` to check the `anyhow::Error` root cause
- Add `action::PlatformLock` for locking a platform protocol
- Expose `action::Transfer` for transfers from host to device
- Add `action::AppletExitStatus` to get the applet exit status
Expand All @@ -25,8 +27,10 @@

### Patch

- Fix incorrect error with UNIX and TCP platform protocols
- Only print commands and file system operations when warnings are logged
- Update dependencies

## 0.1.0

<!-- Increment to skip CHANGELOG.md test: 5 -->
<!-- Increment to skip CHANGELOG.md test: 6 -->
1 change: 1 addition & 0 deletions crates/cli-tools/Cargo.lock

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

1 change: 1 addition & 0 deletions crates/cli-tools/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ cargo_metadata = { version = "0.18.1", default-features = false, optional = true
data-encoding = { version = "2.6.0", default-features = false, features = ["std"], optional = true }
humantime = { version = "2.1.0", default-features = false, optional = true }
indicatif = { version = "0.17.8", default-features = false, optional = true }
log = { version = "0.4.21", default-features = false }
rusb = { version = "0.9.4", default-features = false, optional = true }
serde = { version = "1.0.202", default-features = false, features = ["derive"] }
toml = { version = "0.8.13", default-features = false, features = ["display", "parse"] }
Expand Down
17 changes: 13 additions & 4 deletions crates/cli-tools/src/action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ use tokio::process::Command;
use wasefire_protocol::{self as service, applet, Connection, ConnectionExt};
use wasefire_wire::{self as wire, Yoke};

use crate::error::root_cause_is;
use crate::{cmd, fs};

mod protocol;
Expand Down Expand Up @@ -373,10 +374,18 @@ async fn final_call<S: service::Service>(
connection.send(&S::request(request)).await?;
match connection.receive::<S>().await {
Ok(x) => proof(x)?,
Err(e) => match e.downcast_ref::<rusb::Error>() {
Some(rusb::Error::NoDevice) => Ok(()),
_ => Err(e),
},
Err(e) => {
if root_cause_is::<rusb::Error>(&e, |x| matches!(x, rusb::Error::NoDevice)) {
return Ok(());
}
if root_cause_is::<std::io::Error>(&e, |x| {
use std::io::ErrorKind::*;
matches!(x.kind(), NotConnected | BrokenPipe | UnexpectedEof)
}) {
return Ok(());
}
Err(e)
}
}
}

Expand Down
24 changes: 24 additions & 0 deletions crates/cli-tools/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright 2024 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::error::Error;

/// Checks the root cause of an error.
///
/// Returns whether the root cause of the error is of the provided type and satisfies the predicate.
pub fn root_cause_is<E: Error + Send + Sync + 'static>(
error: &anyhow::Error, predicate: impl FnOnce(&E) -> bool,
) -> bool {
error.root_cause().downcast_ref::<E>().map_or(false, predicate)
}
60 changes: 56 additions & 4 deletions crates/cli-tools/src/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@
//! Wrappers around `tokio::fs` with descriptive errors.

use std::fs::Metadata;
use std::future::Future;
use std::io::ErrorKind;
use std::path::{Component, Path, PathBuf};

use anyhow::{Context, Result};
use serde::de::DeserializeOwned;
use serde::Serialize;
use tokio::fs::{File, OpenOptions};
use tokio::io::{AsyncReadExt, AsyncWriteExt};

pub async fn canonicalize(path: impl AsRef<Path>) -> Result<PathBuf> {
Expand Down Expand Up @@ -144,12 +146,62 @@ pub async fn touch(path: impl AsRef<Path>) -> Result<()> {
write(path, "").await
}

pub async fn write(path: impl AsRef<Path>, contents: impl AsRef<[u8]>) -> Result<()> {
let name = path.as_ref().display();
pub struct WriteParams<P: AsRef<Path>> {
path: P,
options: OpenOptions,
}

impl<P: AsRef<Path>> WriteParams<P> {
pub fn new(path: P) -> Self {
WriteParams { path, options: OpenOptions::new() }
}
pub fn options(&mut self) -> &mut OpenOptions {
&mut self.options
}
}

pub trait WriteFile {
fn path(&self) -> &Path;
fn open(self) -> impl Future<Output = Result<File>>;
}

impl<P: AsRef<Path>> WriteFile for WriteParams<P> {
fn path(&self) -> &Path {
self.path.as_ref()
}
async fn open(self) -> Result<File> {
(&self).open().await
}
}

impl<P: AsRef<Path>> WriteFile for &WriteParams<P> {
fn path(&self) -> &Path {
(*self).path()
}
async fn open(self) -> Result<File> {
Ok(self.options.open(&self.path).await?)
}
}

impl<P: AsRef<Path>> WriteFile for P {
fn path(&self) -> &Path {
self.as_ref()
}
async fn open(self) -> Result<File> {
let mut params = WriteParams::new(self);
params.options().write(true).create(true).truncate(true);
params.open().await
}
}

pub async fn write(file: impl WriteFile, contents: impl AsRef<[u8]>) -> Result<()> {
let name = format!("{}", file.path().display());
let contents = contents.as_ref();
create_parent(path.as_ref()).await?;
create_parent(file.path()).await?;
debug!("write > {name:?}");
tokio::fs::write(path.as_ref(), contents).await.with_context(|| format!("writing {name}"))?;
let mut file = file.open().await.with_context(|| format!("creating {name}"))?;
file.write_all(contents).await.with_context(|| format!("writing {name}"))?;
file.flush().await.with_context(|| format!("flushing {name}"))?;
Ok(())
}

Expand Down
9 changes: 6 additions & 3 deletions crates/cli-tools/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@

macro_rules! debug {
($($x:tt)*) => {
print!("\x1b[1;36m");
print!($($x)*);
println!("\x1b[m");
if log::log_enabled!(log::Level::Warn) {
print!("\x1b[1;36m");
print!($($x)*);
println!("\x1b[m");
}
};
}

#[cfg(feature = "action")]
pub mod action;
pub mod cmd;
pub mod error;
pub mod fs;
1 change: 1 addition & 0 deletions crates/cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

### Minor

- Support `RUST_LOG` to control logging
- Add `platform-lock` to lock a platform protocol
- Add `applet-exit-status` to get an applet exit status
- Implement `applet-{install,uninstall}` for applet management
Expand Down
63 changes: 63 additions & 0 deletions crates/cli/Cargo.lock

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

1 change: 1 addition & 0 deletions crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ path = "src/main.rs"
anyhow = { version = "1.0.86", default-features = false }
clap = { version = "4.5.4", default-features = false, features = ["default", "derive", "env"] }
clap_complete = { version = "4.5.2", default-features = false }
env_logger = { version = "0.11.3", default-features = false, features = ["default"] }
wasefire-cli-tools = { version = "0.2.0-git", path = "../cli-tools", features = ["action"] }

[dependencies.tokio]
Expand Down
2 changes: 2 additions & 0 deletions crates/cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ enum Action {
#[command(flatten)]
action: action::AppletRpc,
},

PlatformList(action::PlatformList),

/// Prints the platform update metadata (possibly binary output).
Expand Down Expand Up @@ -170,6 +171,7 @@ impl Completion {

#[tokio::main]
async fn main() -> Result<()> {
env_logger::init();
let flags = Flags::parse();
let dir = std::env::current_dir()?;
match flags.action {
Expand Down
2 changes: 1 addition & 1 deletion crates/protocol-tokio/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

## 0.1.0-git

<!-- Increment to skip CHANGELOG.md test: 7 -->
<!-- Increment to skip CHANGELOG.md test: 8 -->
6 changes: 3 additions & 3 deletions crates/protocol-tokio/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ features = ["device"]
[dependencies]
anyhow = { version = "1.0.86", default-features = false, features = ["std"] }
wasefire-error = { version = "0.1.2-git", path = "../error", optional = true }
wasefire-logger = { version = "0.1.6-git", path = "../logger" }
wasefire-logger = { version = "0.1.6-git", path = "../logger", optional = true }
wasefire-one-of = { version = "0.1.0-git", path = "../one-of" }

[dependencies.tokio]
Expand All @@ -38,9 +38,9 @@ features = ["host"]
optional = true

[features]
log = ["wasefire-board-api?/log", "wasefire-logger/log"]
log = ["wasefire-board-api?/log", "wasefire-logger?/log"]
# Exactly one of host or device must be selected.
device = ["dep:wasefire-board-api", "dep:wasefire-error"]
device = ["dep:wasefire-board-api", "dep:wasefire-error", "dep:wasefire-logger"]
host = ["dep:wasefire-protocol"]

[lints]
Expand Down
Loading

0 comments on commit 1ff81cc

Please sign in to comment.