lux_lib/remote_package_db/
mod.rs1use crate::{
2 config::{Config, ConfigError},
3 lockfile::{LocalPackageLock, LockfileIntegrityError},
4 manifest::{Manifest, ManifestError},
5 package::{
6 PackageName, PackageReq, PackageSpec, PackageVersion, RemotePackage,
7 RemotePackageTypeFilterSpec,
8 },
9 progress::{Progress, ProgressBar},
10};
11use itertools::Itertools;
12
13use thiserror::Error;
14
15#[derive(Clone, Debug)]
17pub struct RemotePackageDB(Impl);
18
19#[derive(Clone, Debug)]
20enum Impl {
21 LuarocksManifests(Vec<Manifest>),
22 Lock(LocalPackageLock),
23}
24
25#[derive(Error, Debug)]
26pub enum RemotePackageDBError {
27 #[error(transparent)]
28 ManifestError(#[from] ManifestError),
29 #[error(transparent)]
30 ConfigError(#[from] ConfigError),
31}
32
33#[derive(Error, Debug)]
34pub enum SearchError {
35 #[error("no rock that matches '{0}' found")]
36 RockNotFound(PackageReq),
37 #[error("no rock that matches '{0}' found in the lockfile.")]
38 RockNotFoundInLockfile(PackageReq),
39 #[error("error when pulling manifest:\n{0}")]
40 Manifest(#[from] ManifestError),
41}
42
43#[derive(Error, Debug)]
44pub enum RemotePackageDbIntegrityError {
45 #[error(transparent)]
46 Lockfile(#[from] LockfileIntegrityError),
47}
48
49impl RemotePackageDB {
50 pub async fn from_config(
51 config: &Config,
52 progress: &Progress<ProgressBar>,
53 ) -> Result<Self, RemotePackageDBError> {
54 let mut manifests = Vec::new();
55 for server in config.enabled_dev_servers()? {
56 let manifest = Manifest::from_config(server, config, progress).await?;
57 manifests.push(manifest);
58 }
59 for server in config.extra_servers() {
60 let manifest = Manifest::from_config(server.clone(), config, progress).await?;
61 manifests.push(manifest);
62 }
63 manifests.push(Manifest::from_config(config.server().clone(), config, progress).await?);
64 Ok(Self(Impl::LuarocksManifests(manifests)))
65 }
66
67 pub(crate) fn find(
69 &self,
70 package_req: &PackageReq,
71 filter: Option<RemotePackageTypeFilterSpec>,
72 progress: &Progress<ProgressBar>,
73 ) -> Result<RemotePackage, SearchError> {
74 match &self.0 {
75 Impl::LuarocksManifests(manifests) => match manifests.iter().find_map(|manifest| {
76 progress.map(|p| p.set_message(format!("🔎 Searching {}", &manifest.server_url())));
77 manifest.find(package_req, filter.clone())
78 }) {
79 Some(package) => Ok(package),
80 None => Err(SearchError::RockNotFound(package_req.clone())),
81 },
82 Impl::Lock(lockfile) => {
83 match lockfile.has_rock(package_req, filter).map(|local_package| {
84 RemotePackage::new(
85 PackageSpec::new(local_package.spec.name, local_package.spec.version),
86 local_package.source,
87 local_package.source_url,
88 )
89 }) {
90 Some(package) => Ok(package),
91 None => Err(SearchError::RockNotFoundInLockfile(package_req.clone())),
92 }
93 }
94 }
95 }
96
97 pub fn search(&self, package_req: &PackageReq) -> Vec<(&PackageName, Vec<&PackageVersion>)> {
99 match &self.0 {
100 Impl::LuarocksManifests(manifests) => manifests
101 .iter()
102 .flat_map(|manifest| {
103 manifest
104 .metadata()
105 .repository
106 .iter()
107 .filter_map(|(name, elements)| {
108 if name.to_string().contains(&package_req.name().to_string()) {
109 Some((
110 name,
111 elements
112 .keys()
113 .filter(|version| {
114 package_req.version_req().matches(version)
115 })
116 .sorted_by(|a, b| Ord::cmp(b, a))
117 .collect_vec(),
118 ))
119 } else {
120 None
121 }
122 })
123 })
124 .collect(),
125 Impl::Lock(lockfile) => lockfile
126 .rocks()
127 .values()
128 .filter_map(|package| {
129 let name = package.name();
132 if name.to_string().contains(&package_req.name().to_string()) {
133 Some((name, vec![package.version()]))
134 } else {
135 None
136 }
137 })
138 .collect_vec(),
139 }
140 }
141
142 pub(crate) fn latest_version(&self, rock_name: &PackageName) -> Option<PackageVersion> {
144 self.latest_match(&rock_name.clone().into(), None)
145 .map(|result| result.version().clone())
146 }
147
148 pub fn latest_match(
150 &self,
151 package_req: &PackageReq,
152 filter: Option<RemotePackageTypeFilterSpec>,
153 ) -> Option<PackageSpec> {
154 match self.find(package_req, filter, &Progress::no_progress()) {
155 Ok(result) => Some(result.package),
156 Err(_) => None,
157 }
158 }
159}
160
161impl From<Manifest> for RemotePackageDB {
162 fn from(manifest: Manifest) -> Self {
163 Self(Impl::LuarocksManifests(vec![manifest]))
164 }
165}
166
167impl From<LocalPackageLock> for RemotePackageDB {
168 fn from(lock: LocalPackageLock) -> Self {
169 Self(Impl::Lock(lock))
170 }
171}