commit e42465c91492f676e8845dc225e1b4111f0d9098 Author: min Date: Thu Feb 5 18:49:09 2026 -0500 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f6bfadb --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +/demo/out.lua diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..15d8d6f --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,616 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[package]] +name = "anstyle-parse" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "argh" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34ff18325c8a36b82f992e533ece1ec9f9a9db446bd1c14d4f936bac88fcd240" +dependencies = [ + "argh_derive", + "argh_shared", + "rust-fuzzy-search", +] + +[[package]] +name = "argh_derive" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b2b83a50d329d5d8ccc620f5c7064028828538bdf5646acd60dc1f767803" +dependencies = [ + "argh_shared", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "argh_shared" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a464143cc82dedcdc3928737445362466b7674b5db4e2eb8e869846d6d84f4f6" +dependencies = [ + "serde", +] + +[[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 = "cc" +version = "1.2.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b26a0954ae34af09b50f0de26458fa95369a0d478d8236d3f93082b219bd29" +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 = "colog" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df62599ba6adc9c6c04a54278c8209125343dc4775f57b9d76c9a4287e58f2bd" +dependencies = [ + "colored", + "env_logger", + "log", +] + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "colored" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "env_filter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_home" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f84e12ccf0a7ddc17a6c41c93326024c42920d7ee630d04950e6926645c0fe" + +[[package]] +name = "env_logger" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + +[[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.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "jiff" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89a5b5e10d5a9ad6e5d1f4bd58225f655d6fe9767575a5e8ac5a6fe64e04495" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-static" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff7a39c8862fc1369215ccf0a8f12dd4598c7f6484704359f0351bd617034dbf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[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 = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "lpk" +version = "0.2.0" +dependencies = [ + "argh", + "colog", + "log", + "mlua", + "pathdiff", + "walkdir", +] + +[[package]] +name = "lua-src" +version = "550.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e836dc8ae16806c9bdcf42003a88da27d163433e3f9684c52f0301258004a4fb" +dependencies = [ + "cc", +] + +[[package]] +name = "luajit-src" +version = "210.6.6+707c12b" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a86cc925d4053d0526ae7f5bc765dbd0d7a5d1a63d43974f4966cb349ca63295" +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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccd36acfa49ce6ee56d1307a061dd302c564eee757e6e4cd67eb4f7204846fab" +dependencies = [ + "bstr", + "either", + "libc", + "mlua-sys", + "num-traits", + "parking_lot", + "rustc-hash", + "rustversion", +] + +[[package]] +name = "mlua-sys" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f1c3a7fc7580227ece249fd90aa2fa3b39eb2b49d3aec5e103b3e85f2c3dfc8" +dependencies = [ + "cc", + "cfg-if", + "libc", + "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 = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[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 = "pathdiff" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "portable-atomic-util" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9db96d7fa8782dd8c15ce32ffe8680bbd1e978a43bf51a34d39483540495f5" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +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 = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" + +[[package]] +name = "rust-fuzzy-search" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a157657054ffe556d8858504af8a672a054a6e0bd9e8ee531059100c0fa11bb2" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[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 = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[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 = "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 = "unicode-ident" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[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 = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys", +] + +[[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 new file mode 100644 index 0000000..8fb4336 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "lpk" +version = "0.2.0" +edition = "2024" + +[dependencies] +argh = "0.1.13" +colog = "1.4.0" +log = "0.4.29" +mlua = { version = "0.11.6", features = ["lua51", "vendored"] } +pathdiff = "0.2.3" +walkdir = "2.5.0" diff --git a/demo/.pakignore b/demo/.pakignore new file mode 100644 index 0000000..3cbf625 --- /dev/null +++ b/demo/.pakignore @@ -0,0 +1,2 @@ +# outputs +./out.lua diff --git a/demo/index.lua b/demo/index.lua new file mode 100644 index 0000000..cd78886 --- /dev/null +++ b/demo/index.lua @@ -0,0 +1,6 @@ +local mylib = require("mylib") +local myconfig = require("myconfig") + +mylib:log_info("hi " .. myconfig.target) + +return true diff --git a/demo/myconfig.lua b/demo/myconfig.lua new file mode 100644 index 0000000..4e7a577 --- /dev/null +++ b/demo/myconfig.lua @@ -0,0 +1,5 @@ +local config = {} + +config.target = "world" + +return config diff --git a/demo/mylib.lua b/demo/mylib.lua new file mode 100644 index 0000000..6e406e5 --- /dev/null +++ b/demo/mylib.lua @@ -0,0 +1,7 @@ +local mylib = {} + +function mylib:log_info(msg) + print("[info] " .. msg) +end + +return mylib diff --git a/src/compile.rs b/src/compile.rs new file mode 100644 index 0000000..cff86d4 --- /dev/null +++ b/src/compile.rs @@ -0,0 +1,11 @@ +use mlua::prelude::*; + +/// Compiles Lua source into a chunk +pub fn compile(source: &str, chunk_name: &str) -> Vec { + Lua::new() + .load(source) + .set_name(chunk_name) + .into_function() + .expect("failed to convert lua source into function") + .dump(true) +} diff --git a/src/escape.rs b/src/escape.rs new file mode 100644 index 0000000..14acc8d --- /dev/null +++ b/src/escape.rs @@ -0,0 +1,5 @@ +pub fn escape_mod_name(name: &str) -> String { + name.replace('\\', "\\\\") + .replace('\'', "\\'") + .replace('\"', "\\\"") +} diff --git a/src/ignore.rs b/src/ignore.rs new file mode 100644 index 0000000..6165b1e --- /dev/null +++ b/src/ignore.rs @@ -0,0 +1,53 @@ +use std::{ + fs, + path::{Path, PathBuf}, +}; + +use log::info; + +/// Parses .pakignore file contents +fn parse(ignore_path: &Path, content: &str) -> Vec { + // Get tree base path + let base_path = ignore_path.parent().unwrap(); + + // Split pakignore into lines + let lines = content.split('\n'); + + let mut ignore = Vec::new(); + + // Add pakignore to ignored list + ignore.push(ignore_path.to_path_buf()); + + for line in lines { + // Trim whitespace + let line = line.trim(); + + // Skip empty lines and comments + if line.is_empty() || line.starts_with('#') { + continue; + } + + // Convert the &str to a PathBuf + let path = base_path.join(PathBuf::from(line)); + + info!("Adding to ignore list: {}", path.to_str().unwrap()); + + // Add to list + ignore.push(path); + } + + ignore +} + +/// Reads and parses a .pakignore file +pub fn read(path: &Path) -> Vec { + match fs::read_to_string(path) { + Ok(content) => parse(path, &content), + Err(_) => Vec::new(), + } +} + +/// Check if a path is ignored +pub fn is_ignored(ignored: &Vec, file: &Path) -> bool { + ignored.into_iter().any(|path| path == file) +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..8fcc935 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,68 @@ +use std::{fs, path::Path}; + +mod compile; +mod escape; +mod ignore; +mod pack; +mod walk; + +use argh::FromArgs; + +/// lpk - lua project compiler +#[derive(FromArgs, Debug)] +struct Args { + /// the path to the input source tree. + /// This will be packed into one file. + #[argh(option, short = 'i')] + input: Option, + + /// the output file the source tree will be packed to. + /// May be Lua source or binary bytecode chunk. + #[argh(option, short = 'o')] + output: Option, + + /// whether or not to compile the script into Lua 5.1 bytecode. + #[argh(switch, short = 'c')] + compile: bool, + + /// the name of the chunk for compiled bytecode. + #[argh(option, short = 'C')] + chunk_name: Option, +} + +fn main() { + // Initialise logger + colog::init(); + + // Read args + let args: Args = argh::from_env(); + + // Get source tree path + let tree_path_str = args.input.unwrap_or("./".to_string()); + let tree_path = Path::new(&tree_path_str); + + // Walk source tree + let mut tree = walk::walk(tree_path); + log::info!("Walked!"); + + // Pack tree into single source + let source = pack::pack(&mut tree); + log::info!("Packed!"); + + // Prepare for save + let name = args.output.unwrap_or(if !args.compile { + "./out.lua".to_string() + } else { + "./out.bin".to_string() + }); + + // Optionally compile + let source = if args.compile { + compile::compile(&source, &args.chunk_name.unwrap_or("lpk".to_string())) + } else { + Vec::from(source.as_bytes()) + }; + + // Save to file + fs::write(name, &source).expect("failed to write output!"); +} diff --git a/src/module.lua b/src/module.lua new file mode 100644 index 0000000..ddcacdf --- /dev/null +++ b/src/module.lua @@ -0,0 +1,3 @@ +['--[[name]]--'] = function(require) +--[[content]]-- +end, diff --git a/src/pack.rs b/src/pack.rs new file mode 100644 index 0000000..9b3c14f --- /dev/null +++ b/src/pack.rs @@ -0,0 +1,44 @@ +use std::{collections::HashMap, process::exit}; + +use log::error; + +use crate::escape; + +pub fn pack(tree: &mut HashMap) -> String { + // Load templates + let wrapper = include_str!("wrapper.lua"); + let module = include_str!("module.lua"); + + // Try to get index + let index = tree.remove("index"); + if index.is_none() { + error!("Missing index.lua"); + exit(1); + } + let index = index.unwrap(); + + // If it's just index, return it + // There would be no modules to pack + if tree.is_empty() { + return index; + } + + // Add the index + let wrapper = wrapper.replace(r#"--[[index]]--"#, &index); + + // Init modules + let mut modules = String::new(); + + for (name, content) in tree { + let name = escape::escape_mod_name(name); + + modules += &module + .replace("--[[name]]--", &name) + .replace("--[[content]]--", content); + } + + // Add modules + let wrapper = wrapper.replace(r#"--[[modules]]--"#, &modules); + + wrapper +} diff --git a/src/walk.rs b/src/walk.rs new file mode 100644 index 0000000..cc741fe --- /dev/null +++ b/src/walk.rs @@ -0,0 +1,77 @@ +use std::{ + collections::HashMap, + fs, + path::{MAIN_SEPARATOR, Path, PathBuf}, +}; + +use log::{error, info}; +use walkdir::WalkDir; + +use crate::ignore; + +/// Walks a Lua source tree +pub fn walk(tree_path: &Path) -> HashMap { + // Read and parse .pakignore + let mut pakignore_path = PathBuf::from(tree_path); + pakignore_path.push(".pakignore"); + let ignored = ignore::read(&pakignore_path); + + // Resulting source tree + let mut tree: HashMap = HashMap::new(); + + // Walk source tree + for entry in WalkDir::new(tree_path) + .min_depth(1) + .into_iter() + .filter_entry(|e| !ignore::is_ignored(&ignored, e.path())) + { + let entry = entry.expect("failed to get directory entry"); + + if ignore::is_ignored(&ignored, entry.path()) { + continue; + } + + // Skip directories/symlinks + if entry.file_type().is_file() { + let path = entry.path(); + + // Read file extension + let extension = path + .extension() + .and_then(|x| x.to_str()) + .unwrap_or_default(); + + // Get file name for debug outputs + let file_name = path + .file_name() + .and_then(|x| x.to_str()) + .expect("failed to get file name"); + + // Skip non-.lua files + if extension != "lua" { + info!("Skipping non-lua file: {}", file_name); + continue; + } + + // Get the relative path and make module name + let relative = pathdiff::diff_paths(path, tree_path).unwrap(); + let name = relative + .with_extension("") + .to_str() + .unwrap() + .replace(MAIN_SEPARATOR, "/"); + + match fs::read_to_string(path) { + Ok(content) => { + info!("Adding to tree: {}", file_name); + tree.insert(name, content); + } + Err(_) => { + error!("Failed to read, skipping: {}", file_name); + } + } + } + } + + tree +} diff --git a/src/wrapper.lua b/src/wrapper.lua new file mode 100644 index 0000000..e1a2034 --- /dev/null +++ b/src/wrapper.lua @@ -0,0 +1,23 @@ +return (function(require) +--[[index]]-- +end)(setmetatable({ + { +--[[modules]]-- + }, {} +}, { + __call = function(self, mod_name) + local mod_cache, ret_cache = self[1], self[2] + local mod, ret = mod_cache[mod_name], ret_cache[mod_name] + + if not mod then + return require(mod_name) + end + + if mod and not ret then + ret_cache[mod_name] = mod(self) + ret = ret_cache[mod_name] + end + + return ret + end, __metatable = false +})) \ No newline at end of file