From 2cae44b1a3e618ec0b0500a1443ec4a108931499 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 27 Nov 2021 17:00:03 +0100 Subject: [PATCH 1/2] ask to save vid/pid in config if an unrecognized adapter is used --- cargo-espflash/src/main.rs | 2 +- espflash/Cargo.toml | 1 + espflash/src/cli/config.rs | 43 +++++++++++++++++++------ espflash/src/cli/serial.rs | 64 ++++++++++++++++++++++++++++---------- espflash/src/main.rs | 2 +- 5 files changed, 83 insertions(+), 29 deletions(-) diff --git a/cargo-espflash/src/main.rs b/cargo-espflash/src/main.rs index 9c9c2ca5..9a1424f9 100644 --- a/cargo-espflash/src/main.rs +++ b/cargo-espflash/src/main.rs @@ -61,7 +61,7 @@ fn main() -> Result<()> { let CargoSubCommand::Espflash(opts) = Opts::parse().sub_cmd; - let config = Config::load(); + let config = Config::load()?; let metadata = CargoEspFlashMeta::load("Cargo.toml")?; let cargo_config = parse_cargo_config(".")?; diff --git a/espflash/Cargo.toml b/espflash/Cargo.toml index c8670647..07abd74a 100644 --- a/espflash/Cargo.toml +++ b/espflash/Cargo.toml @@ -38,6 +38,7 @@ miette = { version = "3", features = ["fancy"] } crossterm = "0.22" directories-next = "2" dialoguer = "0.9" +serde-hex = "0.1" [package.metadata.binstall] pkg-url = "{ repo }/releases/download/v{ version }/{ name }" diff --git a/espflash/src/cli/config.rs b/espflash/src/cli/config.rs index f36ecf15..fe662cc7 100644 --- a/espflash/src/cli/config.rs +++ b/espflash/src/cli/config.rs @@ -1,25 +1,31 @@ -use std::fs::read; - use directories_next::ProjectDirs; -use serde::Deserialize; +use miette::{IntoDiagnostic, Result, WrapErr}; +use serde::{Deserialize, Serialize}; +use serde_hex::{Compact, SerHex}; use serialport::UsbPortInfo; +use std::fs::{create_dir_all, read, write}; +use std::path::PathBuf; -#[derive(Debug, Deserialize, Default)] +#[derive(Debug, Deserialize, Serialize, Default, Clone)] pub struct Config { #[serde(default)] pub connection: Connection, #[serde(default)] pub usb_device: Vec, + #[serde(skip)] + save_path: PathBuf, } -#[derive(Debug, Deserialize, Default)] +#[derive(Debug, Deserialize, Serialize, Default, Clone)] pub struct Connection { pub serial: Option, } -#[derive(Debug, Deserialize, Default)] +#[derive(Debug, Deserialize, Serialize, Default, Clone)] pub struct UsbDevice { + #[serde(with = "SerHex::")] pub vid: u16, + #[serde(with = "SerHex::")] pub pid: u16, } @@ -31,14 +37,31 @@ impl UsbDevice { impl Config { /// Load the config from config file - pub fn load() -> Self { + pub fn load() -> Result { let dirs = ProjectDirs::from("rs", "esp", "espflash").unwrap(); let file = dirs.config_dir().join("espflash.toml"); - if let Ok(data) = read(&file) { - toml::from_slice(&data).unwrap() + let mut config = if let Ok(data) = read(&file) { + toml::from_slice(&data).into_diagnostic()? } else { Self::default() - } + }; + config.save_path = file; + Ok(config) + } + + pub fn save_with(&self, modify_fn: F) -> Result<()> { + let mut copy = self.clone(); + modify_fn(&mut copy); + + let serialized = toml::to_string(©) + .into_diagnostic() + .wrap_err("Failed to serialize config")?; + create_dir_all(self.save_path.parent().unwrap()) + .into_diagnostic() + .wrap_err("Failed to create config directory")?; + write(&self.save_path, serialized) + .into_diagnostic() + .wrap_err_with(|| format!("Failed to write config to {}", self.save_path.display())) } } diff --git a/espflash/src/cli/serial.rs b/espflash/src/cli/serial.rs index 3c3071f3..5f11c72d 100644 --- a/espflash/src/cli/serial.rs +++ b/espflash/src/cli/serial.rs @@ -23,7 +23,27 @@ pub fn get_serial_port(matches: &ConnectArgs, config: &Config) -> Result { + if Confirm::with_theme(&ColorfulTheme::default()) + .with_prompt("Remember this serial port for future use?") + .interact_opt()? + .unwrap_or_default() + { + if let Err(e) = config.save_with(|config| { + config.usb_device.push(UsbDevice { + vid: usb_info.vid, + pid: usb_info.pid, + }) + }) { + eprintln!("Failed to save config {:#}", e); + } + } + } + _ => {} + } + Ok(port.port_name) } else { Err(Error::NoSerial) } @@ -56,10 +76,11 @@ const KNOWN_DEVICES: &[UsbDevice] = &[ fn select_serial_port( ports: Vec, - configured_devices: &[UsbDevice], -) -> Result { + config: &Config, +) -> Result<(SerialPortInfo, bool), Error> { let device_matches = |info| { - configured_devices + config + .usb_device .iter() .chain(KNOWN_DEVICES.iter()) .any(|dev| dev.matches(info)) @@ -97,7 +118,15 @@ fn select_serial_port( .ok_or(Error::Canceled)?; match ports.get(index) { - Some(port_info) => Ok(port_info.port_name.to_owned()), + Some( + port_info + @ + SerialPortInfo { + port_type: SerialPortType::UsbPort(usb_info), + .. + }, + ) => Ok((port_info.clone(), device_matches(usb_info))), + Some(port_info) => Ok((port_info.clone(), false)), None => Err(Error::NoSerial), } } else if let [port] = ports.as_slice() { @@ -108,19 +137,20 @@ fn select_serial_port( _ => unreachable!(), }; - if device_matches(port_info) - || Confirm::with_theme(&ColorfulTheme::default()) - .with_prompt({ - if let Some(product) = &port_info.product { - format!("Use serial port '{}' - {}?", port_name, product) - } else { - format!("Use serial port '{}'?", port_name) - } - }) - .interact_opt()? - .ok_or(Error::Canceled)? + if device_matches(port_info) { + Ok((port.clone(), true)) + } else if Confirm::with_theme(&ColorfulTheme::default()) + .with_prompt({ + if let Some(product) = &port_info.product { + format!("Use serial port '{}' - {}?", port_name, product) + } else { + format!("Use serial port '{}'?", port_name) + } + }) + .interact_opt()? + .ok_or(Error::Canceled)? { - Ok(port_name) + Ok((port.clone(), false)) } else { Err(Error::NoSerial) } diff --git a/espflash/src/main.rs b/espflash/src/main.rs index c32618d8..aaafe7be 100644 --- a/espflash/src/main.rs +++ b/espflash/src/main.rs @@ -52,7 +52,7 @@ fn main() -> Result<()> { miette::set_panic_hook(); let mut opts = Opts::parse(); - let config = Config::load(); + let config = Config::load()?; // If only a single argument is passed, it's always going to be the ELF file. In // the case that the serial port was not provided as a command-line argument, From f6c8496c626dbadbf4a11fe7b1c8d3d80daff5e1 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Sat, 27 Nov 2021 17:07:25 +0100 Subject: [PATCH 2/2] bumb msrv to 1.56 --- .github/workflows/rust.yml | 2 +- README.md | 2 +- cargo-espflash/Cargo.toml | 2 +- espflash/Cargo.toml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 1137b4de..37bb89fa 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -159,7 +159,7 @@ jobs: - uses: actions-rs/toolchain@v1 with: profile: minimal - toolchain: 1.55 + toolchain: 1.56 override: true - uses: Swatinem/rust-cache@v1 - uses: actions-rs/cargo@v1 diff --git a/README.md b/README.md index 37769c03..4b517c6f 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ This repository contains two applications: | [cargo-espflash] | Cargo subcommand for espflash | | [espflash] | Library and `espflash` binary (_without_ Cargo integration) | -> **NOTE:** requires `rustc >= 1.55.0` in order to build either application +> **NOTE:** requires `rustc >= 1.56.0` in order to build either application ## Installation diff --git a/cargo-espflash/Cargo.toml b/cargo-espflash/Cargo.toml index 2646260b..08bc2f2e 100644 --- a/cargo-espflash/Cargo.toml +++ b/cargo-espflash/Cargo.toml @@ -6,7 +6,7 @@ authors = [ "Jesse Braham ", ] edition = "2018" -rust-version = "1.55" +rust-version = "1.56" description = "Cargo subcommand for flashing Espressif devices over serial" repository = "https://github.com/esp-rs/espflash" license = "GPL-2.0" diff --git a/espflash/Cargo.toml b/espflash/Cargo.toml index 07abd74a..d51fbc36 100644 --- a/espflash/Cargo.toml +++ b/espflash/Cargo.toml @@ -3,7 +3,7 @@ name = "espflash" version = "1.1.0" authors = ["Robin Appelman "] edition = "2018" -rust-version = "1.55" +rust-version = "1.56" license = "GPL-2.0" description = "ESP8266 and ESP32 serial flasher" repository = "https://github.com/esp-rs/espflash"