Skip to content

Commit 2e3f3c3

Browse files
Move non-interactive flag to connect args (#906)
* fix: Move non-interactive flag to connect args * feat: Update changelog * fix: Update cargo-espflash * feat: Filter "dev/tty.*" ports in macos
1 parent c50eb97 commit 2e3f3c3

File tree

7 files changed

+73
-17
lines changed

7 files changed

+73
-17
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3434
- Update checks can now be skipped by setting the the `ESPFLASH_SKIP_UPDATE_CHECK` environment variable (#900)
3535
- `flash_write_size` and `max_ram_block_size` functions no longer take a connection parameter and return a Result type (#903)
3636
- `DefaultProgressCallback` which implements `ProgressCallbacks` but all methods are no-ops (#904)
37+
- Update checks can now be skipped by setting the `ESPFLASH_SKIP_UPDATE_CHECK` environment variable (#900)
3738

3839
### Changed
3940

@@ -82,6 +83,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
8283
- `ResetBeforeOperation` & `ResetAfterOperation` are now public, to allow the creation of a `Connection` (#895)
8384
- `Flasher` now respects its internal `verify` and `skip` flags for all methods. (#901)
8485
- Progress is now reported on skipped segments and verification (#904)
86+
- Moved the `non-interactive` flag to `ConnectArgs` so we also avoid asking the user to select a port (#906)
8587

8688
### Removed
8789

cargo-espflash/src/main.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,11 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> {
348348
let mut monitor_args = args.flash_args.monitor_args;
349349
monitor_args.elf = Some(build_ctx.artifact_path.clone());
350350

351-
check_monitor_args(&args.flash_args.monitor, &monitor_args)?;
351+
check_monitor_args(
352+
&args.flash_args.monitor,
353+
&monitor_args,
354+
args.connect_args.non_interactive,
355+
)?;
352356
check_idf_args(
353357
args.format,
354358
&args.flash_args.erase_parts,
@@ -419,6 +423,7 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> {
419423
Some(&elf_data),
420424
pid,
421425
monitor_args,
426+
args.connect_args.non_interactive,
422427
)
423428
} else {
424429
Ok(())

espflash/src/bin/espflash.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,11 @@ fn erase_parts(args: ErasePartsArgs, config: &Config) -> Result<()> {
234234
fn flash(args: FlashArgs, config: &Config) -> Result<()> {
235235
let mut monitor_args = args.flash_args.monitor_args;
236236
monitor_args.elf = Some(args.image.clone());
237-
check_monitor_args(&args.flash_args.monitor, &monitor_args)?;
237+
check_monitor_args(
238+
&args.flash_args.monitor,
239+
&monitor_args,
240+
args.connect_args.non_interactive,
241+
)?;
238242
check_idf_args(
239243
args.format,
240244
&args.flash_args.erase_parts,
@@ -332,6 +336,7 @@ fn flash(args: FlashArgs, config: &Config) -> Result<()> {
332336
Some(&elf_data),
333337
pid,
334338
monitor_args,
339+
args.connect_args.non_interactive,
335340
)
336341
} else {
337342
Ok(())

espflash/src/cli/mod.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ pub struct ConnectArgs {
9090
/// Serial port connected to target device
9191
#[arg(short = 'p', long, env = "ESPFLASH_PORT")]
9292
pub port: Option<String>,
93+
/// Avoids asking the user for interactions like selecting/resetting the
94+
/// device
95+
#[arg(long)]
96+
pub non_interactive: bool,
9397
}
9498

9599
/// Generate completions for the given shell
@@ -302,11 +306,10 @@ pub struct MonitorConfigArgs {
302306
/// ELF image to load the symbols from
303307
#[arg(long, value_name = "FILE")]
304308
pub elf: Option<PathBuf>,
305-
/// Avoids asking the user for interactions like resetting the device
306-
#[arg(long)]
307-
non_interactive: bool,
308309
/// Avoids restarting the device before monitoring
309-
#[arg(long, requires = "non_interactive")]
310+
///
311+
/// Only valid when `non_interactive` is also set.
312+
#[arg(long)]
310313
no_reset: bool,
311314
/// The encoding of the target's serial output.
312315
#[arg(long, short = 'L')]
@@ -421,7 +424,7 @@ pub fn connect(
421424
.map_err(Error::from)
422425
.wrap_err_with(|| format!("Failed to open serial port {}", port_info.port_name))?;
423426

424-
// NOTE: since `get_serial_port_info` filters out all PCI Port and Bluetooth
427+
// NOTE: since `serial_port_info` filters out all PCI Port and Bluetooth
425428
// serial ports, we can just pretend these types don't exist here.
426429
let port_info = match port_info.port_type {
427430
SerialPortType::UsbPort(info) => info,
@@ -659,6 +662,7 @@ pub fn serial_monitor(args: MonitorArgs, config: &Config) -> Result<()> {
659662
elf.as_deref(),
660663
pid,
661664
monitor_args,
665+
args.connect_args.non_interactive,
662666
)
663667
}
664668

@@ -1095,7 +1099,11 @@ pub fn make_flash_data(
10951099
/// Write a binary to the flash memory of a target device
10961100
pub fn write_bin(args: WriteBinArgs, config: &Config) -> Result<()> {
10971101
// Check monitor arguments
1098-
check_monitor_args(&args.monitor, &args.monitor_args)?;
1102+
check_monitor_args(
1103+
&args.monitor,
1104+
&args.monitor_args,
1105+
args.connect_args.non_interactive,
1106+
)?;
10991107

11001108
// Load the file to be flashed
11011109
let mut f = File::open(&args.file).into_diagnostic()?;
@@ -1132,6 +1140,7 @@ pub fn write_bin(args: WriteBinArgs, config: &Config) -> Result<()> {
11321140
None,
11331141
pid,
11341142
monitor_args,
1143+
args.connect_args.non_interactive,
11351144
)?;
11361145
}
11371146

espflash/src/cli/monitor/mod.rs

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,14 @@ pub fn monitor(
7979
elf: Option<&[u8]>,
8080
pid: u16,
8181
monitor_args: MonitorConfigArgs,
82+
non_interactive: bool,
8283
) -> miette::Result<()> {
83-
println!("Commands:");
84-
println!(" CTRL+R Reset chip");
85-
println!(" CTRL+C Exit");
86-
println!();
87-
88-
if monitor_args.non_interactive && !monitor_args.no_reset {
84+
if !non_interactive {
85+
println!("Commands:");
86+
println!(" CTRL+R Reset chip");
87+
println!(" CTRL+C Exit");
88+
println!();
89+
} else if !monitor_args.no_reset {
8990
reset_after_flash(&mut serial, pid).into_diagnostic()?;
9091
}
9192

@@ -139,7 +140,7 @@ pub fn monitor(
139140
// Don't forget to flush the writer!
140141
stdout.flush().ok();
141142

142-
if !handle_user_input(&mut serial, pid, monitor_args.non_interactive)? {
143+
if !handle_user_input(&mut serial, pid, non_interactive)? {
143144
break;
144145
}
145146
}
@@ -263,14 +264,18 @@ fn handle_key_event(key_event: KeyEvent) -> Option<Vec<u8>> {
263264
}
264265

265266
/// Checks the monitor arguments and emits warnings if they are invalid.
266-
pub fn check_monitor_args(monitor: &bool, monitor_args: &MonitorConfigArgs) -> Result<()> {
267+
pub fn check_monitor_args(
268+
monitor: &bool,
269+
monitor_args: &MonitorConfigArgs,
270+
non_interactive: bool,
271+
) -> Result<()> {
267272
// Check if any monitor args are provided but monitor flag isn't set
268273
if !monitor
269274
&& (monitor_args.elf.is_some()
270275
|| monitor_args.log_format.is_some()
271276
|| monitor_args.output_format.is_some()
272277
|| monitor_args.processors.is_some()
273-
|| monitor_args.non_interactive
278+
|| non_interactive
274279
|| monitor_args.no_reset
275280
|| monitor_args.monitor_baud != 115_200)
276281
{
@@ -279,6 +284,12 @@ pub fn check_monitor_args(monitor: &bool, monitor_args: &MonitorConfigArgs) -> R
279284
);
280285
}
281286

287+
if !non_interactive && monitor_args.no_reset {
288+
warn!(
289+
"The `--no-reset` flag only applies when using the `--non-interactive` flag. Ignoring it."
290+
);
291+
}
292+
282293
// Check if log-format is used with serial but output-format is specified
283294
if let Some(LogFormat::Serial) = monitor_args.log_format {
284295
if monitor_args.output_format.is_some() {

espflash/src/cli/serial.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ pub fn serial_port_info(matches: &ConnectArgs, config: &Config) -> Result<Serial
4141
find_serial_port(&ports, serial)
4242
} else {
4343
let ports = detect_usb_serial_ports(matches.list_all_ports).unwrap_or_default();
44+
if ports.len() > 1 && matches.non_interactive {
45+
return Err(Error::SerialNotSelected);
46+
}
4447
let (port, matches) = select_serial_port(ports, &config.port_config, matches.confirm_port)?;
4548
match &port.port_type {
4649
SerialPortType::UsbPort(usb_info) if !matches => {
@@ -110,6 +113,18 @@ pub(super) fn detect_usb_serial_ports(list_all_ports: bool) -> Result<Vec<Serial
110113
let ports = ports
111114
.into_iter()
112115
.filter(|port_info| {
116+
// On macOS, each USB serial device is exposed twice: once as a
117+
// "/dev/tty.*" callin device and once as a "/dev/cu.*" callout
118+
// device. The latter is what users typically want because opening
119+
// a tty.* device will block until a DCD signal is asserted. To
120+
// avoid confusing users with duplicate entries we hide the tty.*
121+
// variants unless the caller explicitly asked to list *all* ports.
122+
// See https://web.archive.org/web/20120602152224/http://lists.berlios.de/pipermail/gpsd-dev/2005-April/001288.html
123+
#[cfg(target_os = "macos")]
124+
if !list_all_ports && port_info.port_name.starts_with("/dev/tty.") {
125+
return false;
126+
}
127+
113128
if list_all_ports {
114129
matches!(
115130
&port_info.port_type,

espflash/src/error.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,15 @@ pub enum Error {
154154
)]
155155
SerialNotFound(String),
156156

157+
#[error("No serial port was provided")]
158+
#[diagnostic(
159+
code(espflash::serial_not_selected),
160+
help(
161+
"Make sure to provide a serial port via argument, environment variable or configuration file when using the `--non-interactive` flag"
162+
)
163+
)]
164+
SerialNotSelected,
165+
157166
#[error("The {chip} does not support {feature}")]
158167
#[diagnostic(code(espflash::unsupported_feature))]
159168
UnsupportedFeature { chip: Chip, feature: String },

0 commit comments

Comments
 (0)