Add image ls and image rm commands

This commit is contained in:
2026-08-26 23:27:58 +02:00
parent 37f537184c
commit 8b544ab688
3 changed files with 61 additions and 23 deletions
+34
View File
@@ -0,0 +1,34 @@
use std::fs;
use crate::registry::{registry_base_dir, validate_image_name};
use anyhow::Context;
use clap::Subcommand;
#[derive(Subcommand, Debug)]
pub enum ImageCmd {
Ls,
Rm { image: String },
}
pub fn run(cmd: ImageCmd) -> anyhow::Result<()> {
match cmd {
ImageCmd::Ls => ls(),
ImageCmd::Rm { image } => rm(&image),
}
}
fn rm(image: &str) -> Result<(), anyhow::Error> {
validate_image_name(image)?;
let image_dir = registry_base_dir()?.join(image);
fs::remove_dir_all(image_dir).context("Failed to remove image dir")?;
Ok(())
}
fn ls() -> anyhow::Result<()> {
let dir = fs::read_dir(registry_base_dir()?)?;
for entry in dir {
let entry = entry?.file_name();
println!(" {}", entry.to_string_lossy());
}
Ok(())
}
+9
View File
@@ -1,10 +1,13 @@
mod build; mod build;
mod image;
mod qemu; mod qemu;
mod registry; mod registry;
use anyhow::Result; use anyhow::Result;
use clap::{Parser, Subcommand}; use clap::{Parser, Subcommand};
use crate::image::ImageCmd;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(about = "Build bootable initrd VMs from container images")] #[command(about = "Build bootable initrd VMs from container images")]
struct Cli { struct Cli {
@@ -27,6 +30,9 @@ enum Commands {
/// Image tag / registry subdir name /// Image tag / registry subdir name
name: String, name: String,
}, },
/// List slim images in the registry
#[command(subcommand)]
Image(ImageCmd),
} }
fn main() -> Result<()> { fn main() -> Result<()> {
@@ -38,6 +44,9 @@ fn main() -> Result<()> {
Commands::Run { name } => { Commands::Run { name } => {
qemu::run(&name)?; qemu::run(&name)?;
} }
Commands::Image(cmd) => {
image::run(cmd)?;
}
} }
Ok(()) Ok(())
} }
+18 -23
View File
@@ -1,8 +1,8 @@
//! Registry: local storage of built VM artifacts under //! Registry: local storage of built VM artifacts under
//! `$XDG_DATA_HOME/slim-rs/registry/<image>/`. //! `$XDG_DATA_HOME/slim-rs/registry/<image>/`.
use anyhow::{Context, Result, bail}; use anyhow::{Context, Result, anyhow, bail};
use std::path::PathBuf; use std::{fs, io, path::PathBuf};
/// Validate a user-supplied image name before it is used in a registry path. /// Validate a user-supplied image name before it is used in a registry path.
/// ///
@@ -26,30 +26,25 @@ pub(crate) fn validate_image_name(name: &str) -> Result<()> {
Ok(()) Ok(())
} }
pub(crate) fn registry_base_dir() -> Result<PathBuf> {
let base = xdg::BaseDirectories::with_prefix("slim-rs");
base.create_data_directory("registry")
.context("Failed to create XDG_DATA_HOME subdirectory")
}
pub(crate) fn registry_dir(image: &str) -> Result<PathBuf> { pub(crate) fn registry_dir(image: &str) -> Result<PathBuf> {
validate_image_name(image)?; validate_image_name(image)?;
let base = xdg::BaseDirectories::with_prefix("slim-rs"); let base = registry_base_dir()?;
let initrd_path = base
.place_data_file(format!("registry/{image}/initrd")) let reg_dir = base.join(image);
.context("Failed to write to XDG_DATA_HOME")?; fs::create_dir(&reg_dir)
let reg_dir = initrd_path .or_else(|e| {
.parent() (e.kind() == io::ErrorKind::AlreadyExists)
.expect("data file has a parent") .then_some(())
.to_owned(); .ok_or(e)
})
.with_context(|| anyhow!("Failed to create {reg_dir:?}"))?;
// Defense in depth: the constructed path must stay inside the registry.
let registry_root = base
.place_data_file("registry/.root-check")
.context("Failed to write to XDG_DATA_HOME")?
.parent()
.expect("data file has a parent")
.to_owned();
if !reg_dir.starts_with(&registry_root) {
bail!(
"invalid image name '{image}': registry path escapes {}",
registry_root.display()
);
}
Ok(reg_dir) Ok(reg_dir)
} }