debian_analyzer/
versions.rs

1//! Debian version handling utilities.
2
3/// Make an upstream version string suitable for Debian.
4///
5/// # Arguments
6/// * `version` - original upstream version string
7///
8/// # Returns
9/// mangled version string for use in Debian versions
10pub fn debianize_upstream_version(version: &str) -> String {
11    use std::borrow::Cow;
12
13    let mut version = Cow::Borrowed(version);
14
15    // Count underscores and dots to determine if we need to modify
16    let underscore_count = version.chars().filter(|c| *c == '_').count();
17    let dot_count = version.chars().filter(|c| *c == '.').count();
18
19    if underscore_count == 1 && dot_count > 1 {
20        // This is a style commonly used for perl packages.
21        // Most debian packages seem to just drop the underscore.
22        // See
23        // http://blogs.perl.org/users/grinnz/2018/04/a-guide-to-versions-in-perl.html
24        version = Cow::Owned(version.replace('_', ""));
25    } else if underscore_count > 0 && dot_count == 0 {
26        version = Cow::Owned(version.replace('_', "."));
27    }
28
29    // Replace pre-release indicators
30    if version.contains("-rc") || version.contains("-beta") || version.contains("-alpha") {
31        let mut owned = version.into_owned();
32        owned = owned.replace("-rc", "~rc");
33        owned = owned.replace("-beta", "~beta");
34        owned = owned.replace("-alpha", "~alpha");
35        version = Cow::Owned(owned);
36    }
37
38    if let Some((_, a, b, c, d)) =
39        lazy_regex::regex_captures!(r"(.*)\.([0-9])(a|b|rc|alpha|beta)([0-9]*)", &version)
40    {
41        return format!("{}.{}~{}{}", a, b, c, d);
42    }
43
44    version.into_owned()
45}
46
47/// Check whether an upstream version string matches a upstream release.
48///
49/// This will e.g. strip git and dfsg suffixes before comparing.
50///
51/// # Arguments
52/// * `upstream_version` - Upstream version string
53/// * `release_version` - Release to check for
54pub fn matches_release(upstream_version: &str, release_version: &str) -> bool {
55    let release_version = release_version.to_lowercase();
56    let upstream_version = upstream_version.to_lowercase();
57    if upstream_version == release_version {
58        return true;
59    }
60    if let Some((_, base, _)) =
61        lazy_regex::regex_captures!(r"(.*)[~+-](ds|dfsg|git|bzr|svn|hg).*", &upstream_version)
62    {
63        if base == release_version {
64            return true;
65        }
66    }
67    if let Some((_, base)) = lazy_regex::regex_captures!(r"(.*)[~+-].*", &upstream_version) {
68        if base == release_version {
69            return true;
70        }
71    }
72    if let Some((_, lead)) = lazy_regex::regex_captures!(".*~([0-9.]+)$", &upstream_version) {
73        if lead == release_version {
74            return true;
75        }
76    }
77    false
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83    #[test]
84    fn test_debianize_upstream_version() {
85        assert_eq!(debianize_upstream_version("1.0"), "1.0");
86        assert_eq!(debianize_upstream_version("1.0-beta1"), "1.0~beta1");
87        assert_eq!(debianize_upstream_version("1.0-rc1"), "1.0~rc1");
88        assert_eq!(debianize_upstream_version("1.0a1"), "1.0~a1");
89    }
90
91    #[test]
92    fn test_matches_release() {
93        assert!(matches_release("1.0", "1.0"));
94        assert!(matches_release("1.0+ds1", "1.0"));
95        assert!(matches_release("1.14.3+dfsg+~0.15.3", "0.15.3"));
96        assert!(!matches_release("1.0", "1.1"));
97        assert!(!matches_release("1.0+ds1", "1.1"));
98    }
99}