maelstrom-container 0.14.0

Library for downloading and storing OCI container images.
use anyhow::{bail, Result};
use clap::{Parser, Subcommand};
use maelstrom_container::{
    local_registry::LocalRegistry, DockerReference, ImageDownloader, ImageName,
};
use maelstrom_util::config::common::LogLevel;
use std::path::PathBuf;

#[derive(Subcommand)]
enum CliCommands {
    Download {
        image_name: String,
        layer_dir: PathBuf,
        #[arg(short, long)]
        accept_invalid_certs: bool,
    },
    Inspect {
        image_name: String,
        #[arg(short, long)]
        accept_invalid_certs: bool,
    },
    InspectAll {
        image_name: String,
        #[arg(short, long)]
        accept_invalid_certs: bool,
    },
    Registry {
        source_path: PathBuf,
    },
}

#[derive(Parser)]
#[command(styles=maelstrom_util::clap::styles())]
struct CliOptions {
    #[command(subcommand)]
    command: CliCommands,
}

async fn resolve_name(image_name: &str, accept_invalid_certs: bool) -> Result<DockerReference> {
    let image_name: ImageName = image_name.parse()?;

    let ImageName::Docker(mut ref_) = image_name else {
        bail!("local image path not supported yet");
    };

    let client = reqwest::Client::builder()
        .danger_accept_invalid_certs(accept_invalid_certs)
        .build()
        .unwrap();
    let mut downloader = ImageDownloader::new(client);
    let digest = downloader.resolve_tag(&ref_).await?;
    println!("digest = {digest:#?}");
    ref_.tag = None;
    ref_.digest = Some(digest);
    Ok(ref_)
}

#[tokio::main]
async fn run(opt: CliOptions, log: slog::Logger) -> Result<()> {
    match opt.command {
        CliCommands::Download {
            image_name,
            layer_dir,
            accept_invalid_certs,
        } => {
            let ref_ = resolve_name(&image_name, accept_invalid_certs).await?;

            let ind = indicatif::ProgressBar::new(0);
            let client = reqwest::Client::builder()
                .danger_accept_invalid_certs(accept_invalid_certs)
                .build()
                .unwrap();
            let downloader = ImageDownloader::new(client);
            let image = downloader.download_image(&ref_, &layer_dir, ind).await?;
            println!("{image:#?}");
        }
        CliCommands::Inspect {
            image_name,
            accept_invalid_certs,
        } => {
            let ref_ = resolve_name(&image_name, accept_invalid_certs).await?;

            let client = reqwest::Client::builder()
                .danger_accept_invalid_certs(accept_invalid_certs)
                .build()
                .unwrap();
            let downloader = ImageDownloader::new(client);
            let resp = downloader.inspect(&ref_).await?;
            println!("{resp:#?}");
        }
        CliCommands::InspectAll {
            image_name,
            accept_invalid_certs,
        } => {
            let ref_ = resolve_name(&image_name, accept_invalid_certs).await?;

            let client = reqwest::Client::builder()
                .danger_accept_invalid_certs(accept_invalid_certs)
                .build()
                .unwrap();
            let downloader = ImageDownloader::new(client);
            let resp = downloader.inspect_all(&ref_).await?;
            println!("{resp:#?}");
        }
        CliCommands::Registry { source_path } => {
            let registry = LocalRegistry::new(source_path, log).await?;
            println!("listening on {}", registry.address()?);
            registry.run_until_error().await?;
        }
    }
    Ok(())
}

fn main() -> Result<()> {
    let opt = CliOptions::parse();
    maelstrom_util::log::run_with_logger(LogLevel::Debug, |log| run(opt, log))
}