use std::fmt;
use rust_i18n::t;
use tabled::Tabled;
use timeweb_rs::apis::container_registry_api;
use crate::{error::TwcError, output::OutputFormat};
#[derive(Tabled)]
struct RegistryRow {
#[tabled(rename = "ID")]
id: String,
#[tabled(rename = "Name")]
name: String,
#[tabled(rename = "Description")]
description: String,
#[tabled(rename = "Preset ID")]
preset_id: String,
#[tabled(rename = "Disk (GB)")]
disk: String,
#[tabled(rename = "Created")]
created: String
}
impl fmt::Display for RegistryRow {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} {} {} {} {} {}",
self.id, self.name, self.description, self.preset_id, self.disk, self.created
)
}
}
#[derive(Tabled)]
struct RepositoryRow {
#[tabled(rename = "Name")]
name: String,
#[tabled(rename = "Tag")]
tag: String,
#[tabled(rename = "Digest")]
digest: String
}
impl fmt::Display for RepositoryRow {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {} {}", self.name, self.tag, self.digest)
}
}
#[derive(Tabled)]
struct PresetRow {
#[tabled(rename = "ID")]
id: String,
#[tabled(rename = "Description")]
description: String,
#[tabled(rename = "Disk (GB)")]
disk: String,
#[tabled(rename = "Price")]
price: String,
#[tabled(rename = "Location")]
location: String
}
impl fmt::Display for PresetRow {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"{} {} {} {} {}",
self.id, self.description, self.disk, self.price, self.location
)
}
}
fn fmt_id(v: i32) -> String {
v.to_string()
}
fn fmt_disk(disk: &timeweb_rs::models::RegistryOutDiskStats) -> String {
format!("{} / {}", disk.used, disk.size)
}
pub async fn list(
config: &timeweb_rs::apis::configuration::Configuration,
limit: Option<i32>,
offset: Option<i32>,
format: OutputFormat
) -> Result<(), TwcError> {
if limit.is_some() || offset.is_some() {
eprintln!("{}", t!("cli.registry_limit_offset_note"));
}
let resp = container_registry_api::get_registries(config).await?;
let registries = resp.container_registry_list.unwrap_or_default();
let rows: Vec<RegistryRow> = registries
.iter()
.map(|r| RegistryRow {
id: fmt_id(r.id),
name: r.name.clone(),
description: r.description.clone(),
preset_id: fmt_id(r.preset_id),
disk: fmt_disk(&r.disk_stats),
created: r.created_at.to_rfc3339()
})
.collect();
match format {
OutputFormat::Table => {
if rows.is_empty() {
println!("{}", t!("cli.no_registries_found"));
} else {
let table = crate::output::render_table(&rows);
println!("{table}");
}
}
OutputFormat::Json | OutputFormat::Yaml => {
let out = crate::output::serialized(format, ®istries)
.transpose()?
.unwrap_or_default();
println!("{out}");
}
OutputFormat::Quiet => {
for r in ®istries {
println!("{}\t{}", fmt_id(r.id), r.name);
}
}
}
Ok(())
}
pub async fn info(
config: &timeweb_rs::apis::configuration::Configuration,
id: i32,
format: OutputFormat
) -> Result<(), TwcError> {
let resp = container_registry_api::get_registry(config, id).await?;
let r = &resp.container_registry;
match format {
OutputFormat::Table => {
println!("ID: {}", fmt_id(r.id));
println!("Name: {}", r.name);
println!("Description: {}", r.description);
println!("Preset ID: {}", fmt_id(r.preset_id));
println!("Configurator ID: {}", fmt_id(r.configurator_id));
println!("Project ID: {}", fmt_id(r.project_id));
println!("Disk: {}", fmt_disk(&r.disk_stats));
println!("Created at: {}", r.created_at.to_rfc3339());
println!("Updated at: {}", r.updated_at.to_rfc3339());
}
OutputFormat::Json | OutputFormat::Yaml => {
let out = crate::output::serialized(format, &r)
.transpose()?
.unwrap_or_default();
println!("{out}");
}
OutputFormat::Quiet => {
println!("{}\t{}\t{}", fmt_id(r.id), r.name, r.description);
}
}
Ok(())
}
pub async fn create(
config: &timeweb_rs::apis::configuration::Configuration,
name: &str,
format: OutputFormat
) -> Result<(), TwcError> {
let req = timeweb_rs::models::RegistryIn::new(name.to_string());
let resp = container_registry_api::create_registry(config, req).await?;
let r = &resp.container_registry;
match format {
OutputFormat::Table => {
println!(
"{}",
t!("cli.registry_created", name => r.name, id => fmt_id(r.id))
);
}
OutputFormat::Json | OutputFormat::Yaml => {
let out = crate::output::serialized(format, &r)
.transpose()?
.unwrap_or_default();
println!("{out}");
}
OutputFormat::Quiet => {
println!("{}\t{}", fmt_id(r.id), r.name);
}
}
Ok(())
}
pub async fn delete(
config: &timeweb_rs::apis::configuration::Configuration,
id: i32
) -> Result<(), TwcError> {
container_registry_api::delete_registry(config, id).await?;
println!("{}", t!("cli.registry_deleted", id => id));
Ok(())
}
pub async fn update(
config: &timeweb_rs::apis::configuration::Configuration,
id: i32,
description: Option<&str>,
format: OutputFormat
) -> Result<(), TwcError> {
let mut edit = timeweb_rs::models::RegistryEdit::new();
edit.description = description.map(String::from);
let resp = container_registry_api::update_registry(config, id, edit).await?;
let r = &resp.container_registry;
match format {
OutputFormat::Table => {
println!(
"{}",
t!("cli.registry_updated", name => r.name, id => fmt_id(r.id))
);
}
OutputFormat::Json | OutputFormat::Yaml => {
let out = crate::output::serialized(format, &r)
.transpose()?
.unwrap_or_default();
println!("{out}");
}
OutputFormat::Quiet => {
println!("{}\t{}", fmt_id(r.id), r.name);
}
}
Ok(())
}
pub async fn repo_list(
config: &timeweb_rs::apis::configuration::Configuration,
id: i32,
format: OutputFormat
) -> Result<(), TwcError> {
let resp = container_registry_api::get_registry_repositories(config, id).await?;
let repos = resp.container_registries_repositories;
let rows: Vec<RepositoryRow> = repos
.iter()
.map(|repo| RepositoryRow {
name: repo.name.clone(),
tag: repo.tags.tag.clone(),
digest: repo.tags.digest.clone()
})
.collect();
match format {
OutputFormat::Table => {
if rows.is_empty() {
println!("{}", t!("cli.no_repositories_found"));
} else {
let table = crate::output::render_table(&rows);
println!("{table}");
}
}
OutputFormat::Json | OutputFormat::Yaml => {
let out = crate::output::serialized(format, &repos)
.transpose()?
.unwrap_or_default();
println!("{out}");
}
OutputFormat::Quiet => {
for repo in &repos {
println!("{}\t{}", repo.name, repo.tags.tag);
}
}
}
Ok(())
}
pub async fn preset_list(
config: &timeweb_rs::apis::configuration::Configuration,
format: OutputFormat
) -> Result<(), TwcError> {
let resp = container_registry_api::get_registry_presets(config).await?;
let presets = resp.container_registry_presets;
let rows: Vec<PresetRow> = presets
.iter()
.map(|p| PresetRow {
id: fmt_id(p.id),
description: p.description_short.clone(),
disk: p.disk.to_string(),
price: format!("{:.2}", p.price),
location: p.location.clone().unwrap_or_default()
})
.collect();
match format {
OutputFormat::Table => {
if rows.is_empty() {
println!("{}", t!("cli.no_presets_found"));
} else {
let table = crate::output::render_table(&rows);
println!("{table}");
}
}
OutputFormat::Json | OutputFormat::Yaml => {
let out = crate::output::serialized(format, &presets)
.transpose()?
.unwrap_or_default();
println!("{out}");
}
OutputFormat::Quiet => {
for p in &presets {
println!("{}\t{}\t{}", p.id, p.description, p.price);
}
}
}
Ok(())
}