@@ -8,8 +8,11 @@ use std::{
88use cargo_metadata:: Message ;
99use clap:: { AppSettings , Parser } ;
1010use espflash:: {
11- cli:: { clap:: * , connect, monitor:: monitor} ,
12- Chip , Config , FirmwareImage , ImageFormatId , PartitionTable ,
11+ cli:: {
12+ board_info, connect, flash_elf_image, monitor:: monitor, save_elf_as_image, ConnectOpts ,
13+ FlashOpts ,
14+ } ,
15+ Chip , Config , ImageFormatId ,
1316} ;
1417use miette:: { IntoDiagnostic , Result , WrapErr } ;
1518
@@ -24,12 +27,11 @@ mod error;
2427mod package_metadata;
2528
2629#[ derive( Parser ) ]
30+ #[ clap( bin_name = "cargo" , version) ]
2731#[ clap( global_setting = AppSettings :: PropagateVersion ) ]
28- #[ clap( bin_name = "cargo" ) ]
29- #[ clap( version = env!( "CARGO_PKG_VERSION" ) ) ]
3032struct Opts {
3133 #[ clap( subcommand) ]
32- sub_cmd : CargoSubCommand ,
34+ subcommand : CargoSubCommand ,
3335}
3436
3537#[ derive( Parser ) ]
@@ -40,122 +42,137 @@ enum CargoSubCommand {
4042#[ derive( Parser ) ]
4143struct EspFlashOpts {
4244 #[ clap( flatten) ]
43- flash_args : FlashArgs ,
45+ flash_opts : FlashOpts ,
4446 #[ clap( flatten) ]
45- build_args : BuildArgs ,
47+ build_opts : BuildOpts ,
4648 #[ clap( flatten) ]
47- connect_args : ConnectArgs ,
49+ connect_opts : ConnectOpts ,
4850 #[ clap( subcommand) ]
49- sub_cmd : Option < SubCommand > ,
51+ subcommand : Option < SubCommand > ,
5052}
5153
5254#[ derive( Parser ) ]
5355pub enum SubCommand {
56+ /// Display information about the connected board and exit without flashing
57+ BoardInfo ( ConnectOpts ) ,
58+ /// Save the image to disk instead of flashing to device
5459 SaveImage ( SaveImageOpts ) ,
55- BoardInfo ( BoardInfoOpts ) ,
60+ }
61+
62+ #[ derive( Parser ) ]
63+ pub struct BuildOpts {
64+ /// Build the application using the release profile
65+ #[ clap( long) ]
66+ pub release : bool ,
67+ /// Example to build and flash
68+ #[ clap( long) ]
69+ pub example : Option < String > ,
70+ /// Specify a (binary) package within a workspace to be built
71+ #[ clap( long) ]
72+ pub package : Option < String > ,
73+ /// Comma delimited list of build features
74+ #[ clap( long, use_delimiter = true ) ]
75+ pub features : Option < Vec < String > > ,
76+ /// Image format to flash (bootloader/direct-boot)
77+ #[ clap( long) ]
78+ pub format : Option < String > ,
79+ /// Target to build for
80+ #[ clap( long) ]
81+ pub target : Option < String > ,
82+ /// Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details
83+ #[ clap( short = 'Z' ) ]
84+ pub unstable : Option < Vec < String > > ,
85+ }
86+
87+ #[ derive( Parser ) ]
88+ pub struct SaveImageOpts {
89+ #[ clap( flatten) ]
90+ pub build_args : BuildOpts ,
91+ /// File name to save the generated image to
92+ pub file : PathBuf ,
5693}
5794
5895fn main ( ) -> Result < ( ) > {
5996 miette:: set_panic_hook ( ) ;
6097
61- let CargoSubCommand :: Espflash ( opts) = Opts :: parse ( ) . sub_cmd ;
98+ let CargoSubCommand :: Espflash ( opts) = Opts :: parse ( ) . subcommand ;
6299
63100 let config = Config :: load ( ) ?;
64101 let metadata = CargoEspFlashMeta :: load ( "Cargo.toml" ) ?;
65102 let cargo_config = parse_cargo_config ( "." ) ?;
66103
67- match opts. sub_cmd {
68- Some ( SubCommand :: BoardInfo ( matches) ) => board_info ( matches, config, metadata, cargo_config) ,
69- Some ( SubCommand :: SaveImage ( matches) ) => save_image ( matches, config, metadata, cargo_config) ,
70- None => flash ( opts, config, metadata, cargo_config) ,
104+ if let Some ( subcommand) = opts. subcommand {
105+ use SubCommand :: * ;
106+
107+ match subcommand {
108+ BoardInfo ( opts) => board_info ( opts, config) ,
109+ SaveImage ( opts) => save_image ( opts, metadata, cargo_config) ,
110+ }
111+ } else {
112+ flash ( opts, config, metadata, cargo_config)
71113 }
72114}
73115
74116fn flash (
75- matches : EspFlashOpts ,
117+ opts : EspFlashOpts ,
76118 config : Config ,
77119 metadata : CargoEspFlashMeta ,
78120 cargo_config : CargoConfig ,
79121) -> Result < ( ) > {
80- // Connect the Flasher to the target device and print the board information
81- // upon connection. If the '--board-info' flag has been provided, we have
82- // nothing left to do so exit early.
83- let mut flasher = connect ( & matches. connect_args , & config) ?;
84- flasher. board_info ( ) ?;
122+ let mut flasher = connect ( & opts. connect_opts , & config) ?;
85123
86- if matches. flash_args . board_info {
87- return Ok ( ( ) ) ;
88- }
89-
90- let path = build ( & matches. build_args , & cargo_config, Some ( flasher. chip ( ) ) )
124+ let artifact_path = build ( & opts. build_opts , & cargo_config, Some ( flasher. chip ( ) ) )
91125 . wrap_err ( "Failed to build project" ) ?;
92126
93- // If the '--bootloader' option is provided, load the binary file at the
94- // specified path.
95- let bootloader = if let Some ( path) = matches
96- . flash_args
97- . bootloader
98- . as_deref ( )
99- . or_else ( || metadata. bootloader . as_deref ( ) )
100- {
101- let path = fs:: canonicalize ( path) . into_diagnostic ( ) ?;
102- let data = fs:: read ( path) . into_diagnostic ( ) ?;
103- Some ( data)
104- } else {
105- None
106- } ;
107-
108- // If the '--partition-table' option is provided, load the partition table from
109- // the CSV at the specified path.
110- let partition_table = if let Some ( path) = matches
111- . flash_args
112- . partition_table
113- . as_deref ( )
114- . or_else ( || metadata. partition_table . as_deref ( ) )
115- {
116- let path = fs:: canonicalize ( path) . into_diagnostic ( ) ?;
117- let data = fs:: read_to_string ( path)
118- . into_diagnostic ( )
119- . wrap_err ( "Failed to open partition table" ) ?;
120- let table =
121- PartitionTable :: try_from_str ( data) . wrap_err ( "Failed to parse partition table" ) ?;
122- Some ( table)
123- } else {
124- None
125- } ;
126-
127- let image_format = matches
128- . build_args
129- . format
130- . as_deref ( )
131- . map ( ImageFormatId :: from_str)
132- . transpose ( ) ?
133- . or ( metadata. format ) ;
127+ // Print the board information once the project has successfully built. We do
128+ // here rather than upon connection to show the Cargo output prior to the board
129+ // information, rather than breaking up cargo-espflash's output.
130+ flasher. board_info ( ) ?;
134131
135132 // Read the ELF data from the build path and load it to the target.
136- let elf_data = fs:: read ( path) . into_diagnostic ( ) ?;
137- if matches. flash_args . ram {
133+ let elf_data = fs:: read ( artifact_path) . into_diagnostic ( ) ?;
134+
135+ if opts. flash_opts . ram {
138136 flasher. load_elf_to_ram ( & elf_data) ?;
139137 } else {
140- flasher. load_elf_to_flash_with_format (
138+ let bootloader = opts
139+ . flash_opts
140+ . bootloader
141+ . as_deref ( )
142+ . or ( metadata. bootloader . as_deref ( ) ) ;
143+
144+ let partition_table = opts
145+ . flash_opts
146+ . partition_table
147+ . as_deref ( )
148+ . or ( metadata. partition_table . as_deref ( ) ) ;
149+
150+ let image_format = opts
151+ . build_opts
152+ . format
153+ . as_deref ( )
154+ . map ( ImageFormatId :: from_str)
155+ . transpose ( ) ?
156+ . or ( metadata. format ) ;
157+
158+ flash_elf_image (
159+ & mut flasher,
141160 & elf_data,
142161 bootloader,
143162 partition_table,
144163 image_format,
145164 ) ?;
146165 }
147- println ! ( "\n Flashing has completed!" ) ;
148166
149- if matches . flash_args . monitor {
167+ if opts . flash_opts . monitor {
150168 monitor ( flasher. into_serial ( ) ) . into_diagnostic ( ) ?;
151169 }
152170
153- // We're all done!
154171 Ok ( ( ) )
155172}
156173
157174fn build (
158- build_options : & BuildArgs ,
175+ build_options : & BuildOpts ,
159176 cargo_config : & CargoConfig ,
160177 chip : Option < Chip > ,
161178) -> Result < PathBuf > {
@@ -273,12 +290,11 @@ fn build(
273290}
274291
275292fn save_image (
276- matches : SaveImageOpts ,
277- _config : Config ,
293+ opts : SaveImageOpts ,
278294 metadata : CargoEspFlashMeta ,
279295 cargo_config : CargoConfig ,
280296) -> Result < ( ) > {
281- let target = matches
297+ let target = opts
282298 . build_args
283299 . target
284300 . as_deref ( )
@@ -288,45 +304,19 @@ fn save_image(
288304
289305 let chip = Chip :: from_target ( target) . ok_or_else ( || Error :: UnknownTarget ( target. into ( ) ) ) ?;
290306
291- let path = build ( & matches . build_args , & cargo_config, Some ( chip) ) ?;
307+ let path = build ( & opts . build_args , & cargo_config, Some ( chip) ) ?;
292308 let elf_data = fs:: read ( path) . into_diagnostic ( ) ?;
293309
294- let image = FirmwareImage :: from_data ( & elf_data) ?;
295-
296- let image_format = matches
310+ let image_format = opts
297311 . build_args
298312 . format
299313 . as_deref ( )
300314 . map ( ImageFormatId :: from_str)
301315 . transpose ( ) ?
302316 . or ( metadata. format ) ;
303317
304- let flash_image = chip. get_flash_image ( & image, None , None , image_format, None ) ?;
305- let parts: Vec < _ > = flash_image. ota_segments ( ) . collect ( ) ;
306-
307- let out_path = matches. file ;
318+ save_elf_as_image ( chip, & elf_data, opts. file , image_format) ?;
308319
309- match parts. as_slice ( ) {
310- [ single] => fs:: write ( out_path, & single. data ) . into_diagnostic ( ) ?,
311- parts => {
312- for part in parts {
313- let part_path = format ! ( "{:#x}_{}" , part. addr, out_path) ;
314- fs:: write ( part_path, & part. data ) . into_diagnostic ( ) ?
315- }
316- }
317- }
318-
319- Ok ( ( ) )
320- }
321-
322- fn board_info (
323- matches : BoardInfoOpts ,
324- config : Config ,
325- _metadata : CargoEspFlashMeta ,
326- _cargo_config : CargoConfig ,
327- ) -> Result < ( ) > {
328- let mut flasher = connect ( & matches. connect_args , & config) ?;
329- flasher. board_info ( ) ?;
330320 Ok ( ( ) )
331321}
332322
0 commit comments