This commit is contained in:
2025-04-02 09:11:33 +02:00
parent 6cc05ad2eb
commit a32cfb788b
4 changed files with 141 additions and 102 deletions

View File

@@ -1,103 +1,98 @@
use std::process::Command;
use std::collections::HashMap;
use crate::virt::buildah::execute_buildah_command;
use crate::process::CommandResult;
use super::BuildahError;
use serde_json::{self, Value};
use serde::{Deserialize, Serialize};
/// Represents a container image
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Image {
/// Image ID
pub id: String,
/// Image names/tags
pub names: Vec<String>,
/// Image size
pub size: String,
/// Creation timestamp
pub created: String,
}
/// List images in local storage
///
/// # Returns
/// * Array of image details on success or error details
pub fn images() -> Dynamic {
let result = execute_buildah_command(&["images", "--format", "json"]);
/// * Result with array of Image objects on success or error details
pub fn images() -> Result<Vec<Image>, BuildahError> {
let result = execute_buildah_command(&["images", "--format", "json"])?;
let result_map = match result.clone().try_cast::<Map>() {
Some(map) => map,
None => {
return create_result("", "Failed to convert result to map", false, -1);
}
};
let success = match result_map.get("success") {
Some(val) => val.as_bool().unwrap_or(false),
None => false,
};
if success {
let output = match result_map.get("stdout") {
Some(val) => val.to_string(),
None => "".to_string(),
};
// Try to parse the JSON output
match serde_json::from_str::<serde_json::Value>(&output) {
Ok(json) => {
if let serde_json::Value::Array(images) = json {
let mut image_array = Array::new();
// Try to parse the JSON output
match serde_json::from_str::<serde_json::Value>(&result.stdout) {
Ok(json) => {
if let Value::Array(images_json) = json {
let mut images = Vec::new();
for image_json in images_json {
// Extract image ID
let id = match image_json.get("id").and_then(|v| v.as_str()) {
Some(id) => id.to_string(),
None => return Err(BuildahError::ConversionError("Missing image ID".to_string())),
};
for image in images {
let mut image_map = Map::new();
if let Some(id) = image.get("id").and_then(|v| v.as_str()) {
image_map.insert("id".into(), Dynamic::from(id.to_string()));
}
if let Some(name) = image.get("names").and_then(|v| v.as_array()) {
let mut names_array = Array::new();
for name_value in name {
// Extract image names
let names = match image_json.get("names").and_then(|v| v.as_array()) {
Some(names_array) => {
let mut names_vec = Vec::new();
for name_value in names_array {
if let Some(name_str) = name_value.as_str() {
names_array.push(Dynamic::from(name_str.to_string()));
names_vec.push(name_str.to_string());
}
}
image_map.insert("names".into(), Dynamic::from(names_array));
}
if let Some(size) = image.get("size").and_then(|v| v.as_str()) {
image_map.insert("size".into(), Dynamic::from(size.to_string()));
}
if let Some(created) = image.get("created").and_then(|v| v.as_str()) {
image_map.insert("created".into(), Dynamic::from(created.to_string()));
}
image_array.push(Dynamic::from(image_map));
}
let mut result_map = match result.clone().try_cast::<Map>() {
Some(map) => map,
None => Map::new(),
names_vec
},
None => Vec::new(), // Empty vector if no names found
};
result_map.insert("images".into(), Dynamic::from(image_array));
Dynamic::from(result_map)
} else {
create_result(
"",
"Failed to parse image list: Expected JSON array",
false,
-1
)
// Extract image size
let size = match image_json.get("size").and_then(|v| v.as_str()) {
Some(size) => size.to_string(),
None => "Unknown".to_string(), // Default value if size not found
};
// Extract creation timestamp
let created = match image_json.get("created").and_then(|v| v.as_str()) {
Some(created) => created.to_string(),
None => "Unknown".to_string(), // Default value if created not found
};
// Create Image struct and add to vector
images.push(Image {
id,
names,
size,
created,
});
}
},
Err(e) => {
create_result(
"",
&format!("Failed to parse image list JSON: {}", e),
false,
-1
)
Ok(images)
} else {
Err(BuildahError::JsonParseError("Expected JSON array".to_string()))
}
},
Err(e) => {
Err(BuildahError::JsonParseError(format!("Failed to parse image list JSON: {}", e)))
}
} else {
result
}
}
/// Remove one or more images
///
/// # Arguments
/// * `image` - Image ID or name
///
/// # Returns
/// * Success or error details
pub fn image_remove(image: &str) -> Dynamic {
/// * Result with command output or error
pub fn image_remove(image: &str) -> Result<CommandResult, BuildahError> {
execute_buildah_command(&["rmi", image])
}
@@ -109,8 +104,8 @@ pub fn image_remove(image: &str) -> Dynamic {
/// * `tls_verify` - Whether to verify TLS (default: true)
///
/// # Returns
/// * Success or error details
pub fn image_push(image: &str, destination: &str, tls_verify: bool) -> Dynamic {
/// * Result with command output or error
pub fn image_push(image: &str, destination: &str, tls_verify: bool) -> Result<CommandResult, BuildahError> {
let mut args = vec!["push"];
if !tls_verify {
@@ -130,8 +125,8 @@ pub fn image_push(image: &str, destination: &str, tls_verify: bool) -> Dynamic {
/// * `new_name` - New name for the image
///
/// # Returns
/// * Success or error details
pub fn image_tag(image: &str, new_name: &str) -> Dynamic {
/// * Result with command output or error
pub fn image_tag(image: &str, new_name: &str) -> Result<CommandResult, BuildahError> {
execute_buildah_command(&["tag", image, new_name])
}
@@ -142,8 +137,8 @@ pub fn image_tag(image: &str, new_name: &str) -> Dynamic {
/// * `tls_verify` - Whether to verify TLS (default: true)
///
/// # Returns
/// * Success or error details
pub fn image_pull(image: &str, tls_verify: bool) -> Dynamic {
/// * Result with command output or error
pub fn image_pull(image: &str, tls_verify: bool) -> Result<CommandResult, BuildahError> {
let mut args = vec!["pull"];
if !tls_verify {
@@ -165,8 +160,8 @@ pub fn image_pull(image: &str, tls_verify: bool) -> Dynamic {
/// * `rm` - Whether to remove the container after commit
///
/// # Returns
/// * Success or error details
pub fn image_commit(container: &str, image_name: &str, format: Option<&str>, squash: bool, rm: bool) -> Dynamic {
/// * Result with command output or error
pub fn image_commit(container: &str, image_name: &str, format: Option<&str>, squash: bool, rm: bool) -> Result<CommandResult, BuildahError> {
let mut args = vec!["commit"];
if let Some(format_str) = format {
@@ -195,8 +190,8 @@ pub fn image_commit(container: &str, image_name: &str, format: Option<&str>, squ
/// * `options` - Map of configuration options
///
/// # Returns
/// * Success or error details
pub fn config(container: &str, options: Map) -> Dynamic {
/// * Result with command output or error
pub fn config(container: &str, options: HashMap<String, String>) -> Result<CommandResult, BuildahError> {
let mut args_owned: Vec<String> = Vec::new();
args_owned.push("config".to_string());
@@ -204,10 +199,7 @@ pub fn config(container: &str, options: Map) -> Dynamic {
for (key, value) in options.iter() {
let option_name = format!("--{}", key);
args_owned.push(option_name);
if !value.is_unit() {
args_owned.push(value.to_string());
}
args_owned.push(value.clone());
}
args_owned.push(container.to_string());
@@ -217,4 +209,3 @@ pub fn config(container: &str, options: Map) -> Dynamic {
execute_buildah_command(&args)
}