mirror of
https://github.com/sergi0g/cup.git
synced 2025-11-16 09:03:46 -05:00
Update API and improve CLI output
This commit is contained in:
@@ -47,7 +47,7 @@ The data returned from the API or from the CLI is in JSON and looks like this:
|
||||
"remote_digest": "sha256:170f1974d8fc8ca245bcfae5590bc326de347b19719972bf122400fb13dfa42c", // Latest digest available in the registry
|
||||
// If `type` is "version":
|
||||
"version_update_type": "major", // Loosely corresponds to SemVer versioning. Can also be `minor` or `patch`.
|
||||
"new_version": "v3.3.3", // The tag of the latest image.
|
||||
"new_tag": "v3.3.3", // The tag of the latest image.
|
||||
},
|
||||
"error": null, // If checking for the image fails, will be a string with an error message.
|
||||
},
|
||||
|
||||
@@ -1,20 +1,114 @@
|
||||
pub mod spinner;
|
||||
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::{
|
||||
structs::{status::Status, update::Update},
|
||||
structs::{
|
||||
status::Status,
|
||||
update::{Update, UpdateInfo},
|
||||
},
|
||||
utils::{json::to_simple_json, sort_update_vec::sort_update_vec},
|
||||
};
|
||||
|
||||
pub fn print_updates(updates: &[Update], icons: &bool) {
|
||||
let sorted_images = sort_update_vec(updates);
|
||||
let term_width: usize = termsize::get()
|
||||
.unwrap_or(termsize::Size { rows: 24, cols: 80 })
|
||||
.cols as usize;
|
||||
for image in sorted_images {
|
||||
let has_update = image.get_status();
|
||||
let description = has_update.to_string();
|
||||
let sorted_updates = sort_update_vec(updates);
|
||||
let updates_by_server = {
|
||||
let mut servers: FxHashMap<&str, Vec<&Update>> = FxHashMap::default();
|
||||
sorted_updates.iter().for_each(|update| {
|
||||
let key = update.server.as_deref().unwrap_or("");
|
||||
match servers.get_mut(&key) {
|
||||
Some(server) => server.push(update),
|
||||
None => {
|
||||
let _ = servers.insert(key, vec![update]);
|
||||
}
|
||||
}
|
||||
});
|
||||
servers
|
||||
};
|
||||
for (server, updates) in updates_by_server {
|
||||
if server.is_empty() {
|
||||
println!("\x1b[90;1m~ Local images\x1b[0m")
|
||||
} else {
|
||||
println!("\x1b[90;1m~ {}\x1b[0m", server)
|
||||
}
|
||||
let (reference_width, status_width, time_width) =
|
||||
updates.iter().fold((9, 6, 9), |acc, update| {
|
||||
let reference_length = update.reference.len();
|
||||
let status_length = update.get_status().to_string().len()
|
||||
+ match &update.result.info {
|
||||
UpdateInfo::Version(info) => {
|
||||
info.current_version.len() + info.new_version.len() + 6
|
||||
}
|
||||
_ => 0,
|
||||
};
|
||||
let time_length = update.time.to_string().len();
|
||||
return (
|
||||
if reference_length > acc.0 {
|
||||
reference_length
|
||||
} else {
|
||||
acc.0
|
||||
},
|
||||
if status_length > acc.1 {
|
||||
status_length
|
||||
} else {
|
||||
acc.1
|
||||
},
|
||||
if time_length > acc.2 {
|
||||
time_length
|
||||
} else {
|
||||
acc.2
|
||||
},
|
||||
);
|
||||
});
|
||||
println!(
|
||||
" \x1b[90;1m╭{:─<rw$}┬{:─<sw$}┬{:─<tw$}╮\x1b[0m",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
rw = reference_width,
|
||||
sw = status_width + {
|
||||
if *icons {
|
||||
2
|
||||
} else {
|
||||
0
|
||||
}
|
||||
},
|
||||
tw = time_width
|
||||
);
|
||||
println!(
|
||||
" \x1b[90;1m│\x1b[36;1m{:<rw$}\x1b[90;1m│\x1b[36;1m{:<sw$}\x1b[90;1m│\x1b[36;1m{:<tw$}\x1b[90;1m│\x1b[0m",
|
||||
"Reference",
|
||||
"Status",
|
||||
"Time (ms)",
|
||||
rw = reference_width,
|
||||
sw = status_width + {
|
||||
if *icons {
|
||||
2
|
||||
} else {
|
||||
0
|
||||
}
|
||||
},
|
||||
tw = time_width
|
||||
);
|
||||
println!(
|
||||
" \x1b[90;1m├{:─<rw$}┼{:─<sw$}┼{:─<tw$}┤\x1b[0m",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
rw = reference_width,
|
||||
sw = status_width + {
|
||||
if *icons {
|
||||
2
|
||||
} else {
|
||||
0
|
||||
}
|
||||
},
|
||||
tw = time_width
|
||||
);
|
||||
for update in updates {
|
||||
let status = update.get_status();
|
||||
let icon = if *icons {
|
||||
match has_update {
|
||||
match status {
|
||||
Status::UpToDate => "\u{f058} ",
|
||||
Status::Unknown(_) => "\u{f059} ",
|
||||
_ => "\u{f0aa} ",
|
||||
@@ -22,18 +116,49 @@ pub fn print_updates(updates: &[Update], icons: &bool) {
|
||||
} else {
|
||||
""
|
||||
};
|
||||
let color = match has_update {
|
||||
Status::UpdateAvailable | Status::UpdatePatch => "\u{001b}[38;5;12m",
|
||||
Status::UpdateMinor => "\u{001b}[38;5;3m",
|
||||
Status::UpdateMajor => "\u{001b}[38;5;1m",
|
||||
Status::UpToDate => "\u{001b}[38;5;2m",
|
||||
Status::Unknown(_) => "\u{001b}[38;5;8m",
|
||||
let color = match status {
|
||||
Status::UpdateAvailable | Status::UpdatePatch => "\x1b[34m",
|
||||
Status::UpdateMinor => "\x1b[33m",
|
||||
Status::UpdateMajor => "\x1b[31m",
|
||||
Status::UpToDate => "\x1b[32m",
|
||||
Status::Unknown(_) => "\x1b[90m",
|
||||
};
|
||||
let dynamic_space =
|
||||
" ".repeat(term_width - description.len() - icon.len() - image.reference.len());
|
||||
let description = format!(
|
||||
"{} {}",
|
||||
status.to_string(),
|
||||
match &update.result.info {
|
||||
UpdateInfo::Version(info) => {
|
||||
format!("({} → {})", info.current_version, info.new_version)
|
||||
}
|
||||
_ => String::new(),
|
||||
}
|
||||
);
|
||||
println!(
|
||||
"{}{}{}{}{}\u{001b}[0m",
|
||||
color, icon, image.reference, dynamic_space, description
|
||||
" \x1b[90;1m│\x1b[0m{:<rw$}\x1b[90;1m│\x1b[0m{}{}{:<sw$}\x1b[0m\x1b[90;1m│\x1b[0m{:<tw$}\x1b[90;1m│\x1b[0m",
|
||||
update.reference,
|
||||
color,
|
||||
icon,
|
||||
description,
|
||||
update.time,
|
||||
rw = reference_width,
|
||||
sw = status_width,
|
||||
tw = time_width
|
||||
);
|
||||
}
|
||||
println!(
|
||||
" \x1b[90;1m╰{:─<rw$}┴{:─<sw$}┴{:─<tw$}╯\x1b[0m",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
rw = reference_width,
|
||||
sw = status_width + {
|
||||
if *icons {
|
||||
2
|
||||
} else {
|
||||
0
|
||||
}
|
||||
},
|
||||
tw = time_width
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,10 +163,13 @@ impl Image {
|
||||
_ => unreachable!(),
|
||||
}
|
||||
.to_string(),
|
||||
new_version: format_str
|
||||
new_tag: format_str
|
||||
.replacen("{}", &new_tag.major.to_string(), 1)
|
||||
.replacen("{}", &new_tag.minor.unwrap_or(0).to_string(), 1)
|
||||
.replacen("{}", &new_tag.patch.unwrap_or(0).to_string(), 1),
|
||||
// Throwing these in, because they're useful for the CLI output, however we won't (de)serialize them
|
||||
current_version: self.version_info.as_ref().unwrap().current_tag.to_string(),
|
||||
new_version: self.version_info.as_ref().unwrap().latest_remote_tag.as_ref().unwrap().to_string()
|
||||
})
|
||||
}
|
||||
"digest" => {
|
||||
|
||||
@@ -36,6 +36,10 @@ pub enum UpdateInfo {
|
||||
#[cfg_attr(test, derive(PartialEq, Debug))]
|
||||
pub struct VersionUpdateInfo {
|
||||
pub version_update_type: String,
|
||||
pub new_tag: String,
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
pub current_version: String,
|
||||
#[serde(skip_serializing, skip_deserializing)]
|
||||
pub new_version: String,
|
||||
}
|
||||
|
||||
@@ -54,7 +58,7 @@ impl Serialize for VersionUpdateInfo {
|
||||
let mut state = serializer.serialize_struct("VersionUpdateInfo", 3)?;
|
||||
let _ = state.serialize_field("type", "version");
|
||||
let _ = state.serialize_field("version_update_type", &self.version_update_type);
|
||||
let _ = state.serialize_field("new_version", &self.new_version);
|
||||
let _ = state.serialize_field("new_version", &self.new_tag);
|
||||
state.end()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ export default function Image({ data }: { data: Image }) {
|
||||
};
|
||||
const new_reference =
|
||||
data.result.info?.type == "version"
|
||||
? data.reference.split(":")[0] + ":" + data.result.info.new_version
|
||||
? data.reference.split(":")[0] + ":" + data.result.info.new_tag
|
||||
: data.reference;
|
||||
let url: string | null = null;
|
||||
if (clickable_registries.includes(data.parts.registry)) {
|
||||
|
||||
@@ -32,7 +32,7 @@ export interface Image {
|
||||
interface VersionInfo {
|
||||
type: "version";
|
||||
version_update_type: "major" | "minor" | "patch";
|
||||
new_version: string;
|
||||
new_tag: string;
|
||||
}
|
||||
|
||||
interface DigestInfo {
|
||||
|
||||
Reference in New Issue
Block a user