Skip to content

Commit

Permalink
feat(rocks-bin/build): project lockfiles
Browse files Browse the repository at this point in the history
  • Loading branch information
mrcjkb committed Jan 4, 2025
1 parent 757aed0 commit 5443072
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 63 deletions.
22 changes: 19 additions & 3 deletions rocks-lib/src/lockfile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use ssri::Integrity;
use thiserror::Error;

use crate::package::{
PackageName, PackageReq, PackageSpec, PackageVersion, PackageVersionReq, PackageVersionReqError,
PackageName, PackageReq, PackageSpec, PackageVersion, PackageVersionReq,
PackageVersionReqError, RemotePackageTypeFilterSpec,
};
use crate::remote_package_source::RemotePackageSource;

Expand Down Expand Up @@ -184,7 +185,7 @@ impl LocalPackageSpec {
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct LocalPackage {
pub(crate) spec: LocalPackageSpec,
source: RemotePackageSource,
pub(crate) source: RemotePackageSource,
hashes: LocalPackageHashes,
}

Expand Down Expand Up @@ -524,12 +525,27 @@ impl Lockfile {
.into_group_map()
}

pub(crate) fn has_rock(&self, req: &PackageReq) -> Option<LocalPackage> {
pub(crate) fn has_rock(
&self,
req: &PackageReq,
filter: Option<RemotePackageTypeFilterSpec>,
) -> Option<LocalPackage> {
self.list()
.get(req.name())
.map(|packages| {
packages
.iter()
.filter(|package| match &filter {
Some(filter_spec) => match package.source {
RemotePackageSource::LuarocksRockspec(_) => filter_spec.rockspec,
RemotePackageSource::LuarocksSrcRock(_) => filter_spec.src,
RemotePackageSource::LuarocksBinaryRock(_) => filter_spec.binary,
RemotePackageSource::RockspecContent(_) => true,
#[cfg(test)]
RemotePackageSource::Test => unimplemented!(),
},
None => true,
})
.rev()
.find(|package| req.version_req().matches(package.version()))
})?
Expand Down
12 changes: 3 additions & 9 deletions rocks-lib/src/manifest/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,6 @@ impl ManifestMetadata {
self.repository.contains_key(rock_name)
}

pub fn latest_version(&self, rock_name: &PackageName) -> Option<&PackageVersion> {
if !self.has_rock(rock_name) {
return None;
}

self.repository[rock_name].keys().sorted().last()
}

pub fn latest_match(
&self,
lua_package_req: &PackageReq,
Expand Down Expand Up @@ -241,7 +233,9 @@ impl Manifest {
pub fn metadata(&self) -> &ManifestMetadata {
&self.metadata
}
pub fn search(

/// Find a package that matches the requirement, returning the latest match
pub fn find(
&self,
package_req: &PackageReq,
filter: Option<RemotePackageTypeFilterSpec>,
Expand Down
3 changes: 2 additions & 1 deletion rocks-lib/src/operations/resolve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ pub(crate) async fn get_all_dependencies(
.into_iter()
// Exclude packages that are already installed
.filter(|(build_behaviour, package)| {
build_behaviour == &BuildBehaviour::Force || lockfile.has_rock(package).is_none()
build_behaviour == &BuildBehaviour::Force
|| lockfile.has_rock(package, None).is_none()
})
.map(|(build_behaviour, package)| {
let config = config.clone();
Expand Down
8 changes: 8 additions & 0 deletions rocks-lib/src/package/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,14 @@ impl From<PackageSpec> for PackageReq {
}
}

impl From<PackageName> for PackageReq {
fn from(name: PackageName) -> Self {
Self {
name,
version_req: PackageVersionReq::default(),
}
}
}
#[cfg(feature = "lua")]
impl mlua::UserData for PackageReq {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
Expand Down
4 changes: 2 additions & 2 deletions rocks-lib/src/package/outdated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ impl PackageSpec {
.latest_version(&self.name)
.ok_or_else(|| RockNotFound(self.name.clone()))?;

if self.version < *latest_version {
Ok(Some(latest_version.to_owned()))
if self.version < latest_version {
Ok(Some(latest_version))
} else {
Ok(None)
}
Expand Down
133 changes: 85 additions & 48 deletions rocks-lib/src/remote_package_db/mod.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
use std::collections::HashMap;

use crate::{
config::Config,
lockfile::Lockfile,
manifest::{Manifest, ManifestError},
package::{
PackageName, PackageReq, PackageSpec, PackageVersion, RemotePackage,
RemotePackageTypeFilterSpec,
},
progress::{Progress, ProgressBar},
};
use itertools::Itertools as _;
use itertools::Itertools;
use thiserror::Error;

#[derive(Clone)]
pub struct RemotePackageDB(Vec<Manifest>);
pub struct RemotePackageDB(Impl);

#[derive(Clone)]
enum Impl {
LuarocksManifests(Vec<Manifest>),
Lockfile(Lockfile),
}

#[derive(Error, Debug)]
pub enum RemotePackageDBError {
Expand All @@ -37,80 +46,108 @@ impl RemotePackageDB {
manifests.push(manifest);
}
manifests.push(Manifest::from_config(config.server().clone(), config).await?);
Ok(Self(manifests))
Ok(Self(Impl::LuarocksManifests(manifests)))
}

/// Find a package that matches the requirement
/// Find a remote package that matches the requirement, returning the latest match.
pub(crate) fn find(
&self,
package_req: &PackageReq,
filter: Option<RemotePackageTypeFilterSpec>,
progress: &Progress<ProgressBar>,
) -> Result<RemotePackage, SearchError> {
let result = self.0.iter().find_map(|manifest| {
progress.map(|p| p.set_message(format!("🔎 Searching {}", &manifest.server_url())));
manifest.search(package_req, filter.clone())
});
let result = match &self.0 {
Impl::LuarocksManifests(manifests) => manifests.iter().find_map(|manifest| {
progress.map(|p| p.set_message(format!("🔎 Searching {}", &manifest.server_url())));
manifest.find(package_req, filter.clone())
}),
Impl::Lockfile(lockfile) => {
lockfile.has_rock(package_req, filter).map(|local_package| {
RemotePackage::new(
PackageSpec::new(local_package.spec.name, local_package.spec.version),
local_package.source,
)
})
}
};
match result {
Some(package) => Ok(package),
None => Err(SearchError::RockNotFound(package_req.clone())),
}
}

/// Search for all packages that match the requirement
/// Search for all packages that match the requirement.
pub fn search(&self, package_req: &PackageReq) -> Vec<(&PackageName, Vec<&PackageVersion>)> {
self.0
.iter()
.flat_map(|manifest| {
manifest
.metadata()
.repository
.iter()
.filter_map(|(name, elements)| {
if name.to_string().contains(&package_req.name().to_string()) {
Some((
name,
elements
.keys()
.filter(|version| package_req.version_req().matches(version))
.sorted_by(|a, b| Ord::cmp(b, a))
.collect_vec(),
))
} else {
None
}
})
})
.collect()
match &self.0 {
Impl::LuarocksManifests(manifests) => manifests
.iter()
.flat_map(|manifest| {
manifest
.metadata()
.repository
.iter()
.filter_map(|(name, elements)| {
if name.to_string().contains(&package_req.name().to_string()) {
Some((
name,
elements
.keys()
.filter(|version| {
package_req.version_req().matches(version)
})
.sorted_by(|a, b| Ord::cmp(b, a))
.collect_vec(),
))
} else {
None
}
})
})
.collect(),
Impl::Lockfile(lockfile) => lockfile
.rocks()
.iter()
.filter_map(|(_, package)| {
// NOTE: This doesn't group packages by name, but we don't care for now,
// as we shouldn't need to use this function with a lockfile.
let name = package.name();
if name.to_string().contains(&package_req.name().to_string()) {
Some((name, vec![package.version()]))
} else {
None
}
})
.collect_vec(),
}
}

pub fn latest_version(&self, rock_name: &PackageName) -> Option<&PackageVersion> {
self.0
.iter()
.filter_map(|manifest| manifest.metadata().latest_version(rock_name))
.sorted()
.last()
/// Find the latest version for a package by name.
pub(crate) fn latest_version(&self, rock_name: &PackageName) -> Option<PackageVersion> {
self.latest_match(&rock_name.clone().into(), None)
.map(|result| result.version().clone())
}

/// Find the latest package that matches the requirement.
pub fn latest_match(
&self,
package_req: &PackageReq,
filter: Option<RemotePackageTypeFilterSpec>,
) -> Option<PackageSpec> {
self.0
.iter()
.filter_map(|manifest| {
manifest
.metadata()
.latest_match(package_req, filter.clone())
.map(|x| x.0)
})
.last()
match self.find(package_req, filter, &Progress::NoProgress) {
Ok(result) => Some(result.package),
Err(_) => None,
}
}
}

impl From<Manifest> for RemotePackageDB {
fn from(manifest: Manifest) -> Self {
RemotePackageDB(vec![manifest])
Self(Impl::LuarocksManifests(vec![manifest]))
}
}

impl From<Lockfile> for RemotePackageDB {
fn from(lockfile: Lockfile) -> Self {
Self(Impl::Lockfile(lockfile))
}
}

0 comments on commit 5443072

Please sign in to comment.