diff --git a/rocks-bin/src/build.rs b/rocks-bin/src/build.rs index ff7f2fa..11f3a34 100644 --- a/rocks-bin/src/build.rs +++ b/rocks-bin/src/build.rs @@ -9,9 +9,9 @@ use rocks_lib::{ build::BuildBehaviour, config::Config, lockfile::{LockConstraint::Unconstrained, PinnedState}, - manifest::Manifest, package::{PackageName, PackageReq}, progress::MultiProgress, + remote_package_db::RemotePackageDB, rockspec::Rockspec, tree::Tree, }; @@ -69,7 +69,7 @@ pub async fn build(data: Build, config: Config) -> Result<()> { let lua_version = rockspec.lua_version_from_config(&config)?; let tree = Tree::new(config.tree().clone(), lua_version)?; - let manifest = Manifest::from_config(config.server(), &config).await?; + let package_db = RemotePackageDB::from_config(&config).await?; let build_behaviour = match tree.has_rock_and( &PackageReq::new( @@ -114,7 +114,7 @@ pub async fn build(data: Build, config: Config) -> Result<()> { rocks_lib::operations::install( dependencies_to_install, pin, - &manifest, + &package_db, &config, progress_arc, ) diff --git a/rocks-bin/src/download.rs b/rocks-bin/src/download.rs index 99fb263..7dd4310 100644 --- a/rocks-bin/src/download.rs +++ b/rocks-bin/src/download.rs @@ -2,9 +2,9 @@ use clap::Args; use eyre::Result; use rocks_lib::{ config::Config, - manifest::Manifest, package::PackageReq, progress::{MultiProgress, Progress}, + remote_package_db::RemotePackageDB, }; #[derive(Args)] @@ -13,18 +13,13 @@ pub struct Download { } pub async fn download(dl_data: Download, config: Config) -> Result<()> { - let manifest = Manifest::from_config(config.server(), &config).await?; + let package_db = RemotePackageDB::from_config(&config).await?; let progress = MultiProgress::new(); let bar = Progress::Progress(progress.new_bar()); - let rock = rocks_lib::operations::download_to_file( - &dl_data.package_req, - None, - &manifest, - &config, - &bar, - ) - .await?; + let rock = + rocks_lib::operations::download_to_file(&dl_data.package_req, None, &package_db, &bar) + .await?; bar.map(|b| { b.finish_with_message(format!( diff --git a/rocks-bin/src/fetch.rs b/rocks-bin/src/fetch.rs index 42cdb51..f915c48 100644 --- a/rocks-bin/src/fetch.rs +++ b/rocks-bin/src/fetch.rs @@ -3,8 +3,8 @@ use std::path::PathBuf; use eyre::Result; use rocks_lib::{ config::Config, - manifest::Manifest, progress::{MultiProgress, Progress}, + remote_package_db::RemotePackageDB, }; use crate::unpack::UnpackRemote; @@ -13,9 +13,9 @@ pub async fn fetch_remote(data: UnpackRemote, config: Config) -> Result<()> { let package_req = data.package_req; let progress = MultiProgress::new(); let bar = Progress::Progress(progress.new_bar()); - let manifest = Manifest::from_config(config.server(), &config).await?; + let package_db = RemotePackageDB::from_config(&config).await?; let rockspec = - rocks_lib::operations::download_rockspec(&package_req, &manifest, &config, &bar).await?; + rocks_lib::operations::download_rockspec(&package_req, &package_db, &bar).await?; let destination = data .path diff --git a/rocks-bin/src/info.rs b/rocks-bin/src/info.rs index b4943df..432674c 100644 --- a/rocks-bin/src/info.rs +++ b/rocks-bin/src/info.rs @@ -2,10 +2,10 @@ use clap::Args; use eyre::Result; use rocks_lib::{ config::{Config, LuaVersion}, - manifest::Manifest, operations::download_rockspec, package::PackageReq, progress::{MultiProgress, Progress}, + remote_package_db::RemotePackageDB, tree::Tree, }; @@ -17,12 +17,12 @@ pub struct Info { pub async fn info(data: Info, config: Config) -> Result<()> { // TODO(vhyrro): Add `Tree::from(&Config)` let tree = Tree::new(config.tree().clone(), LuaVersion::from(&config)?)?; - let manifest = Manifest::from_config(config.server(), &config).await?; + let package_db = RemotePackageDB::from_config(&config).await?; let progress = MultiProgress::new(); let bar = Progress::Progress(progress.new_bar()); - let rockspec = download_rockspec(&data.package, &manifest, &config, &bar).await?; + let rockspec = download_rockspec(&data.package, &package_db, &bar).await?; bar.map(|b| b.finish_and_clear()); diff --git a/rocks-bin/src/install.rs b/rocks-bin/src/install.rs index f00015a..53f8e7e 100644 --- a/rocks-bin/src/install.rs +++ b/rocks-bin/src/install.rs @@ -5,9 +5,9 @@ use rocks_lib::{ build::BuildBehaviour, config::{Config, LuaVersion}, lockfile::PinnedState, - manifest::Manifest, package::PackageReq, progress::MultiProgress, + remote_package_db::RemotePackageDB, tree::Tree, }; @@ -54,11 +54,17 @@ pub async fn install(data: Install, config: Config) -> Result<()> { }) .collect_vec(); - let manifest = Manifest::from_config(config.server(), &config).await?; + let package_db = RemotePackageDB::from_config(&config).await?; // TODO(vhyrro): If the tree doesn't exist then error out. - rocks_lib::operations::install(packages, pin, &manifest, &config, MultiProgress::new_arc()) - .await?; + rocks_lib::operations::install( + packages, + pin, + &package_db, + &config, + MultiProgress::new_arc(), + ) + .await?; Ok(()) } diff --git a/rocks-bin/src/main.rs b/rocks-bin/src/main.rs index f03726c..43b46e7 100644 --- a/rocks-bin/src/main.rs +++ b/rocks-bin/src/main.rs @@ -43,10 +43,10 @@ pub struct Cli { #[arg(long, value_name = "server")] pub server: Option, - /// Fetch rocks/rockspecs from this server only (overrides - /// any entries in the config file). - #[arg(long, value_name = "server")] - pub only_server: Option, + /// Fetch rocks/rockspecs from this server in addition to the main server + /// (overrides any entries in the config file). + #[arg(long, value_name = "extra-server")] + pub extra_servers: Option>, /// Restrict downloads to paths matching the given URL. #[arg(long, value_name = "url")] @@ -165,7 +165,7 @@ async fn main() { .lua_dir(cli.lua_dir) .lua_version(cli.lua_version) .namespace(cli.namespace) - .only_server(cli.only_server) + .extra_servers(cli.extra_servers) .only_sources(cli.only_sources) .server(cli.server) .tree(cli.tree) diff --git a/rocks-bin/src/outdated.rs b/rocks-bin/src/outdated.rs index 3a21626..9f78608 100644 --- a/rocks-bin/src/outdated.rs +++ b/rocks-bin/src/outdated.rs @@ -5,8 +5,8 @@ use eyre::Result; use itertools::Itertools; use rocks_lib::{ config::{Config, LuaVersion}, - manifest::Manifest, progress::{MultiProgress, ProgressBar}, + remote_package_db::RemotePackageDB, tree::Tree, }; use text_trees::{FormatCharacters, StringTreeNode, TreeFormatting}; @@ -25,7 +25,7 @@ pub async fn outdated(outdated_data: Outdated, config: Config) -> Result<()> { let tree = Tree::new(config.tree().clone(), LuaVersion::from(&config)?)?; - let manifest = Manifest::from_config(config.server(), &config).await?; + let package_db = RemotePackageDB::from_config(&config).await?; // NOTE: This will display all installed versions and each possible upgrade. // However, this should also take into account dependency constraints made by other rocks. @@ -36,7 +36,7 @@ pub async fn outdated(outdated_data: Outdated, config: Config) -> Result<()> { .iter() .filter_map(|rock| { rock.to_package() - .has_update(manifest.metadata()) + .has_update(&package_db) .expect("TODO") .map(|version| (rock, version)) }) diff --git a/rocks-bin/src/remove.rs b/rocks-bin/src/remove.rs index 29465a1..e95229a 100644 --- a/rocks-bin/src/remove.rs +++ b/rocks-bin/src/remove.rs @@ -2,9 +2,9 @@ use clap::Args; use eyre::Result; use rocks_lib::{ config::{Config, LuaVersion}, - manifest::Manifest, package::{PackageName, PackageSpec, PackageVersion}, progress::{MultiProgress, Progress}, + remote_package_db::RemotePackageDB, tree::Tree, }; @@ -17,14 +17,11 @@ pub struct Remove { } pub async fn remove(remove_args: Remove, config: Config) -> Result<()> { - let manifest = Manifest::from_config(config.server(), &config).await?; + let package_db = RemotePackageDB::from_config(&config).await?; let target_version = remove_args .version - .or(manifest - .metadata() - .latest_version(&remove_args.name) - .cloned()) + .or(package_db.latest_version(&remove_args.name).cloned()) .unwrap(); let tree = Tree::new(config.tree().clone(), LuaVersion::from(&config)?)?; diff --git a/rocks-bin/src/search.rs b/rocks-bin/src/search.rs index cf2b017..08ed580 100644 --- a/rocks-bin/src/search.rs +++ b/rocks-bin/src/search.rs @@ -7,9 +7,9 @@ use text_trees::{FormatCharacters, StringTreeNode, TreeFormatting}; use rocks_lib::{ config::Config, - manifest::Manifest, package::{PackageName, PackageReq, PackageVersion}, progress::{MultiProgress, ProgressBar}, + remote_package_db::RemotePackageDB, }; #[derive(Args)] @@ -30,39 +30,20 @@ pub async fn search(data: Search, config: Config) -> Result<()> { let formatting = TreeFormatting::dir_tree(FormatCharacters::box_chars()); - let manifest = Manifest::from_config(config.server(), &config).await?; + let package_db = RemotePackageDB::from_config(&config).await?; let lua_package_req = data.lua_package_req; - let rock_to_version_map: HashMap<&PackageName, Vec<&PackageVersion>> = manifest - .metadata() - .repository - .iter() - .filter_map(|(name, elements)| { - if name - .to_string() - .contains(&lua_package_req.name().to_string()) - { - Some(( - name, - elements - .keys() - .filter(|version| lua_package_req.version_req().matches(version)) - .sorted_by(|a, b| Ord::cmp(b, a)) - .collect_vec(), - )) - } else { - None - } - }) - .collect(); + let result = package_db.search(&lua_package_req); bar.finish_and_clear(); if data.porcelain { + let rock_to_version_map: HashMap<&PackageName, Vec<&PackageVersion>> = + HashMap::from_iter(result); println!("{}", serde_json::to_string(&rock_to_version_map)?); } else { - for (key, versions) in rock_to_version_map.into_iter().sorted() { + for (key, versions) in result.into_iter().sorted() { let mut tree = StringTreeNode::new(key.to_string().to_owned()); for version in versions { diff --git a/rocks-bin/src/test.rs b/rocks-bin/src/test.rs index f1e6d2f..9334a6d 100644 --- a/rocks-bin/src/test.rs +++ b/rocks-bin/src/test.rs @@ -2,10 +2,10 @@ use clap::Args; use eyre::{OptionExt, Result}; use rocks_lib::{ config::Config, - manifest::Manifest, operations::{ensure_busted, ensure_dependencies, run_tests, TestEnv}, progress::MultiProgress, project::Project, + remote_package_db::RemotePackageDB, tree::Tree, }; @@ -26,7 +26,7 @@ pub async fn test(test: Test, config: Config) -> Result<()> { Ok(lua_version) => Ok(lua_version), Err(_) => rockspec.test_lua_version().ok_or_eyre("lua version not set! Please provide a version through `--lua-version ` or add it to your rockspec's dependencies"), }?; - let manifest = Manifest::from_config(config.server(), &config).await?; + let package_db = RemotePackageDB::from_config(&config).await?; let test_config = config.with_lua_version(lua_version); let tree = Tree::new( test_config.tree().clone(), @@ -34,8 +34,8 @@ pub async fn test(test: Test, config: Config) -> Result<()> { )?; let progress = MultiProgress::new_arc(); // TODO(#204): Only ensure busted if running with busted (e.g. a .busted directory exists) - ensure_busted(&tree, &manifest, &test_config, progress.clone()).await?; - ensure_dependencies(rockspec, &tree, &manifest, &test_config, progress).await?; + ensure_busted(&tree, &package_db, &test_config, progress.clone()).await?; + ensure_dependencies(rockspec, &tree, &package_db, &test_config, progress).await?; let test_args = test.test_args.unwrap_or_default(); let test_env = if test.impure { TestEnv::Impure diff --git a/rocks-bin/src/unpack.rs b/rocks-bin/src/unpack.rs index 2a06c8f..b127dba 100644 --- a/rocks-bin/src/unpack.rs +++ b/rocks-bin/src/unpack.rs @@ -4,9 +4,9 @@ use clap::Args; use eyre::Result; use rocks_lib::{ config::Config, - manifest::Manifest, package::PackageReq, progress::{MultiProgress, Progress}, + remote_package_db::RemotePackageDB, }; #[derive(Args)] @@ -49,12 +49,11 @@ and type `rocks make` to build.", pub async fn unpack_remote(data: UnpackRemote, config: Config) -> Result<()> { let package_req = data.package_req; - let manifest = Manifest::from_config(config.server(), &config).await?; + let package_db = RemotePackageDB::from_config(&config).await?; let progress = MultiProgress::new(); let bar = Progress::Progress(progress.new_bar()); - let rock = - rocks_lib::operations::search_and_download_src_rock(&package_req, &manifest, &config, &bar) - .await?; + let rock = rocks_lib::operations::search_and_download_src_rock(&package_req, &package_db, &bar) + .await?; let cursor = Cursor::new(rock.bytes); let destination = data diff --git a/rocks-bin/src/update.rs b/rocks-bin/src/update.rs index 5e7d8ef..6a0597e 100644 --- a/rocks-bin/src/update.rs +++ b/rocks-bin/src/update.rs @@ -3,7 +3,8 @@ use eyre::Result; use rocks_lib::config::LuaVersion; use rocks_lib::lockfile::PinnedState; use rocks_lib::progress::{MultiProgress, ProgressBar}; -use rocks_lib::{config::Config, manifest::Manifest, operations, package::PackageReq, tree::Tree}; +use rocks_lib::remote_package_db::RemotePackageDB; +use rocks_lib::{config::Config, operations, package::PackageReq, tree::Tree}; #[derive(Args)] pub struct Update {} @@ -16,7 +17,7 @@ pub async fn update(config: Config) -> Result<()> { let lockfile = tree.lockfile()?; let rocks = lockfile.rocks(); - let manifest = Manifest::from_config(config.server(), &config).await?; + let package_db = RemotePackageDB::from_config(&config).await?; for package in rocks.values() { if package.pinned() == PinnedState::Unpinned { @@ -26,7 +27,7 @@ pub async fn update(config: Config) -> Result<()> { package.name().to_string(), package.constraint().to_string_opt(), )?, - &manifest, + &package_db, &config, progress.clone(), ) diff --git a/rocks-lib/src/config/mod.rs b/rocks-lib/src/config/mod.rs index ed7094c..8263a22 100644 --- a/rocks-lib/src/config/mod.rs +++ b/rocks-lib/src/config/mod.rs @@ -146,7 +146,7 @@ pub struct NoValidHomeDirectory; pub struct Config { enable_development_rockspecs: bool, server: String, - only_server: Option, + extra_servers: Vec, only_sources: Option, namespace: String, lua_dir: PathBuf, @@ -201,8 +201,8 @@ impl Config { &self.server } - pub fn only_server(&self) -> Option<&String> { - self.only_server.as_ref() + pub fn extra_servers(&self) -> &Vec { + self.extra_servers.as_ref() } pub fn only_sources(&self) -> Option<&String> { @@ -286,7 +286,7 @@ pub enum ConfigError { pub struct ConfigBuilder { enable_development_rockspecs: Option, server: Option, - only_server: Option, + extra_servers: Option>, only_sources: Option, namespace: Option, lua_dir: Option, @@ -321,10 +321,9 @@ impl ConfigBuilder { Self { server, ..self } } - pub fn only_server(self, server: Option) -> Self { + pub fn extra_servers(self, extra_servers: Option>) -> Self { Self { - only_server: server.clone(), - server, + extra_servers, ..self } } @@ -433,7 +432,7 @@ impl ConfigBuilder { server: self .server .unwrap_or_else(|| "https://luarocks.org/".to_string()), - only_server: self.only_server, + extra_servers: self.extra_servers.unwrap_or_default(), only_sources: self.only_sources, namespace: self.namespace.unwrap_or_default(), lua_dir: self.lua_dir.unwrap_or_else(|| data_dir.join("lua")), diff --git a/rocks-lib/src/lib.rs b/rocks-lib/src/lib.rs index bff49f0..33e29dd 100644 --- a/rocks-lib/src/lib.rs +++ b/rocks-lib/src/lib.rs @@ -10,6 +10,7 @@ pub mod package; pub mod path; pub mod progress; pub mod project; +pub mod remote_package_db; pub mod rockspec; pub mod tree; pub mod upload; diff --git a/rocks-lib/src/luarocks_installation.rs b/rocks-lib/src/luarocks_installation.rs index c0cb78e..35983db 100644 --- a/rocks-lib/src/luarocks_installation.rs +++ b/rocks-lib/src/luarocks_installation.rs @@ -15,11 +15,11 @@ use crate::{ config::{Config, LuaVersion, LuaVersionUnset}, lockfile::{LocalPackage, LocalPackageId, LockConstraint, PinnedState}, lua_installation::LuaInstallation, - manifest::{Manifest, ManifestError}, operations::{get_all_dependencies, SearchAndDownloadError}, package::PackageReq, path::Paths, progress::{MultiProgress, Progress, ProgressBar}, + remote_package_db::{RemotePackageDB, RemotePackageDBError}, rockspec::{Rockspec, RockspecFormat}, tree::Tree, }; @@ -37,8 +37,6 @@ pub enum LuaRocksInstallError { #[error(transparent)] Io(#[from] io::Error), #[error(transparent)] - ManifestError(#[from] ManifestError), - #[error(transparent)] BuildError(#[from] BuildError), } @@ -47,7 +45,7 @@ pub enum InstallBuildDependenciesError { #[error(transparent)] Io(#[from] io::Error), #[error(transparent)] - ManifestError(#[from] ManifestError), + RemotePackageDBError(#[from] RemotePackageDBError), #[error(transparent)] SearchAndDownloadError(#[from] SearchAndDownloadError), #[error(transparent)] @@ -98,7 +96,7 @@ impl LuaRocksInstallation { } pub async fn ensure_installed( - self: &LuaRocksInstallation, + &self, progress: &Progress, ) -> Result<(), LuaRocksInstallError> { let mut lockfile = self.tree.lockfile()?; @@ -122,14 +120,14 @@ impl LuaRocksInstallation { } pub async fn install_build_dependencies( - self, + &self, build_backend: &str, rockspec: &Rockspec, progress_arc: Arc>, ) -> Result<(), InstallBuildDependenciesError> { let progress = Arc::clone(&progress_arc); let mut lockfile = self.tree.lockfile()?; - let manifest = Manifest::from_config(self.config.server(), &self.config).await?; + let package_db = RemotePackageDB::from_config(&self.config).await?; let build_dependencies = match rockspec.rockspec_format { Some(RockspecFormat::_1_0 | RockspecFormat::_2_0) => { // XXX: rockspec formats < 3.0 don't support `build_dependencies`, @@ -154,7 +152,7 @@ impl LuaRocksInstallation { tx, build_dependencies, pin, - Arc::new(manifest), + Arc::new(package_db), Arc::new(lockfile.clone()), &self.config, progress_arc, diff --git a/rocks-lib/src/manifest/mod.rs b/rocks-lib/src/manifest/mod.rs index 5ff7199..d7a87d6 100644 --- a/rocks-lib/src/manifest/mod.rs +++ b/rocks-lib/src/manifest/mod.rs @@ -8,7 +8,7 @@ use tokio::{fs, io}; use crate::{ config::{Config, LuaVersion}, - package::{PackageName, PackageReq, PackageSpec, PackageVersion}, + package::{PackageName, PackageReq, PackageSpec, PackageVersion, RemotePackage}, }; #[derive(Error, Debug)] @@ -92,7 +92,7 @@ async fn manifest_from_server( } #[derive(Clone)] -pub struct ManifestMetadata { +pub(crate) struct ManifestMetadata { pub repository: HashMap>>, } @@ -135,14 +135,6 @@ impl ManifestMetadata { self.repository.contains_key(rock_name) } - pub fn available_versions(&self, rock_name: &PackageName) -> Option> { - if !self.has_rock(rock_name) { - return None; - } - - Some(self.repository[rock_name].keys().collect()) - } - pub fn latest_version(&self, rock_name: &PackageName) -> Option<&PackageVersion> { if !self.has_rock(rock_name) { return None; @@ -170,7 +162,7 @@ impl ManifestMetadata { } #[derive(Clone)] -pub struct Manifest { +pub(crate) struct Manifest { server_url: String, metadata: ManifestMetadata, } @@ -194,6 +186,16 @@ impl Manifest { pub fn metadata(&self) -> &ManifestMetadata { &self.metadata } + pub fn search(&self, package_req: &PackageReq) -> Option { + if !self.metadata().has_rock(package_req.name()) { + None + } else { + Some(RemotePackage { + package: self.metadata().latest_match(package_req).unwrap(), + server_url: self.server_url().into(), + }) + } + } } #[derive(Clone, serde::Deserialize)] diff --git a/rocks-lib/src/operations/download.rs b/rocks-lib/src/operations/download.rs index 34faeb9..47c3b64 100644 --- a/rocks-lib/src/operations/download.rs +++ b/rocks-lib/src/operations/download.rs @@ -4,10 +4,9 @@ use bytes::Bytes; use thiserror::Error; use crate::{ - config::Config, - manifest::{Manifest, ManifestError}, package::{PackageName, PackageReq, PackageVersion, RemotePackage}, progress::{Progress, ProgressBar}, + remote_package_db::{RemotePackageDB, SearchError}, rockspec::{Rockspec, RockspecError}, }; @@ -34,21 +33,18 @@ pub enum DownloadRockspecError { pub async fn download_rockspec( package_req: &PackageReq, - manifest: &Manifest, - config: &Config, + package_db: &RemotePackageDB, progress: &Progress, ) -> Result { - let package = search_manifest(package_req, manifest, config, progress).await?; - + let package = package_db.find(package_req, progress)?; progress.map(|p| p.set_message(format!("📥 Downloading rockspec for {}", package_req))); - download_rockspec_impl(package).await } #[derive(Error, Debug)] pub enum SearchAndDownloadError { #[error(transparent)] - Search(#[from] SearchManifestError), + Search(#[from] SearchError), #[error(transparent)] Download(#[from] DownloadSrcRockError), #[error(transparent)] @@ -63,11 +59,10 @@ pub enum SearchAndDownloadError { pub async fn search_and_download_src_rock( package_req: &PackageReq, - manifest: &Manifest, - config: &Config, + package_db: &RemotePackageDB, progress: &Progress, ) -> Result { - let package = search_manifest(package_req, manifest, config, progress).await?; + let package = package_db.find(package_req, progress)?; Ok(download_src_rock(&package, progress).await?) } @@ -87,13 +82,12 @@ pub(crate) async fn download_src_rock( pub async fn download_to_file( package_req: &PackageReq, destination_dir: Option, - manifest: &Manifest, - config: &Config, + package_db: &RemotePackageDB, progress: &Progress, ) -> Result { progress.map(|p| p.set_message(format!("📥 Downloading {}", package_req))); - let rock = search_and_download_src_rock(package_req, manifest, config, progress).await?; + let rock = search_and_download_src_rock(package_req, package_db, progress).await?; let full_rock_name = full_rock_name(&rock.name, &rock.version); tokio::fs::write( destination_dir @@ -110,44 +104,6 @@ pub async fn download_to_file( }) } -#[derive(Error, Debug)] -pub enum SearchManifestError { - #[error(transparent)] - Mlua(#[from] mlua::Error), - #[error("rock '{name}' does not exist on {server}'s manifest")] - RockNotFound { name: PackageName, server: String }, - #[error("error when pulling manifest: {0}")] - Manifest(#[from] ManifestError), -} - -async fn search_manifest( - package_req: &PackageReq, - manifest: &Manifest, - config: &Config, - progress: &Progress, -) -> Result { - progress.map(|p| p.set_message("🔎 Searching manifest...")); - - search_manifest_impl(package_req, manifest, config).await -} - -async fn search_manifest_impl( - package_req: &PackageReq, - manifest: &Manifest, - config: &Config, -) -> Result { - if !manifest.metadata().has_rock(package_req.name()) { - return Err(SearchManifestError::RockNotFound { - name: package_req.name().clone(), - server: config.server().clone(), - }); - } - Ok(RemotePackage { - package: manifest.metadata().latest_match(package_req).unwrap(), - server_url: manifest.server_url().into(), - }) -} - async fn download_rockspec_impl( remote_package: RemotePackage, ) -> Result { diff --git a/rocks-lib/src/operations/install.rs b/rocks-lib/src/operations/install.rs index 7128a27..88d473f 100644 --- a/rocks-lib/src/operations/install.rs +++ b/rocks-lib/src/operations/install.rs @@ -7,9 +7,9 @@ use crate::{ luarocks_installation::{ InstallBuildDependenciesError, LuaRocksError, LuaRocksInstallError, LuaRocksInstallation, }, - manifest::{Manifest, ManifestError}, package::{PackageName, PackageReq}, progress::{MultiProgress, Progress, ProgressBar}, + remote_package_db::RemotePackageDB, rockspec::{BuildBackendSpec, LuaVersionError}, tree::Tree, }; @@ -36,8 +36,6 @@ pub enum InstallError { LuaRocksInstallError(#[from] LuaRocksInstallError), #[error("error installing LuaRocks build dependencies: {0}")] InstallBuildDependenciesError(#[from] InstallBuildDependenciesError), - #[error(transparent)] - ManifestError(#[from] ManifestError), #[error("failed to build {0}: {1}")] BuildError(PackageName, BuildError), } @@ -45,7 +43,7 @@ pub enum InstallError { pub async fn install( packages: Vec<(BuildBehaviour, PackageReq)>, pin: PinnedState, - manifest: &Manifest, + package_db: &RemotePackageDB, config: &Config, progress: Arc>, ) -> Result, InstallError> @@ -57,7 +55,7 @@ where let result = install_impl( packages, pin, - manifest.clone(), + package_db.clone(), config, &mut lockfile, progress, @@ -70,7 +68,7 @@ where async fn install_impl( packages: Vec<(BuildBehaviour, PackageReq)>, pin: PinnedState, - manifest: Manifest, + package_db: RemotePackageDB, config: &Config, lockfile: &mut Lockfile, progress_arc: Arc>, @@ -82,7 +80,7 @@ async fn install_impl( tx, packages, pin, - Arc::new(manifest), + Arc::new(package_db), Arc::new(lockfile.clone()), config, progress_arc.clone(), diff --git a/rocks-lib/src/operations/resolve.rs b/rocks-lib/src/operations/resolve.rs index b7517fe..0f06982 100644 --- a/rocks-lib/src/operations/resolve.rs +++ b/rocks-lib/src/operations/resolve.rs @@ -10,9 +10,9 @@ use crate::{ build::BuildBehaviour, config::Config, lockfile::{LocalPackageId, LocalPackageSpec, LockConstraint, Lockfile, PinnedState}, - manifest::Manifest, package::{PackageReq, PackageVersionReq}, progress::{MultiProgress, Progress}, + remote_package_db::RemotePackageDB, rockspec::Rockspec, }; @@ -30,7 +30,7 @@ pub(crate) async fn get_all_dependencies( tx: UnboundedSender, packages: Vec<(BuildBehaviour, PackageReq)>, pin: PinnedState, - manifest: Arc, + package_db: Arc, lockfile: Arc, config: &Config, progress: Arc>, @@ -45,14 +45,14 @@ pub(crate) async fn get_all_dependencies( .map(|(build_behaviour, package)| { let config = config.clone(); let tx = tx.clone(); - let manifest = Arc::clone(&manifest); + let package_db = Arc::clone(&package_db); let progress = Arc::clone(&progress); let lockfile = Arc::clone(&lockfile); tokio::spawn(async move { let bar = progress.map(|p| p.new_bar()); - let rockspec = download_rockspec(&package, &manifest, &config, &bar) + let rockspec = download_rockspec(&package, &package_db, &bar) .await .unwrap(); @@ -75,7 +75,7 @@ pub(crate) async fn get_all_dependencies( tx.clone(), dependencies, pin, - manifest, + package_db, lockfile, &config, progress, diff --git a/rocks-lib/src/operations/run.rs b/rocks-lib/src/operations/run.rs index 41cf3cc..33f2eb8 100644 --- a/rocks-lib/src/operations/run.rs +++ b/rocks-lib/src/operations/run.rs @@ -4,10 +4,10 @@ use crate::{ build::BuildBehaviour, config::{Config, LuaVersion, LuaVersionUnset}, lockfile::PinnedState, - manifest::{Manifest, ManifestError}, package::{PackageReq, PackageVersionReqError}, path::Paths, progress::MultiProgress, + remote_package_db::{RemotePackageDB, RemotePackageDBError}, tree::Tree, }; use thiserror::Error; @@ -52,18 +52,18 @@ pub async fn run(command: &str, args: Vec, config: Config) -> Result<(), pub enum InstallCmdError { InstallError(#[from] InstallError), PackageVersionReqError(#[from] PackageVersionReqError), - ManifestError(#[from] ManifestError), + RemotePackageDBError(#[from] RemotePackageDBError), } /// Ensure that a command is installed. /// This defaults to the local project tree if cwd is a project root. pub async fn install_command(command: &str, config: &Config) -> Result<(), InstallCmdError> { let package_req = PackageReq::new(command.into(), None)?; - let manifest = Manifest::from_config(config.server(), config).await?; + let package_db = RemotePackageDB::from_config(config).await?; super::install( vec![(BuildBehaviour::NoForce, package_req)], PinnedState::Unpinned, - &manifest, + &package_db, config, MultiProgress::new_arc(), ) diff --git a/rocks-lib/src/operations/test.rs b/rocks-lib/src/operations/test.rs index 33f32be..2ccc8b3 100644 --- a/rocks-lib/src/operations/test.rs +++ b/rocks-lib/src/operations/test.rs @@ -4,11 +4,11 @@ use crate::{ build::BuildBehaviour, config::Config, lockfile::PinnedState, - manifest::Manifest, package::{PackageName, PackageReq, PackageVersionReqError}, path::Paths, progress::{MultiProgress, Progress}, project::Project, + remote_package_db::RemotePackageDB, rockspec::Rockspec, tree::Tree, }; @@ -101,7 +101,7 @@ pub enum InstallTestDependenciesError { /// This defaults to the local project tree if cwd is a project root. pub async fn ensure_busted( tree: &Tree, - manifest: &Manifest, + package_db: &RemotePackageDB, config: &Config, progress: Arc>, ) -> Result<(), InstallTestDependenciesError> { @@ -111,7 +111,7 @@ pub async fn ensure_busted( install( vec![(BuildBehaviour::NoForce, busted_req)], PinnedState::Unpinned, - manifest, + package_db, config, progress, ) @@ -126,7 +126,7 @@ pub async fn ensure_busted( pub async fn ensure_dependencies( rockspec: &Rockspec, tree: &Tree, - manifest: &Manifest, + package_db: &RemotePackageDB, config: &Config, progress: Arc>, ) -> Result<(), InstallTestDependenciesError> { @@ -149,7 +149,7 @@ pub async fn ensure_dependencies( install( dependencies, PinnedState::Unpinned, - manifest, + package_db, config, progress, ) diff --git a/rocks-lib/src/operations/update.rs b/rocks-lib/src/operations/update.rs index 129143d..468c371 100644 --- a/rocks-lib/src/operations/update.rs +++ b/rocks-lib/src/operations/update.rs @@ -6,9 +6,9 @@ use crate::{ build::BuildBehaviour, config::Config, lockfile::{LocalPackage, PinnedState}, - manifest::Manifest, package::{PackageReq, PackageSpec, RockConstraintUnsatisfied}, progress::{MultiProgress, Progress, ProgressBar}, + remote_package_db::RemotePackageDB, }; use super::{install, remove, InstallError, RemoveError}; @@ -34,7 +34,7 @@ pub enum UpdateError { pub async fn update( package: LocalPackage, constraint: PackageReq, - manifest: &Manifest, + package_db: &RemotePackageDB, config: &Config, progress: Arc>, ) -> Result<(), UpdateError> { @@ -42,7 +42,7 @@ pub async fn update( let latest_version = package .to_package() - .has_update_with(&constraint, manifest)?; + .has_update_with(&constraint, package_db)?; if latest_version.is_some() && package.pinned() == PinnedState::Unpinned { // TODO(vhyrro): There's a slight dissonance in the API here. @@ -54,7 +54,7 @@ pub async fn update( install( vec![(BuildBehaviour::NoForce, constraint)], PinnedState::Unpinned, - manifest, + package_db, config, progress, ) diff --git a/rocks-lib/src/package/outdated.rs b/rocks-lib/src/package/outdated.rs index 51a447c..7f74fab 100644 --- a/rocks-lib/src/package/outdated.rs +++ b/rocks-lib/src/package/outdated.rs @@ -2,7 +2,7 @@ use std::fmt::Display; use thiserror::Error; -use crate::manifest::{Manifest, ManifestMetadata}; +use crate::remote_package_db::RemotePackageDB; use super::{version::PackageVersion, PackageName, PackageReq, PackageSpec, PackageVersionReq}; @@ -22,9 +22,9 @@ impl PackageSpec { /// Returns the latest version if found. pub fn has_update( &self, - metadata: &ManifestMetadata, + package_db: &RemotePackageDB, ) -> Result, RockNotFound> { - let latest_version = metadata + let latest_version = package_db .latest_version(&self.name) .ok_or_else(|| RockNotFound(self.name.clone()))?; @@ -40,15 +40,15 @@ impl PackageSpec { pub fn has_update_with( &self, constraint: &PackageReq, - manifest: &Manifest, + package_db: &RemotePackageDB, ) -> Result, RockConstraintUnsatisfied> { - let latest_version = manifest - .metadata() - .latest_match(constraint) - .ok_or_else(|| RockConstraintUnsatisfied { - name: self.name.clone(), - constraint: constraint.version_req.clone(), - })?; + let latest_version = + package_db + .latest_match(constraint) + .ok_or_else(|| RockConstraintUnsatisfied { + name: self.name.clone(), + constraint: constraint.version_req.clone(), + })?; if self.version < latest_version.version { Ok(Some(latest_version.version)) @@ -68,7 +68,10 @@ impl Display for PackageSpec { mod test { use std::path::PathBuf; - use crate::{manifest::ManifestMetadata, package::PackageSpec}; + use crate::{ + manifest::{Manifest, ManifestMetadata}, + package::PackageSpec, + }; #[test] fn rock_has_update() { @@ -76,12 +79,13 @@ mod test { PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("resources/test/manifest-5.1"); let content = String::from_utf8(std::fs::read(&test_manifest_path).unwrap()).unwrap(); let metadata = ManifestMetadata::new(&content).unwrap(); + let package_db = Manifest::new("example.com", metadata).into(); let test_package = PackageSpec::parse("lua-cjson".to_string(), "2.0.0".to_string()).unwrap(); assert_eq!( - test_package.has_update(&metadata).unwrap(), + test_package.has_update(&package_db).unwrap(), Some("2.1.0-1".parse().unwrap()) ); } diff --git a/rocks-lib/src/remote_package_db/mod.rs b/rocks-lib/src/remote_package_db/mod.rs new file mode 100644 index 0000000..d3df85d --- /dev/null +++ b/rocks-lib/src/remote_package_db/mod.rs @@ -0,0 +1,103 @@ +use crate::{ + config::Config, + manifest::{Manifest, ManifestError}, + package::{PackageName, PackageReq, PackageSpec, PackageVersion, RemotePackage}, + progress::{Progress, ProgressBar}, +}; +use itertools::Itertools as _; +use thiserror::Error; + +#[derive(Clone)] +pub struct RemotePackageDB(Vec); + +#[derive(Error, Debug)] +pub enum RemotePackageDBError { + #[error(transparent)] + ManifestError(#[from] ManifestError), +} + +#[derive(Error, Debug)] +pub enum SearchError { + #[error(transparent)] + Mlua(#[from] mlua::Error), + #[error("no rock that matches '{0}' found")] + RockNotFound(PackageReq), + #[error("error when pulling manifest: {0}")] + Manifest(#[from] ManifestError), +} + +impl RemotePackageDB { + pub async fn from_config(config: &Config) -> Result { + let mut manifests = Vec::new(); + for server in config.extra_servers() { + let manifest = Manifest::from_config(server, config).await?; + manifests.push(manifest); + } + manifests.push(Manifest::from_config(config.server(), config).await?); + Ok(Self(manifests)) + } + + /// Find a package that matches the requirement + pub(crate) fn find( + &self, + package_req: &PackageReq, + progress: &Progress, + ) -> Result { + let result = self.0.iter().find_map(|manifest| { + progress.map(|p| p.set_message(format!("🔎 Searching {}", &manifest.server_url()))); + manifest.search(package_req) + }); + match result { + Some(package) => Ok(package), + None => Err(SearchError::RockNotFound(package_req.clone())), + } + } + + /// 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() + } + + pub fn latest_version(&self, rock_name: &PackageName) -> Option<&PackageVersion> { + self.0 + .iter() + .filter_map(|manifest| manifest.metadata().latest_version(rock_name)) + .sorted() + .last() + } + + pub fn latest_match(&self, package_req: &PackageReq) -> Option { + self.0 + .iter() + .filter_map(|manifest| manifest.metadata().latest_match(package_req)) + .last() + } +} + +impl From for RemotePackageDB { + fn from(manifest: Manifest) -> Self { + RemotePackageDB(vec![manifest]) + } +} diff --git a/rocks-lib/tests/test.rs b/rocks-lib/tests/test.rs index 9b14167..cbffd51 100644 --- a/rocks-lib/tests/test.rs +++ b/rocks-lib/tests/test.rs @@ -2,10 +2,10 @@ use std::path::PathBuf; use rocks_lib::{ config::ConfigBuilder, - manifest::Manifest, operations::{ensure_busted, run_tests, TestEnv}, progress::MultiProgress, project::Project, + remote_package_db::RemotePackageDB, tree::Tree, }; @@ -18,10 +18,8 @@ async fn run_busted_test() { let _ = std::fs::remove_dir_all(&tree_root); let config = ConfigBuilder::new().tree(Some(tree_root)).build().unwrap(); let tree = Tree::new(config.tree().clone(), config.lua_version().unwrap().clone()).unwrap(); - let manifest = Manifest::from_config(&config.server(), &config) - .await - .unwrap(); - ensure_busted(&tree, &manifest, &config, MultiProgress::new_arc()) + let package_db = RemotePackageDB::from_config(&config).await.unwrap(); + ensure_busted(&tree, &package_db, &config, MultiProgress::new_arc()) .await .unwrap(); run_tests(project, Vec::new(), TestEnv::Pure, config)