lux_cli/
shell.rs

1use clap::Args;
2use eyre::{eyre, Result, WrapErr};
3use lux_lib::{config::Config, path::Paths};
4use which::which;
5
6use std::{env, path::PathBuf};
7use tokio::process::Command;
8
9use super::utils::project::current_project_or_user_tree;
10
11#[derive(Args)]
12pub struct Shell {
13    /// Add test dependencies to the shell's paths
14    #[arg(long)]
15    test: bool,
16
17    /// Add build dependencies to the shell's paths
18    #[arg(long)]
19    build: bool,
20
21    /// Disable the Lux loader.
22    /// If a rock has conflicting transitive dependencies,
23    /// disabling the Lux loader may result in the wrong modules being loaded.
24    #[arg(long)]
25    no_loader: bool,
26}
27
28pub async fn shell(data: Shell, config: Config) -> Result<()> {
29    if env::var("LUX_SHELL").is_ok_and(|lx_shell_var| lx_shell_var == "1") {
30        return Err(eyre!("Already in a Lux shell."));
31    }
32
33    let tree = current_project_or_user_tree(&config).unwrap();
34
35    let mut path = Paths::new(&tree)?;
36
37    let shell: PathBuf = match env::var("SHELL") {
38        Ok(val) => PathBuf::from(val),
39        Err(_) => {
40            #[cfg(target_os = "linux")]
41            let fallback = which("bash").wrap_err("Cannot find `bash` on your system!")?;
42
43            #[cfg(target_os = "windows")]
44            let fallback = which("cmd.exe").wrap_err("Cannot find `cmd.exe` on your system!")?;
45
46            #[cfg(target_os = "macos")]
47            let fallback = which("zsh").wrap_err("Cannot find `zsh` on your system!")?;
48
49            fallback
50        }
51    };
52
53    if data.test {
54        let test_tree_path = tree.test_tree(&config)?;
55        let test_path = Paths::new(&test_tree_path)?;
56        path.prepend(&test_path);
57    }
58
59    if data.build {
60        let build_tree_path = tree.build_tree(&config)?;
61        let build_path = Paths::new(&build_tree_path)?;
62        path.prepend(&build_path);
63    }
64
65    let lua_path = path.package_path_prepended();
66    let lua_cpath = path.package_cpath_prepended();
67
68    let lua_init = if data.no_loader {
69        None
70    } else if tree.version().lux_lib_dir().is_none() {
71        eprintln!(
72            "⚠️ WARNING: lux-lua library not found.
73    Cannot use the `lux.loader`.
74    To suppress this warning, set the `--no-loader` option.
75                    "
76        );
77        None
78    } else {
79        Some(path.init())
80    };
81
82    let _ = Command::new(&shell)
83        .env("PATH", path.path_prepended().joined())
84        .env("LUA_PATH", lua_path.joined())
85        .env("LUA_CPATH", lua_cpath.joined())
86        .env("LUA_INIT", lua_init.unwrap_or_default())
87        .env("LUX_SHELL", "1")
88        .spawn()?
89        .wait()
90        .await?;
91
92    Ok(())
93}