Skip to main content

lux_lib/manifest/
mod.rs

1use path_slash::PathExt;
2use thiserror::Error;
3use url::Url;
4
5pub use crate::manifest::metadata::*;
6use crate::manifest::metadata_from_server::*;
7use crate::manifest::metadata_from_vendor_dir::manifest_from_vendor_dir;
8use crate::package::{RemotePackageType, RemotePackageTypeFilterSpec};
9use crate::progress::{Progress, ProgressBar};
10use crate::{
11    config::Config,
12    package::{PackageReq, RemotePackage},
13    remote_package_source::RemotePackageSource,
14};
15
16pub mod metadata;
17mod metadata_from_server;
18mod metadata_from_vendor_dir;
19
20#[derive(Error, Debug)]
21pub enum ManifestError {
22    #[error(transparent)]
23    Lua(#[from] ManifestLuaError),
24    #[error("failed to fetch manifest from server:\n{0}")]
25    Server(#[from] ManifestFromServerError),
26    #[error("error parsing URL from `vendor-dir`: {0}:")]
27    Vendor(String),
28}
29
30#[derive(Clone, Debug)]
31pub(crate) struct Manifest {
32    server_url: Url,
33    metadata: ManifestMetadata,
34}
35
36impl Manifest {
37    pub fn new(server_url: Url, metadata: ManifestMetadata) -> Self {
38        Self {
39            server_url,
40            metadata,
41        }
42    }
43
44    pub async fn from_config(
45        server_url: Url,
46        config: &Config,
47        progress: &Progress<ProgressBar>,
48    ) -> Result<Self, ManifestError> {
49        if let Some(vendor_dir) = config.vendor_dir() {
50            let server_url: Url = Url::from_file_path(vendor_dir)
51                .map_err(|_err| ManifestError::Vendor(vendor_dir.to_slash_lossy().to_string()))?;
52            return Ok(Self::new(server_url, manifest_from_vendor_dir(vendor_dir)));
53        }
54        let content = manifest_from_cache_or_server(&server_url, config, progress).await?;
55        match ManifestMetadata::new(&content) {
56            Ok(metadata) => Ok(Self::new(server_url, metadata)),
57            Err(_) => {
58                let manifest = manifest_from_server_only(&server_url, config, progress).await?;
59                Ok(Self::new(server_url, ManifestMetadata::new(&manifest)?))
60            }
61        }
62    }
63
64    pub fn server_url(&self) -> &Url {
65        &self.server_url
66    }
67
68    pub fn metadata(&self) -> &ManifestMetadata {
69        &self.metadata
70    }
71
72    /// Find a package that matches the requirement, returning the latest match
73    pub fn find(
74        &self,
75        package_req: &PackageReq,
76        filter: Option<RemotePackageTypeFilterSpec>,
77    ) -> Option<RemotePackage> {
78        match self.metadata().latest_match(package_req, filter) {
79            None => None,
80            Some((package, package_type)) => {
81                let remote_source = match package_type {
82                    RemotePackageType::Rockspec => {
83                        RemotePackageSource::LuarocksRockspec(self.server_url().clone())
84                    }
85                    RemotePackageType::Src => {
86                        RemotePackageSource::LuarocksSrcRock(self.server_url().clone())
87                    }
88                    RemotePackageType::Binary => {
89                        RemotePackageSource::LuarocksBinaryRock(self.server_url().clone())
90                    }
91                };
92                Some(RemotePackage::new(package, remote_source, None))
93            }
94        }
95    }
96}