Skip to main content

lux_lib/package/
outdated.rs

1use std::fmt::Display;
2
3use crate::package_db::PackageDB;
4use miette::Diagnostic;
5use thiserror::Error;
6
7use super::{version::Version, Name, Req, Spec, VersionReq};
8
9#[derive(Error, Debug, Diagnostic)]
10#[error("rock {0} not found")]
11pub struct RockNotFound(Name);
12
13#[derive(Error, Debug, Diagnostic)]
14#[error("rock {} has no version that satisfies constraint {}", .name, .constraint.to_string())]
15pub struct RockConstraintUnsatisfied {
16    name: Name,
17    constraint: VersionReq,
18}
19
20impl Spec {
21    /// Tries to find a newer version of a given rock.
22    /// Returns the latest version if found.
23    pub async fn has_update(
24        &self,
25        package_db: &PackageDB,
26    ) -> Result<Option<Version>, RockNotFound> {
27        let latest_version = package_db
28            .latest_version(self.name())
29            .await
30            .ok_or_else(|| RockNotFound(self.name().clone()))?;
31
32        if self.version() < &latest_version {
33            Ok(Some(latest_version))
34        } else {
35            Ok(None)
36        }
37    }
38
39    /// Tries to find a newer version of a rock given a constraint.
40    /// Returns the latest version if found.
41    pub async fn has_update_with(
42        &self,
43        constraint: &Req,
44        package_db: &PackageDB,
45    ) -> Result<Option<Version>, RockConstraintUnsatisfied> {
46        let latest_version = package_db
47            .latest_match(constraint, None)
48            .await
49            .ok_or_else(|| RockConstraintUnsatisfied {
50                name: self.name().clone(),
51                constraint: constraint.version_req.clone(),
52            })?;
53
54        if self.version() < latest_version.version() {
55            Ok(Some(latest_version.version().clone()))
56        } else {
57            Ok(None)
58        }
59    }
60}
61
62impl Display for Spec {
63    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64        f.write_str(format!("{} {}", self.name(), self.version()).as_str())
65    }
66}
67
68#[cfg(test)]
69mod tests {
70    use std::path::PathBuf;
71
72    use url::Url;
73
74    use crate::{
75        config::ConfigBuilder,
76        manifest::{Manifest, ManifestMetadata},
77        package::Spec,
78        package_db::PackageDB,
79    };
80
81    #[tokio::test]
82    async fn rock_has_update() {
83        let test_manifest_path =
84            PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("resources/test/manifest-5.1");
85        let content = String::from_utf8(std::fs::read(&test_manifest_path).unwrap()).unwrap();
86        let metadata = ManifestMetadata::new(&content).unwrap();
87        let config = ConfigBuilder::new().unwrap().build().unwrap();
88        let package_db = PackageDB::from_manifest(
89            Manifest::new(
90                Url::parse("https://example.com").unwrap(),
91                metadata,
92                Default::default(),
93            ),
94            &config,
95        );
96
97        let test_package = Spec::parse("lua-cjson".to_string(), "2.0.0".to_string()).unwrap();
98
99        assert_eq!(
100            test_package.has_update(&package_db).await.unwrap(),
101            Some("2.1.0.10-1".parse().unwrap())
102        );
103    }
104}