Initial commit

This commit is contained in:
Filip Tibell 2023-01-18 20:47:14 -05:00
commit 8078425b2d
No known key found for this signature in database
23 changed files with 1450 additions and 0 deletions

23
.github/workflows/build.yaml vendored Normal file
View file

@ -0,0 +1,23 @@
name: Build
on:
push:
jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
profile: minimal
- name: Build
run: cargo build --locked --verbose

26
.github/workflows/lint.yaml vendored Normal file
View file

@ -0,0 +1,26 @@
name: Lint
on:
push:
jobs:
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
components: rustfmt, clippy
- name: Rustfmt
run: cargo fmt -- --check
- name: Clippy
run: cargo clippy

117
.github/workflows/release.yaml vendored Normal file
View file

@ -0,0 +1,117 @@
name: Release
on:
workflow_dispatch:
jobs:
init:
name: Init
runs-on: ubuntu-latest
outputs:
manifest_name: ${{ steps.get_name.outputs.value }}
manifest_version: ${{ steps.get_version.outputs.value }}
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Get name from manifest
uses: SebRollen/toml-action@0ad94c4a52c402aaa76e14e8a43551163b6cedf9
id: get_name
with:
file: Cargo.toml
field: package.name
- name: Get version from manifest
uses: SebRollen/toml-action@0ad94c4a52c402aaa76e14e8a43551163b6cedf9
id: get_version
with:
file: Cargo.toml
field: package.version
create-release:
needs: ["init"]
name: Create release
runs-on: ubuntu-latest
outputs:
upload_url: ${{ steps.create_release.outputs.upload_url }}
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Create release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: v${{ needs.init.outputs.manifest_version }}
release_name: ${{ needs.init.outputs.manifest_version }}
draft: true
release:
needs: ["init", "create-release"]
strategy:
matrix:
include:
- name: Windows x86_64
runner-os: windows-latest
artifact-name: ${{ needs.init.outputs.manifest_name }}-${{ needs.init.outputs.manifest_version }}-windows-x86_64
cargo-target: x86_64-pc-windows-msvc
- name: Linux x86_64
runner-os: ubuntu-latest
artifact-name: ${{ needs.init.outputs.manifest_name }}-${{ needs.init.outputs.manifest_version }}-linux-x86_64
cargo-target: x86_64-unknown-linux-gnu
- name: macOS x86_64
runner-os: macos-latest
artifact-name: ${{ needs.init.outputs.manifest_name }}-${{ needs.init.outputs.manifest_version }}-macos-x86_64
cargo-target: x86_64-apple-darwin
name: Build - ${{ matrix.name }}
runs-on: ${{ matrix.runner-os }}
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
target: ${{ matrix.cargo-target }}
override: true
profile: minimal
- name: Build binary
run: cargo build --locked --release --all-features --target ${{ matrix.cargo-target }}
env:
CARGO_TARGET_DIR: output
OPENSSL_STATIC: 1
- name: Create binary archive
shell: bash
run: |
mkdir -p staging
if [ "${{ matrix.runner-os }}" = "windows-latest" ]; then
cp "output/${{ matrix.cargo-target }}/release/${{ needs.init.outputs.manifest_name }}.exe" staging/
cd staging
7z a ../release.zip *
else
cp "output/${{ matrix.cargo-target }}/release/${{ needs.init.outputs.manifest_name }}" staging/
cd staging
zip ../release.zip *
fi
- name: Upload binary artifact
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.artifact-name }}
path: release.zip
- name: Upload binary to release
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ needs.create-release.outputs.upload_url }}
asset_path: release.zip
asset_name: ${{ matrix.artifact-name }}.zip
asset_content_type: application/octet-stream

23
.github/workflows/test.yaml vendored Normal file
View file

@ -0,0 +1,23 @@
name: Test
on:
push:
jobs:
test:
name: Test
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: stable
override: true
profile: minimal
- name: Test
run: cargo test

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
/target
.DS_Store
*/.DS_Store

7
.luaurc Normal file
View file

@ -0,0 +1,7 @@
{
"languageMode": "strict",
"lint": { "*": true },
"lintErrors": false,
"typeErrors": true,
"globals": []
}

17
.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,17 @@
{
"luau-lsp.types.roblox": false,
"luau-lsp.types.definitionFiles": ["luneTypes.d.luau"],
"luau-lsp.sourcemap.enabled": false,
"editor.formatOnSave": true,
"stylua.searchParentDirectories": true,
"prettier.tabWidth": 2,
"[luau][lua]": {
"editor.defaultFormatter": "JohnnyMorganz.stylua"
},
"[json][jsonc][markdown][yaml]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[rust]": {
"editor.defaultFormatter": "rust-lang.rust-analyzer"
}
}

661
Cargo.lock generated Normal file
View file

@ -0,0 +1,661 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bstr"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
dependencies = [
"memchr",
]
[[package]]
name = "bytes"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
[[package]]
name = "cc"
version = "1.0.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a20104e2335ce8a659d6dd92a51a767a0c062599c73b343fd152cb401e828c3d"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec7a4128863c188deefe750ac1d1dfe66c236909f845af04beed823638dc1b2"
dependencies = [
"bitflags",
"clap_derive",
"clap_lex",
"is-terminal",
"once_cell",
"strsim",
"termcolor",
]
[[package]]
name = "clap_derive"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8"
dependencies = [
"heck",
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "clap_lex"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "783fe232adfca04f90f56201b26d79682d4cd2625e0bc7290b95123afe558ade"
dependencies = [
"os_str_bytes",
]
[[package]]
name = "erased-serde"
version = "0.3.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4ca605381c017ec7a5fef5e548f1cfaa419ed0f6df6367339300db74c92aa7d"
dependencies = [
"serde",
]
[[package]]
name = "errno"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f639046355ee4f37944e44f60642c6f3a7efa3cf6b78c78a0d989a8ce6c396a1"
dependencies = [
"errno-dragonfly",
"libc",
"winapi",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "futures-core"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04909a7a7e4633ae6c4a9ab280aeb86da1236243a77b694a49eacd659a4bd3ac"
[[package]]
name = "futures-macro"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bdfb8ce053d86b91919aad980c220b1fb8401a9394410e1c289ed7e66b61835d"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "futures-task"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ffb393ac5d9a6eaa9d3fdf37ae2776656b706e200c8e16b1bdb227f5198e6ea"
[[package]]
name = "futures-util"
version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "197676987abd2f9cadff84926f410af1c183608d36641465df73ae8211dc65d6"
dependencies = [
"futures-core",
"futures-macro",
"futures-task",
"pin-project-lite",
"pin-utils",
"slab",
]
[[package]]
name = "heck"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "hermit-abi"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
dependencies = [
"libc",
]
[[package]]
name = "io-lifetimes"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7d6c6f8c91b4b9ed43484ad1a938e393caf35960fce7f82a040497207bd8e9e"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "is-terminal"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28dfb6c8100ccc63462345b67d1bbc3679177c75ee4bf59bf29c8b1d110b8189"
dependencies = [
"hermit-abi",
"io-lifetimes",
"rustix",
"windows-sys",
]
[[package]]
name = "itoa"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fad582f4b9e86b6caa621cabeb0963332d92eea04729ab12892c2533951e6440"
[[package]]
name = "libc"
version = "0.2.139"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
[[package]]
name = "linux-raw-sys"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
[[package]]
name = "lock_api"
version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if",
]
[[package]]
name = "luau0-src"
version = "0.5.1+luau558"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e0869ba31f9b152c28bb604ecee6deaa2103a97365bb219781ac137bd487626"
dependencies = [
"cc",
]
[[package]]
name = "lune"
version = "0.0.1"
dependencies = [
"clap",
"mlua",
"serde",
"serde_json",
"tokio",
]
[[package]]
name = "memchr"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "mio"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys",
]
[[package]]
name = "mlua"
version = "0.8.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2ee2ad7a9aa69056b148d9d590344bc155d3ce0d2200e3b2838f7034f6ba33c1"
dependencies = [
"bstr",
"cc",
"erased-serde",
"futures-core",
"futures-task",
"futures-util",
"luau0-src",
"num-traits",
"once_cell",
"pkg-config",
"rustc-hash",
"serde",
]
[[package]]
name = "num-traits"
version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "once_cell"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f61fba1741ea2b3d6a1e3178721804bb716a68a6aeba1149b5d52e3d464ea66"
[[package]]
name = "os_str_bytes"
version = "6.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b7820b9daea5457c9f21c69448905d723fbd21136ccf521748f23fd49e723ee"
[[package]]
name = "parking_lot"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba1ef8814b5c993410bb3adfad7a5ed269563e4a2f90c41f5d85be7fb47133bf"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-sys",
]
[[package]]
name = "pin-project-lite"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "pkg-config"
version = "0.3.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ef7d57beacfaf2d8aee5937dab7b7f28de3cb8b1828479bb5de2a7106f2bae2"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags",
]
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustix"
version = "0.36.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fdebc4b395b7fbb9ab11e462e20ed9051e7b16e42d24042c776eca0ac81b03"
dependencies = [
"bitflags",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "ryu"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb7d1f0d3021d347a83e556fc4683dea2ea09d87bccdf88ff5c12545d89d5efb"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
version = "1.0.152"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "serde_json"
version = "1.0.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877c235533714907a8c2464236f5c4b2a17262ef1bd71f38f35ea592c8da6883"
dependencies = [
"itoa",
"ryu",
"serde",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0"
dependencies = [
"libc",
]
[[package]]
name = "slab"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef"
dependencies = [
"autocfg",
]
[[package]]
name = "smallvec"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "socket2"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
version = "1.0.107"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "termcolor"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
dependencies = [
"winapi-util",
]
[[package]]
name = "tokio"
version = "1.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a12a59981d9e3c38d216785b0c37399f6e415e8d0712047620f189371b0bb"
dependencies = [
"autocfg",
"bytes",
"libc",
"memchr",
"mio",
"num_cpus",
"parking_lot",
"pin-project-lite",
"signal-hook-registry",
"socket2",
"tokio-macros",
"windows-sys",
]
[[package]]
name = "tokio-macros"
version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "unicode-ident"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "wasi"
version = "0.11.0+wasi-snapshot-preview1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-util"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
dependencies = [
"winapi",
]
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.42.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
[[package]]
name = "windows_i686_gnu"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
[[package]]
name = "windows_i686_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"

11
Cargo.toml Normal file
View file

@ -0,0 +1,11 @@
[package]
name = "lune"
version = "0.0.1"
edition = "2021"
[dependencies]
clap = { version = "4.1.1", features = ["derive"] }
mlua = { version = "0.8.7", features = ["luau", "async", "serialize"] }
tokio = { version = "1.24.2", features = ["full"] }
serde = { version = "1.0.152", features = ["derive"] }
serde_json = { version = "1.0.91" }

4
aftman.toml Normal file
View file

@ -0,0 +1,4 @@
[tools]
luau-lsp = "JohnnyMorganz/luau-lsp@1.15.0"
selene = "Kampfkarren/selene@0.24.0"
stylua = "JohnnyMorganz/StyLua@0.16.0"

55
lune.yml Normal file
View file

@ -0,0 +1,55 @@
---
globals:
# FS (filesystem)
fs.readFile:
args:
- type: string
fs.readDir:
args:
- type: string
fs.writeFile:
args:
- type: string
- type: string
fs.writeDir:
args:
- type: string
fs.removeFile:
args:
- type: string
fs.removeDir:
args:
- type: string
fs.isFile:
args:
- type: string
fs.isDir:
args:
- type: string
# JSON
json.encode:
args:
- type: any
- required: false
type: boolean
json.decode:
args:
- type: string
# Process
process.getEnvVars:
process.getEnvVar:
args:
- type: string
process.setEnvVar:
args:
- type: string
- type: string
process.exit:
args:
- required: false
type: number
process.spawn:
args:
- type: string
- required: false
type: table

28
luneTypes.d.luau Normal file
View file

@ -0,0 +1,28 @@
declare fs: {
readFile: (path: string) -> string,
readDir: (path: string) -> { string },
writeFile: (path: string, contents: string) -> (),
writeDir: (path: string) -> (),
removeFile: (path: string) -> (),
removeDir: (path: string) -> (),
isFile: (path: string) -> boolean,
isDir: (path: string) -> boolean,
}
declare json: {
encode: (value: any, pretty: boolean?) -> string,
decode: (encoded: string) -> any,
}
declare process: {
getEnvVars: () -> { string },
getEnvVar: (key: string) -> string?,
setEnvVar: (key: string, value: string) -> (),
exit: (code: number?) -> (),
spawn: (program: string, params: { string }?) -> {
ok: boolean,
code: number,
stdout: string,
stderr: string,
},
}

71
scripts/hello_lune.luau Normal file
View file

@ -0,0 +1,71 @@
print("Hello, lune! 🌙")
-- Use a function from another module
local module = require("scripts/module")
module.hello()
-- Read and print out directories & files in
-- the current directory, with fancy icons
print("\nReading current dir...")
local entries = fs.readDir(".")
-- NOTE: We have to do this outside of the sort function
-- to avoid yielding across the metamethod boundary, any
-- calls to fs functions may yield for any reason
local dirs = {}
for _, entry in entries do
dirs[entry] = fs.isDir(entry)
end
-- Sort directories first, then alphabetically
table.sort(entries, function(entry0, entry1)
if dirs[entry0] ~= dirs[entry1] then
return dirs[entry0]
end
return entry0 < entry1
end)
assert(table.find(entries, "Cargo.toml") ~= nil, "Missing Cargo.toml")
assert(table.find(entries, "Cargo.lock") ~= nil, "Missing Cargo.lock")
for _, entry in entries do
if fs.isDir(entry) then
print("📁 " .. entry)
else
print("📄 " .. entry)
end
end
-- Read and print out environment variables
print("\nReading current environment...")
local vars = process.getEnvVars()
table.sort(vars)
assert(table.find(vars, "PATH") ~= nil, "Missing PATH")
assert(table.find(vars, "PWD") ~= nil, "Missing PWD")
for _, key in vars do
local value = process.getEnvVar(key)
local box = if value and value ~= "" then "✅" else "❌"
print(string.format("[%s] %s", box, key))
end
-- Call out to another program
print("\nSending 4 pings to google...")
local result = process.spawn("ping", {
"google.com",
"-c 4",
})
if result.ok then
print(result.stdout)
else
print(result.stderr)
process.exit(result.code)
end
print("\nGoodbye, lune! 🌙")

7
scripts/module.luau Normal file
View file

@ -0,0 +1,7 @@
local module = {}
function module.hello()
print("\nHello from a module! 🧩")
end
return module

6
selene.toml Normal file
View file

@ -0,0 +1,6 @@
std = "luau+lune"
exclude = ["luneTypes.d.luau"]
[lints]
high_cyclomatic_complexity = "warn"

84
src/cli.rs Normal file
View file

@ -0,0 +1,84 @@
use std::{fs::read_to_string, path::PathBuf};
use clap::Parser;
use mlua::{Lua, Result};
use crate::lune::{fs::LuneFs, json::LuneJson, process::LuneProcess};
/// Lune CLI
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
pub struct Cli {
/// Path to the file to run
path: String,
}
impl Cli {
#[allow(dead_code)]
pub fn from_path<S: AsRef<str>>(path: S) -> Self {
Self {
path: path.as_ref().to_owned(),
}
}
fn parse_file_path(&self) -> Result<PathBuf> {
let parsed_file_path = match &self.path {
path if path.ends_with(".luau") || path.ends_with(".lua") => Some(PathBuf::from(path)),
path => {
let temp_path = PathBuf::from(path);
if temp_path.extension().is_none() {
let as_luau_path = temp_path.with_extension("luau");
let as_lua_path = temp_path.with_extension("lua");
if as_luau_path.exists() {
Some(as_luau_path)
} else if as_lua_path.exists() {
Some(as_lua_path)
} else {
let as_luau_in_scripts_folder = PathBuf::from("scripts").join(as_luau_path);
let as_lua_in_scripts_folder = PathBuf::from("scripts").join(as_lua_path);
if as_luau_in_scripts_folder.exists() {
Some(as_luau_in_scripts_folder)
} else if as_lua_in_scripts_folder.exists() {
Some(as_lua_in_scripts_folder)
} else {
None
}
}
} else {
None
}
}
};
if let Some(file_path) = parsed_file_path {
if file_path.exists() {
Ok(file_path)
} else {
Err(mlua::Error::RuntimeError(format!(
"File does not exist at path: '{}'",
self.path
)))
}
} else {
Err(mlua::Error::RuntimeError(format!(
"Invalid file path: '{}'",
self.path
)))
}
}
pub async fn run(self) -> Result<()> {
// Parse and read the wanted file
let file_path = self.parse_file_path()?;
let file_contents = read_to_string(file_path)?;
// Create a new lua state and add in all lune globals
let lua = Lua::new();
let globals = lua.globals();
globals.set("fs", LuneFs::new())?;
globals.set("process", LuneProcess::new())?;
globals.set("json", LuneJson::new())?;
lua.sandbox(true)?;
// Run the file
lua.load(&file_contents).exec_async().await?;
Ok(())
}
}

109
src/lune/fs.rs Normal file
View file

@ -0,0 +1,109 @@
use std::path::{PathBuf, MAIN_SEPARATOR};
use mlua::{Lua, Result, UserData, UserDataMethods};
use tokio::fs;
pub struct LuneFs();
impl LuneFs {
pub fn new() -> Self {
Self()
}
}
impl UserData for LuneFs {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_async_function("readFile", fs_read_file);
methods.add_async_function("readDir", fs_read_dir);
methods.add_async_function("writeFile", fs_write_file);
methods.add_async_function("writeDir", fs_write_dir);
methods.add_async_function("removeFile", fs_remove_file);
methods.add_async_function("removeDir", fs_remove_dir);
methods.add_async_function("isFile", fs_is_file);
methods.add_async_function("isDir", fs_is_dir);
}
}
async fn fs_read_file(_: &Lua, path: String) -> Result<String> {
Ok(fs::read_to_string(&path)
.await
.map_err(mlua::Error::external)?)
}
async fn fs_read_dir(_: &Lua, path: String) -> Result<Vec<String>> {
let mut dir_strings = Vec::new();
let mut dir = fs::read_dir(&path).await.map_err(mlua::Error::external)?;
while let Some(dir_entry) = dir.next_entry().await.map_err(mlua::Error::external)? {
if let Some(dir_path_str) = dir_entry.path().to_str() {
dir_strings.push(dir_path_str.to_owned());
} else {
return Err(mlua::Error::RuntimeError(format!(
"File path could not be converted into a string: '{}'",
dir_entry.path().display()
)));
}
}
let mut dir_string_prefix = path;
if !dir_string_prefix.ends_with(MAIN_SEPARATOR) {
dir_string_prefix.push(MAIN_SEPARATOR);
}
let dir_strings_no_prefix = dir_strings
.iter()
.map(|inner_path| {
inner_path
.trim()
.strip_prefix(&dir_string_prefix)
.unwrap()
.to_owned()
})
.collect::<Vec<_>>();
Ok(dir_strings_no_prefix)
}
async fn fs_write_file(_: &Lua, (path, contents): (String, String)) -> Result<()> {
Ok(fs::write(&path, &contents)
.await
.map_err(mlua::Error::external)?)
}
async fn fs_write_dir(_: &Lua, path: String) -> Result<()> {
Ok(fs::create_dir_all(&path)
.await
.map_err(mlua::Error::external)?)
}
async fn fs_remove_file(_: &Lua, path: String) -> Result<()> {
Ok(fs::remove_file(&path)
.await
.map_err(mlua::Error::external)?)
}
async fn fs_remove_dir(_: &Lua, path: String) -> Result<()> {
Ok(fs::remove_dir_all(&path)
.await
.map_err(mlua::Error::external)?)
}
async fn fs_is_file(_: &Lua, path: String) -> Result<bool> {
let path = PathBuf::from(path);
if path.exists() {
Ok(fs::metadata(path)
.await
.map_err(mlua::Error::external)?
.is_file())
} else {
Ok(false)
}
}
async fn fs_is_dir(_: &Lua, path: String) -> Result<bool> {
let path = PathBuf::from(path);
if path.exists() {
Ok(fs::metadata(path)
.await
.map_err(mlua::Error::external)?
.is_dir())
} else {
Ok(false)
}
}

28
src/lune/json.rs Normal file
View file

@ -0,0 +1,28 @@
use mlua::{Error, Lua, LuaSerdeExt, Result, UserData, UserDataMethods, Value};
pub struct LuneJson();
impl LuneJson {
pub fn new() -> Self {
Self()
}
}
impl UserData for LuneJson {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_function("encode", json_encode);
methods.add_function("decode", json_decode);
}
}
fn json_encode(_: &Lua, (val, pretty): (Value, Option<bool>)) -> Result<String> {
if let Some(true) = pretty {
Ok(serde_json::to_string_pretty(&val).map_err(Error::external)?)
} else {
Ok(serde_json::to_string(&val).map_err(Error::external)?)
}
}
fn json_decode(lua: &Lua, json: String) -> Result<Value> {
Ok(lua.to_value(&json)?)
}

3
src/lune/mod.rs Normal file
View file

@ -0,0 +1,3 @@
pub mod fs;
pub mod json;
pub mod process;

93
src/lune/process.rs Normal file
View file

@ -0,0 +1,93 @@
use std::{
env::{self, VarError},
process::{exit, Stdio},
};
use mlua::{Error, Lua, Result, Table, UserData, UserDataMethods, Value};
use tokio::process::Command;
pub struct LuneProcess();
impl LuneProcess {
pub fn new() -> Self {
Self()
}
}
impl UserData for LuneProcess {
fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) {
methods.add_function("getEnvVars", process_get_env_vars);
methods.add_function("getEnvVar", process_get_env_var);
methods.add_function("setEnvVar", process_set_env_var);
methods.add_function("exit", process_exit);
methods.add_async_function("spawn", process_spawn);
}
}
fn process_get_env_vars(_: &Lua, _: ()) -> Result<Vec<String>> {
let mut vars = Vec::new();
for (key, _) in env::vars() {
vars.push(key);
}
Ok(vars)
}
fn process_get_env_var(lua: &Lua, key: String) -> Result<Value> {
match env::var(&key) {
Ok(value) => Ok(Value::String(lua.create_string(&value)?)),
Err(VarError::NotPresent) => Ok(Value::Nil),
Err(VarError::NotUnicode(_)) => Err(Error::external(format!(
"The env var '{}' contains invalid utf8",
&key
))),
}
}
fn process_set_env_var(_: &Lua, (key, value): (String, String)) -> Result<()> {
Ok(env::set_var(&key, &value))
}
fn process_exit(_: &Lua, exit_code: Option<i32>) -> Result<()> {
if let Some(code) = exit_code {
exit(code);
} else {
exit(0)
}
}
async fn process_spawn(lua: &Lua, (program, args): (String, Option<Vec<String>>)) -> Result<Table> {
// Create and spawn a child process, and
// wait for it to terminate with output
let mut cmd = Command::new(program);
if let Some(args) = args {
cmd.args(args);
}
let child = cmd
.current_dir(env::current_dir().map_err(mlua::Error::external)?)
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.map_err(mlua::Error::external)?;
let output = child
.wait_with_output()
.await
.map_err(mlua::Error::external)?;
// NOTE: Exit code defaults to 1 if it did not exist and if there
// is any stderr, will otherwise default to 0 if it did not exist
let code = output
.status
.code()
.unwrap_or_else(|| match output.stderr.is_empty() {
true => 0,
false => 1,
});
// Construct and return a readonly lua table with results
let table = lua.create_table()?;
table.raw_set("ok", code == 0)?;
table.raw_set("code", code)?;
table.raw_set("stdout", lua.create_string(&output.stdout)?)?;
table.raw_set("stderr", lua.create_string(&output.stderr)?)?;
table.set_readonly(true);
Ok(table)
}

30
src/main.rs Normal file
View file

@ -0,0 +1,30 @@
use clap::Parser;
use mlua::Result;
mod cli;
mod lune;
mod utils;
use cli::Cli;
use utils::pretty_print_luau_error;
#[tokio::main]
async fn main() -> Result<()> {
let cli = Cli::parse();
match cli.run().await {
Ok(_) => Ok(()),
Err(e) => {
eprintln!();
eprintln!("[ERROR]");
pretty_print_luau_error(&e);
std::process::exit(1);
}
}
}
#[tokio::test]
async fn hello_lune() {
let cli = Cli::from_path("hello_lune");
let result = cli.run().await;
assert!(result.is_ok());
}

33
src/utils.rs Normal file
View file

@ -0,0 +1,33 @@
pub fn pretty_print_luau_error(e: &mlua::Error) {
match e {
mlua::Error::RuntimeError(e) => {
eprintln!("{}", e);
}
mlua::Error::CallbackError { cause, traceback } => {
pretty_print_luau_error(cause.as_ref());
eprintln!("Traceback:");
eprintln!("{}", traceback.strip_prefix("stack traceback:\n").unwrap());
}
mlua::Error::ToLuaConversionError { from, to, message } => {
let msg = message
.clone()
.map(|m| format!("\nDetails:\n\t{m}"))
.unwrap_or_else(|| "".to_string());
eprintln!(
"Failed to convert Rust type '{}' into Luau type '{}'!{}",
from, to, msg
)
}
mlua::Error::FromLuaConversionError { from, to, message } => {
let msg = message
.clone()
.map(|m| format!("\nDetails:\n\t{m}"))
.unwrap_or_else(|| "".to_string());
eprintln!(
"Failed to convert Luau type '{}' into Rust type '{}'!{}",
from, to, msg
)
}
e => eprintln!("{}", e.to_string()),
}
}

10
stylua.toml Normal file
View file

@ -0,0 +1,10 @@
column_width = 100
line_endings = "Unix"
indent_type = "Tabs"
indent_width = 4
quote_style = "AutoPreferDouble"
call_parentheses = "Always"