Skip to main content

lux_lib/operations/
install_project.rs

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