Skip to main content

gem_audit/lockfile/
platform.rs

1/// Known platform patterns that appear after a hyphen in gem versions.
2///
3/// These are ordered from most specific to least specific to ensure
4/// correct matching (e.g., "x86_64-linux-musl" before "x86_64-linux").
5const PLATFORM_PATTERNS: &[&str] = &[
6    "x86_64-linux-gnu",
7    "x86_64-linux-musl",
8    "x86_64-linux",
9    "x86_64-darwin",
10    "x86-linux",
11    "x86-mingw32",
12    "x86-mswin32",
13    "x64-mingw32",
14    "x64-mingw-ucrt",
15    "arm64-darwin",
16    "aarch64-linux-gnu",
17    "aarch64-linux-musl",
18    "aarch64-linux",
19    "arm-linux-gnu",
20    "arm-linux-musl",
21    "arm-linux",
22    "java",
23    "jruby",
24    "mswin32",
25    "mingw32",
26    "universal-darwin",
27];
28
29/// Split a version-platform string like "1.13.10-x86_64-linux" into
30/// the version part and an optional platform suffix.
31///
32/// Used by both the lockfile parser and the lockfile patcher.
33pub fn split_version_platform(input: &str) -> (&str, Option<&str>) {
34    // Try exact suffix match against known patterns (most specific first)
35    for pattern in PLATFORM_PATTERNS {
36        if let Some(prefix) = input.strip_suffix(pattern)
37            && let Some(version) = prefix.strip_suffix('-')
38        {
39            return (version, Some(pattern));
40        }
41    }
42
43    // Fallback heuristic: scan for platform-like suffix after a hyphen
44    for (pos, _) in input.match_indices('-') {
45        let after = &input[pos + 1..];
46        if after.starts_with("x86")
47            || after.starts_with("x64")
48            || after.starts_with("arm")
49            || after.starts_with("aarch")
50            || after == "java"
51            || after == "jruby"
52            || after.starts_with("universal")
53            || after.contains("mingw")
54            || after.contains("mswin")
55        {
56            return (&input[..pos], Some(after));
57        }
58    }
59
60    (input, None)
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn plain_version() {
69        let (v, p) = split_version_platform("1.13.10");
70        assert_eq!(v, "1.13.10");
71        assert_eq!(p, None);
72    }
73
74    #[test]
75    fn x86_64_linux() {
76        let (v, p) = split_version_platform("1.13.10-x86_64-linux");
77        assert_eq!(v, "1.13.10");
78        assert_eq!(p, Some("x86_64-linux"));
79    }
80
81    #[test]
82    fn arm64_darwin() {
83        let (v, p) = split_version_platform("1.13.10-arm64-darwin");
84        assert_eq!(v, "1.13.10");
85        assert_eq!(p, Some("arm64-darwin"));
86    }
87
88    #[test]
89    fn java_platform() {
90        let (v, p) = split_version_platform("9.2.14.0-java");
91        assert_eq!(v, "9.2.14.0");
92        assert_eq!(p, Some("java"));
93    }
94
95    #[test]
96    fn aarch64_linux_musl() {
97        let (v, p) = split_version_platform("1.19.1-aarch64-linux-musl");
98        assert_eq!(v, "1.19.1");
99        assert_eq!(p, Some("aarch64-linux-musl"));
100    }
101
102    #[test]
103    fn x86_64_linux_musl() {
104        let (v, p) = split_version_platform("1.19.1-x86_64-linux-musl");
105        assert_eq!(v, "1.19.1");
106        assert_eq!(p, Some("x86_64-linux-musl"));
107    }
108
109    #[test]
110    fn x86_64_linux_gnu() {
111        let (v, p) = split_version_platform("1.19.1-x86_64-linux-gnu");
112        assert_eq!(v, "1.19.1");
113        assert_eq!(p, Some("x86_64-linux-gnu"));
114    }
115
116    #[test]
117    fn universal_darwin() {
118        let (v, p) = split_version_platform("2.0.0-universal-darwin");
119        assert_eq!(v, "2.0.0");
120        assert_eq!(p, Some("universal-darwin"));
121    }
122}