sagiegurari / cargo-make
1
//! # crate_version_check
2
//!
3
//! Checks crate versions.
4
//!
5

6
#[cfg(test)]
7
#[path = "./crate_version_check_test.rs"]
8
mod crate_version_check_test;
9

10
use dirs;
11
use fsio;
12
use semver::Version;
13
use std::collections::HashMap;
14
use std::env;
15
use std::path::Path;
16
use toml;
17

18 8
#[derive(Deserialize, Debug)]
19
struct CratesRegistryInfo {
20
    v1: Option<HashMap<String, Vec<String>>>,
21
}
22

23 8
fn get_cargo_home() -> Option<String> {
24 8
    let cargo_home = match env::var("CARGO_HOME") {
25 8
        Ok(value) => Some(value.to_string()),
26 2
        Err(_) => match dirs::home_dir() {
27 2
            Some(directory) => match directory.join(".cargo").to_str() {
28 2
                Some(value) => Some(value.to_string()),
29 0
                None => None,
30 2
            },
31 0
            None => None,
32 0
        },
33 4
    };
34

35 8
    match cargo_home {
36 8
        Some(directory) => {
37 8
            let directory_path = Path::new(&directory);
38 8
            if directory_path.exists() && directory_path.is_dir() {
39 8
                Some(directory)
40
            } else {
41 2
                None
42
            }
43 6
        }
44 2
        None => None,
45
    }
46 8
}
47

48 8
fn load_crates_toml(cargo_home: &str) -> Option<CratesRegistryInfo> {
49 8
    let file_path = Path::new(cargo_home).join(".crates.toml");
50

51 8
    if file_path.exists() && file_path.is_file() {
52 8
        match fsio::file::read_text_file(&file_path) {
53 8
            Ok(file_content) => match toml::from_str(&file_content) {
54 8
                Ok(info) => Some(info),
55 0
                Err(error) => {
56 0
                    warn!("Unable to parse crates descriptor, error: {}", &error);
57 0
                    None
58 0
                }
59 6
            },
60 0
            Err(error) => {
61 0
                warn!("Unable to open crates descriptor, error: {}", &error);
62 0
                None
63 0
            }
64 0
        }
65 2
    } else {
66 8
        None
67
    }
68 8
}
69

70 8
fn get_crate_version_from_info(crate_name: &str, info: &CratesRegistryInfo) -> Option<Version> {
71 8
    match info.v1 {
72 8
        Some(ref keys) => {
73 8
            let mut output = None;
74

75 8
            for key in keys.keys() {
76 8
                let parts: Vec<&str> = key.split(' ').collect();
77

78 8
                if parts.len() >= 2 && parts[0] == crate_name {
79 8
                    output = match Version::parse(parts[1]) {
80 8
                        Ok(version) => Some(version),
81 8
                        _ => None,
82 8
                    };
83

84 6
                    break;
85
                }
86 8
            }
87

88 8
            output
89 0
        }
90 8
        None => None,
91
    }
92 8
}
93

94 8
pub(crate) fn get_crate_version(crate_name: &str) -> Option<Version> {
95 8
    let cargo_home = get_cargo_home();
96 8
    match cargo_home {
97 8
        Some(directory) => match load_crates_toml(&directory) {
98 8
            Some(info) => get_crate_version_from_info(&crate_name, &info),
99
            None => {
100 0
                warn!(
101 0
                    "Unable to read crates registry information to validate {} crate version.",
102 0
                    &crate_name
103
                );
104 0
                None
105
            }
106 0
        },
107
        None => {
108 0
            warn!(
109 0
                "Unable to find cargo home directory to validate {} crate version.",
110 0
                &crate_name
111
            );
112 0
            None
113
        }
114
    }
115 8
}
116

117 8
pub(crate) fn is_min_version_valid_for_versions(
118
    min_version: &Version,
119
    installed_version: &Version,
120
) -> bool {
121 8
    if min_version.major > installed_version.major {
122 8
        false
123 8
    } else if min_version.major < installed_version.major {
124 8
        true
125 8
    } else if min_version.minor > installed_version.minor {
126 8
        false
127 8
    } else if min_version.minor < installed_version.minor {
128 8
        true
129
    } else {
130 8
        installed_version.patch >= min_version.patch
131
    }
132 8
}
133

134 8
pub(crate) fn is_min_version_valid(crate_name: &str, min_version: &str) -> bool {
135 8
    let min_semver = Version::parse(min_version);
136 8
    match min_semver {
137 8
        Ok(min_version_values) => match get_crate_version(crate_name) {
138 8
            Some(installed_version_values) => {
139 8
                is_min_version_valid_for_versions(&min_version_values, &installed_version_values)
140 6
            }
141 2
            None => {
142 8
                warn!(
143 0
                    "Unable to read currently installed version for crate: {}",
144 0
                    &crate_name
145
                );
146 8
                true
147
            }
148 2
        },
149
        _ => {
150 8
            warn!("Unable to parse min version value: {}", &min_version);
151 8
            true
152
        }
153
    }
154 8
}

Read our documentation on viewing source code .

Loading