mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-25 04:54:07 +00:00
Prototype server plugins, add example MoonScript plugin
This commit is contained in:
parent
6fcb895d70
commit
4b9fc137f8
9 changed files with 189 additions and 2 deletions
21
Cargo.lock
generated
21
Cargo.lock
generated
|
|
@ -94,6 +94,15 @@ dependencies = [
|
||||||
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bincode"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
|
@ -1224,6 +1233,7 @@ dependencies = [
|
||||||
name = "rojo"
|
name = "rojo"
|
||||||
version = "0.5.0-alpha.0"
|
version = "0.5.0-alpha.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"csv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"csv 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
|
@ -1251,6 +1261,16 @@ dependencies = [
|
||||||
name = "rojo-e2e"
|
name = "rojo-e2e"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rojo-plugin-moonscript"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde_derive 1.0.84 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"serde_json 1.0.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rouille"
|
name = "rouille"
|
||||||
version = "2.2.0"
|
version = "2.2.0"
|
||||||
|
|
@ -1868,6 +1888,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
|
"checksum backtrace-sys 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)" = "797c830ac25ccc92a7f8a7b9862bde440715531514594a6154e3d4a54dd769b6"
|
||||||
"checksum base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "621fc7ecb8008f86d7fb9b95356cd692ce9514b80a86d85b397f32a22da7b9e2"
|
"checksum base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "621fc7ecb8008f86d7fb9b95356cd692ce9514b80a86d85b397f32a22da7b9e2"
|
||||||
"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
|
"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
|
||||||
|
"checksum bincode 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9f2fb9e29e72fd6bc12071533d5dc7664cb01480c59406f656d7ac25c7bd8ff7"
|
||||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||||
"checksum brotli-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4445dea95f4c2b41cde57cc9fee236ae4dbae88d8fcbdb4750fc1bb5d86aaecd"
|
"checksum brotli-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4445dea95f4c2b41cde57cc9fee236ae4dbae88d8fcbdb4750fc1bb5d86aaecd"
|
||||||
|
|
|
||||||
|
|
@ -2,4 +2,5 @@
|
||||||
members = [
|
members = [
|
||||||
"server",
|
"server",
|
||||||
"rojo-e2e",
|
"rojo-e2e",
|
||||||
|
"rojo-plugin-moonscript",
|
||||||
]
|
]
|
||||||
11
rojo-plugin-moonscript/Cargo.toml
Normal file
11
rojo-plugin-moonscript/Cargo.toml
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
[package]
|
||||||
|
name = "rojo-plugin-moonscript"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Lucien Greathouse <me@lpghatguy.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde = "1.0"
|
||||||
|
serde_derive = "1.0"
|
||||||
|
serde_json = "1.0"
|
||||||
|
bincode = "1.0"
|
||||||
80
rojo-plugin-moonscript/src/main.rs
Normal file
80
rojo-plugin-moonscript/src/main.rs
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
io::{self, Write},
|
||||||
|
path::PathBuf,
|
||||||
|
process::{Command, Stdio},
|
||||||
|
};
|
||||||
|
|
||||||
|
use serde_derive::{Serialize, Deserialize};
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
struct InputFile {
|
||||||
|
path: PathBuf,
|
||||||
|
contents: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
struct Metadata {
|
||||||
|
ignore_unknown_instances: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
#[serde(tag = "Type")]
|
||||||
|
enum Property {
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
String {
|
||||||
|
value: String,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
struct Instance {
|
||||||
|
name: String,
|
||||||
|
class_name: String,
|
||||||
|
properties: HashMap<String, Property>,
|
||||||
|
children: Vec<()>,
|
||||||
|
metadata: Metadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
let file: InputFile = bincode::deserialize_from(io::stdin())
|
||||||
|
.expect("Invalid input");
|
||||||
|
|
||||||
|
let mut child = Command::new("moonc")
|
||||||
|
.arg("--")
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.spawn()?;
|
||||||
|
|
||||||
|
{
|
||||||
|
let stdin = child.stdin.as_mut().unwrap();
|
||||||
|
stdin.write_all(&file.contents)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = child.wait_with_output()?;
|
||||||
|
|
||||||
|
let script_name = file.path.file_stem().unwrap().to_string_lossy().into_owned();
|
||||||
|
let compiled = String::from_utf8_lossy(&result.stdout).into_owned();
|
||||||
|
|
||||||
|
let mut properties = HashMap::new();
|
||||||
|
properties.insert("Source".to_owned(), Property::String {
|
||||||
|
value: compiled,
|
||||||
|
});
|
||||||
|
|
||||||
|
let output = Instance {
|
||||||
|
name: script_name,
|
||||||
|
class_name: "ModuleScript".to_owned(),
|
||||||
|
properties,
|
||||||
|
children: Vec::new(),
|
||||||
|
metadata: Metadata {
|
||||||
|
ignore_unknown_instances: false,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let response = serde_json::to_string(&output)
|
||||||
|
.expect("Couldn't serialize to JSON");
|
||||||
|
|
||||||
|
print!("{}", response);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
@ -20,6 +20,7 @@ default = []
|
||||||
bundle-plugin = []
|
bundle-plugin = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
bincode = "1.0"
|
||||||
clap = "2.27"
|
clap = "2.27"
|
||||||
csv = "1.0"
|
csv = "1.0"
|
||||||
env_logger = "0.5"
|
env_logger = "0.5"
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt,
|
fmt,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
|
process::{Command, Stdio},
|
||||||
str,
|
str,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -33,6 +34,13 @@ use crate::{
|
||||||
rbx_session::{MetadataPerPath, MetadataPerInstance},
|
rbx_session::{MetadataPerPath, MetadataPerInstance},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// In a real plugin implementation, this would be part of the project file.
|
||||||
|
// Should the executable name be limited to try to prevent malicious projects
|
||||||
|
// from executing arbitrary code?
|
||||||
|
static PLUGINS: [(&str, &str); 1] = [
|
||||||
|
("moon", "target/debug/rojo-plugin-moonscript"),
|
||||||
|
];
|
||||||
|
|
||||||
const INIT_MODULE_NAME: &str = "init.lua";
|
const INIT_MODULE_NAME: &str = "init.lua";
|
||||||
const INIT_SERVER_NAME: &str = "init.server.lua";
|
const INIT_SERVER_NAME: &str = "init.server.lua";
|
||||||
const INIT_CLIENT_NAME: &str = "init.client.lua";
|
const INIT_CLIENT_NAME: &str = "init.client.lua";
|
||||||
|
|
@ -246,7 +254,65 @@ fn snapshot_imfs_file<'source>(
|
||||||
Some("txt") => snapshot_txt_file(file)?,
|
Some("txt") => snapshot_txt_file(file)?,
|
||||||
Some("rbxmx") => snapshot_xml_model_file(file)?,
|
Some("rbxmx") => snapshot_xml_model_file(file)?,
|
||||||
Some("rbxm") => snapshot_binary_model_file(file)?,
|
Some("rbxm") => snapshot_binary_model_file(file)?,
|
||||||
Some(_) | None => return Ok(None),
|
// In a real plugin implementation, plugins would probably want to
|
||||||
|
// execute before any of the builtin instance routines.
|
||||||
|
//
|
||||||
|
// Alternatively, maybe we want to run the builtin routines and send the
|
||||||
|
// snapshot generated by that routine as well as the original file? That
|
||||||
|
// would open the door to make plugins that transform instances to do
|
||||||
|
// things like add source headers or optimize code without having to
|
||||||
|
// create another kind of plugin.
|
||||||
|
Some(unknown_ext) => {
|
||||||
|
let mut result = None;
|
||||||
|
|
||||||
|
for (plugin_ext, plugin_path) in &PLUGINS {
|
||||||
|
if plugin_ext == &unknown_ext {
|
||||||
|
let mut child = Command::new(plugin_path)
|
||||||
|
// This argument is standard for telling processes to
|
||||||
|
// read from stdin, we can pass it as a courtesy even
|
||||||
|
// though I bet all plugin processes will be
|
||||||
|
// purpose-built to correctly deal with structured input
|
||||||
|
// from Rojo
|
||||||
|
.arg("--")
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.stdout(Stdio::piped())
|
||||||
|
.spawn()
|
||||||
|
.expect("Could not spawn plugin process");
|
||||||
|
|
||||||
|
{
|
||||||
|
let stdin = child.stdin.as_mut().unwrap();
|
||||||
|
// We're using bincode here since it makes Vec<u8>
|
||||||
|
// serialize more cleanly than JSON, but we could use
|
||||||
|
// whatever.
|
||||||
|
bincode::serialize_into(stdin, file)
|
||||||
|
.expect("Could not serialize file into plugin stdin");
|
||||||
|
}
|
||||||
|
|
||||||
|
let output = child.wait_with_output()
|
||||||
|
.expect("Could not wait for plugin process output");
|
||||||
|
|
||||||
|
assert!(output.status.success());
|
||||||
|
|
||||||
|
// I'm accepting JSON for the output because bincode doesn't
|
||||||
|
// implement all of the features needed to actually
|
||||||
|
// deserialize a RbxSnapshotInstance I guess.
|
||||||
|
//
|
||||||
|
// Whatever format is used for plugins, it should probably
|
||||||
|
// be consistent between input/output.
|
||||||
|
//
|
||||||
|
// This also doesn't account for representing failure or a
|
||||||
|
// plugin returning no instance at all.
|
||||||
|
let snapshot: RbxSnapshotInstance<'static> = serde_json::from_slice(&output.stdout)
|
||||||
|
.expect("Could not deserialize plugin output");
|
||||||
|
|
||||||
|
result = Some(snapshot);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
},
|
||||||
|
None => return Ok(None),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(snapshot) = maybe_snapshot.as_mut() {
|
if let Some(snapshot) = maybe_snapshot.as_mut() {
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ impl InstanceChanges {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct RbxSnapshotInstance<'a> {
|
pub struct RbxSnapshotInstance<'a> {
|
||||||
pub name: Cow<'a, str>,
|
pub name: Cow<'a, str>,
|
||||||
pub class_name: Cow<'a, str>,
|
pub class_name: Cow<'a, str>,
|
||||||
|
|
|
||||||
6
test-projects/moonscript/roblox-project.json
Normal file
6
test-projects/moonscript/roblox-project.json
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"name": "moonscript",
|
||||||
|
"tree": {
|
||||||
|
"$path": "src"
|
||||||
|
}
|
||||||
|
}
|
||||||
1
test-projects/moonscript/src/hello.moon
Normal file
1
test-projects/moonscript/src/hello.moon
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
func_a = -> print "Hello, world!"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue