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
|
"remote_digest": "sha256:170f1974d8fc8ca245bcfae5590bc326de347b19719972bf122400fb13dfa42c", // Latest digest available in the registry
|
||||||
// If `type` is "version":
|
// If `type` is "version":
|
||||||
"version_update_type": "major", // Loosely corresponds to SemVer versioning. Can also be `minor` or `patch`.
|
"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.
|
"error": null, // If checking for the image fails, will be a string with an error message.
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,39 +1,164 @@
|
|||||||
pub mod spinner;
|
pub mod spinner;
|
||||||
|
|
||||||
|
use rustc_hash::FxHashMap;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
structs::{status::Status, update::Update},
|
structs::{
|
||||||
|
status::Status,
|
||||||
|
update::{Update, UpdateInfo},
|
||||||
|
},
|
||||||
utils::{json::to_simple_json, sort_update_vec::sort_update_vec},
|
utils::{json::to_simple_json, sort_update_vec::sort_update_vec},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn print_updates(updates: &[Update], icons: &bool) {
|
pub fn print_updates(updates: &[Update], icons: &bool) {
|
||||||
let sorted_images = sort_update_vec(updates);
|
let sorted_updates = sort_update_vec(updates);
|
||||||
let term_width: usize = termsize::get()
|
let updates_by_server = {
|
||||||
.unwrap_or(termsize::Size { rows: 24, cols: 80 })
|
let mut servers: FxHashMap<&str, Vec<&Update>> = FxHashMap::default();
|
||||||
.cols as usize;
|
sorted_updates.iter().for_each(|update| {
|
||||||
for image in sorted_images {
|
let key = update.server.as_deref().unwrap_or("");
|
||||||
let has_update = image.get_status();
|
match servers.get_mut(&key) {
|
||||||
let description = has_update.to_string();
|
Some(server) => server.push(update),
|
||||||
let icon = if *icons {
|
None => {
|
||||||
match has_update {
|
let _ = servers.insert(key, vec![update]);
|
||||||
Status::UpToDate => "\u{f058} ",
|
}
|
||||||
Status::Unknown(_) => "\u{f059} ",
|
|
||||||
_ => "\u{f0aa} ",
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
servers
|
||||||
|
};
|
||||||
|
for (server, updates) in updates_by_server {
|
||||||
|
if server.is_empty() {
|
||||||
|
println!("\x1b[90;1m~ Local images\x1b[0m")
|
||||||
} else {
|
} else {
|
||||||
""
|
println!("\x1b[90;1m~ {}\x1b[0m", server)
|
||||||
};
|
}
|
||||||
let color = match has_update {
|
let (reference_width, status_width, time_width) =
|
||||||
Status::UpdateAvailable | Status::UpdatePatch => "\u{001b}[38;5;12m",
|
updates.iter().fold((9, 6, 9), |acc, update| {
|
||||||
Status::UpdateMinor => "\u{001b}[38;5;3m",
|
let reference_length = update.reference.len();
|
||||||
Status::UpdateMajor => "\u{001b}[38;5;1m",
|
let status_length = update.get_status().to_string().len()
|
||||||
Status::UpToDate => "\u{001b}[38;5;2m",
|
+ match &update.result.info {
|
||||||
Status::Unknown(_) => "\u{001b}[38;5;8m",
|
UpdateInfo::Version(info) => {
|
||||||
};
|
info.current_version.len() + info.new_version.len() + 6
|
||||||
let dynamic_space =
|
}
|
||||||
" ".repeat(term_width - description.len() - icon.len() - image.reference.len());
|
_ => 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!(
|
println!(
|
||||||
"{}{}{}{}{}\u{001b}[0m",
|
" \x1b[90;1m╭{:─<rw$}┬{:─<sw$}┬{:─<tw$}╮\x1b[0m",
|
||||||
color, icon, image.reference, dynamic_space, description
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
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 status {
|
||||||
|
Status::UpToDate => "\u{f058} ",
|
||||||
|
Status::Unknown(_) => "\u{f059} ",
|
||||||
|
_ => "\u{f0aa} ",
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
};
|
||||||
|
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 description = format!(
|
||||||
|
"{} {}",
|
||||||
|
status.to_string(),
|
||||||
|
match &update.result.info {
|
||||||
|
UpdateInfo::Version(info) => {
|
||||||
|
format!("({} → {})", info.current_version, info.new_version)
|
||||||
|
}
|
||||||
|
_ => String::new(),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
" \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!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
.to_string(),
|
.to_string(),
|
||||||
new_version: format_str
|
new_tag: format_str
|
||||||
.replacen("{}", &new_tag.major.to_string(), 1)
|
.replacen("{}", &new_tag.major.to_string(), 1)
|
||||||
.replacen("{}", &new_tag.minor.unwrap_or(0).to_string(), 1)
|
.replacen("{}", &new_tag.minor.unwrap_or(0).to_string(), 1)
|
||||||
.replacen("{}", &new_tag.patch.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" => {
|
"digest" => {
|
||||||
|
|||||||
@@ -36,6 +36,10 @@ pub enum UpdateInfo {
|
|||||||
#[cfg_attr(test, derive(PartialEq, Debug))]
|
#[cfg_attr(test, derive(PartialEq, Debug))]
|
||||||
pub struct VersionUpdateInfo {
|
pub struct VersionUpdateInfo {
|
||||||
pub version_update_type: String,
|
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,
|
pub new_version: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +58,7 @@ impl Serialize for VersionUpdateInfo {
|
|||||||
let mut state = serializer.serialize_struct("VersionUpdateInfo", 3)?;
|
let mut state = serializer.serialize_struct("VersionUpdateInfo", 3)?;
|
||||||
let _ = state.serialize_field("type", "version");
|
let _ = state.serialize_field("type", "version");
|
||||||
let _ = state.serialize_field("version_update_type", &self.version_update_type);
|
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()
|
state.end()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export default function Image({ data }: { data: Image }) {
|
|||||||
};
|
};
|
||||||
const new_reference =
|
const new_reference =
|
||||||
data.result.info?.type == "version"
|
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;
|
: data.reference;
|
||||||
let url: string | null = null;
|
let url: string | null = null;
|
||||||
if (clickable_registries.includes(data.parts.registry)) {
|
if (clickable_registries.includes(data.parts.registry)) {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ export interface Image {
|
|||||||
interface VersionInfo {
|
interface VersionInfo {
|
||||||
type: "version";
|
type: "version";
|
||||||
version_update_type: "major" | "minor" | "patch";
|
version_update_type: "major" | "minor" | "patch";
|
||||||
new_version: string;
|
new_tag: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface DigestInfo {
|
interface DigestInfo {
|
||||||
|
|||||||
Reference in New Issue
Block a user