Skip to content

Commit ccc107b

Browse files
committed
Add partition-table subcommand
1 parent 3a4c02b commit ccc107b

File tree

6 files changed

+374
-67
lines changed

6 files changed

+374
-67
lines changed

Cargo.lock

Lines changed: 51 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

espflash/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ authors = [
66
"Jesse Braham <[email protected]>",
77
]
88
edition = "2021"
9-
rust-version = "1.56"
9+
rust-version = "1.58"
1010
description = "A command-line tool for flashing Espressif devices over serial"
1111
repository = "https://github.com/esp-rs/espflash"
1212
license = "GPL-2.0"
@@ -35,6 +35,7 @@ path = "src/main.rs"
3535
binread = "2.2"
3636
bytemuck = { version = "1.9", features = ["derive"] }
3737
clap = { version = "3.1", features = ["derive"] }
38+
comfy-table = "5"
3839
crossterm = "0.23"
3940
csv = "1.1"
4041
dialoguer = "0.10"

espflash/src/error.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,18 @@ pub enum PartitionTableError {
346346
#[error(transparent)]
347347
#[diagnostic(transparent)]
348348
UnalignedPartitionError(#[from] UnalignedPartitionError),
349+
#[error(transparent)]
350+
#[diagnostic(transparent)]
351+
LengthNotMultipleOf32(#[from] LengthNotMultipleOf32),
352+
#[error(transparent)]
353+
#[diagnostic(transparent)]
354+
InvalidChecksum(#[from] InvalidChecksum),
355+
#[error(transparent)]
356+
#[diagnostic(transparent)]
357+
NoEndMarker(#[from] NoEndMarker),
358+
#[error(transparent)]
359+
#[diagnostic(transparent)]
360+
InvalidPartitionTable(#[from] InvalidPartitionTable),
349361
}
350362

351363
#[derive(Debug, Error, Diagnostic)]
@@ -535,6 +547,26 @@ impl UnalignedPartitionError {
535547
}
536548
}
537549

550+
#[derive(Debug, Error, Diagnostic)]
551+
#[error("Partition table length not a multiple of 32")]
552+
#[diagnostic(code(espflash::partition_table::invalid_length))]
553+
pub struct LengthNotMultipleOf32;
554+
555+
#[derive(Debug, Error, Diagnostic)]
556+
#[error("Checksum invalid")]
557+
#[diagnostic(code(espflash::partition_table::invalid_checksum))]
558+
pub struct InvalidChecksum;
559+
560+
#[derive(Debug, Error, Diagnostic)]
561+
#[error("No end marker found")]
562+
#[diagnostic(code(espflash::partition_table::no_end_marker))]
563+
pub struct NoEndMarker;
564+
565+
#[derive(Debug, Error, Diagnostic)]
566+
#[error("Invalid partition table")]
567+
#[diagnostic(code(espflash::partition_table::invalid_partition_table))]
568+
pub struct InvalidPartitionTable;
569+
538570
#[derive(Debug, Error)]
539571
#[error("{0}")]
540572
pub struct ElfError(&'static str);

espflash/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
pub use chip::Chip;
22
pub use cli::config::Config;
33
pub use elf::{FlashFrequency, FlashMode};
4-
pub use error::Error;
4+
pub use error::{Error, InvalidPartitionTable};
55
pub use flasher::{FlashSize, Flasher};
66
pub use image_format::ImageFormatId;
77
pub use partition_table::PartitionTable;

espflash/src/main.rs

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
use std::{fs, mem::swap, path::PathBuf, str::FromStr};
1+
use std::{fs, io::Write, mem::swap, path::PathBuf, str::FromStr};
22

33
use clap::{IntoApp, Parser};
44
use espflash::{
55
cli::{
66
board_info, connect, flash_elf_image, monitor::monitor, save_elf_as_image, ConnectOpts,
77
FlashConfigOpts, FlashOpts,
88
},
9-
Chip, Config, ImageFormatId,
9+
Chip, Config, ImageFormatId, InvalidPartitionTable, PartitionTable,
1010
};
1111
use miette::{IntoDiagnostic, Result, WrapErr};
1212

@@ -34,6 +34,8 @@ pub enum SubCommand {
3434
BoardInfo(ConnectOpts),
3535
/// Save the image to disk instead of flashing to device
3636
SaveImage(SaveImageOpts),
37+
/// Operations for partitions tables
38+
PartitionTable(PartitionTableOpts),
3739
}
3840

3941
#[derive(Parser)]
@@ -60,13 +62,34 @@ pub struct SaveImageOpts {
6062
pub partition_table: Option<PathBuf>,
6163
}
6264

65+
#[derive(Parser)]
66+
pub struct PartitionTableOpts {
67+
/// Convert CSV parition table to binary representation
68+
#[clap(long, required_unless_present_any = ["info", "to-csv"])]
69+
to_binary: bool,
70+
/// Convert binary partition table to CSV representation
71+
#[clap(long, required_unless_present_any = ["info", "to-binary"])]
72+
to_csv: bool,
73+
/// Show information on partition table
74+
#[clap(short, long, required_unless_present_any = ["to-binary", "to-csv"])]
75+
info: bool,
76+
/// Input partition table
77+
partition_table: PathBuf,
78+
/// Optional output file name, if unset will output to stdout
79+
#[clap(short, long)]
80+
output: Option<PathBuf>,
81+
}
82+
6383
fn main() -> Result<()> {
6484
miette::set_panic_hook();
6585

6686
let mut opts = Opts::parse();
6787
let config = Config::load()?;
6888

69-
if !matches!(opts.subcommand, Some(SubCommand::BoardInfo(..))) {
89+
if !matches!(
90+
opts.subcommand,
91+
Some(SubCommand::BoardInfo(..) | SubCommand::PartitionTable(..)),
92+
) {
7093
// If neither the IMAGE nor SERIAL arguments have been provided, print the
7194
// help message and exit.
7295
if opts.image.is_none() && opts.connect_opts.serial.is_none() {
@@ -89,6 +112,7 @@ fn main() -> Result<()> {
89112
match subcommand {
90113
BoardInfo(opts) => board_info(opts, config),
91114
SaveImage(opts) => save_image(opts),
115+
PartitionTable(opts) => partition_table(opts),
92116
}
93117
} else {
94118
flash(opts, config)
@@ -167,3 +191,50 @@ fn save_image(opts: SaveImageOpts) -> Result<()> {
167191

168192
Ok(())
169193
}
194+
195+
fn partition_table(opts: PartitionTableOpts) -> Result<()> {
196+
if opts.to_binary {
197+
let input = fs::read(&opts.partition_table).into_diagnostic()?;
198+
let part_table = PartitionTable::try_from_str(String::from_utf8(input).into_diagnostic()?)
199+
.into_diagnostic()?;
200+
201+
// Use either stdout or a file if provided for the output.
202+
let mut writer: Box<dyn Write> = if let Some(output) = opts.output {
203+
Box::new(fs::File::create(output).into_diagnostic()?)
204+
} else {
205+
Box::new(std::io::stdout())
206+
};
207+
part_table.save_bin(&mut writer).into_diagnostic()?;
208+
} else if opts.to_csv {
209+
let input = fs::read(&opts.partition_table).into_diagnostic()?;
210+
let part_table = PartitionTable::try_from_bytes(input).into_diagnostic()?;
211+
212+
// Use either stdout or a file if provided for the output.
213+
let mut writer: Box<dyn Write> = if let Some(output) = opts.output {
214+
Box::new(fs::File::create(output).into_diagnostic()?)
215+
} else {
216+
Box::new(std::io::stdout())
217+
};
218+
part_table.save_csv(&mut writer).into_diagnostic()?;
219+
} else if opts.info {
220+
let input = fs::read(&opts.partition_table).into_diagnostic()?;
221+
222+
// Try getting the partition table from either the csv or the binary representation and
223+
// fail otherwise.
224+
let part_table = if let Ok(part_table) =
225+
PartitionTable::try_from_bytes(input.clone()).into_diagnostic()
226+
{
227+
part_table
228+
} else if let Ok(part_table) =
229+
PartitionTable::try_from_str(String::from_utf8(input).into_diagnostic()?)
230+
{
231+
part_table
232+
} else {
233+
return Err((InvalidPartitionTable {}).into());
234+
};
235+
236+
part_table.pretty_print();
237+
}
238+
239+
Ok(())
240+
}

0 commit comments

Comments
 (0)