lux_cli/
install_rockspec.rs1use eyre::eyre;
2use std::{path::PathBuf, sync::Arc};
3
4use clap::Args;
5use eyre::Result;
6use lux_lib::{
7 build::{self, BuildBehaviour},
8 config::Config,
9 lockfile::{OptState, PinnedState},
10 lua_installation::LuaInstallation,
11 lua_rockspec::{BuildBackendSpec, RemoteLuaRockspec},
12 luarocks::luarocks_installation::LuaRocksInstallation,
13 operations::{Install, PackageInstallSpec},
14 progress::MultiProgress,
15 rockspec::{LuaVersionCompatibility, Rockspec},
16 tree,
17};
18
19#[derive(Args, Default)]
20pub struct InstallRockspec {
21 rockspec_path: PathBuf,
23
24 #[arg(long)]
26 pin: bool,
27}
28
29pub async fn install_rockspec(data: InstallRockspec, config: Config) -> Result<()> {
31 let pin = PinnedState::from(data.pin);
32 let path = data.rockspec_path;
33
34 if path
35 .extension()
36 .map(|ext| ext != "rockspec")
37 .unwrap_or(true)
38 {
39 return Err(eyre!("Provided path is not a valid rockspec!"));
40 }
41
42 let progress_arc = MultiProgress::new_arc();
43 let progress = Arc::clone(&progress_arc);
44
45 let content = std::fs::read_to_string(path)?;
46 let rockspec = RemoteLuaRockspec::new(&content)?;
47 let lua_version = rockspec.lua_version_matches(&config)?;
48 let lua = LuaInstallation::new(
49 &lua_version,
50 &config,
51 &progress.map(|progress| progress.new_bar()),
52 )
53 .await?;
54 let tree = config.user_tree(lua_version)?;
55
56 let build_dependencies = rockspec.build_dependencies().current_platform();
59
60 let build_dependencies_to_install = build_dependencies
61 .iter()
62 .filter(|dep| {
63 tree.match_rocks(dep.package_req())
64 .is_ok_and(|rock_match| rock_match.is_found())
65 })
66 .map(|dep| {
67 PackageInstallSpec::new(dep.package_req().clone(), tree::EntryType::Entrypoint)
68 .build_behaviour(BuildBehaviour::NoForce)
69 .pin(pin)
70 .opt(OptState::Required)
71 .maybe_source(dep.source().clone())
72 .build()
73 })
74 .collect();
75
76 Install::new(&config)
77 .packages(build_dependencies_to_install)
78 .tree(tree.build_tree(&config)?)
79 .progress(progress_arc.clone())
80 .install()
81 .await?;
82
83 let dependencies = rockspec.dependencies().current_platform();
84
85 let dependencies_to_install = dependencies
86 .iter()
87 .filter(|dep| {
88 tree.match_rocks(dep.package_req())
89 .is_ok_and(|rock_match| rock_match.is_found())
90 })
91 .map(|dep| {
92 PackageInstallSpec::new(dep.package_req().clone(), tree::EntryType::DependencyOnly)
93 .build_behaviour(BuildBehaviour::NoForce)
94 .pin(pin)
95 .opt(OptState::Required)
96 .maybe_source(dep.source().clone())
97 .build()
98 })
99 .collect();
100
101 Install::new(&config)
102 .packages(dependencies_to_install)
103 .tree(tree.clone())
104 .progress(progress_arc.clone())
105 .install()
106 .await?;
107
108 if let Some(BuildBackendSpec::LuaRock(_)) = &rockspec.build().current_platform().build_backend {
109 let build_tree = tree.build_tree(&config)?;
110 let luarocks = LuaRocksInstallation::new(&config, build_tree)?;
111 let bar = progress.map(|p| p.new_bar());
112 luarocks.ensure_installed(&lua, &bar).await?;
113 }
114
115 build::Build::new()
116 .rockspec(&rockspec)
117 .tree(&tree)
118 .lua(&lua)
119 .entry_type(tree::EntryType::Entrypoint)
120 .config(&config)
121 .progress(&progress.map(|p| p.new_bar()))
122 .pin(pin)
123 .behaviour(BuildBehaviour::Force)
124 .build()
125 .await?;
126
127 Ok(())
128}