use crate::Result;
use crate::config::GlobalConfig;
use crate::config::Paths;
use colored::Colorize;
use std::{fs, io, path::PathBuf};
pub fn execute_status(verbose: bool) -> Result<()> {
let paths = Paths::new()?;
let global_config = GlobalConfig::load(&paths.global_config())?;
let engine = global_config.get_container_engine()?;
if verbose {
eprintln!("Using engine: {}", engine);
}
let flyboat_dir = paths.flyboat_dir();
if flyboat_dir.exists() {
let folder_size = dir_size(&flyboat_dir)?;
println!(
"{}: {} ({})",
"Flyboat directory".bold(),
flyboat_dir.display(),
human_size(folder_size).cyan()
);
} else {
println!(
"{}: {} (not found)",
"Flyboat directory".bold(),
flyboat_dir.display()
);
}
println!();
println!("{}", "Flyboat Images:".bold());
let images_output = crate::docker::execute_command_output(
&engine,
[
"images",
"--filter",
"reference=flyboat-*",
"--format",
"{{.Repository}}:{{.Tag}}\t{{.Size}}\t{{.CreatedSince}}",
],
&paths.flyboat_dir(),
);
match images_output {
Ok(output) if !output.stdout.is_empty() => {
let images = String::from_utf8_lossy(&output.stdout);
println!(
"{:<40} {:<12} {}",
"IMAGE".dimmed(),
"SIZE".dimmed(),
"CREATED".dimmed()
);
for line in images.lines() {
let parts: Vec<&str> = line.split('\t').collect();
if parts.len() >= 3 {
println!("{:<40} {:<12} {}", parts[0].green(), parts[1], parts[2]);
}
}
}
_ => {
println!(" No flyboat images found");
}
}
println!();
println!("{}", "Running Containers:".bold());
let containers_output = crate::docker::execute_command_output(
&engine,
[
"ps",
"--filter",
"name=flyboat-",
"--format",
"{{.Names}}\t{{.Status}}\t{{.Ports}}",
],
&paths.flyboat_dir(),
);
match containers_output {
Ok(output) if !output.stdout.is_empty() => {
let containers = String::from_utf8_lossy(&output.stdout);
println!(
"{:<30} {:<20} {}",
"CONTAINER".dimmed(),
"STATUS".dimmed(),
"PORTS".dimmed()
);
for line in containers.lines() {
let parts: Vec<&str> = line.split('\t').collect();
if parts.len() >= 2 {
let ports = parts.get(2).unwrap_or(&"-");
println!("{:<30} {:<20} {}", parts[0].green(), parts[1], ports);
}
}
}
_ => {
println!(" No running containers");
}
}
println!();
println!("{}", "Docker Disk Usage:".bold());
let df_output =
crate::docker::execute_command_output(&engine, ["system", "df"], &paths.flyboat_dir());
if let Ok(output) = df_output {
let df = String::from_utf8_lossy(&output.stdout);
for line in df.lines() {
println!(" {}", line);
}
}
Ok(())
}
fn dir_size(path: impl Into<PathBuf>) -> io::Result<u64> {
fn dir_size(mut dir: fs::ReadDir) -> io::Result<u64> {
dir.try_fold(0, |acc, file| {
let file = file?;
let size = match file.metadata()? {
data if data.is_dir() => dir_size(fs::read_dir(file.path())?)?,
data => data.len(),
};
Ok(acc + size)
})
}
dir_size(fs::read_dir(path.into())?)
}
fn human_size(bytes: u64) -> String {
let formats = ["B", "kB", "MB", "GB", "TB", "PB", "EB"];
let mut value = bytes;
let mut value_unit_index = 0;
while value > 1000 && value_unit_index < formats.len() - 1 {
value /= 1000;
value_unit_index += 1;
}
format!(
"{value}{}",
formats.get(value_unit_index).map_or("?", |v| v)
)
}