mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-04-20 12:45:05 +00:00
Compare commits
44 Commits
v0.3.x
...
v0.4.0-pre
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2c188738e6 | ||
|
|
ebffba9589 | ||
|
|
ab644c3dfa | ||
|
|
c6cdd8a815 | ||
|
|
d99df59d9b | ||
|
|
c5f8247543 | ||
|
|
72557c9d23 | ||
|
|
1a1b6d923f | ||
|
|
27cf2c8740 | ||
|
|
c08a598d3f | ||
|
|
1318842c36 | ||
|
|
86d7d033d7 | ||
|
|
2df1dfa1cb | ||
|
|
78a1c658d8 | ||
|
|
f52f43fe90 | ||
|
|
58b244b7e9 | ||
|
|
d8bcbee463 | ||
|
|
f00152a9ac | ||
|
|
9720c56765 | ||
|
|
13ce04abb2 | ||
|
|
ab22b55b84 | ||
|
|
73117edbe7 | ||
|
|
d7e2a3542c | ||
|
|
fe240ed577 | ||
|
|
5e98cbe68f | ||
|
|
7a372dc50c | ||
|
|
958b6660be | ||
|
|
e731811911 | ||
|
|
66144cef2f | ||
|
|
68ba3fee6c | ||
|
|
95581dbaa6 | ||
|
|
aaaf3ba0b9 | ||
|
|
b885cae086 | ||
|
|
0f78eb933a | ||
|
|
6ee9a48e20 | ||
|
|
f90c51e923 | ||
|
|
6472a2cbce | ||
|
|
c75cbebbf0 | ||
|
|
12bfcd7b66 | ||
|
|
d365bc076e | ||
|
|
67ac6b7cec | ||
|
|
01325c8c7e | ||
|
|
21e9625c36 | ||
|
|
5bf1f11190 |
@@ -1,10 +1,14 @@
|
|||||||
# Rojo Change Log
|
# Rojo Change Log
|
||||||
|
|
||||||
## Current Master
|
## Current Master (0.4.0)
|
||||||
* No changes
|
* Protocol version 1, which shifts more responsibility onto the server
|
||||||
|
* This is a **major breaking** change!
|
||||||
|
* The server now has a content of 'filter plugins', which transform data at various stages in the pipeline
|
||||||
|
* The server now exposes Roblox instance objects instead of file contents, which lines up with how `rojo pack` will work, and paves the way for more robust syncing.
|
||||||
|
|
||||||
## 0.3.2
|
## 0.3.2
|
||||||
* Fixed `rojo serve` failing to correctly construct an absolute root path when passed as an argument
|
* Fixed `rojo serve` failing to correctly construct an absolute root path when passed as an argument
|
||||||
|
* Fixed intense CPU usage when running `rojo serve`
|
||||||
|
|
||||||
## 0.3.1
|
## 0.3.1
|
||||||
* Improved error reporting when invalid JSON is found in a `rojo.json` project
|
* Improved error reporting when invalid JSON is found in a `rojo.json` project
|
||||||
|
|||||||
269
Cargo.lock
generated
269
Cargo.lock
generated
@@ -6,6 +6,14 @@ dependencies = [
|
|||||||
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aho-corasick"
|
||||||
|
version = "0.6.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ansi_term"
|
name = "ansi_term"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
@@ -18,13 +26,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atty"
|
name = "atty"
|
||||||
version = "0.2.3"
|
version = "0.2.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -48,7 +55,7 @@ version = "0.2.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
"gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -57,7 +64,7 @@ version = "0.2.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"brotli-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"brotli-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -86,7 +93,7 @@ version = "0.2.25"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -100,7 +107,7 @@ version = "2.29.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -175,7 +182,7 @@ name = "env_logger"
|
|||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
"regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -185,8 +192,8 @@ version = "0.1.14"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
"redox_syscall 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -194,7 +201,7 @@ name = "flate2"
|
|||||||
version = "0.2.20"
|
version = "0.2.20"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -205,7 +212,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -213,24 +220,22 @@ name = "fsevent-sys"
|
|||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fuchsia-zircon"
|
name = "fuchsia-zircon"
|
||||||
version = "0.2.1"
|
version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fuchsia-zircon-sys"
|
name = "fuchsia-zircon-sys"
|
||||||
version = "0.2.0"
|
version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
|
||||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gcc"
|
name = "gcc"
|
||||||
@@ -252,7 +257,7 @@ name = "inotify"
|
|||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -269,15 +274,31 @@ dependencies = [
|
|||||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lazy_static"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.34"
|
version = "0.2.35"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
version = "0.3.8"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "log"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matches"
|
name = "matches"
|
||||||
@@ -289,7 +310,15 @@ name = "memchr"
|
|||||||
version = "0.1.11"
|
version = "0.1.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -297,7 +326,7 @@ name = "mime"
|
|||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -317,7 +346,7 @@ version = "0.1.10"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cc 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -326,13 +355,13 @@ version = "0.5.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"miow 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"miow 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
"net2 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"nix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"nix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -354,11 +383,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"buf_redux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"buf_redux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"env_logger 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mime_guess 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mime_guess 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -369,7 +398,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@@ -380,7 +409,7 @@ version = "0.5.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -394,7 +423,7 @@ dependencies = [
|
|||||||
"fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"inotify 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"inotify 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"walkdir 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"walkdir 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -460,7 +489,7 @@ version = "0.7.21"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
"phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -478,16 +507,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.3.18"
|
version = "0.3.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redox_syscall"
|
||||||
version = "0.1.32"
|
version = "0.1.34"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -495,7 +524,7 @@ name = "redox_termios"
|
|||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
"redox_syscall 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -510,22 +539,41 @@ dependencies = [
|
|||||||
"utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.3.9"
|
version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.4.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rojo"
|
name = "rojo"
|
||||||
version = "0.3.2"
|
version = "0.4.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"clap 2.29.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"notify 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"notify 4.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rouille 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rouille 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -538,11 +586,11 @@ dependencies = [
|
|||||||
"filetime 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"filetime 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
"flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"multipart 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"multipart 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
"term 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"tiny_http 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"tiny_http 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@@ -554,11 +602,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "same-file"
|
name = "same-file"
|
||||||
version = "1.0.0"
|
version = "1.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -571,22 +618,22 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.24"
|
version = "1.0.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.24"
|
version = "1.0.27"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_derive_internals 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive_internals"
|
name = "serde_derive_internals"
|
||||||
version = "0.18.0"
|
version = "0.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
@@ -595,13 +642,13 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.8"
|
version = "1.0.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
"num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -647,7 +694,7 @@ name = "tempdir"
|
|||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -664,8 +711,8 @@ name = "termion"
|
|||||||
version = "1.5.1"
|
version = "1.5.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
"redox_syscall 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -683,7 +730,7 @@ version = "2.0.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -695,14 +742,22 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "time"
|
name = "thread_local"
|
||||||
version = "0.1.38"
|
version = "0.3.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
|
]
|
||||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
|
||||||
|
[[package]]
|
||||||
|
name = "time"
|
||||||
|
version = "0.1.39"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"redox_syscall 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -714,7 +769,7 @@ dependencies = [
|
|||||||
"chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
"chrono 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"chunked_transfer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
"chunked_transfer 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
"encoding 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"url 0.2.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
"url 0.2.38 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
@@ -742,6 +797,14 @@ name = "unicode-xid"
|
|||||||
version = "0.0.4"
|
version = "0.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unreachable"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "url"
|
name = "url"
|
||||||
version = "0.2.38"
|
version = "0.2.38"
|
||||||
@@ -767,12 +830,17 @@ name = "utf8-ranges"
|
|||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "utf8-ranges"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "uuid"
|
name = "uuid"
|
||||||
version = "0.1.18"
|
version = "0.1.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -781,12 +849,17 @@ name = "vec_map"
|
|||||||
version = "0.8.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "void"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"same-file 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"same-file 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -794,11 +867,30 @@ name = "winapi"
|
|||||||
version = "0.2.8"
|
version = "0.2.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"winapi-i686-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"winapi-x86_64-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winapi-build"
|
name = "winapi-build"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-i686-pc-windows-gnu"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winapi-x86_64-pc-windows-gnu"
|
||||||
|
version = "0.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ws2_32-sys"
|
name = "ws2_32-sys"
|
||||||
version = "0.2.1"
|
version = "0.2.1"
|
||||||
@@ -810,9 +902,10 @@ dependencies = [
|
|||||||
|
|
||||||
[metadata]
|
[metadata]
|
||||||
"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
|
"checksum aho-corasick 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ca972c2ea5f742bfce5687b9aef75506a764f61d37f8f649047846a9686ddb66"
|
||||||
|
"checksum aho-corasick 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d6531d44de723825aa81398a6415283229725a00fa30713812ab9323faa82fc4"
|
||||||
"checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455"
|
"checksum ansi_term 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6b3568b48b7cefa6b8ce125f9bb4989e52fbcc29ebea88df04cc7c5f12f70455"
|
||||||
"checksum ascii 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae7d751998c189c1d4468cf0a39bb2eae052a9c58d50ebb3b9591ee3813ad50"
|
"checksum ascii 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae7d751998c189c1d4468cf0a39bb2eae052a9c58d50ebb3b9591ee3813ad50"
|
||||||
"checksum atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21e50800ec991574876040fff8ee46b136a53e985286fbe6a3bdfe6421b78860"
|
"checksum atty 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "8352656fd42c30a0c3c89d26dea01e3b77c0ab2af18230835c15e2e13cd51859"
|
||||||
"checksum bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dead7461c1127cf637931a1e50934eb6eee8bff2f74433ac7909e9afcee04a3"
|
"checksum bitflags 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dead7461c1127cf637931a1e50934eb6eee8bff2f74433ac7909e9afcee04a3"
|
||||||
"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.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
|
"checksum bitflags 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3c30d3802dfb7281680d6285f2ccdaa8c2d8fee41f93805dba5c4cf50dc23cf"
|
||||||
@@ -838,17 +931,20 @@ dependencies = [
|
|||||||
"checksum flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "e6234dd4468ae5d1e2dbb06fe2b058696fdc50a339c68a393aefbf00bc81e423"
|
"checksum flate2 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)" = "e6234dd4468ae5d1e2dbb06fe2b058696fdc50a339c68a393aefbf00bc81e423"
|
||||||
"checksum fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c4bbbf71584aeed076100b5665ac14e3d85eeb31fdbb45fbd41ef9a682b5ec05"
|
"checksum fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c4bbbf71584aeed076100b5665ac14e3d85eeb31fdbb45fbd41ef9a682b5ec05"
|
||||||
"checksum fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a772d36c338d07a032d5375a36f15f9a7043bf0cb8ce7cee658e037c6032874"
|
"checksum fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a772d36c338d07a032d5375a36f15f9a7043bf0cb8ce7cee658e037c6032874"
|
||||||
"checksum fuchsia-zircon 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f6c0581a4e363262e52b87f59ee2afe3415361c6ec35e665924eb08afe8ff159"
|
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||||
"checksum fuchsia-zircon-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "43f3795b4bae048dc6123a6b972cadde2e676f9ded08aef6bb77f5f157684a82"
|
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||||
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
|
"checksum gcc 0.3.54 (registry+https://github.com/rust-lang/crates.io-index)" = "5e33ec290da0d127825013597dbdfc28bee4964690c7ce1166cbc2a7bd08b1bb"
|
||||||
"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
|
"checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d"
|
||||||
"checksum inotify 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887fcc180136e77a85e6a6128579a719027b1bab9b1c38ea4444244fe262c20c"
|
"checksum inotify 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887fcc180136e77a85e6a6128579a719027b1bab9b1c38ea4444244fe262c20c"
|
||||||
"checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c"
|
"checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c"
|
||||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||||
"checksum libc 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)" = "36fbc8a8929c632868295d0178dd8f63fc423fd7537ad0738372bd010b3ac9b0"
|
"checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d"
|
||||||
"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b"
|
"checksum libc 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)" = "96264e9b293e95d25bfcbbf8a88ffd1aedc85b754eba8b7d78012f638ba220eb"
|
||||||
|
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
|
||||||
|
"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2"
|
||||||
"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
|
"checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376"
|
||||||
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
|
"checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20"
|
||||||
|
"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d"
|
||||||
"checksum mime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ec0c2f4d901bf1d4a2192a40b4b570ae3b19c51243e549defc1de741940aa787"
|
"checksum mime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ec0c2f4d901bf1d4a2192a40b4b570ae3b19c51243e549defc1de741940aa787"
|
||||||
"checksum mime_guess 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "422acd80644209a8c8c66a20514840d8c092eb1eab2898ca7c548cc1d64c8998"
|
"checksum mime_guess 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "422acd80644209a8c8c66a20514840d8c092eb1eab2898ca7c548cc1d64c8998"
|
||||||
"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
|
"checksum miniz-sys 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "609ce024854aeb19a0ef7567d348aaa5a746b32fb72e336df7fcc16869d7e2b4"
|
||||||
@@ -868,19 +964,21 @@ dependencies = [
|
|||||||
"checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03"
|
"checksum phf_generator 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "6b07ffcc532ccc85e3afc45865469bf5d9e4ef5bfcf9622e3cfe80c2d275ec03"
|
||||||
"checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2"
|
"checksum phf_shared 0.7.21 (registry+https://github.com/rust-lang/crates.io-index)" = "07e24b0ca9643bdecd0632f2b3da6b1b89bbb0030e0b992afc1113b23a7bc2f2"
|
||||||
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
|
||||||
"checksum rand 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)" = "6475140dfd8655aeb72e1fd4b7a1cc1c202be65d71669476e392fe62532b9edd"
|
"checksum rand 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)" = "9e7944d95d25ace8f377da3ac7068ce517e4c646754c43a1b1849177bbf72e59"
|
||||||
"checksum redox_syscall 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ab105df655884ede59d45b7070c8a65002d921461ee813a024558ca16030eea0"
|
"checksum redox_syscall 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "df1a5c588807af3b0cbbfa2f1358f2d5ec6ad546858c1ccd30dfbb127021706b"
|
||||||
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
|
||||||
"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
|
"checksum regex 0.1.80 (registry+https://github.com/rust-lang/crates.io-index)" = "4fd4ace6a8cf7860714a2c2280d6c1f7e6a413486c13298bbc86fd3da019402f"
|
||||||
|
"checksum regex 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "744554e01ccbd98fff8c457c3b092cd67af62a555a43bfe97ae8a0451f7799fa"
|
||||||
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
|
"checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957"
|
||||||
|
"checksum regex-syntax 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8e931c58b93d86f080c734bfd2bce7dd0079ae2331235818133c8be7f422e20e"
|
||||||
"checksum rouille 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d6415f261a8775bef50e9fcfb14ed73209ce637f753f9d1c8c6122559e559001"
|
"checksum rouille 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d6415f261a8775bef50e9fcfb14ed73209ce637f753f9d1c8c6122559e559001"
|
||||||
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
|
"checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda"
|
||||||
"checksum same-file 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "70a18720d745fb9ca6a041b37cb36d0b21066006b6cff8b5b360142d4b81fb60"
|
"checksum same-file 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f3257af0472da4b8b8902102a57bafffd9991f0f43772a8af6153d597e6e4ae2"
|
||||||
"checksum serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c97b18e9e53de541f11e497357d6c5eaeb39f0cb9c8734e274abe4935f6991fa"
|
"checksum serde 0.6.15 (registry+https://github.com/rust-lang/crates.io-index)" = "c97b18e9e53de541f11e497357d6c5eaeb39f0cb9c8734e274abe4935f6991fa"
|
||||||
"checksum serde 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "1c57ab4ec5fa85d08aaf8ed9245899d9bbdd66768945b21113b84d5f595cb6a1"
|
"checksum serde 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "db99f3919e20faa51bb2996057f5031d8685019b5a06139b1ce761da671b8526"
|
||||||
"checksum serde_derive 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "02c92ea07b6e49b959c1481804ebc9bfd92d3c459f1274c9a9546829e42a66ce"
|
"checksum serde_derive 1.0.27 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ba7591cfe93755e89eeecdbcc668885624829b020050e6aec99c2a03bd3fd0"
|
||||||
"checksum serde_derive_internals 0.18.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75c6aac7b99801a16db5b40b7bf0d7e4ba16e76fbf231e32a4677f271cac0603"
|
"checksum serde_derive_internals 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6e03f1c9530c3fb0a0a5c9b826bdd9246a5921ae995d75f512ac917fc4dd55b5"
|
||||||
"checksum serde_json 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7cf5b0b5b4bd22eeecb7e01ac2e1225c7ef5e4272b79ee28a8392a8c8489c839"
|
"checksum serde_json 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c9db7266c7d63a4c4b7fe8719656ccdd51acf1bed6124b174f933b009fb10bcb"
|
||||||
"checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c"
|
"checksum sha1 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cc30b1e1e8c40c121ca33b86c23308a090d19974ef001b4bf6e61fd1a0fb095c"
|
||||||
"checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
|
"checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
|
||||||
"checksum slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d807fd58c4181bbabed77cb3b891ba9748241a552bcc5be698faaebefc54f46e"
|
"checksum slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d807fd58c4181bbabed77cb3b891ba9748241a552bcc5be698faaebefc54f46e"
|
||||||
@@ -893,18 +991,25 @@ dependencies = [
|
|||||||
"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
|
"checksum textwrap 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0b59b6b4b44d867f1370ef1bd91bfb262bf07bf0ae65c202ea2fbc16153b693"
|
||||||
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
|
"checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03"
|
||||||
"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
|
"checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5"
|
||||||
"checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520"
|
"checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963"
|
||||||
|
"checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098"
|
||||||
"checksum tiny_http 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "016f040cfc9b5be610de3619eaaa57017fa0b0b678187327bde75fc146e2a41f"
|
"checksum tiny_http 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "016f040cfc9b5be610de3619eaaa57017fa0b0b678187327bde75fc146e2a41f"
|
||||||
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||||
"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f"
|
"checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f"
|
||||||
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
|
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
|
||||||
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
|
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
|
||||||
|
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||||
"checksum url 0.2.38 (registry+https://github.com/rust-lang/crates.io-index)" = "cbaa8377a162d88e7d15db0cf110c8523453edcbc5bc66d2b6fffccffa34a068"
|
"checksum url 0.2.38 (registry+https://github.com/rust-lang/crates.io-index)" = "cbaa8377a162d88e7d15db0cf110c8523453edcbc5bc66d2b6fffccffa34a068"
|
||||||
"checksum url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa35e768d4daf1d85733418a49fb42e10d7f633e394fccab4ab7aba897053fe2"
|
"checksum url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa35e768d4daf1d85733418a49fb42e10d7f633e394fccab4ab7aba897053fe2"
|
||||||
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
|
"checksum utf8-ranges 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1ca13c08c41c9c3e04224ed9ff80461d97e121589ff27c753a16cb10830ae0f"
|
||||||
|
"checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122"
|
||||||
"checksum uuid 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "78c590b5bd79ed10aad8fb75f078a59d8db445af6c743e55c4a53227fc01c13f"
|
"checksum uuid 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "78c590b5bd79ed10aad8fb75f078a59d8db445af6c743e55c4a53227fc01c13f"
|
||||||
"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
|
"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
|
||||||
|
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||||
"checksum walkdir 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b6d201f4f8998a837196b6de9c73e35af14c992cbb92c4ab641d2c2dce52de"
|
"checksum walkdir 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b6d201f4f8998a837196b6de9c73e35af14c992cbb92c4ab641d2c2dce52de"
|
||||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||||
|
"checksum winapi 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b09fb3b6f248ea4cd42c9a65113a847d612e17505d6ebd1f7357ad68a8bf8693"
|
||||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||||
|
"checksum winapi-i686-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ec6667f60c23eca65c561e63a13d81b44234c2e38a6b6c959025ee907ec614cc"
|
||||||
|
"checksum winapi-x86_64-pc-windows-gnu 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98f12c52b2630cd05d2c3ffd8e008f7f48252c042b4871c72aed9dc733b96668"
|
||||||
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "rojo"
|
name = "rojo"
|
||||||
version = "0.3.2"
|
version = "0.4.0"
|
||||||
authors = ["Lucien Greathouse <me@lpghatguy.com>"]
|
authors = ["Lucien Greathouse <me@lpghatguy.com>"]
|
||||||
description = "A tool to create robust Roblox projects"
|
description = "A tool to create robust Roblox projects"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
@@ -18,3 +18,5 @@ serde_derive = "1.0"
|
|||||||
serde_json = "1.0"
|
serde_json = "1.0"
|
||||||
notify = "4.0.0"
|
notify = "4.0.0"
|
||||||
rand = "0.3"
|
rand = "0.3"
|
||||||
|
regex = "0.2"
|
||||||
|
lazy_static = "1.0"
|
||||||
|
|||||||
49
DESIGN.md
Normal file
49
DESIGN.md
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# Rojo Design - Protocol Version 1
|
||||||
|
This is a super rough draft that I'm trying to use to lay out some of my thoughts.
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
### POST `/read`
|
||||||
|
Accepts a `Vec<Route>` of items to read.
|
||||||
|
|
||||||
|
Returns `Vec<Option<RbxInstance>>`, in the same order as the request.
|
||||||
|
|
||||||
|
### POST `/write`
|
||||||
|
Accepts a `Vec<{ Route, RbxInstance }>` of items to write.
|
||||||
|
|
||||||
|
I imagine that the `Name` attribute of the top-level `RbxInstance` would be ignored in favor of the route name?
|
||||||
|
|
||||||
|
## CLI
|
||||||
|
The `rojo serve` command uses three major components:
|
||||||
|
* A Virtual Filesystem (VFS), which exposes the filesystem as `VfsItem` objects
|
||||||
|
* A VFS watcher, which tracks changes to the filesystem and logs them
|
||||||
|
* An HTTP API, which exposes an interface to the Roblox Studio plugin
|
||||||
|
|
||||||
|
### Transform Plugins
|
||||||
|
Transform plugins (or filter plugins?) can interject in three places:
|
||||||
|
* Transform a `VfsItem` that's being read into an `RbxInstance` in the VFS
|
||||||
|
* Transform an `RbxInstance` that's being written into a `VfsItem` in the VFS
|
||||||
|
* Transform a file change into paths that need to be updated in the VFS watcher
|
||||||
|
|
||||||
|
The plan is to have several built-in plugins that can be rearranged/configured in project settings:
|
||||||
|
|
||||||
|
* Base plugin
|
||||||
|
* Transforms all unhandled files to/from StringValue objects
|
||||||
|
* Script plugin
|
||||||
|
* Transforms `*.lua` files to their appropriate file types
|
||||||
|
* JSON/rbxmx/rbxlx model plugin
|
||||||
|
* External binary plugin
|
||||||
|
* User passes a binary name (like `moonc`) that modifies file contents
|
||||||
|
|
||||||
|
## Roblox Studio Plugin
|
||||||
|
With the protocol version 1 change, the Roblox Studio plugin got a lot simpler. Notably, the plugin doesn't need to be aware of anything about the filesystem's semantics, which is super handy.
|
||||||
|
|
||||||
|
## Bi-directional syncing
|
||||||
|
Quenty laid out a good way to handle bi-directional syncing.
|
||||||
|
|
||||||
|
When receiving a change from the plugin:
|
||||||
|
1. Hash the new contents of the file, store it in a map from routes to hashes
|
||||||
|
2. Write the new file contents to the filesystem
|
||||||
|
3. Later down the line, receive a change event from the filesystem watcher
|
||||||
|
4. When receiving a change, if the item is in the hash map, read it and hash those contents
|
||||||
|
5. If the hash matches the last noted hash, discard the change, else continue as normal
|
||||||
30
README.md
30
README.md
@@ -1,17 +1,24 @@
|
|||||||
<h1 align="center">Rojo</h1>
|
<div align="center">
|
||||||
|
<img src="assets/rojo-logo.png" alt="Rojo" height="150" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div> </div>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<a href="https://travis-ci.org/LPGhatguy/rojo">
|
<a href="https://travis-ci.org/LPGhatguy/rojo">
|
||||||
<img src="https://api.travis-ci.org/LPGhatguy/rojo.svg?branch=master" alt="Travis-CI Build Status" />
|
<img src="https://api.travis-ci.org/LPGhatguy/rojo.svg?branch=master" alt="Travis-CI Build Status" />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div> </div>
|
<hr />
|
||||||
|
|
||||||
Rojo is a flexible multi-tool designed for creating robust Roblox projects. It's in early development, but is still useful for many projects.
|
**Rojo** is a flexible multi-tool designed for creating robust Roblox projects. It's in early development, but is still useful for many projects.
|
||||||
|
|
||||||
It's designed for power users who want to use the **best tools available** for building games, libraries, and plugins.
|
It's designed for power users who want to use the **best tools available** for building games, libraries, and plugins.
|
||||||
|
|
||||||
This is the main Rojo repository, containing the binary server component. For the source for the Roblox plugin, [see the rojo-plugin repository](https://github.com/LPGhatguy/rojo-plugin).
|
This is the main Rojo repository, containing the binary and project server component. For the source for the Roblox plugin, [see the rojo-plugin repository](https://github.com/LPGhatguy/rojo-plugin).
|
||||||
|
|
||||||
|
The master branches of both respositories should always pass all tests and be functional, but are not suitable for production use!
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
@@ -19,10 +26,11 @@ Rojo has a number of desirable features *right now*:
|
|||||||
|
|
||||||
* Work on scripts from the filesystem, in your favorite editor
|
* Work on scripts from the filesystem, in your favorite editor
|
||||||
* Version your place, library, or plugin using Git or another VCS
|
* Version your place, library, or plugin using Git or another VCS
|
||||||
|
* Sync JSON-format models from the filesystem into your game
|
||||||
|
|
||||||
Soon, Rojo will be able to:
|
Later this year, Rojo will be able to:
|
||||||
|
|
||||||
* Sync Roblox objects (including models) bi-directionally between the filesystem and Roblox Studio
|
* Sync rbxmx-format Roblox models bi-directionally between the filesystem and Roblox Studio
|
||||||
* Create installation scripts for libraries to be used in standalone places
|
* Create installation scripts for libraries to be used in standalone places
|
||||||
* Similar to [rbxpacker](https://github.com/LPGhatguy/rbxpacker), another one of my projects
|
* Similar to [rbxpacker](https://github.com/LPGhatguy/rbxpacker), another one of my projects
|
||||||
* Add strongly-versioned dependencies to your project
|
* Add strongly-versioned dependencies to your project
|
||||||
@@ -96,7 +104,7 @@ For example, if you want to map your `src` directory to an object named `My Cool
|
|||||||
|
|
||||||
The `path` parameter is relative to the project file.
|
The `path` parameter is relative to the project file.
|
||||||
|
|
||||||
The `target` starts at `game` and crawls down the tree. If any objects don't exist along the way, they'll be created as `Folder` instances.
|
The `target` parameter is a path to a Roblox object to link the partition to. It starts at `game` and crawls down the tree. If any objects don't exist along the way, they'll be created as `Folder` instances.
|
||||||
|
|
||||||
Run `rojo serve` in the directory containing this project, then press the "Sync In" or "Toggle Polling" buttons in the Roblox Studio plugin to move code into your game.
|
Run `rojo serve` in the directory containing this project, then press the "Sync In" or "Toggle Polling" buttons in the Roblox Studio plugin to move code into your game.
|
||||||
|
|
||||||
@@ -110,6 +118,7 @@ Creation of Roblox instances follows a simple set of rules. The first rule that
|
|||||||
| `*.server.lua` | `Script` | `Source` will contain the file's contents |
|
| `*.server.lua` | `Script` | `Source` will contain the file's contents |
|
||||||
| `*.client.lua` | `LocalScript` | `Source` will contain the file's contents |
|
| `*.client.lua` | `LocalScript` | `Source` will contain the file's contents |
|
||||||
| `*.lua` | `ModuleScript` | `Source` will contain the file's contents |
|
| `*.lua` | `ModuleScript` | `Source` will contain the file's contents |
|
||||||
|
| `*.model.json` | *Varies* | See [this file](test-project/src/hello.model.json) for an example model |
|
||||||
| `*` | `StringValue` | `Value` will contain the file's contents |
|
| `*` | `StringValue` | `Value` will contain the file's contents |
|
||||||
|
|
||||||
Any folders on the filesystem will turn into `Folder` objects unless they contain a file named `init.lua`, `init.server.lua`, or `init.client.lua`. Following the convention of Lua, those objects will instead be whatever the `init` file would turn into.
|
Any folders on the filesystem will turn into `Folder` objects unless they contain a file named `init.lua`, `init.server.lua`, or `init.client.lua`. Following the convention of Lua, those objects will instead be whatever the `init` file would turn into.
|
||||||
@@ -139,5 +148,12 @@ I also have a couple tools that Rojo intends to replace:
|
|||||||
* [rbxfs](https://github.com/LPGhatguy/rbxfs), which has been deprecated by Rojo
|
* [rbxfs](https://github.com/LPGhatguy/rbxfs), which has been deprecated by Rojo
|
||||||
* [rbxpacker](https://github.com/LPGhatguy/rbxpacker), which is still useful
|
* [rbxpacker](https://github.com/LPGhatguy/rbxpacker), which is still useful
|
||||||
|
|
||||||
|
## Contributing
|
||||||
|
Pull requests are welcome!
|
||||||
|
|
||||||
|
The `master` branch of both repositories have tests running on Travis for every commit and pull request. The test suite on `master` should always pass!
|
||||||
|
|
||||||
|
The Rojo and Rojo Plugin repositories should stay in sync with eachother, so that the current `master` of each repository can be used together.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
Rojo is available under the terms of the MIT license. See [LICENSE.md](LICENSE.md) for details.
|
Rojo is available under the terms of the MIT license. See [LICENSE.md](LICENSE.md) for details.
|
||||||
BIN
assets/rojo-logo.png
Normal file
BIN
assets/rojo-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
147
src/bin.rs
147
src/bin.rs
@@ -1,33 +1,27 @@
|
|||||||
#[macro_use]
|
#[macro_use] extern crate serde_derive;
|
||||||
extern crate serde_derive;
|
#[macro_use] extern crate rouille;
|
||||||
|
#[macro_use] extern crate clap;
|
||||||
#[macro_use]
|
#[macro_use] extern crate lazy_static;
|
||||||
extern crate rouille;
|
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate clap;
|
|
||||||
|
|
||||||
extern crate notify;
|
extern crate notify;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
extern crate serde;
|
extern crate serde;
|
||||||
extern crate serde_json;
|
extern crate serde_json;
|
||||||
|
extern crate regex;
|
||||||
|
|
||||||
pub mod web;
|
pub mod web;
|
||||||
pub mod core;
|
pub mod core;
|
||||||
pub mod project;
|
pub mod project;
|
||||||
pub mod pathext;
|
pub mod pathext;
|
||||||
pub mod vfs;
|
pub mod vfs;
|
||||||
pub mod vfs_watch;
|
pub mod rbx;
|
||||||
|
pub mod plugin;
|
||||||
|
pub mod plugins;
|
||||||
|
pub mod commands;
|
||||||
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::process;
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
use core::Config;
|
|
||||||
use pathext::canonicalish;
|
use pathext::canonicalish;
|
||||||
use project::{Project, ProjectLoadError};
|
|
||||||
use vfs::Vfs;
|
|
||||||
use vfs_watch::VfsWatcher;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let matches = clap_app!(rojo =>
|
let matches = clap_app!(rojo =>
|
||||||
@@ -59,27 +53,13 @@ fn main() {
|
|||||||
_ => true,
|
_ => true,
|
||||||
};
|
};
|
||||||
|
|
||||||
let server_id = rand::random::<u64>();
|
|
||||||
|
|
||||||
if verbose {
|
|
||||||
println!("Server ID: {}", server_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
match matches.subcommand() {
|
match matches.subcommand() {
|
||||||
("init", sub_matches) => {
|
("init", sub_matches) => {
|
||||||
let sub_matches = sub_matches.unwrap();
|
let sub_matches = sub_matches.unwrap();
|
||||||
let project_path = Path::new(sub_matches.value_of("PATH").unwrap_or("."));
|
let project_path = Path::new(sub_matches.value_of("PATH").unwrap_or("."));
|
||||||
let full_path = canonicalish(project_path);
|
let full_path = canonicalish(project_path);
|
||||||
|
|
||||||
match Project::init(&full_path) {
|
commands::init(&full_path);
|
||||||
Ok(_) => {
|
|
||||||
println!("Created new empty project at {}", full_path.display());
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("Failed to create new project.\n{}", e);
|
|
||||||
std::process::exit(1);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
("serve", sub_matches) => {
|
("serve", sub_matches) => {
|
||||||
let sub_matches = sub_matches.unwrap();
|
let sub_matches = sub_matches.unwrap();
|
||||||
@@ -89,122 +69,29 @@ fn main() {
|
|||||||
None => std::env::current_dir().unwrap(),
|
None => std::env::current_dir().unwrap(),
|
||||||
};
|
};
|
||||||
|
|
||||||
if verbose {
|
|
||||||
println!("Attempting to locate project at {}", project_path.display());
|
|
||||||
}
|
|
||||||
|
|
||||||
let project = match Project::load(&project_path) {
|
|
||||||
Ok(v) => {
|
|
||||||
println!("Using project from {}", project_path.display());
|
|
||||||
v
|
|
||||||
},
|
|
||||||
Err(err) => {
|
|
||||||
match err {
|
|
||||||
ProjectLoadError::InvalidJson(serde_err) => {
|
|
||||||
eprintln!(
|
|
||||||
"Found invalid JSON!\nProject in: {}\nError: {}",
|
|
||||||
project_path.display(),
|
|
||||||
serde_err,
|
|
||||||
);
|
|
||||||
|
|
||||||
std::process::exit(1);
|
|
||||||
},
|
|
||||||
ProjectLoadError::FailedToOpen | ProjectLoadError::FailedToRead => {
|
|
||||||
eprintln!("Found project file, but failed to read it!");
|
|
||||||
eprintln!(
|
|
||||||
"Check the permissions of the project file at\n{}",
|
|
||||||
project_path.display(),
|
|
||||||
);
|
|
||||||
|
|
||||||
std::process::exit(1);
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
// Any other error is fine; use the default project.
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("Found no project file, using default project...");
|
|
||||||
Project::default()
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let port = {
|
let port = {
|
||||||
match sub_matches.value_of("port") {
|
match sub_matches.value_of("port") {
|
||||||
Some(source) => match source.parse::<u64>() {
|
Some(source) => match source.parse::<u64>() {
|
||||||
Ok(value) => value,
|
Ok(value) => Some(value),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
eprintln!("Invalid port '{}'", source);
|
eprintln!("Invalid port '{}'", source);
|
||||||
std::process::exit(1);
|
process::exit(1);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
None => project.serve_port,
|
None => None,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let config = Config {
|
commands::serve(&project_path, verbose, port);
|
||||||
port,
|
|
||||||
verbose,
|
|
||||||
server_id,
|
|
||||||
};
|
|
||||||
|
|
||||||
if verbose {
|
|
||||||
println!("Loading VFS...");
|
|
||||||
}
|
|
||||||
|
|
||||||
let vfs = {
|
|
||||||
let mut vfs = Vfs::new(config.clone());
|
|
||||||
|
|
||||||
for (name, project_partition) in &project.partitions {
|
|
||||||
let path = {
|
|
||||||
let given_path = Path::new(&project_partition.path);
|
|
||||||
|
|
||||||
if given_path.is_absolute() {
|
|
||||||
given_path.to_path_buf()
|
|
||||||
} else {
|
|
||||||
project_path.join(given_path)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if verbose {
|
|
||||||
println!(
|
|
||||||
"Partition '{}': {} @ {}",
|
|
||||||
name,
|
|
||||||
project_partition.target,
|
|
||||||
project_partition.path
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
vfs.partitions.insert(name.clone(), path);
|
|
||||||
}
|
|
||||||
|
|
||||||
Arc::new(Mutex::new(vfs))
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
|
||||||
let vfs = vfs.clone();
|
|
||||||
let config = config.clone();
|
|
||||||
|
|
||||||
thread::spawn(move || {
|
|
||||||
VfsWatcher::new(config, vfs).start();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
web::start(config.clone(), project.clone(), vfs.clone());
|
|
||||||
|
|
||||||
println!("Server listening on port {}", port);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
thread::park();
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
("pack", _) => {
|
("pack", _) => {
|
||||||
eprintln!("'rojo pack' is not yet implemented!");
|
eprintln!("'rojo pack' is not yet implemented!");
|
||||||
std::process::exit(1);
|
process::exit(1);
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
eprintln!("Please specify a subcommand!");
|
eprintln!("Please specify a subcommand!");
|
||||||
eprintln!("Try 'rojo help' for information.");
|
eprintln!("Try 'rojo help' for information.");
|
||||||
std::process::exit(1);
|
process::exit(1);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
16
src/commands/init.rs
Normal file
16
src/commands/init.rs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process;
|
||||||
|
|
||||||
|
use project::Project;
|
||||||
|
|
||||||
|
pub fn init(project_path: &PathBuf) {
|
||||||
|
match Project::init(project_path) {
|
||||||
|
Ok(_) => {
|
||||||
|
println!("Created new empty project at {}", project_path.display());
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Failed to create new project.\n{}", e);
|
||||||
|
process::exit(1);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
5
src/commands/mod.rs
Normal file
5
src/commands/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
mod serve;
|
||||||
|
mod init;
|
||||||
|
|
||||||
|
pub use self::serve::*;
|
||||||
|
pub use self::init::*;
|
||||||
99
src/commands/serve.rs
Normal file
99
src/commands/serve.rs
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
use std::process;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
use rand;
|
||||||
|
|
||||||
|
use project::{Project, ProjectLoadError};
|
||||||
|
use plugin::{PluginChain};
|
||||||
|
use plugins::{DefaultPlugin, JsonModelPlugin, ScriptPlugin};
|
||||||
|
use vfs::{VfsSession, VfsWatcher};
|
||||||
|
use web;
|
||||||
|
|
||||||
|
pub fn serve(project_path: &PathBuf, verbose: bool, port: Option<u64>) {
|
||||||
|
let server_id = rand::random::<u64>();
|
||||||
|
|
||||||
|
if verbose {
|
||||||
|
println!("Attempting to locate project at {}...", project_path.display());
|
||||||
|
}
|
||||||
|
|
||||||
|
let project = match Project::load(project_path) {
|
||||||
|
Ok(v) => {
|
||||||
|
println!("Using project from {}", project_path.display());
|
||||||
|
v
|
||||||
|
},
|
||||||
|
Err(err) => {
|
||||||
|
match err {
|
||||||
|
ProjectLoadError::InvalidJson(serde_err) => {
|
||||||
|
eprintln!(
|
||||||
|
"Found invalid JSON!\nProject in: {}\nError: {}",
|
||||||
|
project_path.display(),
|
||||||
|
serde_err,
|
||||||
|
);
|
||||||
|
|
||||||
|
process::exit(1);
|
||||||
|
},
|
||||||
|
ProjectLoadError::FailedToOpen | ProjectLoadError::FailedToRead => {
|
||||||
|
eprintln!("Found project file, but failed to read it!");
|
||||||
|
eprintln!(
|
||||||
|
"Check the permissions of the project file at\n{}",
|
||||||
|
project_path.display(),
|
||||||
|
);
|
||||||
|
|
||||||
|
process::exit(1);
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
// Any other error is fine; use the default project.
|
||||||
|
println!("Found no project file, using default project...");
|
||||||
|
Project::default()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let web_config = web::WebConfig {
|
||||||
|
verbose,
|
||||||
|
port: port.unwrap_or(project.serve_port),
|
||||||
|
server_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref PLUGIN_CHAIN: PluginChain = PluginChain::new(vec![
|
||||||
|
Box::new(ScriptPlugin::new()),
|
||||||
|
Box::new(JsonModelPlugin::new()),
|
||||||
|
Box::new(DefaultPlugin::new()),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let vfs = {
|
||||||
|
let mut vfs = VfsSession::new(&PLUGIN_CHAIN);
|
||||||
|
|
||||||
|
for (name, project_partition) in &project.partitions {
|
||||||
|
let path = {
|
||||||
|
let given_path = Path::new(&project_partition.path);
|
||||||
|
|
||||||
|
if given_path.is_absolute() {
|
||||||
|
given_path.to_path_buf()
|
||||||
|
} else {
|
||||||
|
project_path.join(given_path)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
vfs.insert_partition(name, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Arc::new(Mutex::new(vfs))
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("Server listening on port {}", web_config.port);
|
||||||
|
|
||||||
|
{
|
||||||
|
let vfs = vfs.clone();
|
||||||
|
thread::spawn(move || {
|
||||||
|
VfsWatcher::new(vfs).start();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
web::start(web_config, project.clone(), &PLUGIN_CHAIN, vfs.clone());
|
||||||
|
}
|
||||||
@@ -1,6 +1 @@
|
|||||||
#[derive(Debug, Clone)]
|
pub type Route = Vec<String>;
|
||||||
pub struct Config {
|
|
||||||
pub port: u64,
|
|
||||||
pub verbose: bool,
|
|
||||||
pub server_id: u64,
|
|
||||||
}
|
|
||||||
|
|||||||
82
src/plugin.rs
Normal file
82
src/plugin.rs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
use rbx::RbxInstance;
|
||||||
|
use vfs::VfsItem;
|
||||||
|
use core::Route;
|
||||||
|
|
||||||
|
pub enum TransformFileResult {
|
||||||
|
Value(Option<RbxInstance>),
|
||||||
|
Pass,
|
||||||
|
|
||||||
|
// TODO: Error case
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum RbxChangeResult {
|
||||||
|
Write(Option<VfsItem>),
|
||||||
|
Pass,
|
||||||
|
|
||||||
|
// TODO: Error case
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum FileChangeResult {
|
||||||
|
MarkChanged(Option<Vec<Route>>),
|
||||||
|
Pass,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Plugin {
|
||||||
|
/// Invoked when a file is read from the filesystem and needs to be turned
|
||||||
|
/// into a Roblox instance.
|
||||||
|
fn transform_file(&self, plugins: &PluginChain, vfs_item: &VfsItem) -> TransformFileResult;
|
||||||
|
|
||||||
|
/// Invoked when a Roblox Instance change is reported by the Roblox Studio
|
||||||
|
/// plugin and needs to be turned into a file to save.
|
||||||
|
fn handle_rbx_change(&self, route: &Route, rbx_item: &RbxInstance) -> RbxChangeResult;
|
||||||
|
|
||||||
|
/// Invoked when a file changes on the filesystem. The result defines what
|
||||||
|
/// routes are marked as needing to be refreshed.
|
||||||
|
fn handle_file_change(&self, route: &Route) -> FileChangeResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A set of plugins that are composed in order.
|
||||||
|
pub struct PluginChain {
|
||||||
|
plugins: Vec<Box<Plugin + Send + Sync>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PluginChain {
|
||||||
|
pub fn new(plugins: Vec<Box<Plugin + Send + Sync>>) -> PluginChain {
|
||||||
|
PluginChain {
|
||||||
|
plugins,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn transform_file(&self, vfs_item: &VfsItem) -> Option<RbxInstance> {
|
||||||
|
for plugin in &self.plugins {
|
||||||
|
match plugin.transform_file(self, vfs_item) {
|
||||||
|
TransformFileResult::Value(rbx_item) => return rbx_item,
|
||||||
|
TransformFileResult::Pass => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_rbx_change(&self, route: &Route, rbx_item: &RbxInstance) -> Option<VfsItem> {
|
||||||
|
for plugin in &self.plugins {
|
||||||
|
match plugin.handle_rbx_change(route, rbx_item) {
|
||||||
|
RbxChangeResult::Write(vfs_item) => return vfs_item,
|
||||||
|
RbxChangeResult::Pass => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_file_change(&self, route: &Route) -> Option<Vec<Route>> {
|
||||||
|
for plugin in &self.plugins {
|
||||||
|
match plugin.handle_file_change(route) {
|
||||||
|
FileChangeResult::MarkChanged(changes) => return changes,
|
||||||
|
FileChangeResult::Pass => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
67
src/plugins/default_plugin.rs
Normal file
67
src/plugins/default_plugin.rs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use core::Route;
|
||||||
|
use plugin::{Plugin, PluginChain, TransformFileResult, RbxChangeResult, FileChangeResult};
|
||||||
|
use rbx::{RbxInstance, RbxValue};
|
||||||
|
use vfs::VfsItem;
|
||||||
|
|
||||||
|
/// A plugin with simple transforms:
|
||||||
|
/// * Directories become Folder instances
|
||||||
|
/// * Files become StringValue objects with 'Value' as their contents
|
||||||
|
pub struct DefaultPlugin;
|
||||||
|
|
||||||
|
impl DefaultPlugin {
|
||||||
|
pub fn new() -> DefaultPlugin {
|
||||||
|
DefaultPlugin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Plugin for DefaultPlugin {
|
||||||
|
fn transform_file(&self, plugins: &PluginChain, vfs_item: &VfsItem) -> TransformFileResult {
|
||||||
|
match vfs_item {
|
||||||
|
&VfsItem::File { ref contents, .. } => {
|
||||||
|
let mut properties = HashMap::new();
|
||||||
|
|
||||||
|
properties.insert("Value".to_string(), RbxValue::String {
|
||||||
|
value: contents.clone(),
|
||||||
|
});
|
||||||
|
|
||||||
|
TransformFileResult::Value(Some(RbxInstance {
|
||||||
|
name: vfs_item.name().clone(),
|
||||||
|
class_name: "StringValue".to_string(),
|
||||||
|
children: Vec::new(),
|
||||||
|
properties,
|
||||||
|
route: Some(vfs_item.route().to_vec()),
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
&VfsItem::Dir { ref children, .. } => {
|
||||||
|
let mut rbx_children = Vec::new();
|
||||||
|
|
||||||
|
for (_, child_item) in children {
|
||||||
|
match plugins.transform_file(child_item) {
|
||||||
|
Some(rbx_item) => {
|
||||||
|
rbx_children.push(rbx_item);
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TransformFileResult::Value(Some(RbxInstance {
|
||||||
|
name: vfs_item.name().clone(),
|
||||||
|
class_name: "*".to_string(),
|
||||||
|
children: rbx_children,
|
||||||
|
properties: HashMap::new(),
|
||||||
|
route: Some(vfs_item.route().to_vec()),
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_file_change(&self, route: &Route) -> FileChangeResult {
|
||||||
|
FileChangeResult::MarkChanged(Some(vec![route.clone()]))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_rbx_change(&self, _route: &Route, _rbx_item: &RbxInstance) -> RbxChangeResult {
|
||||||
|
RbxChangeResult::Pass
|
||||||
|
}
|
||||||
|
}
|
||||||
55
src/plugins/json_model_plugin.rs
Normal file
55
src/plugins/json_model_plugin.rs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
use regex::Regex;
|
||||||
|
use serde_json;
|
||||||
|
|
||||||
|
use core::Route;
|
||||||
|
use plugin::{Plugin, PluginChain, TransformFileResult, RbxChangeResult, FileChangeResult};
|
||||||
|
use rbx::RbxInstance;
|
||||||
|
use vfs::VfsItem;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref JSON_MODEL_PATTERN: Regex = Regex::new(r"^(.*?)\.model\.json$").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct JsonModelPlugin;
|
||||||
|
|
||||||
|
impl JsonModelPlugin {
|
||||||
|
pub fn new() -> JsonModelPlugin {
|
||||||
|
JsonModelPlugin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Plugin for JsonModelPlugin {
|
||||||
|
fn transform_file(&self, _plugins: &PluginChain, vfs_item: &VfsItem) -> TransformFileResult {
|
||||||
|
match vfs_item {
|
||||||
|
&VfsItem::File { ref contents, .. } => {
|
||||||
|
let rbx_name = match JSON_MODEL_PATTERN.captures(vfs_item.name()) {
|
||||||
|
Some(captures) => captures.get(1).unwrap().as_str().to_string(),
|
||||||
|
None => return TransformFileResult::Pass,
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut rbx_item: RbxInstance = match serde_json::from_str(contents) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Unable to parse JSON Model File named {}: {}", vfs_item.name(), e);
|
||||||
|
|
||||||
|
return TransformFileResult::Pass; // This should be an error in the future!
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
rbx_item.route = Some(vfs_item.route().to_vec());
|
||||||
|
rbx_item.name = rbx_name;
|
||||||
|
|
||||||
|
TransformFileResult::Value(Some(rbx_item))
|
||||||
|
},
|
||||||
|
&VfsItem::Dir { .. } => TransformFileResult::Pass,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_file_change(&self, _route: &Route) -> FileChangeResult {
|
||||||
|
FileChangeResult::Pass
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_rbx_change(&self, _route: &Route, _rbx_item: &RbxInstance) -> RbxChangeResult {
|
||||||
|
RbxChangeResult::Pass
|
||||||
|
}
|
||||||
|
}
|
||||||
7
src/plugins/mod.rs
Normal file
7
src/plugins/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
mod default_plugin;
|
||||||
|
mod script_plugin;
|
||||||
|
mod json_model_plugin;
|
||||||
|
|
||||||
|
pub use self::default_plugin::*;
|
||||||
|
pub use self::script_plugin::*;
|
||||||
|
pub use self::json_model_plugin::*;
|
||||||
124
src/plugins/script_plugin.rs
Normal file
124
src/plugins/script_plugin.rs
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
use core::Route;
|
||||||
|
use plugin::{Plugin, PluginChain, TransformFileResult, RbxChangeResult, FileChangeResult};
|
||||||
|
use rbx::{RbxInstance, RbxValue};
|
||||||
|
use vfs::VfsItem;
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref SERVER_PATTERN: Regex = Regex::new(r"^(.*?)\.server\.lua$").unwrap();
|
||||||
|
static ref CLIENT_PATTERN: Regex = Regex::new(r"^(.*?)\.client\.lua$").unwrap();
|
||||||
|
static ref MODULE_PATTERN: Regex = Regex::new(r"^(.*?)\.lua$").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
static SERVER_INIT: &'static str = "init.server.lua";
|
||||||
|
static CLIENT_INIT: &'static str = "init.client.lua";
|
||||||
|
static MODULE_INIT: &'static str = "init.lua";
|
||||||
|
|
||||||
|
pub struct ScriptPlugin;
|
||||||
|
|
||||||
|
impl ScriptPlugin {
|
||||||
|
pub fn new() -> ScriptPlugin {
|
||||||
|
ScriptPlugin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Plugin for ScriptPlugin {
|
||||||
|
fn transform_file(&self, plugins: &PluginChain, vfs_item: &VfsItem) -> TransformFileResult {
|
||||||
|
match vfs_item {
|
||||||
|
&VfsItem::File { ref contents, .. } => {
|
||||||
|
let name = vfs_item.name();
|
||||||
|
|
||||||
|
let (class_name, rbx_name) = {
|
||||||
|
if let Some(captures) = SERVER_PATTERN.captures(name) {
|
||||||
|
("Script".to_string(), captures.get(1).unwrap().as_str().to_string())
|
||||||
|
} else if let Some(captures) = CLIENT_PATTERN.captures(name) {
|
||||||
|
("LocalScript".to_string(), captures.get(1).unwrap().as_str().to_string())
|
||||||
|
} else if let Some(captures) = MODULE_PATTERN.captures(name) {
|
||||||
|
("ModuleScript".to_string(), captures.get(1).unwrap().as_str().to_string())
|
||||||
|
} else {
|
||||||
|
return TransformFileResult::Pass;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut properties = HashMap::new();
|
||||||
|
|
||||||
|
properties.insert("Source".to_string(), RbxValue::String {
|
||||||
|
value: contents.clone(),
|
||||||
|
});
|
||||||
|
|
||||||
|
TransformFileResult::Value(Some(RbxInstance {
|
||||||
|
name: rbx_name,
|
||||||
|
class_name: class_name,
|
||||||
|
children: Vec::new(),
|
||||||
|
properties,
|
||||||
|
route: Some(vfs_item.route().to_vec()),
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
&VfsItem::Dir { ref children, .. } => {
|
||||||
|
let init_item = {
|
||||||
|
let maybe_item = children.get(SERVER_INIT)
|
||||||
|
.or(children.get(CLIENT_INIT))
|
||||||
|
.or(children.get(MODULE_INIT));
|
||||||
|
|
||||||
|
match maybe_item {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return TransformFileResult::Pass,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut rbx_item = match self.transform_file(plugins, init_item) {
|
||||||
|
TransformFileResult::Value(Some(item)) => item,
|
||||||
|
_ => {
|
||||||
|
eprintln!("Inconsistency detected in ScriptPlugin!");
|
||||||
|
return TransformFileResult::Pass;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
rbx_item.name.clear();
|
||||||
|
rbx_item.name.push_str(vfs_item.name());
|
||||||
|
|
||||||
|
for (child_name, child_item) in children {
|
||||||
|
if child_name == init_item.name() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
match plugins.transform_file(child_item) {
|
||||||
|
Some(child_rbx_item) => {
|
||||||
|
rbx_item.children.push(child_rbx_item);
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TransformFileResult::Value(Some(rbx_item))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_file_change(&self, route: &Route) -> FileChangeResult {
|
||||||
|
let leaf = match route.last() {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return FileChangeResult::Pass,
|
||||||
|
};
|
||||||
|
|
||||||
|
let is_init = leaf == SERVER_INIT
|
||||||
|
|| leaf == CLIENT_INIT
|
||||||
|
|| leaf == MODULE_INIT;
|
||||||
|
|
||||||
|
if is_init {
|
||||||
|
let mut changed = route.clone();
|
||||||
|
changed.pop();
|
||||||
|
|
||||||
|
FileChangeResult::MarkChanged(Some(vec![changed]))
|
||||||
|
} else {
|
||||||
|
FileChangeResult::Pass
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_rbx_change(&self, _route: &Route, _rbx_item: &RbxInstance) -> RbxChangeResult {
|
||||||
|
RbxChangeResult::Pass
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -44,10 +44,19 @@ impl fmt::Display for ProjectInitError {
|
|||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ProjectPartition {
|
pub struct ProjectPartition {
|
||||||
|
/// A slash-separated path to a file or folder, relative to the project's
|
||||||
|
/// directory.
|
||||||
pub path: String,
|
pub path: String,
|
||||||
|
|
||||||
|
/// A dot-separated route to a Roblox instance, relative to game.
|
||||||
pub target: String,
|
pub target: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents a project configured by a user for use with Rojo. Holds anything
|
||||||
|
/// that can be configured with `rojo.json`.
|
||||||
|
///
|
||||||
|
/// In the future, this object will hold dependency information and other handy
|
||||||
|
/// configurables
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
#[serde(default, rename_all = "camelCase")]
|
#[serde(default, rename_all = "camelCase")]
|
||||||
pub struct Project {
|
pub struct Project {
|
||||||
@@ -57,6 +66,7 @@ pub struct Project {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Project {
|
impl Project {
|
||||||
|
/// Creates a new empty Project object with the given name.
|
||||||
pub fn new<T: Into<String>>(name: T) -> Project {
|
pub fn new<T: Into<String>>(name: T) -> Project {
|
||||||
Project {
|
Project {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
@@ -64,10 +74,12 @@ impl Project {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Initializes a new project inside the given folder path.
|
||||||
pub fn init<T: AsRef<Path>>(location: T) -> Result<Project, ProjectInitError> {
|
pub fn init<T: AsRef<Path>>(location: T) -> Result<Project, ProjectInitError> {
|
||||||
let location = location.as_ref();
|
let location = location.as_ref();
|
||||||
let package_path = location.join(PROJECT_FILENAME);
|
let package_path = location.join(PROJECT_FILENAME);
|
||||||
|
|
||||||
|
// We abort if the project file already exists.
|
||||||
match fs::metadata(&package_path) {
|
match fs::metadata(&package_path) {
|
||||||
Ok(_) => return Err(ProjectInitError::AlreadyExists),
|
Ok(_) => return Err(ProjectInitError::AlreadyExists),
|
||||||
Err(_) => {},
|
Err(_) => {},
|
||||||
@@ -78,11 +90,14 @@ impl Project {
|
|||||||
Err(_) => return Err(ProjectInitError::FailedToCreate),
|
Err(_) => return Err(ProjectInitError::FailedToCreate),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Try to give the project a meaningful name.
|
||||||
|
// If we can't, we'll just fall back to a default.
|
||||||
let name = match location.file_name() {
|
let name = match location.file_name() {
|
||||||
Some(v) => v.to_string_lossy().into_owned(),
|
Some(v) => v.to_string_lossy().into_owned(),
|
||||||
None => "new-project".to_string(),
|
None => "new-project".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Configure the project with all of the values we know so far.
|
||||||
let project = Project::new(name);
|
let project = Project::new(name);
|
||||||
let serialized = serde_json::to_string_pretty(&project).unwrap();
|
let serialized = serde_json::to_string_pretty(&project).unwrap();
|
||||||
|
|
||||||
@@ -94,6 +109,8 @@ impl Project {
|
|||||||
Ok(project)
|
Ok(project)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Attempts to load a project from the file named PROJECT_FILENAME from the
|
||||||
|
/// given folder.
|
||||||
pub fn load<T: AsRef<Path>>(location: T) -> Result<Project, ProjectLoadError> {
|
pub fn load<T: AsRef<Path>>(location: T) -> Result<Project, ProjectLoadError> {
|
||||||
let package_path = location.as_ref().join(Path::new(PROJECT_FILENAME));
|
let package_path = location.as_ref().join(Path::new(PROJECT_FILENAME));
|
||||||
|
|
||||||
@@ -120,6 +137,7 @@ impl Project {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Saves the given project file to the given folder with the appropriate name.
|
||||||
pub fn save<T: AsRef<Path>>(&self, location: T) -> Result<(), ProjectSaveError> {
|
pub fn save<T: AsRef<Path>>(&self, location: T) -> Result<(), ProjectSaveError> {
|
||||||
let package_path = location.as_ref().join(Path::new(PROJECT_FILENAME));
|
let package_path = location.as_ref().join(Path::new(PROJECT_FILENAME));
|
||||||
|
|
||||||
@@ -139,7 +157,7 @@ impl Project {
|
|||||||
impl Default for Project {
|
impl Default for Project {
|
||||||
fn default() -> Project {
|
fn default() -> Project {
|
||||||
Project {
|
Project {
|
||||||
name: "some-project".to_string(),
|
name: "new-project".to_string(),
|
||||||
serve_port: 8000,
|
serve_port: 8000,
|
||||||
partitions: HashMap::new(),
|
partitions: HashMap::new(),
|
||||||
}
|
}
|
||||||
|
|||||||
34
src/rbx.rs
Normal file
34
src/rbx.rs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
/// Represents data about a Roblox instance
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
pub struct RbxInstance {
|
||||||
|
pub name: String,
|
||||||
|
pub class_name: String,
|
||||||
|
pub children: Vec<RbxInstance>,
|
||||||
|
pub properties: HashMap<String, RbxValue>,
|
||||||
|
|
||||||
|
/// The route that this instance was generated from, if there was one.
|
||||||
|
pub route: Option<Vec<String>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Any kind value that can be used by Roblox
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "PascalCase", tag = "Type")]
|
||||||
|
pub enum RbxValue {
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
String {
|
||||||
|
value: String,
|
||||||
|
},
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
Bool {
|
||||||
|
value: bool,
|
||||||
|
},
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
|
Number {
|
||||||
|
value: f64,
|
||||||
|
},
|
||||||
|
|
||||||
|
// TODO: Compound types like Vector3
|
||||||
|
}
|
||||||
7
src/vfs/mod.rs
Normal file
7
src/vfs/mod.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
mod vfs_session;
|
||||||
|
mod vfs_item;
|
||||||
|
mod vfs_watcher;
|
||||||
|
|
||||||
|
pub use self::vfs_session::*;
|
||||||
|
pub use self::vfs_item::*;
|
||||||
|
pub use self::vfs_watcher::*;
|
||||||
31
src/vfs/vfs_item.rs
Normal file
31
src/vfs/vfs_item.rs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
/// A VfsItem represents either a file or directory as it came from the filesystem.
|
||||||
|
///
|
||||||
|
/// The interface here is intentionally simplified to make it easier to traverse
|
||||||
|
/// files that have been read into memory.
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase", tag = "type")]
|
||||||
|
pub enum VfsItem {
|
||||||
|
File {
|
||||||
|
route: Vec<String>,
|
||||||
|
contents: String,
|
||||||
|
},
|
||||||
|
Dir {
|
||||||
|
route: Vec<String>,
|
||||||
|
children: HashMap<String, VfsItem>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VfsItem {
|
||||||
|
pub fn name(&self) -> &String {
|
||||||
|
self.route().last().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn route(&self) -> &[String] {
|
||||||
|
match self {
|
||||||
|
&VfsItem::File { ref route, .. } => route,
|
||||||
|
&VfsItem::Dir { ref route, .. } => route,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,30 +1,30 @@
|
|||||||
use std::borrow::Borrow;
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use core::Config;
|
use plugin::PluginChain;
|
||||||
|
use vfs::VfsItem;
|
||||||
|
|
||||||
/// Represents a virtual layer over multiple parts of the filesystem.
|
/// Represents a virtual layer over multiple parts of the filesystem.
|
||||||
///
|
///
|
||||||
/// Paths in this system are represented as slices of strings, and are always
|
/// Paths in this system are represented as slices of strings, and are always
|
||||||
/// relative to a partition, which is an absolute path into the real filesystem.
|
/// relative to a partition, which is an absolute path into the real filesystem.
|
||||||
pub struct Vfs {
|
pub struct VfsSession {
|
||||||
/// Contains all of the partitions mounted by the Vfs.
|
/// Contains all of the partitions mounted by the Vfs.
|
||||||
///
|
///
|
||||||
/// These must be absolute paths!
|
/// These must be absolute paths!
|
||||||
pub partitions: HashMap<String, PathBuf>,
|
partitions: HashMap<String, PathBuf>,
|
||||||
|
|
||||||
/// When the Vfs was initialized; used for change tracking.
|
|
||||||
pub start_time: Instant,
|
|
||||||
|
|
||||||
/// A chronologically-sorted list of routes that changed since the Vfs was
|
/// A chronologically-sorted list of routes that changed since the Vfs was
|
||||||
/// created, along with a timestamp denoting when.
|
/// created, along with a timestamp denoting when.
|
||||||
pub change_history: Vec<VfsChange>,
|
change_history: Vec<VfsChange>,
|
||||||
|
|
||||||
config: Config,
|
/// When the Vfs was initialized; used for change tracking.
|
||||||
|
start_time: Instant,
|
||||||
|
|
||||||
|
plugin_chain: &'static PluginChain,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
@@ -34,26 +34,31 @@ pub struct VfsChange {
|
|||||||
route: Vec<String>,
|
route: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
impl VfsSession {
|
||||||
#[serde(rename_all = "camelCase", tag = "type")]
|
pub fn new(plugin_chain: &'static PluginChain) -> VfsSession {
|
||||||
pub enum VfsItem {
|
VfsSession {
|
||||||
File { contents: String },
|
|
||||||
Dir { children: HashMap<String, VfsItem> },
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Vfs {
|
|
||||||
pub fn new(config: Config) -> Vfs {
|
|
||||||
Vfs {
|
|
||||||
partitions: HashMap::new(),
|
partitions: HashMap::new(),
|
||||||
start_time: Instant::now(),
|
start_time: Instant::now(),
|
||||||
change_history: Vec::new(),
|
change_history: Vec::new(),
|
||||||
config,
|
plugin_chain,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn route_to_path<R: Borrow<str>>(&self, route: &[R]) -> Option<PathBuf> {
|
pub fn get_partitions(&self) -> &HashMap<String, PathBuf> {
|
||||||
|
&self.partitions
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert_partition<P: Into<PathBuf>>(&mut self, name: &str, path: P) {
|
||||||
|
let path = path.into();
|
||||||
|
|
||||||
|
assert!(path.is_absolute());
|
||||||
|
|
||||||
|
self.partitions.insert(name.to_string(), path.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
fn route_to_path(&self, route: &[String]) -> Option<PathBuf> {
|
||||||
let (partition_name, rest) = match route.split_first() {
|
let (partition_name, rest) = match route.split_first() {
|
||||||
Some((first, rest)) => (first.borrow(), rest),
|
Some((first, rest)) => (first, rest),
|
||||||
None => return None,
|
None => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -77,7 +82,8 @@ impl Vfs {
|
|||||||
Some(full_path)
|
Some(full_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_dir<P: AsRef<Path>>(&self, path: P) -> Result<VfsItem, ()> {
|
fn read_dir<P: AsRef<Path>>(&self, route: &[String], path: P) -> Result<VfsItem, ()> {
|
||||||
|
let path = path.as_ref();
|
||||||
let reader = match fs::read_dir(path) {
|
let reader = match fs::read_dir(path) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(_) => return Err(()),
|
Err(_) => return Err(()),
|
||||||
@@ -92,11 +98,13 @@ impl Vfs {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let path = entry.path();
|
let path = entry.path();
|
||||||
|
let name = path.file_name().unwrap().to_string_lossy().into_owned();
|
||||||
|
|
||||||
match self.read_path(&path) {
|
let mut child_route = route.iter().cloned().collect::<Vec<_>>();
|
||||||
|
child_route.push(name.clone());
|
||||||
|
|
||||||
|
match self.read_path(&child_route, &path) {
|
||||||
Ok(child_item) => {
|
Ok(child_item) => {
|
||||||
let name = path.file_name().unwrap().to_string_lossy().into_owned();
|
|
||||||
|
|
||||||
children.insert(name, child_item);
|
children.insert(name, child_item);
|
||||||
},
|
},
|
||||||
Err(_) => {},
|
Err(_) => {},
|
||||||
@@ -104,11 +112,13 @@ impl Vfs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok(VfsItem::Dir {
|
Ok(VfsItem::Dir {
|
||||||
|
route: route.iter().cloned().collect::<Vec<_>>(),
|
||||||
children,
|
children,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_file<P: AsRef<Path>>(&self, path: P) -> Result<VfsItem, ()> {
|
fn read_file<P: AsRef<Path>>(&self, route: &[String], path: P) -> Result<VfsItem, ()> {
|
||||||
|
let path = path.as_ref();
|
||||||
let mut file = match File::open(path) {
|
let mut file = match File::open(path) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(_) => return Err(()),
|
Err(_) => return Err(()),
|
||||||
@@ -122,11 +132,12 @@ impl Vfs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Ok(VfsItem::File {
|
Ok(VfsItem::File {
|
||||||
|
route: route.iter().cloned().collect::<Vec<_>>(),
|
||||||
contents,
|
contents,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_path<P: AsRef<Path>>(&self, path: P) -> Result<VfsItem, ()> {
|
fn read_path<P: AsRef<Path>>(&self, route: &[String], path: P) -> Result<VfsItem, ()> {
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
|
|
||||||
let metadata = match fs::metadata(path) {
|
let metadata = match fs::metadata(path) {
|
||||||
@@ -135,31 +146,38 @@ impl Vfs {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if metadata.is_dir() {
|
if metadata.is_dir() {
|
||||||
self.read_dir(path)
|
self.read_dir(route, path)
|
||||||
} else if metadata.is_file() {
|
} else if metadata.is_file() {
|
||||||
self.read_file(path)
|
self.read_file(route, path)
|
||||||
} else {
|
} else {
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the current time, used for logging timestamps for file changes.
|
||||||
pub fn current_time(&self) -> f64 {
|
pub fn current_time(&self) -> f64 {
|
||||||
let elapsed = self.start_time.elapsed();
|
let elapsed = self.start_time.elapsed();
|
||||||
|
|
||||||
elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 * 1e-9
|
elapsed.as_secs() as f64 + elapsed.subsec_nanos() as f64 * 1e-9
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Register a new change to the filesystem at the given timestamp and VFS
|
||||||
|
/// route.
|
||||||
pub fn add_change(&mut self, timestamp: f64, route: Vec<String>) {
|
pub fn add_change(&mut self, timestamp: f64, route: Vec<String>) {
|
||||||
if self.config.verbose {
|
match self.plugin_chain.handle_file_change(&route) {
|
||||||
println!("Added change {:?}", route);
|
Some(routes) => {
|
||||||
|
for route in routes {
|
||||||
|
self.change_history.push(VfsChange {
|
||||||
|
timestamp,
|
||||||
|
route,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.change_history.push(VfsChange {
|
|
||||||
timestamp,
|
|
||||||
route,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Collect a list of changes that occured since the given timestamp.
|
||||||
pub fn changes_since(&self, timestamp: f64) -> &[VfsChange] {
|
pub fn changes_since(&self, timestamp: f64) -> &[VfsChange] {
|
||||||
let mut marker: Option<usize> = None;
|
let mut marker: Option<usize> = None;
|
||||||
|
|
||||||
@@ -178,18 +196,19 @@ impl Vfs {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read<R: Borrow<str>>(&self, route: &[R]) -> Result<VfsItem, ()> {
|
/// Read an item from the filesystem using the given VFS route.
|
||||||
|
pub fn read(&self, route: &[String]) -> Result<VfsItem, ()> {
|
||||||
match self.route_to_path(route) {
|
match self.route_to_path(route) {
|
||||||
Some(path) => self.read_path(&path),
|
Some(path) => self.read_path(route, &path),
|
||||||
None => Err(()),
|
None => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write<R: Borrow<str>>(&self, _route: &[R], _item: VfsItem) -> Result<(), ()> {
|
pub fn write(&self, _route: &[String], _item: VfsItem) -> Result<(), ()> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn delete<R: Borrow<str>>(&self, _route: &[R]) -> Result<(), ()> {
|
pub fn delete(&self, _route: &[String]) -> Result<(), ()> {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
105
src/vfs/vfs_watcher.rs
Normal file
105
src/vfs/vfs_watcher.rs
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
use std::sync::{mpsc, Arc, Mutex};
|
||||||
|
use std::thread;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher};
|
||||||
|
|
||||||
|
use pathext::path_to_route;
|
||||||
|
use vfs::VfsSession;
|
||||||
|
|
||||||
|
/// An object that registers watchers on the real filesystem and relays those
|
||||||
|
/// changes to the virtual filesystem layer.
|
||||||
|
pub struct VfsWatcher {
|
||||||
|
vfs: Arc<Mutex<VfsSession>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VfsWatcher {
|
||||||
|
pub fn new(vfs: Arc<Mutex<VfsSession>>) -> VfsWatcher {
|
||||||
|
VfsWatcher {
|
||||||
|
vfs,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_watcher(
|
||||||
|
vfs: Arc<Mutex<VfsSession>>,
|
||||||
|
rx: mpsc::Receiver<DebouncedEvent>,
|
||||||
|
partition_name: String,
|
||||||
|
root_path: PathBuf,
|
||||||
|
) {
|
||||||
|
loop {
|
||||||
|
let event = rx.recv().unwrap();
|
||||||
|
|
||||||
|
let mut vfs = vfs.lock().unwrap();
|
||||||
|
let current_time = vfs.current_time();
|
||||||
|
|
||||||
|
match event {
|
||||||
|
DebouncedEvent::Write(ref change_path) |
|
||||||
|
DebouncedEvent::Create(ref change_path) |
|
||||||
|
DebouncedEvent::Remove(ref change_path) => {
|
||||||
|
if let Some(mut route) = path_to_route(&root_path, change_path) {
|
||||||
|
route.insert(0, partition_name.clone());
|
||||||
|
|
||||||
|
vfs.add_change(current_time, route);
|
||||||
|
} else {
|
||||||
|
eprintln!("Failed to get route from {}", change_path.display());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
DebouncedEvent::Rename(ref from_change, ref to_change) => {
|
||||||
|
if let Some(mut route) = path_to_route(&root_path, from_change) {
|
||||||
|
route.insert(0, partition_name.clone());
|
||||||
|
|
||||||
|
vfs.add_change(current_time, route);
|
||||||
|
} else {
|
||||||
|
eprintln!("Failed to get route from {}", from_change.display());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(mut route) = path_to_route(&root_path, to_change) {
|
||||||
|
route.insert(0, partition_name.clone());
|
||||||
|
|
||||||
|
vfs.add_change(current_time, route);
|
||||||
|
} else {
|
||||||
|
eprintln!("Failed to get route from {}", to_change.display());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start(self) {
|
||||||
|
let mut watchers = Vec::new();
|
||||||
|
|
||||||
|
// Create an extra scope so that `vfs` gets dropped and unlocked
|
||||||
|
{
|
||||||
|
let vfs = self.vfs.lock().unwrap();
|
||||||
|
|
||||||
|
for (ref partition_name, ref root_path) in vfs.get_partitions() {
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
|
||||||
|
let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(1))
|
||||||
|
.expect("Unable to create watcher!");
|
||||||
|
|
||||||
|
watcher
|
||||||
|
.watch(&root_path, RecursiveMode::Recursive)
|
||||||
|
.expect("Unable to watch path!");
|
||||||
|
|
||||||
|
watchers.push(watcher);
|
||||||
|
|
||||||
|
{
|
||||||
|
let partition_name = partition_name.to_string();
|
||||||
|
let root_path = root_path.to_path_buf();
|
||||||
|
let vfs = self.vfs.clone();
|
||||||
|
|
||||||
|
thread::spawn(move || {
|
||||||
|
Self::start_watcher(vfs, rx, partition_name, root_path);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
loop {
|
||||||
|
thread::park();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
use std::sync::{mpsc, Arc, Mutex};
|
|
||||||
use std::thread;
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher};
|
|
||||||
|
|
||||||
use core::Config;
|
|
||||||
use pathext::path_to_route;
|
|
||||||
use vfs::Vfs;
|
|
||||||
|
|
||||||
pub struct VfsWatcher {
|
|
||||||
vfs: Arc<Mutex<Vfs>>,
|
|
||||||
watchers: Vec<RecommendedWatcher>,
|
|
||||||
config: Config,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl VfsWatcher {
|
|
||||||
pub fn new(config: Config, vfs: Arc<Mutex<Vfs>>) -> VfsWatcher {
|
|
||||||
VfsWatcher {
|
|
||||||
vfs,
|
|
||||||
watchers: Vec::new(),
|
|
||||||
config,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn start(mut self) {
|
|
||||||
{
|
|
||||||
let outer_vfs = self.vfs.lock().unwrap();
|
|
||||||
|
|
||||||
for (partition_name, root_path) in &outer_vfs.partitions {
|
|
||||||
let (tx, rx) = mpsc::channel();
|
|
||||||
let partition_name = partition_name.clone();
|
|
||||||
let root_path = root_path.clone();
|
|
||||||
|
|
||||||
let mut watcher: RecommendedWatcher = Watcher::new(tx, Duration::from_secs(1))
|
|
||||||
.expect("Unable to create watcher!");
|
|
||||||
|
|
||||||
watcher
|
|
||||||
.watch(&root_path, RecursiveMode::Recursive)
|
|
||||||
.expect("Unable to watch path!");
|
|
||||||
|
|
||||||
self.watchers.push(watcher);
|
|
||||||
|
|
||||||
{
|
|
||||||
let vfs = self.vfs.clone();
|
|
||||||
let config = self.config.clone();
|
|
||||||
|
|
||||||
thread::spawn(move || {
|
|
||||||
loop {
|
|
||||||
let event = rx.recv().unwrap();
|
|
||||||
let mut vfs = vfs.lock().unwrap();
|
|
||||||
let current_time = vfs.current_time();
|
|
||||||
|
|
||||||
if config.verbose {
|
|
||||||
println!("FS event {:?}", event);
|
|
||||||
}
|
|
||||||
|
|
||||||
match event {
|
|
||||||
DebouncedEvent::Write(ref change_path) |
|
|
||||||
DebouncedEvent::Create(ref change_path) |
|
|
||||||
DebouncedEvent::Remove(ref change_path) => {
|
|
||||||
if let Some(mut route) = path_to_route(&root_path, change_path) {
|
|
||||||
route.insert(0, partition_name.clone());
|
|
||||||
|
|
||||||
vfs.add_change(current_time, route);
|
|
||||||
} else {
|
|
||||||
println!("Failed to get route from {}", change_path.display());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
DebouncedEvent::Rename(ref from_change, ref to_change) => {
|
|
||||||
if let Some(mut route) = path_to_route(&root_path, from_change) {
|
|
||||||
route.insert(0, partition_name.clone());
|
|
||||||
|
|
||||||
vfs.add_change(current_time, route);
|
|
||||||
} else {
|
|
||||||
println!("Failed to get route from {}", from_change.display());
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(mut route) = path_to_route(&root_path, to_change) {
|
|
||||||
route.insert(0, partition_name.clone());
|
|
||||||
|
|
||||||
vfs.add_change(current_time, route);
|
|
||||||
} else {
|
|
||||||
println!("Failed to get route from {}", to_change.display());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loop {
|
|
||||||
thread::park();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
187
src/web.rs
187
src/web.rs
@@ -1,16 +1,23 @@
|
|||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread;
|
|
||||||
|
|
||||||
use rouille;
|
use rouille;
|
||||||
use serde;
|
use serde;
|
||||||
use serde_json;
|
use serde_json;
|
||||||
|
|
||||||
use core::Config;
|
|
||||||
use project::Project;
|
use project::Project;
|
||||||
use vfs::{Vfs, VfsChange, VfsItem};
|
use vfs::{VfsSession, VfsChange};
|
||||||
|
use rbx::RbxInstance;
|
||||||
|
use plugin::PluginChain;
|
||||||
|
|
||||||
static MAX_BODY_SIZE: usize = 25 * 1024 * 1025; // 25 MiB
|
static MAX_BODY_SIZE: usize = 25 * 1024 * 1024; // 25 MiB
|
||||||
|
|
||||||
|
/// The set of configuration the web server needs to start.
|
||||||
|
pub struct WebConfig {
|
||||||
|
pub port: u64,
|
||||||
|
pub verbose: bool,
|
||||||
|
pub server_id: u64,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
@@ -25,7 +32,7 @@ struct ServerInfo<'a> {
|
|||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
struct ReadResult<'a> {
|
struct ReadResult<'a> {
|
||||||
items: Vec<Option<VfsItem>>,
|
items: Vec<Option<RbxInstance>>,
|
||||||
server_id: &'a str,
|
server_id: &'a str,
|
||||||
current_time: f64,
|
current_time: f64,
|
||||||
}
|
}
|
||||||
@@ -38,12 +45,24 @@ struct ChangesResult<'a> {
|
|||||||
current_time: f64,
|
current_time: f64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct WriteSpecifier {
|
||||||
|
route: String,
|
||||||
|
item: RbxInstance,
|
||||||
|
}
|
||||||
|
|
||||||
fn json<T: serde::Serialize>(value: T) -> rouille::Response {
|
fn json<T: serde::Serialize>(value: T) -> rouille::Response {
|
||||||
let data = serde_json::to_string(&value).unwrap();
|
let data = serde_json::to_string(&value).unwrap();
|
||||||
rouille::Response::from_data("application/json", data)
|
rouille::Response::from_data("application/json", data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pulls text that may be JSON out of a Rouille Request object.
|
||||||
|
///
|
||||||
|
/// Doesn't do any actual parsing -- all this method does is verify the content
|
||||||
|
/// type of the request and read the request's body.
|
||||||
fn read_json_text(request: &rouille::Request) -> Option<String> {
|
fn read_json_text(request: &rouille::Request) -> Option<String> {
|
||||||
|
// Bail out if the request body isn't marked as JSON
|
||||||
match request.header("Content-Type") {
|
match request.header("Content-Type") {
|
||||||
Some(header) => if !header.starts_with("application/json") {
|
Some(header) => if !header.starts_with("application/json") {
|
||||||
return None;
|
return None;
|
||||||
@@ -56,14 +75,15 @@ fn read_json_text(request: &rouille::Request) -> Option<String> {
|
|||||||
None => return None,
|
None => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Allocate a buffer and read up to MAX_BODY_SIZE+1 bytes into it.
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
match body.take(MAX_BODY_SIZE.saturating_add(1) as u64)
|
match body.take(MAX_BODY_SIZE.saturating_add(1) as u64).read_to_end(&mut out) {
|
||||||
.read_to_end(&mut out)
|
|
||||||
{
|
|
||||||
Ok(_) => {},
|
Ok(_) => {},
|
||||||
Err(_) => return None,
|
Err(_) => return None,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the body was too big (MAX_BODY_SIZE+1), we abort instead of trying to
|
||||||
|
// process it.
|
||||||
if out.len() > MAX_BODY_SIZE {
|
if out.len() > MAX_BODY_SIZE {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@@ -76,6 +96,7 @@ fn read_json_text(request: &rouille::Request) -> Option<String> {
|
|||||||
Some(parsed)
|
Some(parsed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads the body out of a Rouille Request and attempts to turn it into JSON.
|
||||||
fn read_json<T>(request: &rouille::Request) -> Option<T>
|
fn read_json<T>(request: &rouille::Request) -> Option<T>
|
||||||
where
|
where
|
||||||
T: serde::de::DeserializeOwned,
|
T: serde::de::DeserializeOwned,
|
||||||
@@ -90,81 +111,115 @@ where
|
|||||||
Err(_) => return None,
|
Err(_) => return None,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: Change return type to some sort of Result
|
||||||
|
|
||||||
Some(parsed)
|
Some(parsed)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn start(config: Config, project: Project, vfs: Arc<Mutex<Vfs>>) {
|
/// Start the Rojo web server and park our current thread.
|
||||||
|
pub fn start(config: WebConfig, project: Project, plugin_chain: &'static PluginChain, vfs: Arc<Mutex<VfsSession>>) {
|
||||||
let address = format!("localhost:{}", config.port);
|
let address = format!("localhost:{}", config.port);
|
||||||
|
|
||||||
let server_id = config.server_id.to_string();
|
let server_id = config.server_id.to_string();
|
||||||
|
|
||||||
thread::spawn(move || {
|
rouille::start_server(address, move |request| {
|
||||||
rouille::start_server(address, move |request| {
|
router!(request,
|
||||||
router!(request,
|
(GET) (/) => {
|
||||||
(GET) (/) => {
|
// Get a summary of information about the server.
|
||||||
let current_time = {
|
|
||||||
let vfs = vfs.lock().unwrap();
|
|
||||||
|
|
||||||
vfs.current_time()
|
let current_time = {
|
||||||
};
|
|
||||||
|
|
||||||
json(ServerInfo {
|
|
||||||
server_version: env!("CARGO_PKG_VERSION"),
|
|
||||||
protocol_version: 0,
|
|
||||||
server_id: &server_id,
|
|
||||||
project: &project,
|
|
||||||
current_time,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
(GET) (/changes/{ last_time: f64 }) => {
|
|
||||||
let vfs = vfs.lock().unwrap();
|
let vfs = vfs.lock().unwrap();
|
||||||
|
|
||||||
|
vfs.current_time()
|
||||||
|
};
|
||||||
|
|
||||||
|
json(ServerInfo {
|
||||||
|
server_version: env!("CARGO_PKG_VERSION"),
|
||||||
|
protocol_version: 1,
|
||||||
|
server_id: &server_id,
|
||||||
|
project: &project,
|
||||||
|
current_time,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
(GET) (/changes/{ last_time: f64 }) => {
|
||||||
|
// Get the list of changes since the given time.
|
||||||
|
|
||||||
|
let vfs = vfs.lock().unwrap();
|
||||||
|
let current_time = vfs.current_time();
|
||||||
|
let changes = vfs.changes_since(last_time);
|
||||||
|
|
||||||
|
json(ChangesResult {
|
||||||
|
changes,
|
||||||
|
server_id: &server_id,
|
||||||
|
current_time,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
(POST) (/read) => {
|
||||||
|
// Read some instances from the server according to a JSON
|
||||||
|
// format body.
|
||||||
|
|
||||||
|
let read_request: Vec<Vec<String>> = match read_json(&request) {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return rouille::Response::empty_400(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Read the files off of the filesystem that the client
|
||||||
|
// requested.
|
||||||
|
let (items, current_time) = {
|
||||||
|
let vfs = vfs.lock().unwrap();
|
||||||
|
|
||||||
let current_time = vfs.current_time();
|
let current_time = vfs.current_time();
|
||||||
let changes = vfs.changes_since(last_time);
|
|
||||||
|
|
||||||
json(ChangesResult {
|
let mut items = Vec::new();
|
||||||
changes,
|
|
||||||
server_id: &server_id,
|
|
||||||
current_time,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
|
|
||||||
(POST) (/read) => {
|
for route in &read_request {
|
||||||
let read_request: Vec<Vec<String>> = match read_json(&request) {
|
match vfs.read(&route) {
|
||||||
Some(v) => v,
|
Ok(v) => items.push(Some(v)),
|
||||||
None => return rouille::Response::empty_400(),
|
Err(_) => items.push(None),
|
||||||
};
|
|
||||||
|
|
||||||
let (items, current_time) = {
|
|
||||||
let vfs = vfs.lock().unwrap();
|
|
||||||
|
|
||||||
let current_time = vfs.current_time();
|
|
||||||
|
|
||||||
let mut items = Vec::new();
|
|
||||||
|
|
||||||
for route in &read_request {
|
|
||||||
match vfs.read(&route) {
|
|
||||||
Ok(v) => items.push(Some(v)),
|
|
||||||
Err(_) => items.push(None),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
(items, current_time)
|
(items, current_time)
|
||||||
};
|
};
|
||||||
|
|
||||||
json(ReadResult {
|
// Transform all of our VfsItem objects into Roblox instances
|
||||||
server_id: &server_id,
|
// the client can use.
|
||||||
items,
|
let rbx_items = items
|
||||||
current_time,
|
.iter()
|
||||||
|
.map(|item| {
|
||||||
|
match *item {
|
||||||
|
Some(ref item) => plugin_chain.transform_file(item),
|
||||||
|
None => None,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
(POST) (/write) => {
|
if config.verbose {
|
||||||
rouille::Response::empty_404()
|
println!("Got read request: {:?}", read_request);
|
||||||
},
|
println!("Responding with:\n\t{:?}", rbx_items);
|
||||||
|
}
|
||||||
|
|
||||||
_ => rouille::Response::empty_404()
|
json(ReadResult {
|
||||||
)
|
server_id: &server_id,
|
||||||
});
|
items: rbx_items,
|
||||||
|
current_time,
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
(POST) (/write) => {
|
||||||
|
// Not yet implemented.
|
||||||
|
|
||||||
|
let _write_request: Vec<WriteSpecifier> = match read_json(&request) {
|
||||||
|
Some(v) => v,
|
||||||
|
None => return rouille::Response::empty_400(),
|
||||||
|
};
|
||||||
|
|
||||||
|
rouille::Response::empty_404()
|
||||||
|
},
|
||||||
|
|
||||||
|
_ => rouille::Response::empty_404()
|
||||||
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"partitions": {
|
"partitions": {
|
||||||
"src": {
|
"src": {
|
||||||
"path": "src",
|
"path": "src",
|
||||||
"target": "ReplicatedStorage.TestProject"
|
"target": "ReplicatedFirst"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
24
test-project/src/hello.model.json
Normal file
24
test-project/src/hello.model.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"Name": "hello",
|
||||||
|
"ClassName": "Model",
|
||||||
|
"Children": [
|
||||||
|
{
|
||||||
|
"Name": "Some Part",
|
||||||
|
"ClassName": "Part",
|
||||||
|
"Children": [],
|
||||||
|
"Properties": {}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Name": "Some StringValue",
|
||||||
|
"ClassName": "StringValue",
|
||||||
|
"Children": [],
|
||||||
|
"Properties": {
|
||||||
|
"Value": {
|
||||||
|
"Type": "String",
|
||||||
|
"Value": "Hello, world!"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Properties": {}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user