1111//!! ```
1212//! // List available images
1313//! xtask image ls
14- //! // Download a specific image and automatically extract it
14+ //! // Download a specific image and automatically extract it (default behavior)
1515//! xtask image download evm3588_arceos --output-dir ./images
1616//! // Download a specific image without extracting
1717//! xtask image download evm3588_arceos --output-dir ./images --no-extract
2121
2222use anyhow:: { Result , anyhow} ;
2323use clap:: { Parser , Subcommand } ;
24+ use flate2:: read:: GzDecoder ;
2425use sha2:: { Digest , Sha256 } ;
2526use std:: env;
2627use std:: fs;
2728use std:: io:: Read ;
2829use std:: path:: Path ;
29- use std :: process :: Command ;
30+ use tar :: Archive ;
3031use tokio:: io:: { AsyncWriteExt , BufWriter } ;
3132
3233/// Base URL for downloading images
@@ -43,23 +44,28 @@ pub struct ImageArgs {
4344/// Image management commands
4445#[ derive( Subcommand ) ]
4546pub enum ImageCommands {
46- /// List all available image
47+ /// List all available images
4748 Ls ,
49+
4850 /// Download the specified image and automatically extract it
49- #[ command( alias = "pull" ) ]
5051 Download {
52+ /// Name of the image to download
5153 image_name : String ,
54+
55+ /// Output directory for the downloaded image
5256 #[ arg( short, long) ]
5357 output_dir : Option < String > ,
54- #[ arg(
55- short,
56- long,
57- help = "Automatically extract after download (default: true)"
58- ) ]
59- extract : Option < bool > ,
58+
59+ /// Do not extract after download
60+ #[ arg( long, help = "Do not extract after download" ) ]
61+ no_extract : bool ,
6062 } ,
63+
6164 /// Remove the specified image from temp directory
62- Rm { image_name : String } ,
65+ Rm {
66+ /// Name of the image to remove
67+ image_name : String
68+ } ,
6369}
6470
6571/// Representation of a guest image
@@ -315,8 +321,6 @@ fn image_list() -> Result<()> {
315321/// ```
316322/// // Download the evm3588_arceos image to the ./images directory and automatically extract it
317323/// xtask image download evm3588_arceos --output-dir ./images
318- /// // Or use the pull alias
319- /// xtask image pull evm3588_arceos --output-dir ./images
320324/// ```
321325async fn image_download ( image_name : & str , output_dir : Option < String > , extract : bool ) -> Result < ( ) > {
322326 let image = Image :: find_by_name ( image_name) . ok_or_else ( || {
@@ -421,8 +425,6 @@ async fn image_download(image_name: &str, output_dir: Option<String>, extract: b
421425 . await
422426 . map_err ( |e| anyhow ! ( "Error flushing file: {e}" ) ) ?;
423427
424- println ! ( "\n Download completed" ) ;
425-
426428 // Verify downloaded file
427429 match image_verify_sha256 ( & output_path, image. sha256 ) {
428430 Ok ( true ) => {
@@ -431,12 +433,12 @@ async fn image_download(image_name: &str, output_dir: Option<String>, extract: b
431433 Ok ( false ) => {
432434 // Remove the invalid downloaded file
433435 let _ = fs:: remove_file ( & output_path) ;
434- return Err ( anyhow ! ( "Downloaded file SHA256 verification failed" ) ) ;
436+ return Err ( anyhow ! ( "Download completed but file SHA256 verification failed" ) ) ;
435437 }
436438 Err ( e) => {
437439 // Remove the potentially corrupted downloaded file
438440 let _ = fs:: remove_file ( & output_path) ;
439- return Err ( anyhow ! ( "Error verifying downloaded file: {e}" ) ) ;
441+ return Err ( anyhow ! ( "Download completed but error verifying downloaded file: {e}" ) ) ;
440442 }
441443 }
442444
@@ -453,18 +455,13 @@ async fn image_download(image_name: &str, output_dir: Option<String>, extract: b
453455 // Ensure extraction directory exists
454456 fs:: create_dir_all ( & extract_dir) ?;
455457
456- // Use tar command to extract file
457- let mut child = Command :: new ( "tar" )
458- . arg ( "-xzf" )
459- . arg ( & output_path)
460- . arg ( "-C" )
461- . arg ( & extract_dir)
462- . spawn ( ) ?;
463-
464- let status = child. wait ( ) ?;
465- if !status. success ( ) {
466- return Err ( anyhow ! ( "Extraction failed, tar exit code: {status}" ) ) ;
467- }
458+ // Open the compressed tar file
459+ let tar_gz = fs:: File :: open ( & output_path) ?;
460+ let decoder = GzDecoder :: new ( tar_gz) ;
461+ let mut archive = Archive :: new ( decoder) ;
462+
463+ // Extract the archive
464+ archive. unpack ( & extract_dir) ?;
468465
469466 println ! ( "Image extracted to: {}" , extract_dir. display( ) ) ;
470467 }
@@ -529,8 +526,6 @@ fn image_remove(image_name: &str) -> Result<()> {
529526/// // Run image management commands
530527/// xtask image ls
531528/// xtask image download evm3588_arceos --output-dir ./images
532- /// // Or use the pull alias
533- /// xtask image pull evm3588_arceos --output-dir ./images
534529/// xtask image rm evm3588_arceos
535530/// ```
536531pub async fn run_image ( args : ImageArgs ) -> Result < ( ) > {
@@ -541,9 +536,11 @@ pub async fn run_image(args: ImageArgs) -> Result<()> {
541536 ImageCommands :: Download {
542537 image_name,
543538 output_dir,
544- extract ,
539+ no_extract ,
545540 } => {
546- image_download ( & image_name, output_dir, extract. unwrap_or ( true ) ) . await ?;
541+ // Determine if extraction should be performed
542+ let should_extract = !no_extract;
543+ image_download ( & image_name, output_dir, should_extract) . await ?;
547544 }
548545 ImageCommands :: Rm { image_name } => {
549546 image_remove ( & image_name) ?;
0 commit comments