Extract the `MAJOR.MINOR.PATCH` version suffix from a dstack image name. Recognises any ` -MAJOR.MINOR.PATCH[.SUFFIX]` shape, e.g. `dstack-0.5.10`, `dstack-dev-0.5.10`, `dstack-nvidia-0.5.10`, `dstack-nvidia-dev-0.5.10`, `dstack-0.5.10.rc1`, `dstack-dev-0.6.1.dev`. The optional `.SUFFIX` is permitted to be non-numeric (pre-release tag, build label, etc.) and is dropped from the returned s
(image: &str)
| 59 | /// Returns `None` when the segment after the last `-` is not at least a valid |
| 60 | /// `X.Y.Z` triple of non-empty numeric components. |
| 61 | pub fn extract_version_from_image_name(image: &str) -> Option<&str> { |
| 62 | let tail = image.rsplit('-').next()?; |
| 63 | let parts: Vec<&str> = tail.split('.').collect(); |
| 64 | if !(3..=4).contains(&parts.len()) { |
| 65 | return None; |
| 66 | } |
| 67 | let core_numeric = parts[..3] |
| 68 | .iter() |
| 69 | .all(|p| !p.is_empty() && p.parse::<u32>().is_ok()); |
| 70 | let suffix_ok = parts.len() == 3 || !parts[3].is_empty(); |
| 71 | if !(core_numeric && suffix_ok) { |
| 72 | return None; |
| 73 | } |
| 74 | // Slice off the optional `.SUFFIX` so callers get just `X.Y.Z`. |
| 75 | let core_len = parts[0].len() + 1 + parts[1].len() + 1 + parts[2].len(); |
| 76 | Some(&tail[..core_len]) |
| 77 | } |
| 78 | |
| 79 | /// Pick the OVMF variant from an image name like `dstack-0.5.10`. |
| 80 | /// |