Skip to main content

pray_core/
package_spec_version.rs

1use super::PackageSpec;
2use crate::constraint::{normalize_version_constraint, version_satisfies};
3use crate::{PrayError, PrayResult};
4
5impl PackageSpec {
6    pub const LOCAL_VERSION: &'static str = "local";
7
8    pub fn has_release_version(&self) -> bool {
9        !self.version.is_empty() && self.version != Self::LOCAL_VERSION
10    }
11
12    pub fn recorded_version(&self) -> &str {
13        if self.has_release_version() {
14            &self.version
15        } else {
16            Self::LOCAL_VERSION
17        }
18    }
19
20    pub fn require_release_version(&self) -> PrayResult<()> {
21        if self.has_release_version() {
22            Ok(())
23        } else {
24            Err(PrayError::Manifest(format!(
25                "package {} needs a version before it can be packaged",
26                self.name
27            )))
28        }
29    }
30
31    pub fn satisfy_constraint(&self, constraint: &str) -> PrayResult<()> {
32        if !self.has_release_version() {
33            let normalized = normalize_version_constraint(constraint);
34            if normalized.is_empty() || normalized == "*" {
35                return Ok(());
36            }
37            return Err(PrayError::Resolution(format!(
38                "package {} has no version; add spec.version or omit the constraint",
39                self.name
40            )));
41        }
42        if version_satisfies(&self.version, constraint)? {
43            Ok(())
44        } else {
45            Err(PrayError::Resolution(format!(
46                "package {} version {} does not satisfy constraint {}",
47                self.name, self.version, constraint
48            )))
49        }
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    fn spec_with_version(version: &str) -> PackageSpec {
58        PackageSpec {
59            name: "project".to_string(),
60            version: version.to_string(),
61            ..PackageSpec::default()
62        }
63    }
64
65    #[test]
66    fn omitted_version_records_local_and_matches_star() {
67        let spec = spec_with_version("");
68        assert_eq!(spec.recorded_version(), "local");
69        spec.satisfy_constraint("*").expect("star");
70        let error = spec.satisfy_constraint("~> 1.0").expect_err("range");
71        assert!(error.to_string().contains("has no version"));
72        spec.require_release_version().expect_err("pack");
73    }
74
75    #[test]
76    fn release_version_uses_semver_constraints() {
77        let spec = spec_with_version("1.4.3");
78        spec.satisfy_constraint("~> 1.4").expect("matches");
79        spec.require_release_version().expect("pack");
80    }
81}