Skip to content

Commit 635bee4

Browse files
committed
cfsctl: Add top-level images command
Add an 'images' command (alias: list-images) that lists all named image references in the repository. Outputs a table with NAME and DIGEST columns by default, or a JSON array with --json. Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
1 parent b77cca1 commit 635bee4

2 files changed

Lines changed: 101 additions & 8 deletions

File tree

crates/composefs-ctl/src/lib.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ use std::sync::Arc;
4848
use anyhow::{Context as _, Result};
4949
use clap::{Parser, Subcommand, ValueEnum};
5050
use clap_complete::engine::ArgValueCompleter;
51-
#[cfg(any(feature = "oci", feature = "ostree"))]
5251
use comfy_table::{Table, presets::UTF8_FULL};
5352
#[cfg(feature = "ostree")]
5453
use complete::complete_ostree_refs;
@@ -726,6 +725,16 @@ enum Command {
726725
},
727726
/// Imports a composefs image (unsafe!)
728727
ImportImage { reference: String },
728+
/// List all named image references in the repository
729+
#[clap(name = "images", alias = "list-images")]
730+
Images {
731+
/// Output as JSON array
732+
#[clap(long)]
733+
json: bool,
734+
/// Show full digest instead of truncated form
735+
#[clap(long)]
736+
no_trunc: bool,
737+
},
729738
/// Commands for dealing with OCI images and layers
730739
#[cfg(feature = "oci")]
731740
Oci {
@@ -1904,6 +1913,31 @@ where
19041913
} => {
19051914
mount_opts.mount_image(&repo, &name, &mountpoint)?;
19061915
}
1916+
Command::Images { json, no_trunc } => {
1917+
let reply =
1918+
varlink::run_list_image_refs(&repo).map_err(|e| anyhow::anyhow!("{e:?}"))?;
1919+
1920+
if json {
1921+
serde_json::to_writer_pretty(std::io::stdout().lock(), &reply)?;
1922+
println!();
1923+
} else if reply.images.is_empty() {
1924+
println!("No images found");
1925+
} else {
1926+
let mut table = Table::new();
1927+
table.load_preset(UTF8_FULL);
1928+
table.set_header(["NAME", "DIGEST"]);
1929+
1930+
for entry in &reply.images {
1931+
let digest_display = if !no_trunc && entry.digest.len() > 12 {
1932+
&entry.digest[..12]
1933+
} else {
1934+
&entry.digest
1935+
};
1936+
table.add_row([entry.name.as_str(), digest_display]);
1937+
}
1938+
println!("{table}");
1939+
}
1940+
}
19071941
Command::ImageObjects { name } => {
19081942
let objects = repo.objects_for_image(&name)?;
19091943
for object in objects {

crates/composefs-ctl/src/varlink.rs

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,41 @@ async fn run_image_objects<ObjectID: FsVerityHashValue>(
407407
Ok(ImageObjectsReply { object_ids })
408408
}
409409

410+
/// A single image reference entry.
411+
#[derive(Debug, Clone, Serialize, Deserialize, zlink::introspect::Type)]
412+
pub struct ImageRefEntry {
413+
/// The reference name.
414+
pub name: String,
415+
/// The fs-verity digest the reference points to.
416+
pub digest: String,
417+
}
418+
419+
/// Reply listing all named image references in the repository.
420+
#[derive(Debug, Clone, Serialize, Deserialize, zlink::introspect::Type)]
421+
pub struct ListImageRefsReply {
422+
/// The image references.
423+
pub images: Vec<ImageRefEntry>,
424+
}
425+
426+
/// Collect all named image references from the repository.
427+
pub fn run_list_image_refs<ObjectID: FsVerityHashValue>(
428+
repo: &Repository<ObjectID>,
429+
) -> std::result::Result<ListImageRefsReply, RepositoryError> {
430+
let refs = repo
431+
.list_image_refs("")
432+
.map_err(|e| RepositoryError::InternalError {
433+
message: format!("{e:#}"),
434+
})?;
435+
let images = refs
436+
.into_iter()
437+
.map(|(name, target)| {
438+
let digest = target.rsplit('/').next().unwrap_or(&target).to_string();
439+
ImageRefEntry { name, digest }
440+
})
441+
.collect();
442+
Ok(ListImageRefsReply { images })
443+
}
444+
410445
/// Options for a `Mount` call. All fields are optional for forward
411446
/// compatibility — new mount options can be added without breaking the
412447
/// wire format.
@@ -743,9 +778,10 @@ mod service_impl {
743778
#![allow(missing_docs)]
744779

745780
use super::{
746-
CfsctlService, FsckReply, GcReply, ImageObjectsReply, InitRepositoryReply, MountParams,
747-
MountReply, OpenRepo, OpenRepositoryReply, RepositoryError, run_fsck, run_gc,
748-
run_image_objects, run_init_repository, run_mount,
781+
CfsctlService, FsckReply, GcReply, ImageObjectsReply, InitRepositoryReply,
782+
ListImageRefsReply, MountParams, MountReply, OpenRepo, OpenRepositoryReply,
783+
RepositoryError, run_fsck, run_gc, run_image_objects, run_init_repository,
784+
run_list_image_refs, run_mount,
749785
};
750786
use composefs::fsverity::{Algorithm, Sha256HashValue, Sha512HashValue};
751787

@@ -852,6 +888,17 @@ mod service_impl {
852888
}
853889
}
854890

891+
/// List all named image references in the repository.
892+
async fn list_image_refs(
893+
&self,
894+
handle: u64,
895+
) -> std::result::Result<ListImageRefsReply, RepositoryError> {
896+
match self.lookup_repo(handle)? {
897+
OpenRepo::Sha256(ref r) => run_list_image_refs::<Sha256HashValue>(r),
898+
OpenRepo::Sha512(ref r) => run_list_image_refs::<Sha512HashValue>(r),
899+
}
900+
}
901+
855902
/// Create a detached mount of an image and return the mount fd.
856903
///
857904
/// If overlay upper/work directories are needed, pass them as two fds
@@ -898,10 +945,11 @@ mod service_impl {
898945
parse_local_fetch, pull_stream,
899946
};
900947
use super::{
901-
CfsctlService, FsckReply, GcReply, ImageObjectsReply, InitRepositoryReply, MountParams,
902-
MountReply, OpenRepo, OpenRepositoryReply, RepositoryError, run_compute_id, run_fsck,
903-
run_gc, run_image_objects, run_init_repository, run_inspect, run_list_images, run_mount,
904-
run_oci_fsck, run_oci_mount, run_tag, run_untag,
948+
CfsctlService, FsckReply, GcReply, ImageObjectsReply, InitRepositoryReply,
949+
ListImageRefsReply, MountParams, MountReply, OpenRepo, OpenRepositoryReply,
950+
RepositoryError, run_compute_id, run_fsck, run_gc, run_image_objects, run_init_repository,
951+
run_inspect, run_list_image_refs, run_list_images, run_mount, run_oci_fsck, run_oci_mount,
952+
run_tag, run_untag,
905953
};
906954
use composefs::fsverity::{Algorithm, Sha256HashValue, Sha512HashValue};
907955

@@ -1010,6 +1058,17 @@ mod service_impl {
10101058
}
10111059
}
10121060

1061+
/// List all named image references in the repository.
1062+
async fn list_image_refs(
1063+
&self,
1064+
handle: u64,
1065+
) -> std::result::Result<ListImageRefsReply, RepositoryError> {
1066+
match self.lookup_repo(handle)? {
1067+
OpenRepo::Sha256(ref r) => run_list_image_refs::<Sha256HashValue>(r),
1068+
OpenRepo::Sha512(ref r) => run_list_image_refs::<Sha512HashValue>(r),
1069+
}
1070+
}
1071+
10131072
/// Create a detached mount of an image and return the mount fd.
10141073
///
10151074
/// If overlay upper/work directories are needed, pass them as two fds

0 commit comments

Comments
 (0)