Skip to content

Commit 4abfa1b

Browse files
authored
Merge pull request #44 from esp-rs/better-errors
improved error messages
2 parents eae7b16 + f5db7ac commit 4abfa1b

File tree

11 files changed

+393
-156
lines changed

11 files changed

+393
-156
lines changed

cargo-espflash/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ categories = [
2424
]
2525

2626
[dependencies]
27-
anyhow = "1.0"
27+
miette = "2"
2828
cargo_metadata = "0.14"
2929
clap = "2.33"
3030
espflash = { version = "*", path = "../espflash" }
3131
guess_host_triple = "0.1"
3232
serde = { version = "1.0", features = ["derive"] }
3333
serial = "0.4"
3434
toml = "0.5"
35+
thiserror = "1"

cargo-espflash/src/error.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
use miette::Diagnostic;
2+
use thiserror::Error;
3+
4+
#[derive(Error, Debug, Diagnostic)]
5+
#[non_exhaustive]
6+
pub enum Error {
7+
#[error("No executable artifact found")]
8+
#[diagnostic(
9+
code(cargo_espflash::no_artifact),
10+
help("If you're trying to run an example you need to specify it using the `--example` argument")
11+
)]
12+
NoArtifact,
13+
#[error("'build-std' not configured")]
14+
#[diagnostic(
15+
code(cargo_espflash::build_std),
16+
help(
17+
"cargo currently requires the unstable 'build-std' feature, ensure \
18+
that .cargo/config{{.toml}} has the appropriate options.\n \
19+
\tSee: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std"
20+
)
21+
)]
22+
NoBuildStd,
23+
#[error("Multiple build artifacts found")]
24+
#[diagnostic(
25+
code(cargo_espflash::multiple_artifacts),
26+
help("Please specify which artifact to flash using --bin")
27+
)]
28+
MultipleArtifacts,
29+
}

cargo-espflash/src/main.rs

Lines changed: 34 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
1-
use anyhow::{anyhow, bail, Context};
21
use cargo_metadata::Message;
32
use clap::{App, Arg, SubCommand};
3+
use error::Error;
44
use espflash::{Config, Flasher, PartitionTable};
5+
use miette::{IntoDiagnostic, Result, WrapErr};
56
use serial::{BaudRate, SerialPort};
67

78
use std::{
@@ -12,9 +13,11 @@ use std::{
1213
};
1314

1415
mod cargo_config;
16+
mod error;
17+
1518
use cargo_config::has_build_std;
1619

17-
fn main() -> anyhow::Result<()> {
20+
fn main() -> Result<()> {
1821
let mut app = App::new(env!("CARGO_PKG_NAME"))
1922
.bin_name("cargo")
2023
.subcommand(
@@ -84,7 +87,7 @@ fn main() -> anyhow::Result<()> {
8487
let matches = match matches.subcommand_matches("espflash") {
8588
Some(matches) => matches,
8689
None => {
87-
app.print_help()?;
90+
app.print_help().into_diagnostic()?;
8891
exit(0);
8992
}
9093
};
@@ -99,7 +102,7 @@ fn main() -> anyhow::Result<()> {
99102
} else if let Some(serial) = config.connection.serial {
100103
serial
101104
} else {
102-
app.print_help()?;
105+
app.print_help().into_diagnostic()?;
103106
exit(0);
104107
};
105108

@@ -120,15 +123,19 @@ fn main() -> anyhow::Result<()> {
120123
// Attempt to open the serial port and set its initial baud rate.
121124
println!("Serial port: {}", port);
122125
println!("Connecting...\n");
123-
let mut serial = serial::open(&port).context(format!("Failed to open serial port {}", port))?;
124-
serial.reconfigure(&|settings| {
125-
settings.set_baud_rate(BaudRate::Baud115200)?;
126-
Ok(())
127-
})?;
126+
let mut serial = serial::open(&port)
127+
.map_err(espflash::Error::from)
128+
.wrap_err_with(|| format!("Failed to open serial port {}", port))?;
129+
serial
130+
.reconfigure(&|settings| {
131+
settings.set_baud_rate(BaudRate::Baud115200)?;
132+
Ok(())
133+
})
134+
.into_diagnostic()?;
128135

129136
// Parse the baud rate if provided as as a command-line argument.
130137
let speed = if let Some(speed) = matches.value_of("speed") {
131-
let speed = speed.parse::<usize>()?;
138+
let speed = speed.parse::<usize>().into_diagnostic()?;
132139
Some(BaudRate::from_speed(speed))
133140
} else {
134141
None
@@ -145,8 +152,8 @@ fn main() -> anyhow::Result<()> {
145152
// If the '--bootloader' option is provided, load the binary file at the
146153
// specified path.
147154
let bootloader = if let Some(path) = matches.value_of("bootloader") {
148-
let path = fs::canonicalize(path)?;
149-
let data = fs::read(path)?;
155+
let path = fs::canonicalize(path).into_diagnostic()?;
156+
let data = fs::read(path).into_diagnostic()?;
150157
Some(data)
151158
} else {
152159
None
@@ -155,19 +162,16 @@ fn main() -> anyhow::Result<()> {
155162
// If the '--partition-table' option is provided, load the partition table from
156163
// the CSV at the specified path.
157164
let partition_table = if let Some(path) = matches.value_of("partition_table") {
158-
let path = fs::canonicalize(path)?;
159-
let data = fs::read_to_string(path)?;
160-
161-
match PartitionTable::try_from_str(data) {
162-
Ok(t) => Some(t),
163-
Err(e) => bail!("{}", e),
164-
}
165+
let path = fs::canonicalize(path).into_diagnostic()?;
166+
let data = fs::read_to_string(path).into_diagnostic()?;
167+
let table = PartitionTable::try_from_str(data)?;
168+
Some(table)
165169
} else {
166170
None
167171
};
168172

169173
// Read the ELF data from the build path and load it to the target.
170-
let elf_data = fs::read(path.unwrap())?;
174+
let elf_data = fs::read(path.unwrap()).into_diagnostic()?;
171175
if matches.is_present("ram") {
172176
flasher.load_elf_to_ram(&elf_data)?;
173177
} else {
@@ -183,16 +187,12 @@ fn board_info(flasher: &Flasher) {
183187
println!("Flash size: {}", flasher.flash_size());
184188
}
185189

186-
fn build(release: bool, example: Option<&str>, features: Option<&str>) -> anyhow::Result<PathBuf> {
190+
fn build(release: bool, example: Option<&str>, features: Option<&str>) -> Result<PathBuf> {
187191
// The 'build-std' unstable cargo feature is required to enable
188192
// cross-compilation. If it has not been set then we cannot build the
189193
// application.
190194
if !has_build_std(".") {
191-
bail!(
192-
"cargo currently requires the unstable 'build-std' feature, ensure \
193-
that .cargo/config{.toml} has the appropriate options.\n \
194-
See: https://doc.rust-lang.org/cargo/reference/unstable.html#build-std"
195-
);
195+
return Err(Error::NoBuildStd.into());
196196
};
197197

198198
// Build the list of arguments to pass to 'cargo build'.
@@ -219,8 +219,10 @@ fn build(release: bool, example: Option<&str>, features: Option<&str>) -> anyhow
219219
.args(&["--message-format", "json-diagnostic-rendered-ansi"])
220220
.stdout(Stdio::piped())
221221
.stderr(Stdio::inherit())
222-
.spawn()?
223-
.wait_with_output()?;
222+
.spawn()
223+
.into_diagnostic()?
224+
.wait_with_output()
225+
.into_diagnostic()?;
224226

225227
// Parse build output.
226228
let messages = Message::parse_stream(&output.stdout[..]);
@@ -229,12 +231,11 @@ fn build(release: bool, example: Option<&str>, features: Option<&str>) -> anyhow
229231
let mut target_artifact = None;
230232

231233
for message in messages {
232-
match message? {
234+
match message.into_diagnostic()? {
233235
Message::CompilerArtifact(artifact) => {
234236
if artifact.executable.is_some() {
235237
if target_artifact.is_some() {
236-
// We found multiple binary artifacts, so we don't know which one to use.
237-
bail!("Multiple artifacts found, please specify one with --bin");
238+
return Err(Error::MultipleArtifacts.into());
238239
} else {
239240
target_artifact = Some(artifact);
240241
}
@@ -258,16 +259,9 @@ fn build(release: bool, example: Option<&str>, features: Option<&str>) -> anyhow
258259
}
259260

260261
// If no target artifact was found, we don't have a path to return.
261-
if target_artifact.is_none() {
262-
bail!("Artifact not found");
263-
}
262+
let target_artifact = target_artifact.ok_or(Error::NoArtifact)?;
264263

265-
let artifact_path = PathBuf::from(
266-
target_artifact
267-
.unwrap()
268-
.executable
269-
.ok_or_else(|| anyhow!("artifact executable path is missing"))?,
270-
);
264+
let artifact_path = target_artifact.executable.unwrap().into();
271265

272266
Ok(artifact_path)
273267
}

espflash/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ strum_macros = "0.21.1"
3333
csv = "1.1.6"
3434
regex = "1.5.4"
3535
flate2 = "1"
36+
miette = "2"
3637

3738
[dev-dependencies]
3839
pretty_assertions = "0.7.1"

espflash/src/chip/esp8266.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use super::{ChipType, EspCommonHeader, SegmentHeader, ESP_MAGIC};
44
use crate::{
55
chip::{Chip, SpiRegisters},
66
elf::{update_checksum, CodeSegment, FirmwareImage, RomSegment, ESP_CHECKSUM_MAGIC},
7+
error::FlashDetectError,
78
flasher::FlashSize,
89
Error, PartitionTable,
910
};
@@ -96,7 +97,7 @@ impl ChipType for Esp8266 {
9697
}
9798
}
9899

99-
fn encode_flash_size(size: FlashSize) -> Result<u8, Error> {
100+
fn encode_flash_size(size: FlashSize) -> Result<u8, FlashDetectError> {
100101
match size {
101102
FlashSize::Flash256Kb => Ok(0x10),
102103
FlashSize::Flash512Kb => Ok(0x00),
@@ -105,7 +106,7 @@ fn encode_flash_size(size: FlashSize) -> Result<u8, Error> {
105106
FlashSize::Flash4Mb => Ok(0x40),
106107
FlashSize::Flash8Mb => Ok(0x80),
107108
FlashSize::Flash16Mb => Ok(0x90),
108-
FlashSize::FlashRetry => Err(Error::UnsupportedFlash(size as u8)),
109+
FlashSize::FlashRetry => Err(FlashDetectError::from(size as u8)),
109110
}
110111
}
111112

espflash/src/chip/mod.rs

Lines changed: 11 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ use crate::{
77
Error, PartitionTable,
88
};
99

10-
use std::{io::Write, str::FromStr};
10+
use std::io::Write;
1111

12+
use crate::error::{ChipDetectError, FlashDetectError};
1213
use crate::flash_target::{Esp32Target, Esp8266Target, FlashTarget, RamTarget};
1314
use crate::flasher::SpiAttachParams;
1415
pub use esp32::Esp32;
@@ -102,14 +103,14 @@ pub enum Chip {
102103
}
103104

104105
impl Chip {
105-
pub fn from_magic(magic: u32) -> Option<Self> {
106+
pub fn from_magic(magic: u32) -> Result<Self, ChipDetectError> {
106107
match magic {
107-
Esp32::CHIP_DETECT_MAGIC_VALUE => Some(Chip::Esp32),
108+
Esp32::CHIP_DETECT_MAGIC_VALUE => Ok(Chip::Esp32),
108109
Esp32c3::CHIP_DETECT_MAGIC_VALUE | Esp32c3::CHIP_DETECT_MAGIC_VALUE2 => {
109-
Some(Chip::Esp32c3)
110+
Ok(Chip::Esp32c3)
110111
}
111-
Esp8266::CHIP_DETECT_MAGIC_VALUE => Some(Chip::Esp8266),
112-
_ => None,
112+
Esp8266::CHIP_DETECT_MAGIC_VALUE => Ok(Chip::Esp8266),
113+
_ => Err(ChipDetectError::from(magic)),
113114
}
114115
}
115116

@@ -154,19 +155,6 @@ impl Chip {
154155
}
155156
}
156157

157-
impl FromStr for Chip {
158-
type Err = Error;
159-
160-
fn from_str(s: &str) -> Result<Self, Self::Err> {
161-
match s {
162-
"esp32" => Ok(Chip::Esp32),
163-
"esp32c3" => Ok(Chip::Esp32c3),
164-
"esp8266" => Ok(Chip::Esp8266),
165-
_ => Err(Error::UnrecognizedChip),
166-
}
167-
}
168-
}
169-
170158
#[derive(Copy, Clone, Zeroable, Pod, Debug)]
171159
#[repr(C)]
172160
struct EspCommonHeader {
@@ -186,16 +174,16 @@ struct SegmentHeader {
186174

187175
// Note that this function ONLY applies to the ESP32 and variants; the ESP8266
188176
// has defined its own version rather than using this implementation.
189-
fn encode_flash_size(size: FlashSize) -> Result<u8, Error> {
177+
fn encode_flash_size(size: FlashSize) -> Result<u8, FlashDetectError> {
190178
match size {
191-
FlashSize::Flash256Kb => Err(Error::UnsupportedFlash(size as u8)),
192-
FlashSize::Flash512Kb => Err(Error::UnsupportedFlash(size as u8)),
179+
FlashSize::Flash256Kb => Err(FlashDetectError::from(size as u8)),
180+
FlashSize::Flash512Kb => Err(FlashDetectError::from(size as u8)),
193181
FlashSize::Flash1Mb => Ok(0x00),
194182
FlashSize::Flash2Mb => Ok(0x10),
195183
FlashSize::Flash4Mb => Ok(0x20),
196184
FlashSize::Flash8Mb => Ok(0x30),
197185
FlashSize::Flash16Mb => Ok(0x40),
198-
FlashSize::FlashRetry => Err(Error::UnsupportedFlash(size as u8)),
186+
FlashSize::FlashRetry => Err(FlashDetectError::from(size as u8)),
199187
}
200188
}
201189

espflash/src/connection.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::thread::sleep;
33
use std::time::Duration;
44

55
use crate::encoder::SlipEncoder;
6-
use crate::error::{Error, RomError};
6+
use crate::error::{ConnectionError, Error, RomError};
77
use binread::io::Cursor;
88
use binread::{BinRead, BinReaderExt};
99
use serial::{BaudRate, SerialPort, SerialPortSettings};
@@ -135,7 +135,7 @@ impl Connection {
135135
}
136136
}
137137
}
138-
Err(Error::ConnectionFailed)
138+
Err(Error::Connection(ConnectionError::ConnectionFailed))
139139
}
140140

141141
fn read(&mut self) -> Result<Vec<u8>, Error> {

0 commit comments

Comments
 (0)