Skip to content

Commit c827191

Browse files
committed
dstack-mr: allow optional non-numeric suffix on image-name version
Accept `<prefix>-X.Y.Z[.SUFFIX]` shapes when parsing the version out of vm_config.image, where the prefix can be any dash-chain (dstack-dev, dstack-nvidia, dstack-nvidia-dev, ...) and the trailing `.SUFFIX` is optional and may be non-numeric (e.g. dstack-0.6.1.dev, dstack-0.5.10.rc1). Only the numeric X.Y.Z is returned and forwarded to ovmf_variant_for_version; the suffix is dropped because it doesn't affect the variant choice.
1 parent c5eb9aa commit c827191

1 file changed

Lines changed: 42 additions & 12 deletions

File tree

dstack-mr/src/lib.rs

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,23 +45,34 @@ pub fn ovmf_variant_for_version(version: &str) -> Result<OvmfVariant> {
4545
})
4646
}
4747

48-
/// Extract a dotted version suffix (e.g. "0.5.10") from a dstack image name like
49-
/// `dstack-0.5.10`, `dstack-dev-0.5.10`, or `dstack-nvidia-0.5.10`.
48+
/// Extract the `MAJOR.MINOR.PATCH` version suffix from a dstack image name.
5049
///
51-
/// Returns `None` when the image name does not end with a recognisable
52-
/// `MAJOR.MINOR.PATCH` segment.
50+
/// Recognises any `<prefix>-MAJOR.MINOR.PATCH[.SUFFIX]` shape, e.g.
51+
/// `dstack-0.5.10`, `dstack-dev-0.5.10`, `dstack-nvidia-0.5.10`,
52+
/// `dstack-nvidia-dev-0.5.10`, `dstack-0.5.10.rc1`, `dstack-dev-0.6.1.dev`.
53+
///
54+
/// The optional `.SUFFIX` is permitted to be non-numeric (pre-release tag,
55+
/// build label, etc.) and is dropped from the returned slice — only the
56+
/// numeric `X.Y.Z` is needed to pick the OVMF variant.
57+
///
58+
/// Returns `None` when the segment after the last `-` is not at least a valid
59+
/// `X.Y.Z` triple of non-empty numeric components.
5360
pub fn extract_version_from_image_name(image: &str) -> Option<&str> {
5461
let tail = image.rsplit('-').next()?;
5562
let parts: Vec<&str> = tail.split('.').collect();
56-
if parts.len() == 3
57-
&& parts
58-
.iter()
59-
.all(|p| !p.is_empty() && p.parse::<u32>().is_ok())
60-
{
61-
Some(tail)
62-
} else {
63-
None
63+
if !(3..=4).contains(&parts.len()) {
64+
return None;
65+
}
66+
let core_numeric = parts[..3]
67+
.iter()
68+
.all(|p| !p.is_empty() && p.parse::<u32>().is_ok());
69+
let suffix_ok = parts.len() == 3 || !parts[3].is_empty();
70+
if !(core_numeric && suffix_ok) {
71+
return None;
6472
}
73+
// Slice off the optional `.SUFFIX` so callers get just `X.Y.Z`.
74+
let core_len = parts[0].len() + 1 + parts[1].len() + 1 + parts[2].len();
75+
Some(&tail[..core_len])
6576
}
6677

6778
/// Pick the OVMF variant from an image name like `dstack-0.5.10`.
@@ -111,6 +122,7 @@ mod ovmf_variant_tests {
111122

112123
#[test]
113124
fn parses_version_from_image_name() {
125+
// Three-segment plain versions across the known prefix shapes.
114126
assert_eq!(
115127
extract_version_from_image_name("dstack-0.5.10"),
116128
Some("0.5.10")
@@ -127,9 +139,27 @@ mod ovmf_variant_tests {
127139
extract_version_from_image_name("dstack-nvidia-dev-0.6.1"),
128140
Some("0.6.1")
129141
);
142+
// Optional .SUFFIX is allowed and dropped; suffix may be non-numeric.
143+
assert_eq!(
144+
extract_version_from_image_name("dstack-0.5.10.rc1"),
145+
Some("0.5.10")
146+
);
147+
assert_eq!(
148+
extract_version_from_image_name("dstack-dev-0.6.1.dev"),
149+
Some("0.6.1")
150+
);
151+
assert_eq!(
152+
extract_version_from_image_name("dstack-nvidia-dev-0.5.10.1"),
153+
Some("0.5.10")
154+
);
155+
// Rejections.
130156
assert_eq!(extract_version_from_image_name("dstack"), None);
131157
assert_eq!(extract_version_from_image_name("dstack-rc1"), None);
132158
assert_eq!(extract_version_from_image_name("dstack-0.5"), None);
159+
assert_eq!(extract_version_from_image_name("dstack-0.5.10."), None);
160+
assert_eq!(extract_version_from_image_name("dstack-0.5.10.1.2"), None);
161+
assert_eq!(extract_version_from_image_name("dstack-0..10"), None);
162+
assert_eq!(extract_version_from_image_name("dstack-a.b.c"), None);
133163
}
134164

135165
#[test]

0 commit comments

Comments
 (0)