Skip to content

Commit cba96fb

Browse files
committed
feat: remove extract and add rm command for build tool
1 parent a0bcd38 commit cba96fb

File tree

1 file changed

+117
-101
lines changed

1 file changed

+117
-101
lines changed

xtask/src/image.rs

Lines changed: 117 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,30 @@
11
//! xtask/src/image.rs
22
//! Guest Image management commands for the Axvisor build configuration tool
33
//! (https://github.com/arceos-hypervisor/xtask).
4-
//!
5-
//! This module provides functionality to list, download, and extract
4+
//!
5+
//! This module provides functionality to list, download, and remove
66
//! pre-built guest images for various supported boards and architectures. The images
7-
//! are downloaded from a specified URL base and verified using SHA-256 checksums. The extracted
8-
//! images are placed in a specified output directory.
7+
//! are downloaded from a specified URL base and verified using SHA-256 checksums. The downloaded
8+
//! images are automatically extracted to a specified output directory. Images can also be removed
9+
//! from the temporary directory.
910
//! ! Usage examples:
1011
//!! ```
1112
//! // List available images
1213
//! xtask image ls
13-
//! // Download a specific image
14+
//! // Download a specific image and automatically extract it
1415
//! xtask image download evm3588_arceos --output-dir ./images
15-
//! // Extract a downloaded image
16-
//! xtask image extract ./images/evm3588_arceos.tar.gz --output-dir ./extracted
16+
//! // Download a specific image without extracting
17+
//! xtask image download evm3588_arceos --output-dir ./images --no-extract
18+
//! // Remove a specific image from temp directory
19+
//! xtask image rm evm3588_arceos
1720
//! ```
1821
1922
use anyhow::{Result, anyhow};
2023
use clap::{Parser, Subcommand};
2124
use std::path::{Path};
2225
use std::process::Command;
2326
use std::fs;
27+
use std::env;
2428

2529
/// Base URL for downloading images
2630
const IMAGE_URL_BASE: &str = "https://github.com/arceos-hypervisor/axvisor-guest/releases/download/v0.0.16/";
@@ -37,17 +41,17 @@ pub struct ImageArgs {
3741
pub enum ImageCommands {
3842
/// List all available image
3943
Ls,
40-
/// Download the specified image
44+
/// Download the specified image and automatically extract it
4145
Download {
4246
image_name: String,
4347
#[arg(short, long)]
4448
output_dir: Option<String>,
49+
#[arg(short, long, help = "Automatically extract after download (default: true)")]
50+
extract: Option<bool>,
4551
},
46-
/// Extract the specified image file
47-
Extract {
48-
input_file: String,
49-
#[arg(short, long)]
50-
output_dir: Option<String>,
52+
/// Remove the specified image from temp directory
53+
Rm {
54+
image_name: String,
5155
},
5256
}
5357

@@ -202,6 +206,30 @@ impl Image {
202206
}
203207
}
204208

209+
/// Verify the SHA256 checksum of a file
210+
/// # Arguments
211+
/// * `file_path` - The path to the file to verify
212+
/// * `expected_sha256` - The expected SHA256 checksum as a hex string
213+
/// # Returns
214+
/// * `Result<bool>` - Result indicating whether the checksum matches
215+
/// # Errors
216+
/// * `anyhow::Error` - If any error occurs during the verification process
217+
fn image_verify_sha256(file_path: &Path, expected_sha256: &str) -> Result<bool> {
218+
let output = Command::new("sha256sum")
219+
.arg(file_path)
220+
.output()?;
221+
222+
if !output.status.success() {
223+
return Err(anyhow!("Failed to calculate SHA256"));
224+
}
225+
226+
let stdout = String::from_utf8(output.stdout)?;
227+
let actual_sha256 = stdout.split_whitespace().next()
228+
.ok_or_else(|| anyhow!("Unable to parse SHA256 output"))?;
229+
230+
Ok(actual_sha256 == expected_sha256)
231+
}
232+
205233
/// List all available images
206234
/// # Returns
207235
/// * `Result<()>` - Result indicating success or failure
@@ -236,20 +264,23 @@ fn image_list() -> Result<()> {
236264
// Return Ok to indicate successful execution
237265
}
238266

239-
/// Download the specified image
267+
/// Download the specified image and optionally extract it
240268
/// # Arguments
241269
/// * `image_name` - The name of the image to download
242-
/// * `output_dir` - Optional output directory to save the downloaded image
270+
/// * `output_dir` - Optional output directory to save the downloaded image
271+
/// * `extract` - Whether to automatically extract the image after download (default: true)
243272
/// # Returns
244273
/// * `Result<()>` - Result indicating success or failure
245274
/// # Errors
246-
/// * `anyhow::Error` - If any error occurs during the download process
275+
/// * `anyhow::Error` - If any error occurs during the download or extraction process
247276
/// # Examples
248277
/// ```
249-
/// // Download the evm3588_arceos image to the ./images directory
278+
/// // Download the evm3588_arceos image to the ./images directory and automatically extract it
250279
/// xtask image download evm3588_arceos --output-dir ./images
280+
/// // Download the evm3588_arceos image to the ./images directory without extracting
281+
/// xtask image download evm3588_arceos --output-dir ./images --no-extract
251282
/// ```
252-
fn image_download(image_name: &str, output_dir: Option<String>) -> Result<()> {
283+
fn image_download(image_name: &str, output_dir: Option<String>, extract: bool) -> Result<()> {
253284
let image = Image::find_by_name(image_name)
254285
.ok_or_else(|| anyhow!("Image not found: {}. Use 'xtask image ls' to view available images", image_name))?;
255286

@@ -267,9 +298,9 @@ fn image_download(image_name: &str, output_dir: Option<String>) -> Result<()> {
267298
}
268299
}
269300
None => {
270-
// If not specified, use tmp directory under current working directory
271-
let current_dir = std::env::current_dir()?;
272-
current_dir.join("tmp").join(format!("{}.tar.gz", image_name))
301+
// If not specified, use system temporary directory
302+
let temp_dir = env::temp_dir();
303+
temp_dir.join("axvisor").join(format!("{}.tar.gz", image_name))
273304
}
274305
};
275306

@@ -335,99 +366,83 @@ fn image_download(image_name: &str, output_dir: Option<String>) -> Result<()> {
335366
}
336367
}
337368

338-
Ok(())
339-
}
340-
341-
/// Verify the SHA256 checksum of a file
342-
/// # Arguments
343-
/// * `file_path` - The path to the file to verify
344-
/// * `expected_sha256` - The expected SHA256 checksum as a hex string
345-
/// # Returns
346-
/// * `Result<bool>` - Result indicating whether the checksum matches
347-
/// # Errors
348-
/// * `anyhow::Error` - If any error occurs during the verification process
349-
fn image_verify_sha256(file_path: &Path, expected_sha256: &str) -> Result<bool> {
350-
let output = Command::new("sha256sum")
351-
.arg(file_path)
352-
.output()?;
353-
354-
if !output.status.success() {
355-
return Err(anyhow!("Failed to calculate SHA256"));
369+
// If extract flag is true, extract the downloaded file
370+
if extract {
371+
println!("Extracting downloaded file...");
372+
373+
// Determine extraction output directory
374+
let extract_dir = output_path.parent()
375+
.ok_or_else(|| anyhow!("Unable to determine parent directory of downloaded file"))?
376+
.join(image_name);
377+
378+
// Ensure extraction directory exists
379+
fs::create_dir_all(&extract_dir)?;
380+
381+
println!("Extracting to: {}", extract_dir.display());
382+
383+
// Use tar command to extract file
384+
let mut child = Command::new("tar")
385+
.arg("-xzf")
386+
.arg(&output_path)
387+
.arg("-C")
388+
.arg(&extract_dir)
389+
.spawn()?;
390+
391+
let status = child.wait()?;
392+
if !status.success() {
393+
return Err(anyhow!("Extraction failed, tar exit code: {}", status));
394+
}
395+
396+
println!("Extraction completed successfully");
397+
println!("Image extracted to: {}", extract_dir.display());
356398
}
357399

358-
let stdout = String::from_utf8(output.stdout)?;
359-
let actual_sha256 = stdout.split_whitespace().next()
360-
.ok_or_else(|| anyhow!("Unable to parse SHA256 output"))?;
361-
362-
Ok(actual_sha256 == expected_sha256)
400+
Ok(())
363401
}
364402

365-
/// Extract the specified image file
403+
/// Remove the specified image from temp directory
366404
/// # Arguments
367-
/// * `input_file` - The path to the input image file
368-
/// * `output_dir` - Optional output directory to extract the image to
405+
/// * `image_name` - The name of the image to remove
369406
/// # Returns
370407
/// * `Result<()>` - Result indicating success or failure
371408
/// # Errors
372-
/// * `anyhow::Error` - If any error occurs during the extraction process
409+
/// * `anyhow::Error` - If any error occurs during the removal process
373410
/// # Examples
374411
/// ```
375-
/// // Extract the image file ./images/evm3588_arceos.tar.gz to ./extracted
376-
/// xtask image extract ./images/evm3588_arceos.tar.gz --output-dir ./extracted
412+
/// // Remove the evm3588_arceos image from temp directory
413+
/// xtask image rm evm3588_arceos
377414
/// ```
378-
fn image_extract(input_file: &str, output_dir: Option<String>) -> Result<()> {
379-
let input_path = {
380-
let path = Path::new(input_file);
381-
if path.is_absolute() {
382-
path.to_path_buf()
383-
} else {
384-
let current_dir = std::env::current_dir()?;
385-
current_dir.join(path)
386-
}
387-
};
388-
389-
let output_path = match output_dir {
390-
Some(dir) => {
391-
let path = Path::new(&dir);
392-
if path.is_absolute() {
393-
path.to_path_buf()
394-
} else {
395-
let current_dir = std::env::current_dir()?;
396-
current_dir.join(path)
397-
}
398-
}
399-
None => {
400-
input_path.parent()
401-
.ok_or_else(|| anyhow!("Unable to determine parent directory of input file"))?
402-
.to_path_buf()
403-
}
404-
};
415+
fn image_remove(image_name: &str) -> Result<()> {
416+
// Check if the image name is valid by looking it up
417+
let _image = Image::find_by_name(image_name)
418+
.ok_or_else(|| anyhow!("Image not found: {}. Use 'xtask image ls' to view available images", image_name))?;
405419

406-
// Check if input file exists
407-
if !input_path.exists() {
408-
return Err(anyhow!("Input file does not exist: {}", input_path.display()));
409-
}
420+
let temp_dir = env::temp_dir().join("axvisor");
421+
let tar_file = temp_dir.join(format!("{}.tar.gz", image_name));
422+
let extract_dir = temp_dir.join(image_name);
410423

411-
// Ensure output directory exists
412-
fs::create_dir_all(&output_path)?;
424+
let mut removed = false;
413425

414-
println!("Extracting file: {}", input_path.display());
415-
println!("Target directory: {}", output_path.display());
426+
// Remove the tar file if it exists
427+
if tar_file.exists() {
428+
println!("Removing tar file: {}", tar_file.display());
429+
fs::remove_file(&tar_file)?;
430+
removed = true;
431+
}
416432

417-
// Use tar command to extract file
418-
let mut child = Command::new("tar")
419-
.arg("-xzf")
420-
.arg(&input_path)
421-
.arg("-C")
422-
.arg(&output_path)
423-
.spawn()?;
433+
// Remove the extracted directory if it exists
434+
if extract_dir.exists() {
435+
println!("Removing extracted directory: {}", extract_dir.display());
436+
fs::remove_dir_all(&extract_dir)?;
437+
removed = true;
438+
}
424439

425-
let status = child.wait()?;
426-
if !status.success() {
427-
return Err(anyhow!("Extraction failed, tar exit code: {}", status));
440+
if !removed {
441+
println!("No files found for image: {}", image_name);
442+
} else {
443+
println!("Successfully removed image: {}", image_name);
428444
}
429445

430-
println!("Extraction completed");
431446
Ok(())
432447
}
433448

@@ -443,18 +458,19 @@ fn image_extract(input_file: &str, output_dir: Option<String>) -> Result<()> {
443458
/// // Run image management commands
444459
/// xtask image ls
445460
/// xtask image download evm3588_arceos --output-dir ./images
446-
/// xtask image extract ./images/evm3588_arceos.tar.gz --output-dir ./extracted
461+
/// xtask image download evm3588_arceos --output-dir ./images --no-extract
462+
/// xtask image rm evm3588_arceos
447463
/// ```
448464
pub fn run_image(args: ImageArgs) -> Result<()> {
449465
match args.command {
450466
ImageCommands::Ls => {
451467
image_list()?;
452468
}
453-
ImageCommands::Download { image_name, output_dir } => {
454-
image_download(&image_name, output_dir)?;
469+
ImageCommands::Download { image_name, output_dir, extract } => {
470+
image_download(&image_name, output_dir, extract.unwrap_or(true))?;
455471
}
456-
ImageCommands::Extract { input_file, output_dir } => {
457-
image_extract(&input_file, output_dir)?;
472+
ImageCommands::Rm { image_name } => {
473+
image_remove(&image_name)?;
458474
}
459475
}
460476

0 commit comments

Comments
 (0)