Skip to main content

zoi_lua/
functions.rs

1use crate::api;
2use mlua::Lua;
3use zoi_core::utils;
4
5/// Bootstraps the Lua environment for executing a package definition.
6///
7/// This function populates the global Lua scope with system information,
8/// directory paths, and utility functions that the `.pkg.lua` script
9/// expects to have available. It effectively creates the "sandbox" where
10/// package builds and installations are defined.
11pub fn setup_lua_environment(
12    lua: &Lua,
13    platform: &str,
14    version_override: Option<&str>,
15    file_path: Option<&str>,
16    create_pkg_dir: Option<&str>,
17    build_dir: Option<&str>,
18    staging_dir: Option<&str>,
19    sub_package: Option<&str>,
20    scope: Option<zoi_core::types::Scope>,
21    build_type: Option<&str>,
22    quiet: bool,
23) -> Result<(), mlua::Error> {
24    // Initialize the global PKG table for script use
25    let pkg_table = if let Ok(table) = lua.globals().get::<mlua::Table>("PKG") {
26        table
27    } else {
28        let table = lua.create_table()?;
29        lua.globals().set("PKG", table.clone())?;
30        table
31    };
32
33    if let Some(bt) = build_type {
34        lua.globals().set("BUILD_TYPE", bt)?;
35    }
36
37    // Initialize internal metadata capture tables if they don't exist
38    if lua
39        .globals()
40        .get::<mlua::Table>("__ZoiPackageMeta")
41        .is_err()
42    {
43        let pkg_meta_table = lua.create_table()?;
44        lua.globals().set("__ZoiPackageMeta", pkg_meta_table)?;
45    }
46    if lua
47        .globals()
48        .get::<mlua::Table>("__ZoiPackageDeps")
49        .is_err()
50    {
51        let pkg_deps_table = lua.create_table()?;
52        lua.globals().set("__ZoiPackageDeps", pkg_deps_table)?;
53    }
54    if lua
55        .globals()
56        .get::<mlua::Table>("__ZoiPackageUpdates")
57        .is_err()
58    {
59        let pkg_updates_table = lua.create_table()?;
60        lua.globals()
61            .set("__ZoiPackageUpdates", pkg_updates_table)?;
62    }
63    if lua
64        .globals()
65        .get::<mlua::Table>("__ZoiPackageHooks")
66        .is_err()
67    {
68        let pkg_hooks_table = lua.create_table()?;
69        lua.globals().set("__ZoiPackageHooks", pkg_hooks_table)?;
70    }
71    if lua
72        .globals()
73        .get::<mlua::Table>("__ZoiPackageService")
74        .is_err()
75    {
76        let pkg_service_table = lua.create_table()?;
77        lua.globals()
78            .set("__ZoiPackageService", pkg_service_table)?;
79    }
80
81    // Host System Information
82    // Exposes a 'SYSTEM' table containing OS, Architecture, Distro, etc.
83    // Allow maintainers to write platform-specific logic easily.
84    let system_table = lua.create_table()?;
85    let parts: Vec<&str> = platform.split('-').collect();
86    system_table.set("OS", *parts.first().unwrap_or(&""))?;
87    system_table.set("ARCH", *parts.get(1).unwrap_or(&""))?;
88    if let Some(distro) = utils::get_linux_distribution() {
89        system_table.set("DISTRO", distro)?;
90    }
91    if let Some(de) = utils::get_desktop_environment() {
92        system_table.set("DE", de)?;
93    }
94    if let Some(server) = utils::get_display_server() {
95        system_table.set("SERVER", server)?;
96    }
97    if let Some(dv) = utils::get_distro_version() {
98        system_table.set("DISTRO_VER", dv)?;
99    }
100    if let Some(kernel) = utils::get_kernel_version() {
101        system_table.set("KERNEL_VER", kernel)?;
102    }
103    if let Some(init) = utils::get_init_system() {
104        system_table.set("INIT", init)?;
105    }
106    if let Some(cpu) = utils::get_cpu_info() {
107        system_table.set("CPU", cpu)?;
108    }
109    if let Some(gpu) = utils::get_gpu_info() {
110        system_table.set("GPU", gpu)?;
111    }
112    if let Some(manager) = utils::get_native_package_manager() {
113        system_table.set("MANAGER", manager)?;
114    }
115    lua.globals().set("SYSTEM", system_table)?;
116
117    let zoi_table = lua.create_table()?;
118    if let Some(ver) = version_override {
119        zoi_table.set("VERSION", ver)?;
120    }
121
122    if let Some(s) = scope {
123        let scope_str = format!("{:?}", s).to_lowercase();
124        zoi_table.set("scope", scope_str)?;
125    }
126
127    if let Some(dir) = create_pkg_dir {
128        zoi_table.set("CREATE_PKG_DIR", dir)?;
129    }
130
131    if let Some(sub) = sub_package {
132        lua.globals().set("SUBPKG", sub)?;
133    }
134
135    let path_table = lua.create_table()?;
136    if let Some(home_dir) = utils::get_user_home() {
137        path_table.set("user", home_dir.join(".zoi").to_string_lossy().to_string())?;
138    }
139
140    let system_bin_path = if cfg!(target_os = "windows") {
141        "C:\\ProgramData\\zoi\\pkgs\\bin".to_string()
142    } else {
143        "/usr/local/bin".to_string()
144    };
145    path_table.set("system", system_bin_path)?;
146
147    zoi_table.set("PATH", path_table)?;
148
149    if let Some(home_dir) = utils::get_user_home() {
150        pkg_table.set("home", home_dir.to_string_lossy().to_string())?;
151        pkg_table.set(
152            "store",
153            home_dir
154                .join(".zoi")
155                .join("pkgs")
156                .join("store")
157                .to_string_lossy()
158                .to_string(),
159        )?;
160    }
161
162    if let Ok(current_dir) = std::env::current_dir() {
163        pkg_table.set("template", current_dir.to_string_lossy().to_string())?;
164    }
165
166    let root = if cfg!(target_os = "windows") {
167        "C:\\"
168    } else {
169        "/"
170    };
171    pkg_table.set("root", root)?;
172
173    if let Some(path_str) = file_path {
174        let abs_path = if let Ok(p) = std::fs::canonicalize(path_str) {
175            p
176        } else {
177            std::path::Path::new(path_str).to_path_buf()
178        };
179        pkg_table.set("lua", abs_path.to_string_lossy().to_string())?;
180    }
181    zoi_table.set("PKG", pkg_table.clone())?;
182
183    let location_table = lua.create_table()?;
184    if let Some(sd) = staging_dir {
185        let staging_path = std::path::Path::new(sd);
186        location_table.set(
187            "PKGSTORE",
188            staging_path.join("pkgstore").to_string_lossy().to_string(),
189        )?;
190        location_table.set(
191            "HOME",
192            staging_path.join("usrhome").to_string_lossy().to_string(),
193        )?;
194        location_table.set(
195            "ROOT",
196            staging_path.join("usrroot").to_string_lossy().to_string(),
197        )?;
198        location_table.set(
199            "TEMPLATE",
200            staging_path
201                .join("createpkgdir")
202                .to_string_lossy()
203                .to_string(),
204        )?;
205    } else {
206        if let Some(home_dir) = utils::get_user_home() {
207            location_table.set(
208                "PKGSTORE",
209                home_dir
210                    .join(".zoi")
211                    .join("pkgs")
212                    .join("store")
213                    .to_string_lossy()
214                    .to_string(),
215            )?;
216            location_table.set("HOME", home_dir.to_string_lossy().to_string())?;
217        }
218        let root = if cfg!(target_os = "windows") {
219            "C:\\"
220        } else {
221            "/"
222        };
223        location_table.set("ROOT", root.to_string())?;
224        if let Ok(current_dir) = std::env::current_dir() {
225            location_table.set("TEMPLATE", current_dir.to_string_lossy().to_string())?;
226        }
227    }
228    if let Some(path_str) = file_path {
229        let abs_path = if let Ok(p) = std::fs::canonicalize(path_str) {
230            p
231        } else {
232            std::path::Path::new(path_str).to_path_buf()
233        };
234        location_table.set(
235            "PKGLUADIR",
236            abs_path
237                .parent()
238                .unwrap_or(&abs_path)
239                .to_string_lossy()
240                .to_string(),
241        )?;
242    }
243    if let Some(bd) = build_dir {
244        location_table.set("BUILDDIR", bd)?;
245        lua.globals().set("BUILD_DIR", bd)?;
246    }
247    if let Some(sd) = staging_dir {
248        location_table.set("STAGINGDIR", sd)?;
249        lua.globals().set("STAGING_DIR", sd)?;
250    }
251    zoi_table.set("LOCATION", location_table.clone())?;
252    lua.globals().set("LOCATION", location_table)?;
253
254    lua.globals().set("ZOI", zoi_table)?;
255
256    let utils_table = lua.create_table()?;
257    lua.globals().set("UTILS", utils_table)?;
258
259    api::http::add_fetch_util(lua)?;
260    api::parse::add_parse_util(lua)?;
261    api::http::add_git_fetch_util(lua)?;
262    api::download::add_download_util(lua, quiet)?;
263    api::fs::add_file_util(lua, quiet)?;
264    api::fs::add_zcp(lua)?;
265    api::fs::add_zlicense(lua)?;
266    api::fs::add_zdoc(lua)?;
267    api::fs::add_zman(lua)?;
268    api::fs::add_zshell(lua)?;
269    api::fs::add_zsed(lua, quiet)?;
270    api::fs::add_zln(lua)?;
271    api::fs::add_zchmod(lua)?;
272    api::fs::add_zchown(lua)?;
273    api::fs::add_zmkdir(lua)?;
274    api::crypto::add_verify_hash(lua, quiet)?;
275    api::fs::add_zrm(lua)?;
276    api::system::add_cmd_util(lua, quiet)?;
277    api::system::add_zpatch(lua, quiet)?;
278    api::fs::add_fs_util(lua)?;
279    api::fs::add_find_util(lua)?;
280    api::archive::add_archive_util(lua)?;
281    api::archive::add_extract_util(lua, quiet)?;
282    api::crypto::add_verify_signature(lua, quiet)?;
283    api::crypto::add_add_pgp_key(lua, quiet)?;
284    api::lifecycle::add_package_lifecycle_functions(lua)?;
285
286    if let Some(path_str) = file_path {
287        let path = std::path::Path::new(path_str);
288        api::lifecycle::add_import_util(lua, path)?;
289        api::lifecycle::add_include_util(lua, path)?;
290    }
291
292    if let Some(sub) = sub_package {
293        lua.globals().set("SUBPKG", sub)?;
294    }
295
296    Ok(())
297}