lux_lib/operations/
install_project.rs1use bon::Builder;
2use itertools::Itertools;
3use std::sync::Arc;
4use thiserror::Error;
5
6use crate::{
7 build::{Build, BuildBehaviour, BuildError},
8 config::Config,
9 lockfile::LocalPackage,
10 lua_installation::{LuaInstallation, LuaInstallationError},
11 luarocks::luarocks_installation::{LuaRocksError, LuaRocksInstallError, LuaRocksInstallation},
12 operations::{install_dependencies::prepare_dependencies_for_build, InstallDependencies},
13 progress::{MultiProgress, Progress},
14 project::{project_toml::LocalProjectTomlValidationError, Project, ProjectError},
15 tree::{self, InstallTree, TreeError},
16};
17
18use super::InstallError;
19
20#[derive(Debug, Error)]
21pub enum InstallProjectError {
22 #[error(transparent)]
23 LocalProjectTomlValidation(#[from] LocalProjectTomlValidationError),
24 #[error(transparent)]
25 Project(#[from] ProjectError),
26 #[error(transparent)]
27 LuaInstallation(#[from] LuaInstallationError),
28 #[error(transparent)]
29 Tree(#[from] TreeError),
30 #[error(transparent)]
31 LuaRocks(#[from] LuaRocksError),
32 #[error(transparent)]
33 LuaRocksInstall(#[from] LuaRocksInstallError),
34 #[error("error installind dependencies:\n{0}")]
35 InstallDependencies(InstallError),
36 #[error("error installind build dependencies:\n{0}")]
37 InstallBuildDependencies(InstallError),
38 #[error("error building project:\n{0}")]
39 Build(#[from] BuildError),
40}
41
42#[derive(Builder)]
46#[builder(start_fn = new, finish_fn(name = _build, vis = ""))]
47pub struct InstallProject<'a, T>
48where
49 T: InstallTree,
50{
51 project: &'a Project,
52
53 config: &'a Config,
54
55 tree: &'a T,
56
57 progress: Option<Arc<Progress<MultiProgress>>>,
58}
59
60impl<
61 T: InstallTree + Sync + Send + Clone + 'static,
62 State: install_project_builder::State + install_project_builder::IsComplete,
63 > InstallProjectBuilder<'_, T, State>
64{
65 pub async fn build(self) -> Result<LocalPackage, InstallProjectError> {
67 let args = self._build();
68 let config = args.config;
69 let project = args.project;
70 let tree = args.tree;
71 let build_tree = tree.build_tree(config)?;
72 let progress_arc = args
73 .progress
74 .clone()
75 .unwrap_or_else(|| MultiProgress::new_arc(args.config));
76 let lua = LuaInstallation::new_from_config(
77 config,
78 &progress_arc.map(|progress| progress.new_bar()),
79 )
80 .await?;
81 let luarocks = LuaRocksInstallation::new(config, build_tree.clone())?;
82 let mut dependencies_to_install = Vec::new();
83 let mut build_dependencies_to_install = Vec::new();
84 let project_toml = project.toml().into_local()?;
85 prepare_dependencies_for_build(
86 &project_toml,
87 tree,
88 &mut dependencies_to_install,
89 &mut build_dependencies_to_install,
90 );
91
92 InstallDependencies::new()
93 .dependencies(dependencies_to_install.into_iter().unique().collect_vec())
94 .build_dependencies(
95 build_dependencies_to_install
96 .into_iter()
97 .unique()
98 .collect_vec(),
99 )
100 .tree(tree)
101 .lua(&lua)
102 .luarocks(&luarocks)
103 .config(config)
104 .progress(progress_arc.clone())
105 .build()
106 .await
107 .map_err(InstallProjectError::InstallBuildDependencies)?;
108
109 let package = Build::new()
110 .rockspec(&project_toml)
111 .lua(&lua)
112 .tree(tree)
113 .entry_type(tree::EntryType::Entrypoint)
114 .config(config)
115 .progress(&progress_arc.map(|p| p.new_bar()))
116 .behaviour(BuildBehaviour::Force)
117 .build()
118 .await?;
119
120 let lockfile = tree.lockfile()?;
121 let dependencies = lockfile
122 .rocks()
123 .iter()
124 .filter_map(|(pkg_id, value)| {
125 if lockfile.is_entrypoint(pkg_id) {
126 Some(value)
127 } else {
128 None
129 }
130 })
131 .cloned()
132 .collect_vec();
133 let mut lockfile = lockfile.write_guard();
134 lockfile.add_entrypoint(&package);
135 for dep in dependencies {
136 lockfile.add_dependency(&package, &dep);
137 lockfile.remove_entrypoint(&dep);
138 }
139 Ok(package)
140 }
141}