diff --git a/src/registry.rs b/src/registry.rs index 54e5db8..d713354 100644 --- a/src/registry.rs +++ b/src/registry.rs @@ -149,7 +149,7 @@ pub async fn get_latest_tag( tags.len() ); let (new_tags, next) = - match get_extra_tags(&next_url.unwrap(), headers.clone(), base, client).await { + match get_extra_tags(&next_url.unwrap(), headers.clone(), base, &image.version_info.as_ref().unwrap().format_str, client).await { Ok(t) => t, Err(message) => { return Image { @@ -163,10 +163,6 @@ pub async fn get_latest_tag( next_url = next; } let tag = tags.iter().max(); - let current_tag = match &image.version_info { - Some(data) => data.current_tag.clone(), - _ => unreachable!(), - }; let time = timestamp() - start; debug!( config.debug, @@ -179,8 +175,8 @@ pub async fn get_latest_tag( get_latest_digest( &Image { version_info: Some(VersionInfo { - current_tag, latest_remote_tag: Some(t.clone()), + ..image.version_info.as_ref().unwrap().clone() }), time_ms: image.time_ms + time, ..image.clone() @@ -193,8 +189,8 @@ pub async fn get_latest_tag( } else { Image { version_info: Some(VersionInfo { - current_tag, latest_remote_tag: Some(t.clone()), + ..image.version_info.as_ref().unwrap().clone() }), time_ms: image.time_ms + time, ..image.clone() @@ -209,6 +205,7 @@ pub async fn get_extra_tags( url: &str, headers: Vec<(&str, Option<&str>)>, base: &Version, + format_str: &str, client: &Client, ) -> Result<(Vec, Option), String> { let response = client.get(url, headers, false).await; @@ -223,12 +220,13 @@ pub async fn get_extra_tags( let result = response_json["tags"] .members() .filter_map(|tag| Version::from_tag(&tag.to_string())) - .filter(|tag| match (base.minor, tag.minor) { + .filter(|(tag, format_string)| match (base.minor, tag.minor) { (Some(_), Some(_)) | (None, None) => { - matches!((base.patch, tag.patch), (Some(_), Some(_)) | (None, None)) + matches!((base.patch, tag.patch), (Some(_), Some(_)) | (None, None)) && format_str == *format_string } _ => false, }) + .map(|(tag, _)| tag) .dedup() .collect(); Ok((result, next_url)) diff --git a/src/structs/image.rs b/src/structs/image.rs index 294bc22..24f395a 100644 --- a/src/structs/image.rs +++ b/src/structs/image.rs @@ -23,6 +23,7 @@ pub struct DigestInfo { pub struct VersionInfo { pub current_tag: Version, pub latest_remote_tag: Option, + pub format_str: String } /// Image struct that contains all information that may be needed by a function working with an image. @@ -62,8 +63,9 @@ impl Image { local_digests, remote_digest: None, }), - version_info: version_tag.map(|vtag| VersionInfo { + version_info: version_tag.map(|(vtag, format_str)| VersionInfo { current_tag: vtag, + format_str, latest_remote_tag: None, }), ..Default::default() @@ -78,13 +80,14 @@ impl Image { let (registry, repository, tag) = split(reference); let version_tag = Version::from_tag(&tag); match version_tag { - Some(version) => Self { + Some((version, format_str)) => Self { reference: reference.to_string(), registry, repository, tag, version_info: Some(VersionInfo { current_tag: version, + format_str, latest_remote_tag: None, }), ..Default::default() diff --git a/src/structs/version.rs b/src/structs/version.rs index bc32363..958ce03 100644 --- a/src/structs/version.rs +++ b/src/structs/version.rs @@ -14,8 +14,8 @@ pub struct Version { } impl Version { - /// Tries to parse the tag into semver-like parts. - pub fn from_tag(tag: &str) -> Option { + /// Tries to parse the tag into semver-like parts. Returns a Version object and a string usable in format! with {} in the positions matches were found + pub fn from_tag(tag: &str) -> Option<(Self, String)> { /// Heavily modified version of the official semver regex based on common tagging schemes for container images. Sometimes it matches more than once, but we'll try to select the best match. static VERSION_REGEX: Lazy = Lazy::new(|| { Regex::new( @@ -43,19 +43,35 @@ impl Version { } match best_match { Some(c) => { + let mut positions = Vec::new(); let major: u32 = match c.name("major") { - Some(major) => major.as_str().parse().unwrap(), + Some(major) => { + positions.push((major.start(), major.end())); + major.as_str().parse().unwrap() + } None => return None, }; - let minor: Option = - c.name("minor").map(|minor| minor.as_str().parse().unwrap()); - let patch: Option = - c.name("patch").map(|patch| patch.as_str().parse().unwrap()); - Some(Version { - major, - minor, - patch, - }) + let minor: Option = c.name("minor").map(|minor| { + positions.push((minor.start(), minor.end())); + minor.as_str().parse().unwrap() + }); + let patch: Option = c.name("patch").map(|patch| { + positions.push((patch.start(), patch.end())); + patch.as_str().parse().unwrap() + }); + let mut format_str = tag.to_string(); + positions.reverse(); + positions.iter().for_each(|(start, end)| { + format_str.replace_range(*start..*end, "{}"); + }); + Some(( + Version { + major, + minor, + patch, + }, + format_str, + )) } None => None, } @@ -145,21 +161,21 @@ mod tests { #[test] #[rustfmt::skip] fn version() { - assert_eq!(Version::from_tag("5.3.2" ), Some(Version { major: 5, minor: Some(3), patch: Some(2) })); - assert_eq!(Version::from_tag("14" ), Some(Version { major: 14, minor: None, patch: None })); - assert_eq!(Version::from_tag("v0.107.53" ), Some(Version { major: 0, minor: Some(107), patch: Some(53) })); - assert_eq!(Version::from_tag("12-alpine" ), Some(Version { major: 12, minor: None, patch: None })); - assert_eq!(Version::from_tag("0.9.5-nginx" ), Some(Version { major: 0, minor: Some(9), patch: Some(5) })); - assert_eq!(Version::from_tag("v27.0" ), Some(Version { major: 27, minor: Some(0), patch: None })); - assert_eq!(Version::from_tag("16.1" ), Some(Version { major: 16, minor: Some(1), patch: None })); - assert_eq!(Version::from_tag("version-1.5.6" ), Some(Version { major: 1, minor: Some(5), patch: Some(6) })); - assert_eq!(Version::from_tag("15.4-alpine" ), Some(Version { major: 15, minor: Some(4), patch: None })); - assert_eq!(Version::from_tag("pg14-v0.2.0" ), Some(Version { major: 0, minor: Some(2), patch: Some(0) })); - assert_eq!(Version::from_tag("18-jammy-full.s6-v0.88.0"), Some(Version { major: 0, minor: Some(88), patch: Some(0) })); - assert_eq!(Version::from_tag("fpm-2.1.0-prod" ), Some(Version { major: 2, minor: Some(1), patch: Some(0) })); - assert_eq!(Version::from_tag("7.3.3.50" ), Some(Version { major: 7, minor: Some(3), patch: Some(3) })); - assert_eq!(Version::from_tag("1.21.11-0" ), Some(Version { major: 1, minor: Some(21), patch: Some(11) })); - assert_eq!(Version::from_tag("4.1.2.1-full" ), Some(Version { major: 4, minor: Some(1), patch: Some(2) })); - assert_eq!(Version::from_tag("v4.0.3-ls215" ), Some(Version { major: 4, minor: Some(0), patch: Some(3) })); + assert_eq!(Version::from_tag("5.3.2" ), Some((Version { major: 5, minor: Some(3), patch: Some(2) }, String::from("{}.{}.{}" )))); + assert_eq!(Version::from_tag("14" ), Some((Version { major: 14, minor: None, patch: None }, String::from("{}" )))); + assert_eq!(Version::from_tag("v0.107.53" ), Some((Version { major: 0, minor: Some(107), patch: Some(53) }, String::from("v{}.{}.{}" )))); + assert_eq!(Version::from_tag("12-alpine" ), Some((Version { major: 12, minor: None, patch: None }, String::from("{}-alpine" )))); + assert_eq!(Version::from_tag("0.9.5-nginx" ), Some((Version { major: 0, minor: Some(9), patch: Some(5) }, String::from("{}.{}.{}-nginx" )))); + assert_eq!(Version::from_tag("v27.0" ), Some((Version { major: 27, minor: Some(0), patch: None }, String::from("v{}.{}" )))); + assert_eq!(Version::from_tag("16.1" ), Some((Version { major: 16, minor: Some(1), patch: None }, String::from("{}.{}" )))); + assert_eq!(Version::from_tag("version-1.5.6" ), Some((Version { major: 1, minor: Some(5), patch: Some(6) }, String::from("version-{}.{}.{}" )))); + assert_eq!(Version::from_tag("15.4-alpine" ), Some((Version { major: 15, minor: Some(4), patch: None }, String::from("{}.{}-alpine" )))); + assert_eq!(Version::from_tag("pg14-v0.2.0" ), Some((Version { major: 0, minor: Some(2), patch: Some(0) }, String::from("pg14-v{}.{}.{}" )))); + assert_eq!(Version::from_tag("18-jammy-full.s6-v0.88.0"), Some((Version { major: 0, minor: Some(88), patch: Some(0) }, String::from("18-jammy-full.s6-v{}.{}.{}")))); + assert_eq!(Version::from_tag("fpm-2.1.0-prod" ), Some((Version { major: 2, minor: Some(1), patch: Some(0) }, String::from("fpm-{}.{}.{}-prod" )))); + assert_eq!(Version::from_tag("7.3.3.50" ), Some((Version { major: 7, minor: Some(3), patch: Some(3) }, String::from("{}.{}.{}.50" )))); + assert_eq!(Version::from_tag("1.21.11-0" ), Some((Version { major: 1, minor: Some(21), patch: Some(11) }, String::from("{}.{}.{}-0" )))); + assert_eq!(Version::from_tag("4.1.2.1-full" ), Some((Version { major: 4, minor: Some(1), patch: Some(2) }, String::from("{}.{}.{}.1-full" )))); + assert_eq!(Version::from_tag("v4.0.3-ls215" ), Some((Version { major: 4, minor: Some(0), patch: Some(3) }, String::from("v{}.{}.{}-ls215" )))); } } diff --git a/src/utils/sort_update_vec.rs b/src/utils/sort_update_vec.rs index 1f86517..311a909 100644 --- a/src/utils/sort_update_vec.rs +++ b/src/utils/sort_update_vec.rs @@ -126,6 +126,7 @@ mod tests { minor: Some(42), patch: Some(1000), }), + format_str: String::new() }), ..Default::default() } @@ -145,6 +146,7 @@ mod tests { minor: Some(47), patch: Some(2), }), + format_str: String::new() }), ..Default::default() } @@ -164,6 +166,7 @@ mod tests { minor: Some(0), patch: None, }), + format_str: String::new() }), ..Default::default() }