lux_lib/operations/
run_lua.rs

1//! Run the `lua` binary with some given arguments.
2//!
3//! The interfaces exposed here ensure that the correct version of Lua is being used.
4
5use bon::Builder;
6
7use crate::config::Config;
8
9use std::{
10    io,
11    path::{Path, PathBuf},
12};
13
14use thiserror::Error;
15use tokio::process::Command;
16
17use crate::{
18    lua_installation::{LuaBinary, LuaBinaryError},
19    path::{Paths, PathsError},
20    tree::Tree,
21    tree::TreeError,
22};
23
24#[derive(Error, Debug)]
25pub enum RunLuaError {
26    #[error("error running lua: {0}")]
27    LuaBinary(#[from] LuaBinaryError),
28    #[error("failed to run {lua_cmd}: {source}")]
29    LuaCommandFailed {
30        lua_cmd: String,
31        #[source]
32        source: io::Error,
33    },
34    #[error("{lua_cmd} exited with non-zero exit code: {}", exit_code.map(|code| code.to_string()).unwrap_or("unknown".into()))]
35    LuaCommandNonZeroExitCode {
36        lua_cmd: String,
37        exit_code: Option<i32>,
38    },
39    #[error(transparent)]
40    Paths(#[from] PathsError),
41
42    #[error(transparent)]
43    Tree(#[from] TreeError),
44}
45
46#[derive(Builder)]
47#[builder(start_fn = new, finish_fn(name = _build, vis = ""))]
48pub struct RunLua<'a> {
49    root: &'a Path,
50    tree: &'a Tree,
51    config: &'a Config,
52    lua_cmd: LuaBinary,
53    args: &'a Vec<String>,
54    prepend_test_paths: Option<bool>,
55    prepend_build_paths: Option<bool>,
56    disable_loader: Option<bool>,
57    lua_init: Option<String>,
58    welcome_message: Option<String>,
59}
60
61impl<State> RunLuaBuilder<'_, State>
62where
63    State: run_lua_builder::State + run_lua_builder::IsComplete,
64{
65    pub async fn run_lua(self) -> Result<(), RunLuaError> {
66        let args = self._build();
67        let mut paths = Paths::new(args.tree)?;
68
69        if args.prepend_test_paths.unwrap_or(false) {
70            let test_tree_path = args.tree.test_tree(args.config)?;
71
72            let test_path = Paths::new(&test_tree_path)?;
73
74            paths.prepend(&test_path);
75        }
76
77        if args.prepend_build_paths.unwrap_or(false) {
78            let build_tree_path = args.tree.build_tree(args.config)?;
79
80            let build_path = Paths::new(&build_tree_path)?;
81
82            paths.prepend(&build_path);
83        }
84
85        let lua_cmd: PathBuf = args.lua_cmd.try_into()?;
86
87        let loader_init = if args.disable_loader.unwrap_or(false) {
88            "".to_string()
89        } else if args.tree.version().lux_lib_dir().is_none() {
90            eprintln!(
91                "⚠️ WARNING: lux-lua library not found.
92Cannot use the `lux.loader`.
93To suppress this warning, set the `--no-loader` option.
94                "
95            );
96            "".to_string()
97        } else {
98            paths.init()
99        };
100        let lua_init = format!(
101            r#"print([==[{}]==])
102            {}
103            print([==[
104{}
105]==])
106        "#,
107            args.welcome_message.unwrap_or_default(),
108            args.lua_init.unwrap_or_default(),
109            loader_init
110        );
111
112        let status = match Command::new(&lua_cmd)
113            .current_dir(args.root)
114            .args(args.args)
115            .env("PATH", paths.path_prepended().joined())
116            .env("LUA_PATH", paths.package_path().joined())
117            .env("LUA_CPATH", paths.package_cpath().joined())
118            .env("LUA_INIT", lua_init)
119            .status()
120            .await
121        {
122            Ok(status) => Ok(status),
123            Err(err) => Err(RunLuaError::LuaCommandFailed {
124                lua_cmd: lua_cmd.to_string_lossy().to_string(),
125                source: err,
126            }),
127        }?;
128        if status.success() {
129            Ok(())
130        } else {
131            Err(RunLuaError::LuaCommandNonZeroExitCode {
132                lua_cmd: lua_cmd.to_string_lossy().to_string(),
133                exit_code: status.code(),
134            })
135        }
136    }
137}