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::PackageVersion, PackageName, PackageReq, PackageSpec, PackageVersionReq};
8
9#[derive(Error, Debug, Diagnostic)]
10#[error("rock {0} not found")]
11pub struct RockNotFound(PackageName);
12
13#[derive(Error, Debug, Diagnostic)]
14#[error("rock {} has no version that satisfies constraint {}", .name, .constraint.to_string())]
15pub struct RockConstraintUnsatisfied {
16    name: PackageName,
17    constraint: PackageVersionReq,
18}
19
20impl PackageSpec {
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<PackageVersion>, 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: &PackageReq,
44        package_db: &PackageDB,
45    ) -> Result<Option<PackageVersion>, 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))
56        } else {
57            Ok(None)
58        }
59    }
60}
61
62impl Display for PackageSpec {
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::PackageSpec,
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 =
98            PackageSpec::parse("lua-cjson".to_string(), "2.0.0".to_string()).unwrap();
99
100        assert_eq!(
101            test_package.has_update(&package_db).await.unwrap(),
102            Some("2.1.0.10-1".parse().unwrap())
103        );
104    }
105}