lux_cli/
build.rs

1use eyre::Context;
2use itertools::Itertools;
3use std::sync::Arc;
4
5use clap::Args;
6use eyre::Result;
7use lux_lib::{
8    build::{self, BuildBehaviour},
9    config::Config,
10    luarocks::luarocks_installation::LuaRocksInstallation,
11    operations::{Install, PackageInstallSpec, Sync},
12    progress::MultiProgress,
13    project::Project,
14    rockspec::Rockspec,
15    tree,
16};
17
18#[derive(Args, Default)]
19pub struct Build {
20    /// Ignore the project's lockfile and don't create one.
21    #[arg(long)]
22    no_lock: bool,
23
24    /// Build only the dependencies
25    #[arg(long)]
26    only_deps: bool,
27}
28
29pub async fn build(data: Build, config: Config) -> Result<()> {
30    let project = Project::current_or_err()?;
31    let progress_arc = MultiProgress::new_arc();
32    let progress = Arc::clone(&progress_arc);
33
34    let project_toml = project.toml().into_local()?;
35    let project_tree = project.tree(&config)?;
36
37    let dependencies = project_toml
38        .dependencies()
39        .current_platform()
40        .iter()
41        .cloned()
42        .collect_vec();
43
44    let build_dependencies = project_toml
45        .build_dependencies()
46        .current_platform()
47        .iter()
48        .cloned()
49        .collect_vec();
50
51    let build_tree = project.build_tree(&config)?;
52    let luarocks = LuaRocksInstallation::new(&config, build_tree.clone())?;
53
54    if data.no_lock {
55        let dependencies_to_install = dependencies
56            .into_iter()
57            .filter(|dep| {
58                project_tree
59                    .match_rocks(dep.package_req())
60                    .is_ok_and(|rock_match| !rock_match.is_found())
61            })
62            .map(|dep| {
63                PackageInstallSpec::new(dep.clone().into_package_req(), tree::EntryType::Entrypoint)
64                    .pin(*dep.pin())
65                    .opt(*dep.opt())
66                    .maybe_source(dep.source().clone())
67                    .build()
68            })
69            .collect();
70
71        Install::new(&config)
72            .packages(dependencies_to_install)
73            .project(&project)?
74            .progress(progress.clone())
75            .install()
76            .await?;
77
78        let build_dependencies_to_install = build_dependencies
79            .into_iter()
80            .filter(|dep| {
81                project_tree
82                    .match_rocks(dep.package_req())
83                    .is_ok_and(|rock_match| !rock_match.is_found())
84            })
85            .map(|dep| {
86                PackageInstallSpec::new(dep.clone().into_package_req(), tree::EntryType::Entrypoint)
87                    .pin(*dep.pin())
88                    .opt(*dep.opt())
89                    .maybe_source(dep.source().clone())
90                    .build()
91            })
92            .collect_vec();
93
94        if !build_dependencies_to_install.is_empty() {
95            let bar = progress.map(|p| p.new_bar());
96            luarocks.ensure_installed(&bar).await?;
97            Install::new(&config)
98                .packages(build_dependencies_to_install)
99                .tree(build_tree)
100                .progress(progress.clone())
101                .install()
102                .await?;
103        }
104    } else {
105        Sync::new(&project, &config)
106            .progress(progress.clone())
107            .sync_dependencies()
108            .await
109            .wrap_err(
110                "
111syncing dependencies with the project lockfile failed.
112Use --no-lock to force a new build.
113",
114            )?;
115
116        Sync::new(&project, &config)
117            .progress(progress.clone())
118            .sync_build_dependencies()
119            .await
120            .wrap_err(
121                "
122syncing build dependencies with the project lockfile failed.
123Use --no-lock to force a new build.
124",
125            )?;
126    }
127
128    if !data.only_deps {
129        let package = build::Build::new(
130            &project_toml,
131            &project_tree,
132            tree::EntryType::Entrypoint,
133            &config,
134            &progress.map(|p| p.new_bar()),
135        )
136        .behaviour(BuildBehaviour::Force)
137        .build()
138        .await?;
139
140        let lockfile = project_tree.lockfile()?;
141        let dependencies = lockfile
142            .rocks()
143            .iter()
144            .filter_map(|(pkg_id, value)| {
145                if lockfile.is_entrypoint(pkg_id) {
146                    Some(value)
147                } else {
148                    None
149                }
150            })
151            .cloned()
152            .collect_vec();
153        let mut lockfile = lockfile.write_guard();
154        lockfile.add_entrypoint(&package);
155        for dep in dependencies {
156            lockfile.add_dependency(&package, &dep);
157            lockfile.remove_entrypoint(&dep);
158        }
159    }
160
161    Ok(())
162}