lux_lib/operations/
install_rockspec.rs1use bon::Builder;
2use miette::Diagnostic;
3use thiserror::Error;
4
5use crate::{
6 build::{self, BuildBehaviour, BuildError},
7 config::Config,
8 lockfile::{LocalPackage, OptState, PinnedState},
9 lua_installation::{LuaInstallation, LuaInstallationError},
10 lua_rockspec::{BuildBackendSpec, LuaVersionError, RemoteLuaRockspec},
11 luarocks::luarocks_installation::{LuaRocksError, LuaRocksInstallError, LuaRocksInstallation},
12 operations::{Install, InstallError, PackageInstallSpec},
13 rockspec::{LuaVersionCompatibility, Rockspec},
14 tree::{self, InstallTree, TreeError},
15};
16
17#[derive(Debug, Error, Diagnostic)]
18#[error(transparent)]
19#[non_exhaustive]
20pub enum InstallRockspecError {
21 #[diagnostic(transparent)]
22 LuaInstallation(#[from] LuaInstallationError),
23 #[diagnostic(transparent)]
24 LuaVersion(#[from] LuaVersionError),
25 #[diagnostic(transparent)]
26 Tree(#[from] TreeError),
27 #[diagnostic(transparent)]
28 Install(#[from] InstallError),
29 #[diagnostic(transparent)]
30 LuaRocks(#[from] LuaRocksError),
31 #[diagnostic(transparent)]
32 LuaRocksInstall(#[from] LuaRocksInstallError),
33 #[diagnostic(transparent)]
34 Build(#[from] BuildError),
35}
36
37#[derive(Builder)]
39#[builder(start_fn = new, finish_fn(name = _build, vis = ""))]
40pub struct InstallRockspec<'a, T>
41where
42 T: InstallTree,
43{
44 rockspec: RemoteLuaRockspec,
45
46 pin: PinnedState,
47
48 config: &'a Config,
49
50 tree: &'a T,
51}
52
53impl<
54 T: InstallTree + Sync + Send + Clone + 'static,
55 State: install_rockspec_builder::State + install_rockspec_builder::IsComplete,
56 > InstallRockspecBuilder<'_, T, State>
57{
58 pub async fn install(self) -> Result<LocalPackage, InstallRockspecError> {
59 let args = self._build();
60 let rockspec = args.rockspec;
61 let pin = args.pin;
62 let config = args.config;
63 let tree = args.tree;
64
65 let lua_version = rockspec.lua_version_matches(config)?;
66 let lua = LuaInstallation::new(&lua_version, config).await?;
67
68 let build_dependencies = rockspec.build_dependencies().current_platform();
71
72 let build_dependencies_to_install = build_dependencies
73 .iter()
74 .filter(|dep| {
75 !matches!(
77 dep.name().to_string().as_str(),
78 "luarocks-build-rust-mlua" | "luarocks-build-treesitter-parser"
79 )
80 })
81 .filter(|dep| {
82 tree.match_rocks(dep.package_req())
83 .is_ok_and(|rock_match| rock_match.is_found())
84 })
85 .map(|dep| {
86 PackageInstallSpec::new(dep.package_req().clone(), tree::EntryType::Entrypoint)
87 .build_behaviour(BuildBehaviour::NoForce)
88 .pin(pin)
89 .opt(OptState::Required)
90 .maybe_source(dep.source().clone())
91 .build()
92 })
93 .collect();
94
95 Install::new(config)
96 .packages(build_dependencies_to_install)
97 .tree(tree.build_tree(config)?)
98 .install()
99 .await?;
100
101 let dependencies = rockspec.dependencies().current_platform();
102
103 let mut dependencies_to_install = Vec::new();
104 for dep in dependencies {
105 let rock_match = tree.match_rocks(dep.package_req())?;
106 if !rock_match.is_found() {
107 let dep = PackageInstallSpec::new(
108 dep.package_req().clone(),
109 tree::EntryType::DependencyOnly,
110 )
111 .build_behaviour(BuildBehaviour::NoForce)
112 .pin(pin)
113 .opt(OptState::Required)
114 .maybe_source(dep.source().clone())
115 .build();
116 dependencies_to_install.push(dep);
117 }
118 }
119
120 let dependencies = Install::new(config)
121 .packages(dependencies_to_install)
122 .tree(tree.clone())
123 .install()
124 .await?;
125
126 if let Some(BuildBackendSpec::LuaRock(_)) =
127 &rockspec.build().current_platform().build_backend
128 {
129 let build_tree = tree.build_tree(config)?;
130 let luarocks = LuaRocksInstallation::new(config, build_tree)?;
131 luarocks.ensure_installed(&lua).await?;
132 }
133
134 let package = build::Build::new()
135 .rockspec(&rockspec)
136 .tree(tree)
137 .lua(&lua)
138 .entry_type(tree::EntryType::Entrypoint)
139 .config(config)
140 .pin(pin)
141 .behaviour(BuildBehaviour::Force)
142 .build()
143 .await?;
144
145 let lockfile = tree.lockfile()?;
146 let mut lockfile = lockfile.write_guard();
147 lockfile.add_entrypoint(&package);
148 for dep in dependencies {
149 lockfile.add_dependency(&package, &dep);
150 }
151 Ok(package)
152 }
153}