diff --git a/src/check.rs b/src/check.rs index a42355a..4150a17 100644 --- a/src/check.rs +++ b/src/check.rs @@ -1,6 +1,6 @@ use futures::future::join_all; use itertools::Itertools; -use rustc_hash::FxHashMap; +use rustc_hash::{FxHashMap, FxHashSet}; use crate::{ config::Config, @@ -13,7 +13,24 @@ use crate::{ /// Returns a list of updates for all images passed in. pub async fn get_updates(references: &Option>, config: &Config) -> Vec { // 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::>(); + 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. let registries: Vec<&String> = images @@ -55,7 +72,7 @@ pub async fn get_updates(references: &Option>, config: &Config) -> V } // 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 for image in &images { let token = tokens.get(image.registry.as_str()).unwrap(); diff --git a/src/registry.rs b/src/registry.rs index b8ff34c..b2e85e1 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -150,7 +150,7 @@ pub async fn get_latest_tag( }; match tag { Some(t) => { - if t == base { + if t == base && image.digest_info.is_some() { // Tags are equal so we'll compare digests get_latest_digest( &Image { diff --git a/src/structs/image.rs b/src/structs/image.rs index 0fa4023..1da2c9a 100644 --- a/src/structs/image.rs +++ b/src/structs/image.rs @@ -2,6 +2,7 @@ use json::{object, JsonValue}; use crate::{ config::Config, + error, http::Client, registry::{get_latest_digest, get_latest_tag}, structs::{status::Status, version::Version}, @@ -40,7 +41,7 @@ pub struct 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(image: T) -> Option { let tags = image.tags().unwrap(); let digests = image.digests().unwrap(); @@ -61,8 +62,8 @@ impl Image { local_digests, remote_digest: None, }), - version_info: version_tag.map(|stag| VersionInfo { - current_tag: stag, + version_info: version_tag.map(|vtag| VersionInfo { + current_tag: vtag, latest_remote_tag: None, }), ..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 pub fn has_update(&self) -> Status { if self.error.is_some() {