Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add partition-table subcommand #172

Merged
merged 3 commits into from
May 3, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: 1.56
toolchain: 1.58
override: true
- uses: Swatinem/rust-cache@v1
- uses: actions-rs/cargo@v1
Expand Down
55 changes: 51 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion espflash/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ authors = [
"Jesse Braham <[email protected]>",
]
edition = "2021"
rust-version = "1.56"
rust-version = "1.58"
description = "A command-line tool for flashing Espressif devices over serial"
repository = "https://github.com/esp-rs/espflash"
license = "GPL-2.0"
Expand Down Expand Up @@ -35,6 +35,7 @@ path = "src/main.rs"
binread = "2.2"
bytemuck = { version = "1.9", features = ["derive"] }
clap = { version = "3.1", features = ["derive"] }
comfy-table = "5"
crossterm = "0.23"
csv = "1.1"
dialoguer = "0.10"
Expand Down
32 changes: 32 additions & 0 deletions espflash/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,18 @@ pub enum PartitionTableError {
#[error(transparent)]
#[diagnostic(transparent)]
UnalignedPartitionError(#[from] UnalignedPartitionError),
#[error(transparent)]
#[diagnostic(transparent)]
LengthNotMultipleOf32(#[from] LengthNotMultipleOf32),
#[error(transparent)]
#[diagnostic(transparent)]
InvalidChecksum(#[from] InvalidChecksum),
#[error(transparent)]
#[diagnostic(transparent)]
NoEndMarker(#[from] NoEndMarker),
#[error(transparent)]
#[diagnostic(transparent)]
InvalidPartitionTable(#[from] InvalidPartitionTable),
}

#[derive(Debug, Error, Diagnostic)]
Expand Down Expand Up @@ -535,6 +547,26 @@ impl UnalignedPartitionError {
}
}

#[derive(Debug, Error, Diagnostic)]
#[error("Partition table length not a multiple of 32")]
#[diagnostic(code(espflash::partition_table::invalid_length))]
pub struct LengthNotMultipleOf32;

#[derive(Debug, Error, Diagnostic)]
#[error("Checksum invalid")]
#[diagnostic(code(espflash::partition_table::invalid_checksum))]
pub struct InvalidChecksum;

#[derive(Debug, Error, Diagnostic)]
#[error("No end marker found")]
#[diagnostic(code(espflash::partition_table::no_end_marker))]
pub struct NoEndMarker;

#[derive(Debug, Error, Diagnostic)]
#[error("Invalid partition table")]
#[diagnostic(code(espflash::partition_table::invalid_partition_table))]
pub struct InvalidPartitionTable;

#[derive(Debug, Error)]
#[error("{0}")]
pub struct ElfError(&'static str);
Expand Down
2 changes: 1 addition & 1 deletion espflash/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
pub use chip::Chip;
pub use cli::config::Config;
pub use elf::{FlashFrequency, FlashMode};
pub use error::Error;
pub use error::{Error, InvalidPartitionTable};
pub use flasher::{FlashSize, Flasher};
pub use image_format::ImageFormatId;
pub use partition_table::PartitionTable;
Expand Down
77 changes: 74 additions & 3 deletions espflash/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use std::{fs, mem::swap, path::PathBuf, str::FromStr};
use std::{fs, io::Write, mem::swap, path::PathBuf, str::FromStr};

use clap::{IntoApp, Parser};
use espflash::{
cli::{
board_info, connect, flash_elf_image, monitor::monitor, save_elf_as_image, ConnectOpts,
FlashConfigOpts, FlashOpts,
},
Chip, Config, ImageFormatId,
Chip, Config, ImageFormatId, InvalidPartitionTable, PartitionTable,
};
use miette::{IntoDiagnostic, Result, WrapErr};

Expand Down Expand Up @@ -34,6 +34,8 @@ pub enum SubCommand {
BoardInfo(ConnectOpts),
/// Save the image to disk instead of flashing to device
SaveImage(SaveImageOpts),
/// Operations for partitions tables
PartitionTable(PartitionTableOpts),
}

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

#[derive(Parser)]
pub struct PartitionTableOpts {
/// Convert CSV parition table to binary representation
#[clap(long, required_unless_present_any = ["info", "to-csv"])]
to_binary: bool,
/// Convert binary partition table to CSV representation
#[clap(long, required_unless_present_any = ["info", "to-binary"])]
to_csv: bool,
/// Show information on partition table
#[clap(short, long, required_unless_present_any = ["to-binary", "to-csv"])]
info: bool,
Comment on lines +68 to +75
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it might make more sense to have these as sub commands

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine as they terminate the chain of commands and I don't like too deeply nested subcommands.

/// Input partition table
partition_table: PathBuf,
/// Optional output file name, if unset will output to stdout
#[clap(short, long)]
output: Option<PathBuf>,
}

fn main() -> Result<()> {
miette::set_panic_hook();

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

if !matches!(opts.subcommand, Some(SubCommand::BoardInfo(..))) {
if !matches!(
opts.subcommand,
Some(SubCommand::BoardInfo(..) | SubCommand::PartitionTable(..)),
) {
// If neither the IMAGE nor SERIAL arguments have been provided, print the
// help message and exit.
if opts.image.is_none() && opts.connect_opts.serial.is_none() {
Expand All @@ -89,6 +112,7 @@ fn main() -> Result<()> {
match subcommand {
BoardInfo(opts) => board_info(opts, config),
SaveImage(opts) => save_image(opts),
PartitionTable(opts) => partition_table(opts),
}
} else {
flash(opts, config)
Expand Down Expand Up @@ -167,3 +191,50 @@ fn save_image(opts: SaveImageOpts) -> Result<()> {

Ok(())
}

fn partition_table(opts: PartitionTableOpts) -> Result<()> {
if opts.to_binary {
let input = fs::read(&opts.partition_table).into_diagnostic()?;
let part_table = PartitionTable::try_from_str(String::from_utf8(input).into_diagnostic()?)
.into_diagnostic()?;

// Use either stdout or a file if provided for the output.
let mut writer: Box<dyn Write> = if let Some(output) = opts.output {
Box::new(fs::File::create(output).into_diagnostic()?)
} else {
Box::new(std::io::stdout())
};
part_table.save_bin(&mut writer).into_diagnostic()?;
} else if opts.to_csv {
let input = fs::read(&opts.partition_table).into_diagnostic()?;
let part_table = PartitionTable::try_from_bytes(input).into_diagnostic()?;

// Use either stdout or a file if provided for the output.
let mut writer: Box<dyn Write> = if let Some(output) = opts.output {
Box::new(fs::File::create(output).into_diagnostic()?)
} else {
Box::new(std::io::stdout())
};
part_table.save_csv(&mut writer).into_diagnostic()?;
} else if opts.info {
let input = fs::read(&opts.partition_table).into_diagnostic()?;

// Try getting the partition table from either the csv or the binary representation and
// fail otherwise.
let part_table = if let Ok(part_table) =
PartitionTable::try_from_bytes(input.clone()).into_diagnostic()
{
part_table
} else if let Ok(part_table) =
PartitionTable::try_from_str(String::from_utf8(input).into_diagnostic()?)
{
part_table
} else {
return Err((InvalidPartitionTable {}).into());
};

part_table.pretty_print();
}

Ok(())
}
Loading