mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-10-23 05:51:39 +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)",
|
||||
]
|
||||
|
||||
[[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]]
|
||||
name = "bitflags"
|
||||
version = "0.7.0"
|
||||
|
|
@ -1224,6 +1233,7 @@ dependencies = [
|
|||
name = "rojo"
|
||||
version = "0.5.0-alpha.0"
|
||||
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)",
|
||||
"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)",
|
||||
|
|
@ -1251,6 +1261,16 @@ dependencies = [
|
|||
name = "rojo-e2e"
|
||||
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]]
|
||||
name = "rouille"
|
||||
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 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 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 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"
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@
|
|||
members = [
|
||||
"server",
|
||||
"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 = []
|
||||
|
||||
[dependencies]
|
||||
bincode = "1.0"
|
||||
clap = "2.27"
|
||||
csv = "1.0"
|
||||
env_logger = "0.5"
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ use std::{
|
|||
collections::HashMap,
|
||||
fmt,
|
||||
path::{Path, PathBuf},
|
||||
process::{Command, Stdio},
|
||||
str,
|
||||
};
|
||||
|
||||
|
|
@ -33,6 +34,13 @@ use crate::{
|
|||
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_SERVER_NAME: &str = "init.server.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("rbxmx") => snapshot_xml_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() {
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ impl InstanceChanges {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct RbxSnapshotInstance<'a> {
|
||||
pub 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