Skip to content

Commit cdddf53

Browse files
jneemSergioGasquez
andauthored
If exactly one port matches, use it (#374)
* If exactly one port matches, use it * Update espflash/src/cli/serial.rs Co-authored-by: Sergio Gasquez Arcos <[email protected]> --------- Co-authored-by: Sergio Gasquez Arcos <[email protected]>
1 parent 8d9973e commit cdddf53

File tree

1 file changed

+41
-63
lines changed

1 file changed

+41
-63
lines changed

espflash/src/cli/serial.rs

Lines changed: 41 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
1-
use std::cmp::Ordering;
21
#[cfg(not(target_os = "windows"))]
32
use std::fs;
43

54
use crossterm::style::Stylize;
65
use dialoguer::{theme::ColorfulTheme, Confirm, Select};
76
use log::{error, info};
87
use miette::{IntoDiagnostic, Result};
9-
use serialport::{available_ports, SerialPortInfo, SerialPortType, UsbPortInfo};
8+
use serialport::{available_ports, SerialPortInfo, SerialPortType};
109

1110
use crate::{
1211
cli::{config::UsbDevice, Config, ConnectArgs},
@@ -26,7 +25,7 @@ pub fn get_serial_port_info(
2625
// Users may optionally specify the device's VID and PID in the configuration
2726
// file. If no VID/PID has been provided, the user will always be prompted to
2827
// select a serial port. If some VID and PID were provided then the user will
29-
// also be prompted to select a port, unless there is only one found and its VID
28+
// also be prompted to select a port, unless there is only one found whose VID
3029
// and PID match the configured values.
3130
//
3231
// The call to canonicalize() was originally added to resolve
@@ -186,53 +185,50 @@ fn select_serial_port(
186185
mut ports: Vec<SerialPortInfo>,
187186
config: &Config,
188187
) -> Result<(SerialPortInfo, bool), Error> {
189-
fn device_matches(config: &Config, info: &UsbPortInfo) -> bool {
190-
config
188+
// Does this port match a known one?
189+
let matches = |port: &SerialPortInfo| match &port.port_type {
190+
SerialPortType::UsbPort(info) => config
191191
.usb_device
192192
.iter()
193193
.chain(KNOWN_DEVICES.iter())
194-
.any(|dev| dev.matches(info))
195-
}
194+
.any(|dev| dev.matches(info)),
195+
_ => false,
196+
};
196197

197-
if ports.len() > 1 {
198-
// Multiple serial ports detected
198+
if let [port] = ports
199+
.iter()
200+
.filter(|&p| matches(p))
201+
.collect::<Vec<_>>()
202+
.as_slice()
203+
{
204+
// There is a unique recognized device.
205+
Ok(((*port).to_owned(), true))
206+
} else if ports.len() > 1 {
207+
// Multiple serial ports detected.
199208
info!("Detected {} serial ports", ports.len());
200209
info!("Ports which match a known common dev board are highlighted");
201210
info!("Please select a port");
202211

203-
ports.sort_by(|a, b| {
204-
let a_matches = match &a.port_type {
205-
SerialPortType::UsbPort(info) => device_matches(config, info),
206-
_ => false,
207-
};
208-
let b_matches = match &b.port_type {
209-
SerialPortType::UsbPort(info) => device_matches(config, info),
210-
_ => false,
211-
};
212-
match (a_matches, b_matches) {
213-
(true, true) | (false, false) => Ordering::Equal,
214-
(true, false) => Ordering::Less,
215-
(false, true) => Ordering::Greater,
216-
}
217-
});
212+
ports.sort_by_key(|a| !matches(a));
218213

219214
let port_names = ports
220215
.iter()
221-
.map(|port_info| match &port_info.port_type {
222-
SerialPortType::UsbPort(info) => {
223-
let formatted = if device_matches(config, info) {
224-
port_info.port_name.as_str().bold()
225-
} else {
226-
port_info.port_name.as_str().reset()
227-
};
228-
229-
if let Some(product) = &info.product {
230-
format!("{} - {}", formatted, product)
231-
} else {
232-
formatted.to_string()
216+
.map(|port_info| {
217+
let formatted = if matches(port_info) {
218+
port_info.port_name.as_str().bold()
219+
} else {
220+
port_info.port_name.as_str().reset()
221+
};
222+
match &port_info.port_type {
223+
SerialPortType::UsbPort(info) => {
224+
if let Some(product) = &info.product {
225+
format!("{} - {}", formatted, product)
226+
} else {
227+
formatted.to_string()
228+
}
233229
}
230+
_ => formatted.to_string(),
234231
}
235-
_ => port_info.port_name.clone(),
236232
})
237233
.collect::<Vec<_>>();
238234

@@ -250,37 +246,19 @@ fn select_serial_port(
250246
.ok_or(Error::Cancelled)?;
251247

252248
match ports.get(index) {
253-
Some(port_info) => {
254-
let matches = if let SerialPortType::UsbPort(usb_info) = &port_info.port_type {
255-
device_matches(config, usb_info)
256-
} else {
257-
false
258-
};
259-
260-
Ok((port_info.to_owned(), matches))
261-
}
249+
Some(port_info) => Ok((port_info.to_owned(), matches(port_info))),
262250
None => Err(Error::SerialNotFound(
263251
port_names.get(index).unwrap().to_string(),
264252
)),
265253
}
266254
} else if let [port] = ports.as_slice() {
267-
// Single serial port detected
255+
// A single port, but we didn't recognize it. Prompt for confirmation.
268256
let port_name = port.port_name.clone();
269-
let port_info = match &port.port_type {
270-
SerialPortType::UsbPort(info) => info,
271-
SerialPortType::PciPort | SerialPortType::Unknown => &UsbPortInfo {
272-
vid: 0,
273-
pid: 0,
274-
serial_number: None,
275-
manufacturer: None,
276-
product: None,
277-
},
278-
_ => unreachable!(),
257+
let product = match &port.port_type {
258+
SerialPortType::UsbPort(info) => info.product.as_ref(),
259+
_ => None,
279260
};
280-
281-
if device_matches(config, port_info) {
282-
Ok((port.to_owned(), true))
283-
} else if confirm_port(&port_name, port_info)? {
261+
if confirm_port(&port_name, product)? {
284262
Ok((port.to_owned(), false))
285263
} else {
286264
Err(Error::SerialNotFound(port_name))
@@ -292,10 +270,10 @@ fn select_serial_port(
292270
}
293271

294272
/// Ask the user to confirm the use of a serial port.
295-
fn confirm_port(port_name: &str, port_info: &UsbPortInfo) -> Result<bool, Error> {
273+
fn confirm_port(port_name: &str, product: Option<&String>) -> Result<bool, Error> {
296274
Confirm::with_theme(&ColorfulTheme::default())
297275
.with_prompt({
298-
if let Some(product) = &port_info.product {
276+
if let Some(product) = product {
299277
format!("Use serial port '{}' - {}?", port_name, product)
300278
} else {
301279
format!("Use serial port '{}'?", port_name)

0 commit comments

Comments
 (0)