m/cup
1
0
mirror of https://github.com/sergi0g/cup.git synced 2025-11-16 17:13:46 -05:00

Support checking for version updates for images that aren't available locally

This commit is contained in:
Sergio
2024-11-16 13:05:46 +02:00
parent 4519c534a1
commit 88d346b480
3 changed files with 48 additions and 7 deletions

View File

@@ -1,6 +1,6 @@
use futures::future::join_all; use futures::future::join_all;
use itertools::Itertools; use itertools::Itertools;
use rustc_hash::FxHashMap; use rustc_hash::{FxHashMap, FxHashSet};
use crate::{ use crate::{
config::Config, config::Config,
@@ -13,7 +13,24 @@ use crate::{
/// Returns a list of updates for all images passed in. /// Returns a list of updates for all images passed in.
pub async fn get_updates(references: &Option<Vec<String>>, config: &Config) -> Vec<Image> { pub async fn get_updates(references: &Option<Vec<String>>, config: &Config) -> Vec<Image> {
// Get images // Get images
let images = get_images_from_docker_daemon(config, references).await; let mut images = get_images_from_docker_daemon(config, references).await;
let extra_images = match references {
Some(refs) => {
let image_refs: FxHashSet<&String> = images.iter().map(|image| &image.reference).collect();
let extra = refs.iter().filter(|&reference| !image_refs.contains(reference)).collect::<Vec<&String>>();
let mut handles = Vec::with_capacity(extra.len());
for reference in extra {
let future = Image::from_reference(reference);
handles.push(future)
}
Some(join_all(handles).await)
},
None => None
};
if let Some(extra_imgs) = extra_images {
images.extend_from_slice(&extra_imgs);
}
// Get a list of unique registries our images belong to. We are unwrapping the registry because it's guaranteed to be there. // Get a list of unique registries our images belong to. We are unwrapping the registry because it's guaranteed to be there.
let registries: Vec<&String> = images let registries: Vec<&String> = images
@@ -55,7 +72,7 @@ pub async fn get_updates(references: &Option<Vec<String>>, config: &Config) -> V
} }
// Create a Vec to store futures so we can await them all at once. // Create a Vec to store futures so we can await them all at once.
let mut handles = Vec::new(); let mut handles = Vec::with_capacity(images.len());
// Loop through images and get the latest digest for each // Loop through images and get the latest digest for each
for image in &images { for image in &images {
let token = tokens.get(image.registry.as_str()).unwrap(); let token = tokens.get(image.registry.as_str()).unwrap();

View File

@@ -150,7 +150,7 @@ pub async fn get_latest_tag(
}; };
match tag { match tag {
Some(t) => { Some(t) => {
if t == base { if t == base && image.digest_info.is_some() {
// Tags are equal so we'll compare digests // Tags are equal so we'll compare digests
get_latest_digest( get_latest_digest(
&Image { &Image {

View File

@@ -2,6 +2,7 @@ use json::{object, JsonValue};
use crate::{ use crate::{
config::Config, config::Config,
error,
http::Client, http::Client,
registry::{get_latest_digest, get_latest_tag}, registry::{get_latest_digest, get_latest_tag},
structs::{status::Status, version::Version}, structs::{status::Status, version::Version},
@@ -40,7 +41,7 @@ pub struct Image {
} }
impl Image { impl Image {
/// Creates an populates the fields of an Image object based on the ImageSummary from the Docker daemon /// Creates and populates the fields of an Image object based on the ImageSummary from the Docker daemon
pub async fn from_inspect_data<T: InspectData>(image: T) -> Option<Self> { pub async fn from_inspect_data<T: InspectData>(image: T) -> Option<Self> {
let tags = image.tags().unwrap(); let tags = image.tags().unwrap();
let digests = image.digests().unwrap(); let digests = image.digests().unwrap();
@@ -61,8 +62,8 @@ impl Image {
local_digests, local_digests,
remote_digest: None, remote_digest: None,
}), }),
version_info: version_tag.map(|stag| VersionInfo { version_info: version_tag.map(|vtag| VersionInfo {
current_tag: stag, current_tag: vtag,
latest_remote_tag: None, latest_remote_tag: None,
}), }),
..Default::default() ..Default::default()
@@ -72,6 +73,29 @@ impl Image {
} }
} }
/// Creates and populates the fields of an Image object based on a reference. If the tag is not recognized as a version string, exits the program with an error.
pub async fn from_reference(reference: &str) -> Self {
let (registry, repository, tag) = split(&reference);
let version_tag = Version::from_tag(&tag);
match version_tag {
Some(version) => Self {
reference: reference.to_string(),
registry,
repository,
tag,
version_info: Some(VersionInfo {
current_tag: version,
latest_remote_tag: None,
}),
..Default::default()
},
None => error!(
"Image {} is not available locally and does not have a recognizable tag format!",
reference
),
}
}
/// Compares remote digest of the image with its local digests to determine if it has an update or not /// Compares remote digest of the image with its local digests to determine if it has an update or not
pub fn has_update(&self) -> Status { pub fn has_update(&self) -> Status {
if self.error.is_some() { if self.error.is_some() {