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(cpu) = utils::get_cpu_info() {
104        system_table.set("CPU", cpu)?;
105    }
106    if let Some(gpu) = utils::get_gpu_info() {
107        system_table.set("GPU", gpu)?;
108    }
109    if let Some(manager) = utils::get_native_package_manager() {
110        system_table.set("MANAGER", manager)?;
111    }
112    lua.globals().set("SYSTEM", system_table)?;
113
114    let zoi_table = lua.create_table()?;
115    if let Some(ver) = version_override {
116        zoi_table.set("VERSION", ver)?;
117    }
118
119    if let Some(s) = scope {
120        let scope_str = format!("{:?}", s).to_lowercase();
121        zoi_table.set("scope", scope_str)?;
122    }
123
124    if let Some(dir) = create_pkg_dir {
125        zoi_table.set("CREATE_PKG_DIR", dir)?;
126    }
127
128    if let Some(sub) = sub_package {
129        lua.globals().set("SUBPKG", sub)?;
130    }
131
132    let path_table = lua.create_table()?;
133    if let Some(home_dir) = utils::get_user_home() {
134        path_table.set("user", home_dir.join(".zoi").to_string_lossy().to_string())?;
135    }
136
137    let system_bin_path = if cfg!(target_os = "windows") {
138        "C:\\ProgramData\\zoi\\pkgs\\bin".to_string()
139    } else {
140        "/usr/local/bin".to_string()
141    };
142    path_table.set("system", system_bin_path)?;
143
144    zoi_table.set("PATH", path_table)?;
145
146    if let Some(home_dir) = utils::get_user_home() {
147        pkg_table.set("home", home_dir.to_string_lossy().to_string())?;
148        pkg_table.set(
149            "store",
150            home_dir
151                .join(".zoi")
152                .join("pkgs")
153                .join("store")
154                .to_string_lossy()
155                .to_string(),
156        )?;
157    }
158
159    if let Ok(current_dir) = std::env::current_dir() {
160        pkg_table.set("template", current_dir.to_string_lossy().to_string())?;
161    }
162
163    let root = if cfg!(target_os = "windows") {
164        "C:\\"
165    } else {
166        "/"
167    };
168    pkg_table.set("root", root)?;
169
170    if let Some(path_str) = file_path {
171        let abs_path = if let Ok(p) = std::fs::canonicalize(path_str) {
172            p
173        } else {
174            std::path::Path::new(path_str).to_path_buf()
175        };
176        pkg_table.set("lua", abs_path.to_string_lossy().to_string())?;
177    }
178    zoi_table.set("PKG", pkg_table.clone())?;
179
180    let location_table = lua.create_table()?;
181    if let Some(sd) = staging_dir {
182        let staging_path = std::path::Path::new(sd);
183        location_table.set(
184            "PKGSTORE",
185            staging_path.join("pkgstore").to_string_lossy().to_string(),
186        )?;
187        location_table.set(
188            "HOME",
189            staging_path.join("usrhome").to_string_lossy().to_string(),
190        )?;
191        location_table.set(
192            "ROOT",
193            staging_path.join("usrroot").to_string_lossy().to_string(),
194        )?;
195        location_table.set(
196            "TEMPLATE",
197            staging_path
198                .join("createpkgdir")
199                .to_string_lossy()
200                .to_string(),
201        )?;
202    } else {
203        if let Some(home_dir) = utils::get_user_home() {
204            location_table.set(
205                "PKGSTORE",
206                home_dir
207                    .join(".zoi")
208                    .join("pkgs")
209                    .join("store")
210                    .to_string_lossy()
211                    .to_string(),
212            )?;
213            location_table.set("HOME", home_dir.to_string_lossy().to_string())?;
214        }
215        let root = if cfg!(target_os = "windows") {
216            "C:\\"
217        } else {
218            "/"
219        };
220        location_table.set("ROOT", root.to_string())?;
221        if let Ok(current_dir) = std::env::current_dir() {
222            location_table.set("TEMPLATE", current_dir.to_string_lossy().to_string())?;
223        }
224    }
225    if let Some(path_str) = file_path {
226        let abs_path = if let Ok(p) = std::fs::canonicalize(path_str) {
227            p
228        } else {
229            std::path::Path::new(path_str).to_path_buf()
230        };
231        location_table.set(
232            "PKGLUADIR",
233            abs_path
234                .parent()
235                .unwrap_or(&abs_path)
236                .to_string_lossy()
237                .to_string(),
238        )?;
239    }
240    if let Some(bd) = build_dir {
241        location_table.set("BUILDDIR", bd)?;
242        lua.globals().set("BUILD_DIR", bd)?;
243    }
244    if let Some(sd) = staging_dir {
245        location_table.set("STAGINGDIR", sd)?;
246        lua.globals().set("STAGING_DIR", sd)?;
247    }
248    zoi_table.set("LOCATION", location_table.clone())?;
249    lua.globals().set("LOCATION", location_table)?;
250
251    lua.globals().set("ZOI", zoi_table)?;
252
253    let utils_table = lua.create_table()?;
254    lua.globals().set("UTILS", utils_table)?;
255
256    api::http::add_fetch_util(lua)?;
257    api::parse::add_parse_util(lua)?;
258    api::http::add_git_fetch_util(lua)?;
259    api::download::add_download_util(lua, quiet)?;
260    api::fs::add_file_util(lua, quiet)?;
261    api::fs::add_zcp(lua)?;
262    api::fs::add_zlicense(lua)?;
263    api::fs::add_zdoc(lua)?;
264    api::fs::add_zman(lua)?;
265    api::fs::add_zshell(lua)?;
266    api::fs::add_zsed(lua, quiet)?;
267    api::fs::add_zln(lua)?;
268    api::fs::add_zchmod(lua)?;
269    api::fs::add_zchown(lua)?;
270    api::fs::add_zmkdir(lua)?;
271    api::crypto::add_verify_hash(lua, quiet)?;
272    api::fs::add_zrm(lua)?;
273    api::system::add_cmd_util(lua, quiet)?;
274    api::system::add_zpatch(lua, quiet)?;
275    api::fs::add_fs_util(lua)?;
276    api::fs::add_find_util(lua)?;
277    api::archive::add_archive_util(lua)?;
278    api::archive::add_extract_util(lua, quiet)?;
279    api::crypto::add_verify_signature(lua, quiet)?;
280    api::crypto::add_add_pgp_key(lua, quiet)?;
281    api::lifecycle::add_package_lifecycle_functions(lua)?;
282
283    if let Some(path_str) = file_path {
284        let path = std::path::Path::new(path_str);
285        api::lifecycle::add_import_util(lua, path)?;
286        api::lifecycle::add_include_util(lua, path)?;
287    }
288
289    if let Some(sub) = sub_package {
290        lua.globals().set("SUBPKG", sub)?;
291    }
292
293    Ok(())
294}