zoi/pkg/lua/
parser.rs

1use super::functions;
2use crate::{pkg::types, utils};
3use anyhow::{Result, anyhow};
4use mlua::{self, Lua, LuaSerdeExt, Table, Value};
5use std::fs;
6
7pub fn parse_lua_package_for_platform(
8    file_path: &str,
9    platform: &str,
10    version_override: Option<&str>,
11    quiet: bool,
12) -> Result<types::Package> {
13    let lua_code = fs::read_to_string(file_path)?;
14    let lua = Lua::new();
15
16    let pkg_meta_table = lua.create_table().map_err(|e| anyhow!(e.to_string()))?;
17    let pkg_deps_table = lua.create_table().map_err(|e| anyhow!(e.to_string()))?;
18    let pkg_updates_table = lua.create_table().map_err(|e| anyhow!(e.to_string()))?;
19    let pkg_hooks_table = lua.create_table().map_err(|e| anyhow!(e.to_string()))?;
20    lua.globals()
21        .set("__ZoiPackageMeta", pkg_meta_table)
22        .map_err(|e| anyhow!(e.to_string()))?;
23    lua.globals()
24        .set("__ZoiPackageDeps", pkg_deps_table)
25        .map_err(|e| anyhow!(e.to_string()))?;
26    lua.globals()
27        .set("__ZoiPackageUpdates", pkg_updates_table)
28        .map_err(|e| anyhow!(e.to_string()))?;
29    lua.globals()
30        .set("__ZoiPackageHooks", pkg_hooks_table)
31        .map_err(|e| anyhow!(e.to_string()))?;
32
33    let pkg_table = lua.create_table().map_err(|e| anyhow!(e.to_string()))?;
34    lua.globals()
35        .set("PKG", pkg_table)
36        .map_err(|e| anyhow!(e.to_string()))?;
37
38    functions::setup_lua_environment(
39        &lua,
40        platform,
41        version_override,
42        Some(file_path),
43        None,
44        None,
45        quiet,
46    )
47    .map_err(|e| anyhow!("Failed to setup Lua environment for '{}': {}", file_path, e))?;
48
49    lua.load(&lua_code).exec().map_err(|e| {
50        anyhow!(
51            "Failed to execute Lua package file '{}':
52{}",
53            file_path,
54            e
55        )
56    })?;
57
58    let final_pkg_meta: Table = lua
59        .globals()
60        .get("__ZoiPackageMeta")
61        .map_err(|e| anyhow!(e.to_string()))?;
62    let final_pkg_deps: Table = lua
63        .globals()
64        .get("__ZoiPackageDeps")
65        .map_err(|e| anyhow!(e.to_string()))?;
66    let final_pkg_updates: Table = lua
67        .globals()
68        .get("__ZoiPackageUpdates")
69        .map_err(|e| anyhow!(e.to_string()))?;
70    let final_pkg_hooks: Table = lua
71        .globals()
72        .get("__ZoiPackageHooks")
73        .map_err(|e| anyhow!(e.to_string()))?;
74
75    let mut package: types::Package =
76        lua.from_value(Value::Table(final_pkg_meta)).map_err(|e| {
77            anyhow!(
78                "Failed to parse 'metadata' block in package file '{}':
79{}",
80                file_path,
81                e
82            )
83        })?;
84
85    package.dependencies = if final_pkg_deps.is_empty() {
86        None
87    } else {
88        Some(lua.from_value(Value::Table(final_pkg_deps)).map_err(|e| {
89            anyhow!(
90                "Failed to parse 'dependencies' block in package file '{}':
91{}",
92                file_path,
93                e
94            )
95        })?)
96    };
97
98    package.updates = if final_pkg_updates.is_empty() {
99        None
100    } else {
101        Some(
102            lua.from_value(Value::Table(final_pkg_updates))
103                .map_err(|e| {
104                    anyhow!(
105                        "Failed to parse 'updates' block in package file '{}':
106{}",
107                        file_path,
108                        e
109                    )
110                })?,
111        )
112    };
113
114    package.hooks = if final_pkg_hooks.is_empty() {
115        None
116    } else {
117        Some(lua.from_value(Value::Table(final_pkg_hooks)).map_err(|e| {
118            anyhow!(
119                "Failed to parse 'hooks' block in package file '{}':
120{}",
121                file_path,
122                e
123            )
124        })?)
125    };
126
127    Ok(package)
128}
129
130pub fn parse_lua_package(
131    file_path: &str,
132    version_override: Option<&str>,
133    quiet: bool,
134) -> Result<types::Package> {
135    let platform = utils::get_platform()?;
136    parse_lua_package_for_platform(file_path, &platform, version_override, quiet)
137}