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