Skip to main content

lux_lib/pipeline/
discover.rs

1use miette::Diagnostic;
2use thiserror::Error;
3
4use crate::{
5    lua_rockspec::RemoteLuaRockspec,
6    operations,
7    package::{PackageReq, PackageSpec, RemotePackage},
8    package_db::SearchError,
9    remote_package_source::RemotePackageSource,
10    rockspec::Rockspec,
11};
12use std::path::PathBuf;
13
14use super::materialise::PackageSource;
15
16#[derive(Clone, Debug)]
17pub(crate) struct FoundPackage {
18    pub(crate) remote: RemotePackage,
19    pub(crate) rockspec: RemoteLuaRockspec,
20    pub(crate) artifact: Option<PackageSource>,
21}
22
23impl FoundPackage {
24    /// Builds a discovered package from an already-parsed rockspec, so it can
25    /// be resolved as a root without contacting a remote package database.
26    pub(crate) fn from_rockspec(rockspec: RemoteLuaRockspec) -> Self {
27        let source = rockspec
28            .to_lua_remote_rockspec_string()
29            .map(RemotePackageSource::RockspecContent)
30            .unwrap_or(RemotePackageSource::Local);
31        let remote = RemotePackage::new(
32            PackageSpec::new(rockspec.package().clone(), rockspec.version().clone()),
33            source,
34            None,
35        );
36        Self {
37            remote,
38            rockspec,
39            artifact: None,
40        }
41    }
42
43    /// Builds a discovered package from a project root rockspec, using the
44    /// project's own directory as the source.
45    pub(crate) fn from_project_root(rockspec: RemoteLuaRockspec, root_dir: PathBuf) -> Self {
46        let remote = RemotePackage::new(
47            PackageSpec::new(rockspec.package().clone(), rockspec.version().clone()),
48            RemotePackageSource::Local,
49            None,
50        );
51        Self {
52            remote,
53            rockspec,
54            artifact: Some(PackageSource::SourceDir(root_dir)),
55        }
56    }
57}
58
59#[derive(Error, Debug, Diagnostic)]
60#[non_exhaustive]
61pub enum DiscoverError {
62    #[error(transparent)]
63    #[diagnostic(transparent)]
64    Search(#[from] SearchError),
65    #[error("failed to acquire metadata for '{0}'")]
66    #[diagnostic(forward(1))]
67    Download(PackageReq, Box<operations::SearchAndDownloadError>),
68    #[error("failed to fetch vendored package for '{0}'")]
69    #[diagnostic(forward(1))]
70    FetchVendored(PackageReq, Box<operations::FetchVendoredError>),
71    #[error(transparent)]
72    #[diagnostic(transparent)]
73    Project(#[from] crate::project::ProjectError),
74    #[error(transparent)]
75    #[diagnostic(transparent)]
76    LocalRockspec(#[from] crate::project::IntoLocalRockspecError),
77}
78
79#[cfg(test)]
80mod tests {
81    use super::*;
82
83    #[test]
84    fn from_rockspec_builds_local_found_package() {
85        let content = "rockspec_format = '1.0'\npackage = 'foo'\nversion = '1.0.0-1'\nsource = { url = 'https://example.com/foo.zip' }";
86        let Ok(rockspec) = RemoteLuaRockspec::new(content) else {
87            unreachable!("invalid test rockspec");
88        };
89
90        let found = FoundPackage::from_rockspec(rockspec);
91
92        assert_eq!(found.remote.spec.name().to_string(), "foo");
93        assert_eq!(found.remote.spec.version().to_string(), "1.0.0-1");
94        assert!(matches!(
95            found.remote.source,
96            RemotePackageSource::RockspecContent(_)
97        ));
98        assert!(found.artifact.is_none());
99    }
100}