feat: initial manifest parsing

This commit is contained in:
user0-07161 2026-01-15 19:49:57 +01:00
parent 083e7dcce1
commit 299534fc67
6 changed files with 1082 additions and 2 deletions

476
Cargo.lock generated Normal file
View file

@ -0,0 +1,476 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "anyhow"
version = "1.0.100"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
[[package]]
name = "atomic-polyfill"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
dependencies = [
"critical-section",
]
[[package]]
name = "autocfg"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
[[package]]
name = "bitflags"
version = "2.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
[[package]]
name = "bstr"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab"
dependencies = [
"memchr",
"serde",
]
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cc"
version = "1.2.52"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3"
dependencies = [
"find-msvc-tools",
"shlex",
]
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "cobs"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
dependencies = [
"thiserror",
]
[[package]]
name = "critical-section"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
[[package]]
name = "either"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
[[package]]
name = "embedded-io"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
[[package]]
name = "embedded-io"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
[[package]]
name = "env_home"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe"
[[package]]
name = "errno"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "find-msvc-tools"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f449e6c6c08c865631d4890cfacf252b3d396c9bcc83adb6623cdb02a8336c41"
[[package]]
name = "hash32"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
dependencies = [
"byteorder",
]
[[package]]
name = "heapless"
version = "0.7.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f"
dependencies = [
"atomic-polyfill",
"hash32",
"rustc_version",
"serde",
"spin",
"stable_deref_trait",
]
[[package]]
name = "libc"
version = "0.2.180"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
[[package]]
name = "linux-raw-sys"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039"
[[package]]
name = "lock_api"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
"scopeguard",
]
[[package]]
name = "lua-src"
version = "548.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdc4e1aff422ad5f08cffb4719603dcdbc2be2307f4c1510d7aab74b7fa88ca8"
dependencies = [
"cc",
]
[[package]]
name = "luajit-src"
version = "210.6.5+7152e15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29e64ac463f01a02ee793423f9b351369cf244c5ee8bb9e2729a75b2eb404181"
dependencies = [
"cc",
"which",
]
[[package]]
name = "memchr"
version = "2.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
[[package]]
name = "mlua"
version = "0.11.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "935ac67539907efcd7198137eb7358e052555f77fe1b2916600a2249351f2b33"
dependencies = [
"anyhow",
"bstr",
"either",
"libc",
"mlua-sys",
"num-traits",
"parking_lot",
"rustc-hash",
"rustversion",
]
[[package]]
name = "mlua-sys"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c968af21bf6b19fc9ca8e7b85ee16f86e4c9e3d0591de101a5608086bda0ad8"
dependencies = [
"cc",
"cfg-if",
"lua-src",
"luajit-src",
"pkg-config",
]
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]]
name = "okfr"
version = "0.1.0"
dependencies = [
"anyhow",
"mlua",
"postcard",
"serde",
]
[[package]]
name = "parking_lot"
version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-link",
]
[[package]]
name = "pkg-config"
version = "0.3.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c"
[[package]]
name = "postcard"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24"
dependencies = [
"cobs",
"embedded-io 0.4.0",
"embedded-io 0.6.1",
"heapless",
"serde",
]
[[package]]
name = "proc-macro2"
version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
"bitflags",
]
[[package]]
name = "rustc-hash"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
[[package]]
name = "rustc_version"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92"
dependencies = [
"semver",
]
[[package]]
name = "rustix"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "rustversion"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "semver"
version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2"
[[package]]
name = "serde"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [
"serde_core",
"serde_derive",
]
[[package]]
name = "serde_core"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
dependencies = [
"lock_api",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596"
[[package]]
name = "syn"
version = "2.0.114"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "2.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "2.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
[[package]]
name = "which"
version = "8.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d3fabb953106c3c8eea8306e4393700d7657561cb43122571b172bbfb7c7ba1d"
dependencies = [
"env_home",
"rustix",
"winsafe",
]
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]
[[package]]
name = "winsafe"
version = "0.0.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"

View file

@ -1,6 +1,10 @@
[package]
name = "dunnopkg"
name = "okfr"
version = "0.1.0"
edition = "2024"
[dependencies]
anyhow = "1.0.100"
mlua = { version = "0.11.5", features = ["vendored", "lua54", "anyhow"] }
postcard = { version = "1.1.3", features = ["alloc"] }
serde = { version = "1.0.228", features = ["derive"] }

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 the dunix contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -1,3 +1,87 @@
fn main() {
mod manifest_parser;
fn main() -> anyhow::Result<()> {
println!("Hello, world!");
Ok(())
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use crate::manifest_parser::{Okfr, PackageInfo};
#[test]
fn pkginfo_parser() {
let lua = mlua::Lua::new();
let script = r#"
local hello = okfr:package({
name = "hello_world",
version = "v0.0.1"
})
local cmake = okfr:fetch({
package = "github:kitware/cmake",
branch = "master"
})
local clang = okfr:fetch({
package = "github:teamdunno/okfr_repo/clang",
-- branch defaults to main
})
local ninja = okfr:fetch({
package = "github:ninja-build/ninja",
branch = "master"
})
hello:time("build"):depend_on({
cmake,
clang,
ninja
})
hello:step({
name = "Fetching",
runs = "git clone https://github.com/teesh3rt/cpp_hello .",
work_in = hello:path("source")
})
hello:step({
name = "Preparing for build",
runs = "mkdir build",
work_in = hello:path("source")
})
hello:step({
name = "Building",
runs = "cmake --build . --parallel --config Release",
work_in = okfr.helpers:join_path(hello:path("source"), "build")
})
okfr.helpers:make_usr_bin(hello)
hello:step({
name = "Installing",
runs = "mv {} {}",
args = {
okfr.helpers:join_path(hello:path("source"), "build", "Release", "hello_world"),
okfr.helpers:join_path(hello:path("out"), "usr", "bin")
},
work_in = hello:path("source")
})
return hello
"#;
let _pkg_info: PackageInfo = Okfr::run(
script.to_string(),
PathBuf::from("/tmp/build"),
PathBuf::from("/tmp/out"),
lua,
)
.unwrap();
}
}

View file

@ -0,0 +1,2 @@
mod structs;
pub use structs::*;

View file

@ -0,0 +1,493 @@
use std::{
cell::RefCell,
collections::{HashMap, HashSet},
mem::transmute,
path::PathBuf,
process::Command,
rc::Rc,
slice,
str::FromStr,
};
use mlua::{FromLua, FromLuaMulti, IntoLua, IntoLuaMulti, Lua, UserData};
pub struct Okfr {}
pub struct OkfrHelpers {}
#[derive(Debug, PartialEq, Eq, Hash)]
pub struct FetchedDep {
package_source: PackageSource,
branch: Option<String>,
}
#[derive(Debug, PartialEq, Eq, Hash)]
pub enum PackageSource {
Git(String),
}
#[derive(Debug)]
pub struct PackageInfo {
name: String,
version: String,
deps: Rc<RefCell<HashMap<DepTime, HashSet<FetchedDep>>>>,
steps: Rc<RefCell<Vec<Step>>>,
create_dirs: Rc<RefCell<Vec<Dir>>>,
}
#[derive(Debug)]
pub struct Step {
pub name: String,
pub runs: Vec<String>,
pub works_in: BuildPath,
pub args: Option<mlua::Table>,
}
#[derive(Debug)]
pub enum Dir {
UsrBin,
}
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum DepTime {
Source,
Out,
}
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
pub enum BuildPath {
Build,
Run,
Joined(Box<Self>, PathBuf),
}
#[derive(Debug)]
pub struct DepFunc {
deptime: DepTime,
rc: Rc<RefCell<HashMap<DepTime, HashSet<FetchedDep>>>>,
}
pub enum ErrorType {
NoPrefix,
InvalidPrefix(String),
}
impl Into<Vec<u8>> for BuildPath {
fn into(self) -> Vec<u8> {
postcard::to_allocvec(&self).unwrap().to_vec()
}
}
impl From<Vec<u8>> for BuildPath {
fn from(value: Vec<u8>) -> Self {
postcard::from_bytes(&value).unwrap()
}
}
impl Into<String> for PackageSource {
fn into(self) -> String {
match self {
Self::Git(git_url) => format!("git:{git_url}"),
}
}
}
impl TryFrom<String> for PackageSource {
type Error = ErrorType;
fn try_from(value: String) -> Result<Self, Self::Error> {
let split_value = value.split_once(":").ok_or(ErrorType::NoPrefix)?;
match split_value.0 {
"git" => Ok(PackageSource::Git(split_value.1.to_owned())),
"github" => Ok(PackageSource::Git(format!(
"https://github.com/{}",
split_value.1.to_owned()
))),
unknown_prefix => Err(ErrorType::InvalidPrefix(unknown_prefix.to_owned())),
}
}
}
impl From<ErrorType> for mlua::Error {
fn from(error: ErrorType) -> mlua::Error {
match error {
ErrorType::NoPrefix => mlua::Error::SyntaxError {
message: "you did not pass a prefix".to_owned(),
incomplete_input: false,
},
ErrorType::InvalidPrefix(invalid_prefix) => mlua::Error::SyntaxError {
message: format!("the prefix you passed is invalid: {invalid_prefix}"),
incomplete_input: false,
},
}
}
}
impl Okfr {
pub fn run(
script: String,
build_path: PathBuf,
out_path: PathBuf,
lua: mlua::Lua,
) -> mlua::Result<PackageInfo> {
lua.globals().set("okfr", Okfr {}).unwrap();
let pkg_info_lua: mlua::AnyUserData = lua.load(script).eval()?;
let pkg_info: PackageInfo = pkg_info_lua.take()?;
let mut vec = Vec::new();
for step in pkg_info.steps.borrow_mut().iter_mut() {
if let Some(args) = &step.args {
for arg in args.sequence_values() {
let arg: mlua::Value = arg?;
match arg {
mlua::Value::String(string) => {
vec.push(string.to_string_lossy().to_string())
}
mlua::Value::Table(table) => {
let mut vec_val = Vec::new();
let mut tmp_vec = Vec::new();
for val in table.sequence_values() {
let val: u8 = val?;
vec_val.push(val);
}
let val: BuildPath = vec_val.into();
match val {
BuildPath::Run => {
vec.push(out_path.to_string_lossy().to_string());
}
BuildPath::Build => {
vec.push(build_path.to_string_lossy().to_string());
}
BuildPath::Joined(val, path) => {
match *val {
BuildPath::Run => {
tmp_vec.push(out_path.to_string_lossy().to_string());
}
BuildPath::Build => {
tmp_vec.push(build_path.to_string_lossy().to_string());
}
BuildPath::Joined(_, _) => {
unreachable!("you can't have a `Joined` in a `Joined`");
}
}
tmp_vec.push(path.to_string_lossy().to_string());
vec.push(tmp_vec.join("/"));
}
}
}
_ => {
unreachable!("value had an unhandable type");
}
}
}
}
for cmd in step.runs.iter_mut() {
while cmd.contains("{}") && !vec.is_empty() {
*cmd = cmd.replacen("{}", &vec.remove(0), 1);
}
}
// ensure there is no reference to the Lua instance
step.args = None;
}
Ok(pkg_info)
}
}
impl FromLuaMulti for PackageInfo {
fn from_lua_multi(values: mlua::MultiValue, _: &mlua::Lua) -> mlua::Result<Self> {
let table = values.into_vec()[0]
.as_table()
.ok_or(mlua::Error::SyntaxError {
message: "unable to properly parse passed argument to mlua::MultiValue".to_string(),
incomplete_input: false,
})?
.clone();
let name: String = table.get("name")?;
let version: String = table.get("version")?;
Ok(PackageInfo {
name,
version,
steps: Rc::new(RefCell::new(Vec::new())),
deps: Rc::new(RefCell::new(HashMap::new())),
create_dirs: Rc::new(RefCell::new(Vec::new())),
})
}
}
impl IntoLuaMulti for BuildPath {
fn into_lua_multi(self, lua: &mlua::Lua) -> mlua::Result<mlua::MultiValue> {
let vec: Vec<u8> = self.into();
let table = lua.create_table()?;
for val in vec {
table.push(val)?;
}
table.into_lua_multi(lua)
}
}
impl FromLua for FetchedDep {
fn from_lua(value: mlua::Value, lua: &mlua::Lua) -> mlua::Result<Self> {
let table = value
.as_table()
.ok_or(mlua::Error::SyntaxError {
message: "unable to properly parse passed argument to Table".to_string(),
incomplete_input: false,
})?
.clone();
let package_unparsed: String = table.get("package")?;
let branch: Option<String> = table.get("branch").ok();
let package: PackageSource = package_unparsed.try_into()?;
Ok(FetchedDep {
package_source: package,
branch,
})
}
}
impl FromLua for Step {
fn from_lua(value: mlua::Value, _: &mlua::Lua) -> mlua::Result<Self> {
let mut commands: Vec<String> = Vec::new();
let table = value
.as_table()
.ok_or(mlua::Error::SyntaxError {
message: "unable to properly parse passed argument to Table".to_string(),
incomplete_input: false,
})?
.clone();
let name: String = table.get("name")?;
let runs: mlua::Value = table.get("runs")?;
let works_in: BuildPath = table.get("work_in")?;
match runs {
mlua::Value::String(string) => {
let string = string.to_string_lossy();
commands.push(string);
}
mlua::Value::Table(table) => {
for val in table.sequence_values() {
let val = val?;
commands.push(val);
}
}
_ => {}
}
Ok(Step {
name,
runs: commands,
works_in,
args: table.get::<mlua::Table>("args").ok(),
})
}
}
impl FromLua for BuildPath {
fn from_lua(value: mlua::Value, lua: &mlua::Lua) -> mlua::Result<Self> {
let mut vec = Vec::new();
let table = value
.as_table()
.ok_or(mlua::Error::SyntaxError {
message: "unable to properly parse passed argument to Table".to_string(),
incomplete_input: false,
})?
.clone();
for val in table.sequence_values() {
let val: u8 = val?;
vec.push(val);
}
Ok(BuildPath::from(vec))
}
}
impl IntoLuaMulti for FetchedDep {
fn into_lua_multi(self, lua: &mlua::Lua) -> mlua::Result<mlua::MultiValue> {
let table = lua.create_table()?;
table.set("package", {
let pkg_source: String = self.package_source.into();
pkg_source
})?;
if let Some(branch) = self.branch {
table.set("branch", branch.clone())?;
}
table.into_lua_multi(lua)
}
}
impl UserData for Okfr {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
methods.add_method("package", |_, _, info: PackageInfo| Ok(info));
methods.add_method("fetch", |_, _, info: FetchedDep| Ok(info));
}
fn add_fields<F: mlua::UserDataFields<Self>>(fields: &mut F) {
fields.add_field("helpers", OkfrHelpers {});
}
}
impl UserData for OkfrHelpers {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
methods.add_method("join_path", |_, _, args: mlua::MultiValue| {
let args = args.into_vec();
let mut build_path: Option<BuildPath> = None;
let mut path: Vec<String> = Vec::new();
for (idx, arg) in args.iter().enumerate() {
match arg {
mlua::Value::String(string) => {
if idx == 0 {
return Err(mlua::Error::SyntaxError {
message: "you can only write to the `source` or the `out` path"
.to_owned(),
incomplete_input: false,
});
}
path.push(string.to_string_lossy())
}
mlua::Value::Table(table) => {
if idx != 0 {
return Err(mlua::Error::SyntaxError {
message: "you cannot have a `out` or `source` path here".to_owned(),
incomplete_input: false,
});
}
let mut vec: Vec<u8> = Vec::new();
for val in table.sequence_values() {
let val = val?;
vec.push(val);
}
build_path = Some(vec.into());
}
other_type => {
dbg!(other_type.type_name());
}
}
}
let path =
BuildPath::Joined(Box::new(build_path.unwrap()), PathBuf::from(path.join("/")));
Ok(path)
});
methods.add_method("make_usr_bin", |_, _, package_info: mlua::Value| {
// TODO: uncommenting this breaks execution with "Error: userdata has been destructed"
/*if let mlua::Value::UserData(user_data) = package_info {
let pkg_info: PackageInfo = user_data.take()?;
let mut dirs = pkg_info.create_dirs.borrow_mut();
dirs.push(Dir::UsrBin);
}*/
Ok(())
});
}
}
impl UserData for PackageInfo {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
methods.add_method_mut("time", |_, pkg_info, time: String| {
let deptime = match &time as &str {
"build" => DepTime::Source,
"out" => DepTime::Out,
_ => {
return Err(mlua::Error::SyntaxError {
message: r#"time needs to be either "build" or "run""#.to_string(),
incomplete_input: false,
});
}
};
Ok(DepFunc {
rc: pkg_info.deps.clone(),
deptime,
})
});
methods.add_method("step", |_, pkg_info, step: Step| {
let mut rc_val = pkg_info.steps.borrow_mut();
rc_val.push(step);
Ok(())
});
methods.add_method("path", |_, pkg_info, path_type: String| {
let build_path = match &path_type as &str {
"source" => BuildPath::Build,
"out" => BuildPath::Run,
_ => {
return Err(mlua::Error::SyntaxError {
message: "unknown path type, can be either `source` or `out`".to_owned(),
incomplete_input: false,
});
}
};
Ok(build_path)
});
}
}
impl UserData for DepFunc {
fn add_methods<M: mlua::UserDataMethods<Self>>(methods: &mut M) {
methods.add_method("depend_on", |_, depfunc, passed_deps: Vec<FetchedDep>| {
let mut rc_val = depfunc.rc.borrow_mut();
let mut deps = rc_val.remove(&depfunc.deptime).unwrap_or(HashSet::new());
for dep in passed_deps {
deps.insert(dep);
}
rc_val.insert(depfunc.deptime, deps);
Ok(())
});
}
}