From ac6f4e4942accde4c3c4a8389c7e04b93a6f319d Mon Sep 17 00:00:00 2001 From: Alexander Koz Date: Sat, 6 Apr 2024 18:46:31 +0400 Subject: [PATCH 1/5] various fixes & improvements --- Cargo.lock | 4 +- cargo/Cargo.toml | 2 +- cargo/src/main.rs | 2 +- support/device/Cargo.toml | 2 +- support/device/src/device/methods.rs | 2 +- support/device/src/device/query.rs | 53 +++++++++++++++++++----- support/device/src/device/serial.rs | 47 +++++++++++---------- support/device/src/error.rs | 2 +- support/device/src/interface/async.rs | 33 +-------------- support/device/src/interface/blocking.rs | 4 -- support/device/src/interface/mod.rs | 5 +-- support/device/src/mount/methods.rs | 12 +++++- support/device/src/mount/mod.rs | 3 -- support/device/src/retry.rs | 25 +++++++++++ 14 files changed, 111 insertions(+), 85 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f1107cea..803b57a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -710,7 +710,7 @@ dependencies = [ [[package]] name = "cargo-playdate" -version = "0.4.0-beta.2" +version = "0.4.0-beta.3" dependencies = [ "anstyle", "anyhow", @@ -3849,7 +3849,7 @@ dependencies = [ [[package]] name = "playdate-device" -version = "0.2.2" +version = "0.2.3" dependencies = [ "async-std", "clap", diff --git a/cargo/Cargo.toml b/cargo/Cargo.toml index 0176f35e..c38ee146 100644 --- a/cargo/Cargo.toml +++ b/cargo/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cargo-playdate" -version = "0.4.0-beta.2" +version = "0.4.0-beta.3" readme = "README.md" description = "Build tool for neat yellow console." keywords = ["playdate", "build", "cargo", "plugin", "cargo-subcommand"] diff --git a/cargo/src/main.rs b/cargo/src/main.rs index 4d53b871..cbd6222c 100644 --- a/cargo/src/main.rs +++ b/cargo/src/main.rs @@ -189,7 +189,7 @@ fn execute(config: &Config) -> CargoResult<()> { .map(|m| m.device.value.as_ref()) .flatten() { - format!("on the '{}'", query.to_printable_string()).into() + format!("on the '{}'", query.to_value_string()).into() } else { "on a device".into() } diff --git a/support/device/Cargo.toml b/support/device/Cargo.toml index 97a48219..69558770 100644 --- a/support/device/Cargo.toml +++ b/support/device/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "playdate-device" -version = "0.2.2" +version = "0.2.3" readme = "README.md" description = "Cross-platform interface Playdate device, async & blocking." keywords = ["playdate", "usb", "serial"] diff --git a/support/device/src/device/methods.rs b/support/device/src/device/methods.rs index d0311f7b..b9c6e36e 100644 --- a/support/device/src/device/methods.rs +++ b/support/device/src/device/methods.rs @@ -49,7 +49,7 @@ pub async fn wait_mode_change(mut dev: Device, to: Mode, retry: Retries::Err; impl FromStr for Value { - type Err = crate::error::Error; + type Err = Error; fn from_str(dev: &str) -> Result { let name = dev.trim(); if name.is_empty() { - return Err(ParseError::from(name).into()); + return Err(error::ParseError::from(name).into()); } #[cfg(windows)] match name.strip_prefix("COM").map(|s| s.parse::()) { Some(Ok(com)) => return Ok(Value::Com(com)), Some(Err(err)) => { - use std::io::{Error, ErrorKind}; - - return Err(Error::new( - ErrorKind::InvalidInput, - format!("Invalid format, seems to COM port, but {err}."), - ).into()); + return Err(Error::invalid(format!("Invalid format, seems to COM port, but {err}."))); }, None => { /* nothing there */ }, } @@ -124,12 +119,12 @@ impl FromStr for Value { } impl<'s> TryFrom<&'s str> for Value { - type Error = crate::error::Error; + type Error = Error; fn try_from(dev: &'s str) -> Result { Self::from_str(dev) } } impl Value { - pub fn to_printable_string(&self) -> String { + pub fn to_value_string(&self) -> String { match self { Self::Serial(sn) => sn.to_string(), Self::Path(p) => p.display().to_string(), @@ -137,3 +132,39 @@ impl Value { } } } + + +pub mod error { + use std::backtrace::Backtrace; + use std::str::FromStr; + use thiserror::Error; + use miette::Diagnostic; + + pub type ParseError = ::Err; + + + #[derive(Error, Debug, Diagnostic)] + pub enum DeviceQueryError { + #[error(transparent)] + #[diagnostic(transparent)] + DeviceSerial { + #[backtrace] + #[from] + source: ParseError, + }, + + #[error("Invalid query format: {message}")] + Invalid { + message: String, + #[backtrace] + backtrace: Backtrace, + }, + } + + impl DeviceQueryError { + pub fn invalid(message: String) -> Self { + Self::Invalid { message, + backtrace: Backtrace::capture() } + } + } +} diff --git a/support/device/src/device/serial.rs b/support/device/src/device/serial.rs index c6ae4d04..e07a9375 100644 --- a/support/device/src/device/serial.rs +++ b/support/device/src/device/serial.rs @@ -37,9 +37,9 @@ impl SerialNumber { } impl FromStr for SerialNumber { - type Err = DeviceSerialFormatError; + type Err = error::SerialNumberFormatError; fn from_str(s: &str) -> Result { - Self::contained_in(s).ok_or_else(|| DeviceSerialFormatError::from(s)) + Self::contained_in(s).ok_or_else(|| error::SerialNumberFormatError::from(s)) } } @@ -82,30 +82,33 @@ impl std::fmt::Display for SerialNumber { } -use std::backtrace::Backtrace; -use thiserror::Error; -use miette::Diagnostic; +pub mod error { + use std::backtrace::Backtrace; + use thiserror::Error; + use miette::Diagnostic; -#[derive(Error, Debug, Diagnostic)] -#[error("Invalid serial number: {value}, expected format: PDUN-XNNNNNN.")] -pub struct DeviceSerialFormatError { - pub value: String, - #[backtrace] - backtrace: Backtrace, -} -impl DeviceSerialFormatError { - fn new(value: String) -> Self { - Self { value, - backtrace: Backtrace::capture() } + #[derive(Error, Debug, Diagnostic)] + #[error("invalid serial number `{value}`, expected format `PDUN-XNNNNNN`.")] + pub struct SerialNumberFormatError { + pub value: String, + #[backtrace] + backtrace: Backtrace, } -} -impl From for DeviceSerialFormatError { - fn from(value: String) -> Self { Self::new(value) } -} + impl SerialNumberFormatError { + fn new(value: String) -> Self { + Self { value, + backtrace: Backtrace::capture() } + } + } + + impl From for SerialNumberFormatError { + fn from(value: String) -> Self { Self::new(value) } + } -impl From<&str> for DeviceSerialFormatError { - fn from(value: &str) -> Self { Self::new(value.to_owned()) } + impl From<&str> for SerialNumberFormatError { + fn from(value: &str) -> Self { Self::new(value.to_owned()) } + } } diff --git a/support/device/src/error.rs b/support/device/src/error.rs index eec4aeab..34b4bf92 100644 --- a/support/device/src/error.rs +++ b/support/device/src/error.rs @@ -108,7 +108,7 @@ pub enum Error { DeviceSerial { #[backtrace] #[from] - source: crate::device::serial::DeviceSerialFormatError, + source: crate::device::serial::error::SerialNumberFormatError, }, #[error(transparent)] diff --git a/support/device/src/interface/async.rs b/support/device/src/interface/async.rs index dccbbc50..e6f88bfe 100644 --- a/support/device/src/interface/async.rs +++ b/support/device/src/interface/async.rs @@ -5,8 +5,6 @@ use crate::error::Error; pub trait Out: In { - // type Error: std::error::Error; - fn send(&self, data: &[u8]) -> impl Future>; fn send_cmd(&self, cmd: Command) -> impl Future> { @@ -27,36 +25,7 @@ pub trait Out: In { } } -pub trait In { - // type Error: std::error::Error = crate::error::Error; -} +pub trait In {} pub trait Interface: Out {} impl Interface for T {} - - -// pub trait AsyncSend { -// fn send_cmd(&mut self, -// cmd: crate::device::command::Command) -// -> impl std::future::Future>; -// } - - -// mod ext { -// use super::*; - - -// impl AsyncSend for T -// where T: tokio::io::AsyncWriteExt, -// Self: Unpin -// { -// #[cfg_attr(feature = "tracing", tracing::instrument(skip(self)))] -// async fn send_cmd(&mut self, cmd: crate::device::command::Command) -> Result { -// let cmd = cmd.with_break(); -// let bytes = cmd.as_bytes(); -// self.write_all(bytes).await?; -// self.flush().await?; -// Ok(bytes.len()) -// } -// } -// } diff --git a/support/device/src/interface/blocking.rs b/support/device/src/interface/blocking.rs index cdced8b8..b5cefca3 100644 --- a/support/device/src/interface/blocking.rs +++ b/support/device/src/interface/blocking.rs @@ -2,14 +2,10 @@ use crate::device::command::Command; use crate::error::Error; pub trait Out: In { - // type Error: std::error::Error = crate::error::Error; - - // fn send(&self, data: &[u8]) -> Result; fn send_cmd(&self, cmd: Command) -> Result; } pub trait In { - // type Error: std::error::Error = crate::error::Error; } pub trait Interface: In + Out {} diff --git a/support/device/src/interface/mod.rs b/support/device/src/interface/mod.rs index 8529986c..d268a3c5 100644 --- a/support/device/src/interface/mod.rs +++ b/support/device/src/interface/mod.rs @@ -65,7 +65,6 @@ impl r#async::In for Interface where crate::usb::Interface: r#async::In, crate::serial::Interface: r#async::In { - // type Error = Error; } @@ -79,6 +78,4 @@ impl blocking::Out for Interface { } } -impl blocking::In for Interface { - // type Error = crate::error::Error; -} +impl blocking::In for Interface {} diff --git a/support/device/src/mount/methods.rs b/support/device/src/mount/methods.rs index f06c92e4..24a802bd 100644 --- a/support/device/src/mount/methods.rs +++ b/support/device/src/mount/methods.rs @@ -312,7 +312,7 @@ async fn wait_mount_point(dev: Device, retry: Retries) -> Result Result>> { +pub async fn unmount(query: Query) -> Result> { match query.value { Some(QueryValue::Path(path)) => { // TODO: Check query is path and this is mounted volume. @@ -324,7 +324,15 @@ pub async fn unmount(query: Query) -> Result todo!("ERROR: not supported (impossible)"), Some(QueryValue::Serial(sn)) => unmount_mb_sn(Some(sn)), _ => unmount_mb_sn(None), - }.await + }.map_ok(|stream| { + stream.inspect(|(dev, res)| { + if let Some(err) = res.as_ref().err() { + error!("{dev}: {err}"); + warn!("Please press 'A' on the Playdate to exit Data Disk mode."); + } + }) + }) + .await } /// Unmount device(s), then wait for state change to [`Data`][usb::mode::Mode::Data]. diff --git a/support/device/src/mount/mod.rs b/support/device/src/mount/mod.rs index 59d02988..cba30b5c 100644 --- a/support/device/src/mount/mod.rs +++ b/support/device/src/mount/mod.rs @@ -21,9 +21,6 @@ mod methods; pub use methods::*; -// TODO: If unmount fails, do warn!("Please press 'A' on the Playdate to exit Data Disk mode.") - - // TODO: MountError for this module diff --git a/support/device/src/retry.rs b/support/device/src/retry.rs index b702d484..c94c14d4 100644 --- a/support/device/src/retry.rs +++ b/support/device/src/retry.rs @@ -88,3 +88,28 @@ impl IterTime for Duration { calc_interval(total_wait, self) } } + + +pub fn retry_blocking(retry: Retries, f: F) -> Result + where F: Fn() -> Result, + E: Into { + let total = &retry.total; + let iteration = retry.iters.interval(total); + let retries_num = total.as_millis() / iteration.as_millis(); + trace!("start retries: {retries_num} * {iteration:?} ≈ {total:?}."); + + let mut counter = retries_num; + loop { + trace!("try: {}/{retries_num}", retries_num - counter); + match f() { + Ok(r) => return Ok(r), + Err(e) => { + counter -= 1; + if counter == 0 { + return Err(e.into()); + } + std::thread::sleep(iteration); + }, + } + } +} From 313a2441c6a8f276e82bd35e66419ab7c8c4e397 Mon Sep 17 00:00:00 2001 From: Alexander Koz Date: Sat, 6 Apr 2024 18:49:28 +0400 Subject: [PATCH 2/5] fmt --- support/device/src/interface/blocking.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/support/device/src/interface/blocking.rs b/support/device/src/interface/blocking.rs index b5cefca3..92947222 100644 --- a/support/device/src/interface/blocking.rs +++ b/support/device/src/interface/blocking.rs @@ -5,8 +5,7 @@ pub trait Out: In { fn send_cmd(&self, cmd: Command) -> Result; } -pub trait In { -} +pub trait In {} pub trait Interface: In + Out {} // impl + Out, Err> Interface for T {} From e12391fe7fe38309251f7f97a7c8b4bc813321e5 Mon Sep 17 00:00:00 2001 From: Alexander Koz Date: Tue, 9 Apr 2024 13:39:23 +0400 Subject: [PATCH 3/5] fix path --- cargo/Cargo.toml | 4 ++++ support/device/src/mount/win.rs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/cargo/Cargo.toml b/cargo/Cargo.toml index c38ee146..d2e94445 100644 --- a/cargo/Cargo.toml +++ b/cargo/Cargo.toml @@ -93,3 +93,7 @@ rand = "0.8" [target.'cfg(unix)'.dev-dependencies] nix = { version = "0.28", features = ["signal"] } + + +[features] +eject = ["device/eject"] # windows only, enable one more unmount method diff --git a/support/device/src/mount/win.rs b/support/device/src/mount/win.rs index 9ebb17d9..3b4a9332 100644 --- a/support/device/src/mount/win.rs +++ b/support/device/src/mount/win.rs @@ -158,7 +158,7 @@ pub async fn volume_for(dev: &Device) -> Result { } let sn = dev.info().serial_number().ok_or_else(|| { - Error::DeviceSerial { source: crate::device::serial::DeviceSerialFormatError::from("missed") } + Error::DeviceSerial { source: crate::device::serial::error::DeviceSerialFormatError::from("missed sn") } })?; let sn = SerialNumber::try_from(sn)?; let dev_addr = dev.info().device_address() as u32; From 25f7a53a54bc5df88ea063ffccfe5c0fbedc1842 Mon Sep 17 00:00:00 2001 From: Alexander Koz Date: Tue, 9 Apr 2024 20:02:09 +0400 Subject: [PATCH 4/5] fix path --- support/device/src/mount/win.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/support/device/src/mount/win.rs b/support/device/src/mount/win.rs index 3b4a9332..03950afb 100644 --- a/support/device/src/mount/win.rs +++ b/support/device/src/mount/win.rs @@ -158,7 +158,7 @@ pub async fn volume_for(dev: &Device) -> Result { } let sn = dev.info().serial_number().ok_or_else(|| { - Error::DeviceSerial { source: crate::device::serial::error::DeviceSerialFormatError::from("missed sn") } + Error::DeviceSerial { source: crate::device::serial::error::SerialNumberFormatError::from("missed sn") } })?; let sn = SerialNumber::try_from(sn)?; let dev_addr = dev.info().device_address() as u32; From c99432cc53e10a3f998417ef8c9fd51941079e42 Mon Sep 17 00:00:00 2001 From: Alexander Koz Date: Tue, 9 Apr 2024 20:08:48 +0400 Subject: [PATCH 5/5] fix fmt check suggestions --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d5f59707..6ba4789a 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -370,6 +370,7 @@ jobs: run: cargo fmt --all - name: Suggest Changes + continue-on-error: true if: success() && (github.event_name == 'pull_request' || github.event_name == 'pull_request_target') # https://docs.github.com/en/rest/pulls/reviews?apiVersion=2022-11-28#create-a-review-for-a-pull-request uses: parkerbxyz/suggest-changes@v1