Skip to main content

lux_lib/operations/
install_rockspec.rs

1use crate::package;
2use bon::Builder;
3use miette::Diagnostic;
4use thiserror::Error;
5
6use crate::{
7    build::{self, BuildBehaviour},
8    config::Config,
9    drivers::install_packages::{self, InstallPackages},
10    lockfile::{LockedPackage, OptState, PinnedState},
11    lua_installation,
12    lua_rockspec::{LuaVersionError, RemoteLuaRockspec},
13    luarocks::luarocks_installation::{LuaRocksError, LuaRocksInstallError},
14    operations::PackageInstallSpec,
15    package_db::{self, PackageDB},
16    pipeline::discover::FoundPackage,
17    rockspec::{LuaVersionCompatibility, Rockspec},
18    tree::{self, InstallTree},
19};
20
21#[derive(Debug, Error, Diagnostic)]
22#[error(transparent)]
23#[non_exhaustive]
24pub enum InstallRockspecError {
25    #[diagnostic(transparent)]
26    LuaInstallation(#[from] lua_installation::Error),
27    #[diagnostic(transparent)]
28    LuaVersion(#[from] LuaVersionError),
29    #[diagnostic(transparent)]
30    PackageDB(#[from] package_db::Error),
31    #[diagnostic(transparent)]
32    Tree(#[from] tree::Error),
33    #[diagnostic(transparent)]
34    Install(#[from] Box<install_packages::Error>),
35    #[diagnostic(transparent)]
36    LuaRocks(#[from] LuaRocksError),
37    #[diagnostic(transparent)]
38    LuaRocksInstall(#[from] Box<LuaRocksInstallError>),
39    #[diagnostic(transparent)]
40    Build(#[from] Box<build::Error>),
41    #[error("package '{0}' was not installed")]
42    PackageNotInstalled(package::Name),
43}
44
45impl From<install_packages::Error> for InstallRockspecError {
46    fn from(source: install_packages::Error) -> Self {
47        Self::Install(Box::new(source))
48    }
49}
50
51impl From<LuaRocksInstallError> for InstallRockspecError {
52    fn from(source: LuaRocksInstallError) -> Self {
53        Self::LuaRocksInstall(Box::new(source))
54    }
55}
56
57impl From<build::Error> for InstallRockspecError {
58    fn from(source: build::Error) -> Self {
59        Self::Build(Box::new(source))
60    }
61}
62
63/// Installs a Lua RockSpec into a [`Tree`].
64#[derive(Builder)]
65#[builder(start_fn = new, finish_fn(name = _build, vis = ""))]
66pub struct InstallRockspec<'a, T>
67where
68    T: InstallTree,
69{
70    rockspec: RemoteLuaRockspec,
71
72    pin: PinnedState,
73
74    config: &'a Config,
75
76    tree: &'a T,
77}
78
79impl<
80        T: InstallTree + Sync + Send + Clone + 'static,
81        State: install_rockspec_builder::State + install_rockspec_builder::IsComplete,
82    > InstallRockspecBuilder<'_, T, State>
83{
84    pub async fn install(self) -> Result<LockedPackage, InstallRockspecError> {
85        let args = self._build();
86        let rockspec = args.rockspec;
87        let pin = args.pin;
88        let config = args.config;
89        let tree = args.tree;
90
91        rockspec.lua_version_matches(config)?;
92
93        let name = rockspec.package().clone();
94        let root = FoundPackage::from_rockspec(rockspec);
95        let package_db = PackageDB::from_config(config).await?.with_local(vec![root]);
96
97        let install_spec = PackageInstallSpec::new(
98            package::Req::from(name.clone()),
99            tree::EntryType::Entrypoint,
100        )
101        .build_behaviour(BuildBehaviour::Force)
102        .pin(pin)
103        .opt(OptState::Required)
104        .build();
105
106        InstallPackages::new(config, tree)
107            .package_db(package_db)
108            .package(install_spec)
109            .install()
110            .await?
111            .0
112            .into_iter()
113            .find(|package| package.name() == &name)
114            .ok_or(InstallRockspecError::PackageNotInstalled(name))
115    }
116}