diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..ea0a198 --- /dev/null +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index 8e144e3..417f99a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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"] } diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..69f5a34 --- /dev/null +++ b/LICENSE @@ -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. diff --git a/src/main.rs b/src/main.rs index e7a11a9..7062efe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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(); + } } diff --git a/src/manifest_parser/mod.rs b/src/manifest_parser/mod.rs new file mode 100644 index 0000000..7a536ef --- /dev/null +++ b/src/manifest_parser/mod.rs @@ -0,0 +1,2 @@ +mod structs; +pub use structs::*; diff --git a/src/manifest_parser/structs.rs b/src/manifest_parser/structs.rs new file mode 100644 index 0000000..5ace478 --- /dev/null +++ b/src/manifest_parser/structs.rs @@ -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, +} + +#[derive(Debug, PartialEq, Eq, Hash)] +pub enum PackageSource { + Git(String), +} + +#[derive(Debug)] +pub struct PackageInfo { + name: String, + version: String, + + deps: Rc>>>, + steps: Rc>>, + + create_dirs: Rc>>, +} + +#[derive(Debug)] +pub struct Step { + pub name: String, + pub runs: Vec, + pub works_in: BuildPath, + + pub args: Option, +} + +#[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, PathBuf), +} + +#[derive(Debug)] +pub struct DepFunc { + deptime: DepTime, + rc: Rc>>>, +} + +pub enum ErrorType { + NoPrefix, + InvalidPrefix(String), +} + +impl Into> for BuildPath { + fn into(self) -> Vec { + postcard::to_allocvec(&self).unwrap().to_vec() + } +} + +impl From> for BuildPath { + fn from(value: Vec) -> Self { + postcard::from_bytes(&value).unwrap() + } +} + +impl Into for PackageSource { + fn into(self) -> String { + match self { + Self::Git(git_url) => format!("git:{git_url}"), + } + } +} + +impl TryFrom for PackageSource { + type Error = ErrorType; + + fn try_from(value: String) -> Result { + 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 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 { + 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 { + 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 { + let vec: Vec = 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 { + 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 = 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 { + let mut commands: 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(); + + 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::("args").ok(), + }) + } +} + +impl FromLua for BuildPath { + fn from_lua(value: mlua::Value, lua: &mlua::Lua) -> mlua::Result { + 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 { + 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>(methods: &mut M) { + methods.add_method("package", |_, _, info: PackageInfo| Ok(info)); + methods.add_method("fetch", |_, _, info: FetchedDep| Ok(info)); + } + + fn add_fields>(fields: &mut F) { + fields.add_field("helpers", OkfrHelpers {}); + } +} + +impl UserData for OkfrHelpers { + fn add_methods>(methods: &mut M) { + methods.add_method("join_path", |_, _, args: mlua::MultiValue| { + let args = args.into_vec(); + + let mut build_path: Option = None; + let mut path: Vec = 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 = 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>(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>(methods: &mut M) { + methods.add_method("depend_on", |_, depfunc, passed_deps: Vec| { + 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(()) + }); + } +}