lux_lib/operations/
build_workspace.rs1use crate::{
2 build::BuildBehaviour,
3 config::Config,
4 drivers::sync::{Sync, SyncError, SyncMode, TargetSet},
5 lockfile::LockedPackage,
6 package::PackageName,
7 workspace::Workspace,
8};
9use bon::Builder;
10use thiserror::Error;
11use tracing::{info_span, Instrument};
12
13#[derive(Debug, Error, miette::Diagnostic)]
14#[non_exhaustive]
15pub enum BuildWorkspaceError {
16 #[error(transparent)]
17 #[diagnostic(transparent)]
18 Sync(Box<SyncError>),
19}
20
21impl From<SyncError> for BuildWorkspaceError {
22 fn from(source: SyncError) -> Self {
23 Self::Sync(Box::new(source))
24 }
25}
26
27#[derive(Builder)]
28#[builder(start_fn = new, finish_fn(name = _build, vis = ""))]
29pub struct BuildWorkspace<'a> {
30 #[builder(start_fn)]
31 workspace: &'a Workspace,
32
33 #[builder(start_fn)]
34 config: &'a Config,
35
36 package: Option<PackageName>,
38
39 no_lock: bool,
41
42 only_deps: bool,
44
45 #[builder(default = BuildBehaviour::Force)]
46 behaviour: BuildBehaviour,
47}
48
49impl<State: build_workspace_builder::State + build_workspace_builder::IsComplete>
50 BuildWorkspaceBuilder<'_, State>
51{
52 pub async fn build(self) -> Result<Vec<LockedPackage>, BuildWorkspaceError> {
53 let build = self._build();
54 let span = match &build.package {
55 Some(package) => info_span!("Building workspace", package = package.to_string()),
56 None => info_span!("Building workspace"),
57 };
58 async move {
59 let report = Sync::new(build.workspace, build.config)
60 .mode(SyncMode::Open)
61 .targets(match build.package {
62 Some(package) => TargetSet::member(package, false),
63 None => TargetSet::all(build.workspace, false),
64 })
65 .behaviour(build.behaviour)
66 .only_deps(build.only_deps)
67 .no_lock(build.no_lock)
68 .sync()
69 .await?;
70 Ok(report.added().to_vec())
71 }
72 .instrument(span)
73 .await
74 }
75}
76
77#[cfg(all(test, feature = "impure_tests"))]
78mod tests {
79 use super::*;
80
81 use crate::{
82 config::ConfigBuilder, fs, lua_installation::detect_installed_lua_version,
83 lua_version::LuaVersion, tree::InstallTree,
84 };
85 use assert_fs::prelude::PathCopy;
86 use std::path::PathBuf;
87
88 #[tokio::test]
89 async fn builtin_build_autodetect_bin_scripts() {
91 let project_root =
92 PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("resources/test/sample-projects/init/");
93 let data_dir: PathBuf = assert_fs::TempDir::new().unwrap().path().into();
94 let temp_dir = assert_fs::TempDir::new().unwrap();
95 temp_dir.copy_from(&project_root, &["**"]).unwrap();
96 let project_root = temp_dir.path();
97 let foo_bin_dir = project_root.join("src").join("bin");
98 fs::tokio::create_dir_all(&foo_bin_dir).await.unwrap();
99 let foo_bin_file = foo_bin_dir.join("foo");
100 fs::tokio::write(&foo_bin_file, "print('hello')")
101 .await
102 .unwrap();
103 let bar_bin_dir = project_root.join("bin");
104 fs::tokio::create_dir_all(&bar_bin_dir).await.unwrap();
105 let bar_bin_file = bar_bin_dir.join("bar");
106 fs::tokio::write(&bar_bin_file, "print('hello')")
107 .await
108 .unwrap();
109 let lua_version = detect_installed_lua_version().or(Some(LuaVersion::Lua51));
110 let config = ConfigBuilder::new()
111 .unwrap()
112 .data_dir(Some(data_dir))
113 .lua_version(lua_version)
114 .build()
115 .unwrap();
116 let workspace = Workspace::from_exact(project_root).unwrap().unwrap();
117 let tree = workspace.tree(&config).unwrap();
118 BuildWorkspace::new(&workspace, &config)
119 .no_lock(false)
120 .only_deps(false)
121 .build()
122 .await
123 .unwrap();
124 let bin_dir = tree.bin();
125 assert!(bin_dir.join("foo").is_file());
126 assert!(bin_dir.join("bar").is_file());
127 }
128
129 #[tokio::test]
130 async fn builtin_build_support_src_init_lua() {
132 let data_dir: PathBuf = assert_fs::TempDir::new().unwrap().path().into();
133 let project_root =
134 PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("resources/test/sample-projects/init/");
135 let temp_dir = assert_fs::TempDir::new().unwrap();
136 temp_dir.copy_from(&project_root, &["**"]).unwrap();
137 let project_root = temp_dir.path();
138 let src_dir = project_root.join("src");
139 fs::tokio::create_dir_all(&src_dir).await.unwrap();
140 let init_lua_file = src_dir.join("init.lua");
141 fs::tokio::write(&init_lua_file, "print('hello')")
142 .await
143 .unwrap();
144 let lua_version = detect_installed_lua_version().or(Some(LuaVersion::Lua51));
145 let config = ConfigBuilder::new()
146 .unwrap()
147 .data_dir(Some(data_dir))
148 .lua_version(lua_version)
149 .build()
150 .unwrap();
151 let workspace = Workspace::from_exact(project_root).unwrap().unwrap();
152 let package = BuildWorkspace::new(&workspace, &config)
153 .no_lock(false)
154 .only_deps(false)
155 .build()
156 .await
157 .unwrap();
158 let package = package.first().unwrap();
159 let tree = workspace.tree(&config).unwrap();
160 let src_dir = tree.layout_for(&package.spec).src;
161 assert!(src_dir.join("init.lua").is_file());
162 }
163}